Docs · v0.1.0

The SocialKit API.

JSON in, JSON out. Bearer auth, rate-limited. This reference is generated from the OpenAPI spec, so it cannot drift from what the API actually does.

Quickstart

60 seconds
  1. 01

    Create an account

    One public call returns your first key. The plaintext is shown once, store it now.

    curl -X POST https://api.socialkit.sh/v1/account \
      -H "Content-Type: application/json" \
      -d '{ "email": "you@example.com" }'
  2. 02

    Export your key

    export SOCIALKIT_KEY="sk_live_..."
  3. 03

    Score your first post

    curl -X POST https://api.socialkit.sh/v1/score \
      -H "Authorization: Bearer $SOCIALKIT_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "post": "Most onboarding flows fail at step one. We cut ours from 11 fields to 3 and activation jumped 40% in a week."
    }'
  4. 04

    Read the response

    You get an overall score (0-100), a one-line verdict, a per-dimension breakdown, and a ranked list of signals. See ScoreResult.

API reference

52 endpoints

Intelligence

Score, rewrite, plan, generate. The knowledge primitives.

POST/v1/scoreBearer

Grades a draft against the platform's feed-ranking behavior and returns an overall score (0-100), a per-dimension breakdown, ranked signals (what helps, what leaks reach), the detected hook archetype, and the format multiplier. LinkedIn is the only platform live today.

Request body ScoreRequest
Example request
curl -X POST https://api.socialkit.sh/v1/score \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "post": "Most onboarding flows fail at step one. We cut ours from 11 fields to 3 and activation jumped 40% in a week."
}'
Responses
POST/v1/rewriteBearer

Scores the original, rewrites it to lift the weak dimensions without inventing facts, then re-grades the rewrite. Returns both scores and the list of changes made. The after-score is reported as measured; it is never massaged to look like an improvement.

Request body ScoreRequest
Example request
curl -X POST https://api.socialkit.sh/v1/rewrite \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "post": "We are excited to announce that our team has been working hard on some new features we think you will really love."
}'
Responses
  • 200Rewrite producedRewriteResult
  • 400Invalid request bodyError
  • 401Missing or invalid API keyError
  • 429Rate limit exceeded. Two budgets apply per key: an overall request budget (headers `x-ratelimit-limit` / `-remaining` / `-reset`) and a separate, tighter budget for the model-backed endpoints (score, rewrite, generate, plan, and voice distillation), reported on those endpoints as `x-ratelimit-llm-limit` / `-remaining` / `-reset`. Either budget can trigger this response.Error
  • 502The model or gateway misbehaved; safe to retryError
POST/v1/generateBearer

Drafts up to three native LinkedIn posts from a brief, scores each, and returns them sorted by overall score (best first).

Request body GenerateRequest
Example request
curl -X POST https://api.socialkit.sh/v1/generate \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "brief": "A shipping receipt about cutting onboarding to 3 fields",
  "count": 1
}'
Responses
  • 200Candidates generatedGenerateResult
  • 400Invalid request bodyError
  • 401Missing or invalid API keyError
  • 429Rate limit exceeded. Two budgets apply per key: an overall request budget (headers `x-ratelimit-limit` / `-remaining` / `-reset`) and a separate, tighter budget for the model-backed endpoints (score, rewrite, generate, plan, and voice distillation), reported on those endpoints as `x-ratelimit-llm-limit` / `-remaining` / `-reset`. Either budget can trigger this response.Error
  • 502The model or gateway misbehaved; safe to retryError
POST/v1/planBearer

Returns a calendar of post ideas spread across content pillars and hook archetypes. Each item is an outline (hook, angle, format, archetype), not a finished draft. Use generate to expand an item into a post.

Request body PlanRequest
Example request
curl -X POST https://api.socialkit.sh/v1/plan \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "brief": "AI-native engineering and build-in-public receipts",
  "count": 5,
  "cadence": "weekdays"
}'
Responses
  • 200Plan producedPlanResult
  • 400Invalid request bodyError
  • 401Missing or invalid API keyError
  • 429Rate limit exceeded. Two budgets apply per key: an overall request budget (headers `x-ratelimit-limit` / `-remaining` / `-reset`) and a separate, tighter budget for the model-backed endpoints (score, rewrite, generate, plan, and voice distillation), reported on those endpoints as `x-ratelimit-llm-limit` / `-remaining` / `-reset`. Either budget can trigger this response.Error
  • 502The model or gateway misbehaved; safe to retryError

Account

Sign up and manage API keys.

POST/v1/accountPublic

Public endpoint. Creates an account for an email and returns the first API key in plaintext. The plaintext is shown exactly once; store it now. Rate limited per IP.

Example request
curl -X POST https://api.socialkit.sh/v1/account \
  -H "Content-Type: application/json" \
  -d '{
  "email": "string"
}'
Responses
  • 201Account createdCreateAccountResult
  • 400Invalid request bodyError
  • 409An account already exists for that emailError
  • 429Rate limit exceeded. Two budgets apply per key: an overall request budget (headers `x-ratelimit-limit` / `-remaining` / `-reset`) and a separate, tighter budget for the model-backed endpoints (score, rewrite, generate, plan, and voice distillation), reported on those endpoints as `x-ratelimit-llm-limit` / `-remaining` / `-reset`. Either budget can trigger this response.Error
GET/v1/keysBearer

Returns key metadata only. Secrets are never returned.

Example request
curl https://api.socialkit.sh/v1/keys \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
POST/v1/keysBearer
Request body CreateKeyRequest
Example request
curl -X POST https://api.socialkit.sh/v1/keys \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
Responses
POST/v1/keys/{id}/rotateBearer
Path parameters
idrequiredstringThe API key id (e.g. `key_...`).
Example request
curl -X POST https://api.socialkit.sh/v1/keys/key_8fa3c1d9/rotate \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
DELETE/v1/keys/{id}Bearer
Path parameters
idrequiredstringThe API key id (e.g. `key_...`).
Example request
curl -X DELETE https://api.socialkit.sh/v1/keys/key_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses

Memory

Brands and voices. Reusable context that conditions generation: a brand is workspace context, a voice is a writing profile. Pass their ids to generate and plan.

GET/v1/brandsBearer
Example request
curl https://api.socialkit.sh/v1/brands \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
POST/v1/brandsBearer
Request body BrandCreateRequest
Example request
curl -X POST https://api.socialkit.sh/v1/brands \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "SocialKit",
  "description": "The social primitive your agent calls.",
  "audience": "Founders and developers shipping in public.",
  "themes": [
    "shipping receipts",
    "AI-native engineering"
  ],
  "linkPolicy": "Never link out in the body."
}'
Responses
GET/v1/brands/{id}Bearer
Path parameters
idrequiredstringThe brand id (e.g. `brd_...`).
Example request
curl https://api.socialkit.sh/v1/brands/brd_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
PATCH/v1/brands/{id}Bearer

Partial update. Only the fields present in the body are changed.

Path parameters
idrequiredstringThe brand id (e.g. `brd_...`).
Request body BrandUpdateRequest
Example request
curl -X PATCH https://api.socialkit.sh/v1/brands/brd_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
Responses
  • 200Brand updatedBrandResult
  • 400Invalid request bodyError
  • 401Missing or invalid API keyError
  • 404Resource not found for this accountError
DELETE/v1/brands/{id}Bearer

Deletes the brand. Voices attached to it are kept but detached (their brandId becomes null).

Path parameters
idrequiredstringThe brand id (e.g. `brd_...`).
Example request
curl -X DELETE https://api.socialkit.sh/v1/brands/brd_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
GET/v1/voicesBearer
Example request
curl https://api.socialkit.sh/v1/voices \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
POST/v1/voicesBearer

Creates a voice. Supply `samples` and the profile is distilled from them (the common path, same as POST /v1/voices/build). Omit `samples` and the explicit `traits`/`doNot`/`exemplars` you pass are stored as-is.

Request body VoiceCreateRequest
Example request
curl -X POST https://api.socialkit.sh/v1/voices \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Founder voice",
  "samples": [
    "We shipped the new scorer today. 11 dimensions down to 6.",
    "Paused a $675/day campaign. The CAC math stopped working."
  ]
}'
Responses
POST/v1/voices/buildBearer

Reads sample posts, extracts the traits to imitate, the things to never do, and a few exemplar snippets, then saves the result as a voice. Returns the saved voice; pass its id to generate or plan.

Request body BuildVoiceRequest
Example request
curl -X POST https://api.socialkit.sh/v1/voices/build \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Founder voice",
  "samples": [
    "We shipped the new scorer today. 11 dimensions down to 6.",
    "Paused a $675/day campaign. The CAC math stopped working."
  ]
}'
Responses
  • 201Voice built and savedVoiceResult
  • 400Invalid request bodyError
  • 401Missing or invalid API keyError
  • 429Rate limit exceeded. Two budgets apply per key: an overall request budget (headers `x-ratelimit-limit` / `-remaining` / `-reset`) and a separate, tighter budget for the model-backed endpoints (score, rewrite, generate, plan, and voice distillation), reported on those endpoints as `x-ratelimit-llm-limit` / `-remaining` / `-reset`. Either budget can trigger this response.Error
  • 502The model or gateway misbehaved; safe to retryError
GET/v1/voices/{id}Bearer
Path parameters
idrequiredstringThe voice id (e.g. `voi_...`).
Example request
curl https://api.socialkit.sh/v1/voices/voi_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
PATCH/v1/voices/{id}Bearer

Partial update. Only the fields present in the body are changed.

Path parameters
idrequiredstringThe voice id (e.g. `voi_...`).
Request body VoiceUpdateRequest
Example request
curl -X PATCH https://api.socialkit.sh/v1/voices/voi_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
Responses
  • 200Voice updatedVoiceResult
  • 400Invalid request bodyError
  • 401Missing or invalid API keyError
  • 404Resource not found for this accountError
DELETE/v1/voices/{id}Bearer
Path parameters
idrequiredstringThe voice id (e.g. `voi_...`).
Example request
curl -X DELETE https://api.socialkit.sh/v1/voices/voi_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses

Channels

Connected social accounts (OAuth pipes). Connect via the platform's OAuth flow, report health, refresh tokens, and disconnect. Tokens are encrypted at rest and never returned. LinkedIn is the only platform live today.

GET/v1/channelsBearer

Returns channel metadata only. Tokens are never included.

Example request
curl https://api.socialkit.sh/v1/channels \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
POST/v1/channels/linkedin/connectBearer

Starts the OAuth handshake. Returns an authorization URL to redirect the member to, plus the opaque state token that ties the callback back to this account. PKCE is handled for you. Disabled (503) when the deployment has no token-vault key or LinkedIn app credentials.

Example request
curl -X POST https://api.socialkit.sh/v1/channels/linkedin/connect \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
Responses
GET/v1/channels/linkedin/callbackPublic

Where LinkedIn redirects after the member authorizes. Public: trust comes from the single-use, account-bound state, not the query params. Exchanges the code for tokens, seals them into the vault, and returns the connected channel. Not called directly by API clients.

Path parameters
coderequiredstringThe authorization code from LinkedIn.
staterequiredstringThe opaque state token returned by connect.
Example request
curl https://api.socialkit.sh/v1/channels/linkedin/callback
Responses
  • 200Channel connectedChannelResult
  • 400Invalid or expired OAuth stateError
  • 502The token exchange with the platform failedError
  • 503The capability is not configured on this deploymentError
GET/v1/channels/{id}Bearer
Path parameters
idrequiredstringThe channel id (e.g. `chn_...`).
Example request
curl https://api.socialkit.sh/v1/channels/id_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
DELETE/v1/channels/{id}Bearer

Wipes the stored tokens (unrecoverable) and marks the channel revoked. The row is kept for history.

Path parameters
idrequiredstringThe channel id (e.g. `chn_...`).
Example request
curl -X DELETE https://api.socialkit.sh/v1/channels/id_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
POST/v1/channels/{id}/refreshBearer

Refreshes the access token if it is at or near expiry; a no-op when the token is still fresh. Returns the current channel either way.

Path parameters
idrequiredstringThe channel id (e.g. `chn_...`).
Example request
curl -X POST https://api.socialkit.sh/v1/channels/id_8fa3c1d9/refresh \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
  • 200Channel refreshed (or already fresh)ChannelResult
  • 401Missing or invalid API keyError
  • 404Resource not found for this accountError
  • 502The token refresh with the platform failedError
  • 503The capability is not configured on this deploymentError

Media

Uploaded images, video, and PDF carousels referenced by posts at publish time. Bytes are stored in object storage; the API returns metadata and a content download endpoint.

GET/v1/mediaBearer

Results are paginated newest-first; page with limit and offset and follow pagination.hasMore.

Path parameters
limitrequiredintegerMaximum media items to return (default 50, max 100).
offsetrequiredintegerNumber of media items to skip from the newest.
Example request
curl https://api.socialkit.sh/v1/media \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
POST/v1/mediaBearer

Upload raw bytes with the file's Content-Type header (validated against an allowlist). Optionally scope to a brand with the brandId query param and supply a filename with the X-Filename header. Returns the stored media metadata.

Path parameters
brandIdrequiredstringOptional brand to attach the media to. Must belong to the account.
X-FilenamerequiredstringOptional original filename, reduced to a basename.
Example request
curl -X POST https://api.socialkit.sh/v1/media \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
  • 201Media uploadedMediaResult
  • 400Invalid request bodyError
  • 401Missing or invalid API keyError
  • 413The file exceeds the size limit for its typeError
  • 415Unsupported content typeError
GET/v1/media/{id}Bearer
Path parameters
idrequiredstringThe media id (e.g. `med_...`).
Example request
curl https://api.socialkit.sh/v1/media/id_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
DELETE/v1/media/{id}Bearer

Removes the metadata row and the stored object.

Path parameters
idrequiredstringThe media id (e.g. `med_...`).
Example request
curl -X DELETE https://api.socialkit.sh/v1/media/id_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
GET/v1/media/{id}/contentBearer
Path parameters
idrequiredstringThe media id (e.g. `med_...`).
Example request
curl https://api.socialkit.sh/v1/media/id_8fa3c1d9/content \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
  • 200The raw file bytes, with the original Content-Type.
  • 401Missing or invalid API keyError
  • 404Resource not found for this accountError

Posts

The content lifecycle: draft, schedule, publish. Posts move through a strict state machine (draft -> scheduled/publishing -> published/failed). Publishing is exactly-once: a replayed or concurrent publish returns 409.

GET/v1/postsBearer

Optionally filter by status. Results are paginated newest-first; page with limit and offset and follow pagination.hasMore. Posts carry no token material.

Path parameters
statusrequiredstringFilter to one post status.
limitrequiredintegerMaximum posts to return (default 50, max 100).
offsetrequiredintegerNumber of posts to skip from the newest.
Example request
curl https://api.socialkit.sh/v1/posts \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
POST/v1/postsBearer

Creates a post in the draft state. Supply the text plus optional brand, channel, and media references. Any brandId or channelId must belong to the calling account. Pass an Idempotency-Key header to make a retry of this call safe (a replay returns the original post, not a duplicate).

Path parameters
Idempotency-KeyrequiredstringA client-chosen key (max 255 chars) that makes a creation safe to retry. The first successful (2xx) response is cached per API key for 24 hours; replaying the same key returns that stored response verbatim with an `idempotent-replay: true` header and creates nothing new. Non-2xx responses are not cached, so a failed call leaves the key reusable. Best-effort: a sequential retry after a timeout is deduped, but two truly concurrent requests may both execute.
Request body CreatePostRequest
Example request
curl -X POST https://api.socialkit.sh/v1/posts \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "We cut onboarding from 11 fields to 3. Activation up 40%."
}'
Responses
GET/v1/posts/{id}Bearer
Path parameters
idrequiredstringThe post id (e.g. `pst_...`).
Example request
curl https://api.socialkit.sh/v1/posts/id_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
  • 200Post foundPostResult
  • 401Missing or invalid API keyError
  • 404Resource not found for this accountError
PATCH/v1/posts/{id}Bearer

Partial update. Only draft posts can be edited; editing a post in any other state returns 409. Omit a field to leave it unchanged.

Path parameters
idrequiredstringThe post id (e.g. `pst_...`).
Request body UpdatePostRequest
Example request
curl -X PATCH https://api.socialkit.sh/v1/posts/id_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
Responses
  • 200Post updatedPostResult
  • 400Invalid request bodyError
  • 401Missing or invalid API keyError
  • 404Resource not found for this accountError
  • 409The request conflicts with the resource's current stateError
DELETE/v1/posts/{id}Bearer
Path parameters
idrequiredstringThe post id (e.g. `pst_...`).
Example request
curl -X DELETE https://api.socialkit.sh/v1/posts/id_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
POST/v1/posts/{id}/publishBearer

Publishes immediately through the exactly-once path. A replayed or concurrent call returns 409 not_claimable. A revoked channel leaves the post failed and returns 409 channel_revoked with the failed post embedded. A platform error returns 502 publish_failed.

Path parameters
idrequiredstringThe post id (e.g. `pst_...`).
Example request
curl -X POST https://api.socialkit.sh/v1/posts/id_8fa3c1d9/publish \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
  • 200Post publishedPostResult
  • 400Invalid request bodyError
  • 401Missing or invalid API keyError
  • 404Resource not found for this accountError
  • 409Not in a publishable state (not_claimable) or the channel is revoked (channel_revoked). The terminal post is embedded alongside the error.PostErrorResult
  • 502The platform rejected the publish (publish_failed).PostErrorResult
  • 503The capability is not configured on this deploymentError
POST/v1/posts/{id}/scoreBearer

Scores the stored post's text and persists the score against the post, building the score-vs-reality dataset. Distinct from POST /v1/score, which grades arbitrary text without saving.

Path parameters
idrequiredstringThe post id (e.g. `pst_...`).
Example request
curl -X POST https://api.socialkit.sh/v1/posts/id_8fa3c1d9/score \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
  • 200Post scored and recordedStoredScoreResult
  • 401Missing or invalid API keyError
  • 404Resource not found for this accountError
  • 502The model or gateway misbehaved; safe to retryError
GET/v1/posts/{id}/scoresBearer
Path parameters
idrequiredstringThe post id (e.g. `pst_...`).
Example request
curl https://api.socialkit.sh/v1/posts/id_8fa3c1d9/scores \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses

Scheduling

Bulk-schedule a week of posts and read the cross-channel calendar of scheduled and published content. Due posts are published by a per-minute cron through the same exactly-once path as publish-now.

POST/v1/posts/bulk-scheduleBearer

Creates a batch of posts and schedules each for its runAt time in a single call (the /plan week made concrete). Each item is validated independently; any bad reference fails the whole batch. Pass an Idempotency-Key header to make a retry of the whole batch safe.

Path parameters
Idempotency-KeyrequiredstringA client-chosen key (max 255 chars) that makes a creation safe to retry. The first successful (2xx) response is cached per API key for 24 hours; replaying the same key returns that stored response verbatim with an `idempotent-replay: true` header and creates nothing new. Non-2xx responses are not cached, so a failed call leaves the key reusable. Best-effort: a sequential retry after a timeout is deduped, but two truly concurrent requests may both execute.
Request body BulkScheduleRequest
Example request
curl -X POST https://api.socialkit.sh/v1/posts/bulk-schedule \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "items": [
    {
      "text": "Day one shipping receipt.",
      "channelId": "chn_example",
      "runAt": 1893456000000
    },
    {
      "text": "Day two contrarian take.",
      "channelId": "chn_example",
      "runAt": 1893542400000
    }
  ]
}'
Responses
POST/v1/posts/{id}/scheduleBearer

Sets the post to scheduled for runAt and enqueues a single pending job. Re-scheduling cancels the prior pending job. The per-minute cron publishes due posts through the exactly-once path.

Path parameters
idrequiredstringThe post id (e.g. `pst_...`).
Request body SchedulePostRequest
Example request
curl -X POST https://api.socialkit.sh/v1/posts/id_8fa3c1d9/schedule \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "runAt": 1893456000000
}'
Responses
  • 200Post scheduledPostResult
  • 400Invalid request bodyError
  • 401Missing or invalid API keyError
  • 404Resource not found for this accountError
  • 409The request conflicts with the resource's current stateError
POST/v1/posts/{id}/cancelBearer

Moves the post to canceled and cancels its pending job. A post in a terminal state (published, failed) cannot be canceled and returns 409.

Path parameters
idrequiredstringThe post id (e.g. `pst_...`).
Example request
curl -X POST https://api.socialkit.sh/v1/posts/id_8fa3c1d9/cancel \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
  • 200Post canceledPostResult
  • 401Missing or invalid API keyError
  • 404Resource not found for this accountError
  • 409The request conflicts with the resource's current stateError
GET/v1/calendarBearer

Returns scheduled and published posts within an optional time window, ordered chronologically. from/to are unix-ms timestamps.

Path parameters
fromrequiredintegerStart of the window, unix epoch milliseconds.
torequiredintegerEnd of the window, unix epoch milliseconds.
Example request
curl https://api.socialkit.sh/v1/calendar \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses

Webhooks

Signed event callbacks (post.published, post.failed, post.scored, channel.disconnected). The signing secret is returned once at creation. Deliveries are retried with backoff; inspect them per endpoint.

GET/v1/webhooksBearer

Returns the account's endpoints (secrets never included) plus the set of events you can subscribe to.

Example request
curl https://api.socialkit.sh/v1/webhooks \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
POST/v1/webhooksBearer

Registers a signed callback URL. The signing secret is returned once in this response and never again; store it now. Omit events to subscribe to all of them.

Example request
curl -X POST https://api.socialkit.sh/v1/webhooks \
  -H "Authorization: Bearer $SOCIALKIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/hooks/socialkit"
}'
Responses
GET/v1/webhooks/{id}Bearer
Path parameters
idrequiredstringThe webhook endpoint id (e.g. `whk_...`).
Example request
curl https://api.socialkit.sh/v1/webhooks/id_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
DELETE/v1/webhooks/{id}Bearer
Path parameters
idrequiredstringThe webhook endpoint id (e.g. `whk_...`).
Example request
curl -X DELETE https://api.socialkit.sh/v1/webhooks/id_8fa3c1d9 \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
GET/v1/webhooks/{id}/deliveriesBearer

Returns delivery attempts with status and retry state, newest-first. Results are paginated; page with limit and offset and follow pagination.hasMore.

Path parameters
idrequiredstringThe webhook endpoint id (e.g. `whk_...`).
limitrequiredintegerMaximum deliveries to return (default 50, max 100).
offsetrequiredintegerNumber of deliveries to skip from the newest.
Example request
curl https://api.socialkit.sh/v1/webhooks/id_8fa3c1d9/deliveries \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses

Metrics

Engagement for published posts. Each poll appends a time-series snapshot; a per-minute cron sweeps the least-recently-polled posts. Roll snapshots up into account analytics, and correlate predicted scores with measured engagement in the calibration dataset.

GET/v1/posts/{id}/metricsBearer

Returns the latest engagement snapshot plus the full time-series history (newest first) for a published post. Counters are null when the platform does not expose that dimension for the post type.

Path parameters
idrequiredstringThe post id (e.g. `pst_...`).
Example request
curl https://api.socialkit.sh/v1/posts/id_8fa3c1d9/metrics \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
POST/v1/posts/{id}/metrics/refreshBearer

Polls the platform for the post's current engagement and stores a new snapshot. Mirrors the per-minute cron sweep for a single post. A draft or unpublished post returns 409; a revoked channel returns 409.

Path parameters
idrequiredstringThe post id (e.g. `pst_...`).
Example request
curl -X POST https://api.socialkit.sh/v1/posts/id_8fa3c1d9/metrics/refresh \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
  • 200A fresh snapshot was storedMetricRefreshResult
  • 400Invalid request bodyError
  • 401Missing or invalid API keyError
  • 404Resource not found for this accountError
  • 409The request conflicts with the resource's current stateError
  • 502The model or gateway misbehaved; safe to retryError
  • 503The capability is not configured on this deploymentError
GET/v1/analyticsBearer

Aggregates the latest snapshot of every published post into account totals and a per-platform breakdown. Optional from/to filter on the post's published time (unix-ms).

Path parameters
fromrequiredintegerStart of the window, unix epoch milliseconds.
torequiredintegerEnd of the window, unix epoch milliseconds.
Example request
curl https://api.socialkit.sh/v1/analytics \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses
GET/v1/calibrationBearer

The calibration dataset: each published post that has both a recorded score and a metric snapshot, pairing the predicted score with the measured engagement. Posts missing either are omitted.

Example request
curl https://api.socialkit.sh/v1/calibration \
  -H "Authorization: Bearer $SOCIALKIT_KEY"
Responses

Schemas

80 types
Platformenum

Target platform. Only `linkedin` is live; others are planned.

linkedin
MediaKindenum

The media attached to the post. Drives the format multiplier.

nonesingle-imagemulti-imagedocumentvideopolllink
FollowerBandenum

Author follower bucket. Optional context for calibration.

under-500500-2k2k-10k10k-50k50k-plus
Dimensionenum

A scored dimension of the post.

hookalgorithmFitspecificitystructurevoiceengagement
HookArchetypeenum

The classified shape of the post's opening hook.

contrarianstatementquestionpure-numberstoryother
ScoreRequestobject
FieldTypeNotes
platformPlatform
postrequiredstringThe full post text to grade.
authorNamestringOptional author name for context.
authorHeadlinestringOptional author headline/title for context.
followerBandFollowerBand
mediaMediaKind
hasExternalLinkbooleanWhether the post body or its preview points off-platform. External links cap algorithm fit. Derived from the post text when omitted.
hashtagCountintegerNumber of hashtags. Six or more caps algorithm fit. Derived from the post text when omitted.
dayOfWeekintegerPlanned publish day, Sunday=0. Optional.
hourLocalintegerPlanned publish hour in the author's local time. Optional.
ScoreBreakdownobject

Per-dimension scores, each 0-100.

FieldTypeNotes
hookrequirednumber
algorithmFitrequirednumber
specificityrequirednumber
structurerequirednumber
voicerequirednumber
engagementrequirednumber
Signalobject

One ranked observation about the post.

FieldTypeNotes
dimensionrequiredDimension
impactrequiredstringpositivenegative
weightrequiredintegerHow much this signal moved the score (1-5).
labelrequiredstringShort headline a human reads at a glance.
detailrequiredstringOne sentence on the specific move in the post.
rulestringThe named algorithm rule this ties to, if any.
ScoreResultobject
FieldTypeNotes
schemarequiredstringScore schema version.
overallrequirednumberWeighted overall score.
breakdownrequiredScoreBreakdown
verdictrequiredstringOne-line plain-language verdict.
signalsrequiredSignal[]
hookArchetyperequiredHookArchetype
hookArchetypeNoterequiredstringBenchmark note for the detected hook archetype.
formatMultiplierrequirednumberReach multiplier implied by the chosen media format.
formatNoterequiredstringWhy the format multiplier is what it is.
RewriteChangeobject

One edit the rewrite made, tied to a scored dimension.

FieldTypeNotes
dimensionrequiredDimension
noterequiredstringOne sentence on what changed and why.
RewriteResultobject

The rewrite plus the before/after scores. The after-score is reported as measured and is never massaged to look like an improvement.

FieldTypeNotes
rewriterequiredstringThe rewritten post.
changesrequiredRewriteChange[]
beforerequiredScoreResult
afterrequiredScoreResult
GenerateRequestobject
FieldTypeNotes
briefrequiredstringWhat the post should be about.
authorNamestringOptional author name for voice context.
authorHeadlinestringOptional author headline/title for context.
followerBandFollowerBand
mediaMediaKind
archetypeHookArchetype
countintegerHow many drafts to produce (1-3, default 1).
brandIdstringOptional brand id whose context (business, audience, themes, link policy) conditions the drafts. Must belong to the calling account.
voiceIdstringOptional voice id whose traits and exemplars the drafts imitate. Must belong to the calling account.
GeneratedCandidateobject
FieldTypeNotes
postrequiredstringThe generated post text.
scorerequiredScoreResult
GenerateResultobject
FieldTypeNotes
candidatesrequiredGeneratedCandidate[]Drafts sorted by overall score, best first.
Cadenceenum

Posting rhythm hint for the calendar.

dailyweekdays3x-week
PlanRequestobject
FieldTypeNotes
briefrequiredstringThemes, goals, or topics the calendar should cover.
countintegerNumber of calendar slots (1-14, default 5).
authorNamestringOptional author name for context.
authorHeadlinestringOptional author headline/title for context.
followerBandFollowerBand
cadenceCadence
brandIdstringOptional brand id whose context conditions the plan. Must belong to the calling account.
voiceIdstringOptional voice id whose style conditions the plan. Must belong to the calling account.
PlanItemobject
FieldTypeNotes
slotrequiredinteger1-based ordinal in the plan.
pillarrequiredstringThe content pillar this idea serves.
hookrequiredstringThe opening line to write.
anglerequiredstringOne sentence on the take or argument.
formatrequiredMediaKind
archetyperequiredHookArchetype
PlanResultobject
FieldTypeNotes
itemsrequiredPlanItem[]
Accountobject
FieldTypeNotes
idrequiredstringAccount id (e.g. `acc_...`).
emailrequiredstring
planrequiredstringBilling plan. New accounts start on `free`.
ApiKeyobject

API key metadata. The secret is never included.

FieldTypeNotes
idrequiredstringKey id (e.g. `key_...`).
namerequiredstringHuman-readable label for the key.
keyPrefixrequiredstringThe first characters of the secret, for display.
createdAtrequiredintegerCreation time, epoch milliseconds.
lastUsedAtrequiredinteger | nullLast successful auth, epoch milliseconds, or null.
revokedAtrequiredinteger | nullRevocation time, epoch milliseconds, or null if live.
CreateAccountRequestobject
FieldTypeNotes
emailrequiredstring
namestringOptional label for the first key. Defaults to `default`.
CreateAccountResultobject
FieldTypeNotes
accountrequiredAccount
keyrequiredApiKey
apiKeyrequiredstringThe plaintext key, shown exactly once. Store it now; it cannot be retrieved again.
CreateKeyRequestobject
FieldTypeNotes
namestringOptional label for the key. Defaults to `default`.
CreateKeyResultobject
FieldTypeNotes
keyrequiredApiKey
apiKeyrequiredstringThe plaintext key, shown exactly once.
KeyListResultobject
FieldTypeNotes
keysrequiredApiKey[]
RevokeResultobject
FieldTypeNotes
revokedrequiredbooleanTrue when the key was revoked.
Brandobject

Workspace context that conditions generation.

FieldTypeNotes
idrequiredstringBrand id (e.g. `brd_...`).
namerequiredstring
descriptionrequiredstring | nullWho the business is.
audiencerequiredstring | nullWho the brand talks to.
themesrequiredstring[]Recurring themes the brand posts about.
linkPolicyrequiredstring | nullFree-text policy on outbound links.
createdAtrequiredintegerCreation time, epoch milliseconds.
updatedAtrequiredintegerLast update time, epoch milliseconds.
BrandCreateRequestobject
FieldTypeNotes
namerequiredstring
descriptionstring | null
audiencestring | null
themesstring[]
linkPolicystring | null
BrandUpdateRequestobject

Partial update; omit a field to leave it unchanged.

FieldTypeNotes
namestring
descriptionstring | null
audiencestring | null
themesstring[]
linkPolicystring | null
BrandResultobject
FieldTypeNotes
brandrequiredBrand
BrandListResultobject
FieldTypeNotes
brandsrequiredBrand[]
Voiceobject

A reusable writing profile distilled from sample posts.

FieldTypeNotes
idrequiredstringVoice id (e.g. `voi_...`).
brandIdrequiredstring | nullThe brand this voice belongs to, or null.
namerequiredstring
traitsrequiredstring[]Stylistic traits to imitate.
doNotrequiredstring[]Things this voice never does.
exemplarsrequiredstring[]Few-shot snippets that anchor the voice.
createdAtrequiredintegerCreation time, epoch milliseconds.
updatedAtrequiredintegerLast update time, epoch milliseconds.
VoiceCreateRequestobject
FieldTypeNotes
namerequiredstring
brandIdstringOptional brand to attach the voice to.
samplesstring[]1-12 sample posts in the target voice. When present, the profile is distilled from them and any traits/doNot/exemplars you also pass are ignored.
traitsstring[]
doNotstring[]
exemplarsstring[]
VoiceUpdateRequestobject

Partial update; omit a field to leave it unchanged.

FieldTypeNotes
namestring
brandIdstring | nullReattach to a brand, or null to detach.
traitsstring[]
doNotstring[]
exemplarsstring[]
BuildVoiceRequestobject
FieldTypeNotes
namerequiredstring
brandIdstringOptional brand to attach the built voice to.
samplesrequiredstring[]1-12 sample posts written in the target voice.
VoiceResultobject
FieldTypeNotes
voicerequiredVoice
VoiceListResultobject
FieldTypeNotes
voicesrequiredVoice[]
DeleteResultobject
FieldTypeNotes
deletedrequiredbooleanTrue when the resource was deleted.
ChannelStatusenum

Connection health of the channel.

connectedexpiredrevokederror
Channelobject

A connected social account. Carries no token material.

FieldTypeNotes
idrequiredstringChannel id (e.g. `chn_...`).
accountIdrequiredstringThe owning account id.
brandIdrequiredstring | nullThe brand this channel belongs to, or null.
platformrequiredstringThe platform, e.g. `linkedin`.
platformUserIdrequiredstring | nullThe platform's stable user id for the connected member.
handlerequiredstring | nullA display handle or name for the connected account.
statusrequiredChannelStatus
scopesrequiredstring[]Granted OAuth scopes.
expiresAtrequiredinteger | nullAccess token expiry, epoch milliseconds, or null.
lastRefreshAtrequiredinteger | nullLast token refresh, epoch milliseconds, or null.
createdAtrequiredintegerCreation time, epoch milliseconds.
updatedAtrequiredintegerLast update time, epoch milliseconds.
ChannelResultobject
FieldTypeNotes
channelrequiredChannel
ChannelListResultobject
FieldTypeNotes
channelsrequiredChannel[]
ConnectChannelRequestobject
FieldTypeNotes
brandIdstringOptional brand to scope the channel to. Must belong to the calling account.
ConnectChannelResultobject
FieldTypeNotes
urlrequiredstringThe platform authorization URL to redirect the member to.
staterequiredstringThe opaque, single-use state token tying the callback to this account. Returned for visibility; the callback validates it.
Mediaobject

Metadata for an uploaded file. The storage key is never returned.

FieldTypeNotes
idrequiredstringMedia id (e.g. `med_...`).
accountIdrequiredstringThe owning account id.
brandIdrequiredstring | nullThe brand this media belongs to, or null.
contentTyperequiredstringThe validated MIME type of the stored bytes.
sizerequiredintegerSize in bytes.
filenamerequiredstring | nullThe original filename (basename), or null.
sha256requiredstringSHA-256 of the bytes, hex-encoded.
createdAtrequiredintegerUpload time, epoch milliseconds.
MediaResultobject
FieldTypeNotes
mediarequiredMedia
MediaListResultobject
FieldTypeNotes
mediarequiredMedia[]
paginationrequiredobject
PostStatusenum

Where the post sits in its lifecycle.

draftscheduledpublishingpublishedfailedcanceled
Postobject

A unit of content. Carries no token material.

FieldTypeNotes
idrequiredstringPost id (e.g. `pst_...`).
accountIdrequiredstringThe owning account id.
brandIdrequiredstring | nullThe brand this post belongs to, or null.
channelIdrequiredstring | nullThe channel this post publishes to, or null.
platformrequiredstringThe target platform, e.g. `linkedin`.
statusrequiredPostStatus
textrequiredstringThe post body.
mediaIdsrequiredstring[]Ids of media attached to the post.
scheduledForrequiredinteger | nullScheduled publish time, epoch milliseconds, or null.
publishedAtrequiredinteger | nullActual publish time, epoch milliseconds, or null.
platformPostIdrequiredstring | nullThe platform's id for the published post, or null.
platformUrlrequiredstring | nullPublic URL of the published post, or null.
errorrequiredstring | nullThe last publish error, or null.
createdAtrequiredintegerCreation time, epoch milliseconds.
updatedAtrequiredintegerLast update time, epoch milliseconds.
PostResultobject
FieldTypeNotes
postrequiredPost
PostListResultobject
FieldTypeNotes
postsrequiredPost[]
paginationrequiredobject
PostErrorResultobject

An error with the affected post's terminal state embedded.

FieldTypeNotes
errorrequiredobject
postrequiredPost
CreatePostRequestobject
FieldTypeNotes
textrequiredstringThe post body.
channelIdstring | nullChannel to publish to. Must belong to the account.
brandIdstring | nullBrand to attach. Must belong to the account.
platformstringTarget platform. Defaults from the channel, else linkedin.
mediaIdsstring[]
UpdatePostRequestobject

Partial update; omit a field to leave it unchanged. Draft only.

FieldTypeNotes
textstring
channelIdstring | null
brandIdstring | null
mediaIdsstring[]
SchedulePostRequestobject
FieldTypeNotes
runAtrequiredintegerWhen to publish, epoch milliseconds. Must be in the future.
BulkScheduleItemobject
FieldTypeNotes
textrequiredstring
runAtrequiredintegerWhen to publish this post, epoch milliseconds.
channelIdstring | null
brandIdstring | null
platformstring
mediaIdsstring[]
BulkScheduleRequestobject
FieldTypeNotes
itemsrequiredBulkScheduleItem[]
PostScoreobject

A score recorded against a stored post.

FieldTypeNotes
idrequiredstringScore id (e.g. `psc_...`).
postIdrequiredstring
scorerequiredintegerThe overall score, rounded.
verdictrequiredstring | nullOne-line plain-language verdict, or null.
payloadrequiredobjectThe full ScoreResult captured at scoring time.
createdAtrequiredintegerWhen the score was recorded, epoch milliseconds.
StoredScoreResultobject
FieldTypeNotes
scorerequiredPostScore
resultrequiredScoreResult
PostScoreListResultobject
FieldTypeNotes
scoresrequiredPostScore[]
CalendarEntryobject
FieldTypeNotes
postIdrequiredstring
statusrequiredPostStatus
whenrequiredintegerScheduled or published time, epoch milliseconds.
channelIdrequiredstring | null
platformrequiredstring
previewrequiredstringA short preview of the post text.
CalendarResultobject
FieldTypeNotes
calendarrequiredCalendarEntry[]
MetricSnapshotobject

One engagement snapshot for a post. Each counter is null when the platform did not report that dimension (distinct from a reported zero).

FieldTypeNotes
idrequiredstringSnapshot id (e.g. `met_...`).
postIdrequiredstring
impressionsrequiredinteger | null
likesrequiredinteger | null
commentsrequiredinteger | null
sharesrequiredinteger | null
clicksrequiredinteger | null
fetchedAtrequiredintegerWhen this snapshot was captured, epoch milliseconds.
PostMetricsResultobject
FieldTypeNotes
latestrequiredobjectThe most recent snapshot, or null if never polled.
historyrequiredMetricSnapshot[]All snapshots, newest first.
MetricRefreshResultobject
FieldTypeNotes
snapshotrequiredMetricSnapshot
MetricTotalsobject
FieldTypeNotes
postsrequiredintegerPosts counted (those with at least one snapshot).
impressionsrequiredinteger
likesrequiredinteger
commentsrequiredinteger
sharesrequiredinteger
clicksrequiredinteger
engagementsrequiredintegerlikes + comments + shares + clicks.
PlatformTotalsobject
FieldTypeNotes
Analyticsobject
FieldTypeNotes
AnalyticsResultobject
FieldTypeNotes
analyticsrequiredAnalytics
CalibrationRowobject

A published post paired with its predicted score and measured engagement. Only posts that have both appear.

FieldTypeNotes
postIdrequiredstring
platformrequiredstring
scorerequiredintegerThe latest recorded score.
verdictrequiredstring | null
publishedAtrequiredinteger | nullWhen the post was published, epoch milliseconds.
impressionsrequiredinteger | null
likesrequiredinteger | null
commentsrequiredinteger | null
sharesrequiredinteger | null
clicksrequiredinteger | null
engagementsrequiredintegerlikes + comments + shares + clicks (nulls counted as 0).
CalibrationResultobject
FieldTypeNotes
calibrationrequiredCalibrationRow[]
WebhookEventenum

An event you can subscribe a webhook to.

post.publishedpost.failedpost.scoredchannel.disconnected
WebhookEndpointobject

A signed callback endpoint. The secret is never included here.

FieldTypeNotes
idrequiredstringWebhook id (e.g. `whk_...`).
accountIdrequiredstring
urlrequiredstringThe callback URL.
eventsrequiredWebhookEvent[]
statusrequiredstringactivedisabled
createdAtrequiredintegerCreation time, epoch milliseconds.
updatedAtrequiredintegerLast update time, epoch milliseconds.
CreateWebhookRequestobject
FieldTypeNotes
urlrequiredstringThe HTTPS callback URL to deliver events to.
eventsWebhookEvent[]Events to subscribe to. Omit to subscribe to all.
CreateWebhookResultobject
FieldTypeNotes
webhookrequiredWebhookEndpoint
secretrequiredstringThe signing secret, returned once (it cannot be retrieved again). Every delivery carries an x-socialkit-timestamp header (epoch seconds) and an x-socialkit-signature header of the form `sha256=<hex>`. To verify: reject the request if the timestamp is not recent (e.g. older than five minutes, which blocks replays), then compute HMAC-SHA256 over the string `<timestamp>.<raw body>` with this secret and compare it, in constant time, to the hex in the signature header.
WebhookResultobject
FieldTypeNotes
webhookrequiredWebhookEndpoint
WebhookListResultobject
FieldTypeNotes
webhooksrequiredWebhookEndpoint[]
eventsrequiredWebhookEvent[]The full set of subscribable events.
WebhookDeliveryobject
FieldTypeNotes
idrequiredstring
webhookIdrequiredstring
eventrequiredstring
statusrequiredstringpendingsendingdeliveredfaileddead
attemptsrequiredintegerNumber of delivery attempts so far.
lastStatusCoderequiredinteger | nullHTTP status of the last attempt, or null.
lastErrorrequiredstring | nullError from the last attempt, or null.
nextAttemptAtrequiredinteger | nullWhen the next retry is due, epoch milliseconds, or null.
createdAtrequiredinteger
updatedAtrequiredinteger
DeliveryListResultobject
FieldTypeNotes
deliveriesrequiredWebhookDelivery[]
paginationrequiredobject
Errorobject
FieldTypeNotes
errorrequiredobject

Need something we don't have?

SocialKit is a thin layer. If you want a new endpoint, a new surface, or a model swap, tell us. We ship weekly.

hello@socialkit.sh