API reference, v1

SotialMedia API

Schedule content across connected social accounts from your own systems. Every endpoint below is served under https://sotialmedia.com/api/v1 and described by the generated OpenAPI 3.1 document.

Authentication

Create an API key under your organization (API keys page). Keys look like sm_live_..., belong to one organization and can be limited to one workspace and to a set of scopes such as drafts.* or publications.*. Send the key on every request:

Authorization: Bearer sm_live_...

Operations marked Console session are reserved for signed-in people because they must be attributed to a person: creating keys and approving publications.

Conventions

  • JSON in and out, UTC timestamps in ISO 8601, ids are UUIDs ordered by creation time.
  • Every response carries X-Request-Id. Quote it when you contact support.
  • Lists accept limit (1 to 200) and cursor; follow nextCursor until it is null.
  • Each API key may make 600 requests per minute. Above that you get 429 with Retry-After and X-RateLimit-Remaining.
  • Organization limits (connected accounts, scheduled publications, API requests) answer 402 quota_exceeded.

Errors

All errors share one shape. Codes: unauthorized, forbidden, not_found, conflict, validation_failed, idempotency_mismatch, invalid_state, quota_exceeded, rate_limited, mfa_required, upstream_error, internal.

{
  "error": {
    "code": "validation_failed",
    "message": "Request validation failed",
    "details": { "issues": [{ "path": "scheduledFor", "message": "Invalid input" }] }
  },
  "requestId": "4c1f0d2e-7a9b-4c3d-9e1f-2b3c4d5e6f70"
}

Versioning

Versioning policy: the version is part of the path (/api/v1). Changes within v1 are additive only: new endpoints, new optional request fields, new response fields and new enum values may appear without notice, so clients must ignore unknown fields. Breaking changes ship as a new path version. Deprecated endpoints and versions are announced at least 90 days ahead and respond with a Sunset header (RFC 8594) carrying the retirement date, plus a Deprecation header, until they are removed.

Quickstart: draft, then schedule

1. Create a draft in a workspace. The draft is channel-agnostic; per-channel overrides are optional variants.

curl -X POST https://sotialmedia.com/api/v1/workspaces/$WORKSPACE_ID/drafts \
  -H "Authorization: Bearer $SOTIALMEDIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Launch day",
    "body": "We are live. Read the announcement on our site."
  }'

2. Schedule it on a connected account. scheduledFor is either an instant with a zone offset or a wall clock time in timezone. Send an Idempotency-Key so a retried request never creates a second publication: the same key with the same body returns the original (with Idempotent-Replayed: true), the same key with a different body is rejected with 422 idempotency_mismatch.

curl -X POST https://sotialmedia.com/api/v1/workspaces/$WORKSPACE_ID/publications \
  -H "Authorization: Bearer $SOTIALMEDIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: launch-2026-11-02-x" \
  -d '{
    "draftId": "$DRAFT_ID",
    "socialConnectionId": "$CONNECTION_ID",
    "scheduledFor": "2026-11-02T09:00:00",
    "timezone": "America/Denver"
  }'

3. Poll the publication or subscribe to webhooks. The detail response includes the status history and an attempt summary; platform level request details stay with operators.

curl https://sotialmedia.com/api/v1/workspaces/$WORKSPACE_ID/publications/$PUBLICATION_ID \
  -H "Authorization: Bearer $SOTIALMEDIA_API_KEY"

Webhooks

Register an HTTPS endpoint and choose event types (publication.scheduled, publication.published, publication.failed, publication.needs_attention, publication.cancelled, connection.connected, connection.revoked, connection.error). Each delivery is a POST with a JSON body { type, occurredAt, data } and the header:

X-SotialMedia-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">

Verify with the signing secret shown once when the endpoint is created. After a rotation, deliveries carry two v1 values for 24 hours so you can switch secrets without downtime. Reject timestamps older than five minutes. Failed deliveries are retried with exponential backoff; the delivery log is available through the API and the console.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifySotialMediaSignature(rawBody, header, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return header.split(",").some((p) => p.startsWith("v1=") && safeEqual(p.slice(3), expected));
}

function safeEqual(a, b) {
  const x = Buffer.from(a, "hex"), y = Buffer.from(b, "hex");
  return x.length === y.length && timingSafeEqual(x, y);
}

Endpoints

System

Health and the contract itself. No authentication.

MethodPathSummaryAuthPermission
GET/api/v1/health
Health check
Liveness with a database ping. Returns 503 when the database is unreachable.
Public
GET/api/v1/openapi.json
OpenAPI document
This document.
Public

Me

The authenticated principal.

MethodPathSummaryAuthPermission
GET/api/v1/me
Current principal
For an API key: its organization, workspace restriction and scopes. For a console session: the user and their organizations.
API key

Organizations

Organization details, workspaces and usage against entitlements.

MethodPathSummaryAuthPermission
GET/api/v1/organizations/{orgId}
Get organization
API keyorg.read
GET/api/v1/organizations/{orgId}/workspaces
List workspaces
A workspace-scoped key only sees its own workspace.
API keyorg.read
GET/api/v1/organizations/{orgId}/usage
Usage and entitlements
Current period counters per dimension with the soft and hard limits of the organization's plan.
API keyorg.read

Workspaces

A workspace holds one brand's connected accounts, media, drafts and publications.

MethodPathSummaryAuthPermission
GET/api/v1/workspaces/{workspaceId}
Get workspace
API keyworkspace.read

Connections

Connected social accounts. Credentials never leave the platform.

MethodPathSummaryAuthPermission
GET/api/v1/workspaces/{workspaceId}/connections
List connected accounts
API keyconnections.read
GET/api/v1/workspaces/{workspaceId}/connections/{connectionId}
Get connected account
API keyconnections.read
DELETE/api/v1/workspaces/{workspaceId}/connections/{connectionId}
Disconnect account
Queues a disconnect job: the platform authorization is revoked where supported, credentials are discarded and pending publications on the account are cancelled.
API keyconnections.manage

Media

Upload flow: register, PUT to the signed URL, complete, poll until ready.

MethodPathSummaryAuthPermission
GET/api/v1/workspaces/{workspaceId}/media
List media assets
API keymedia.read
POST/api/v1/workspaces/{workspaceId}/media
Register a media asset
Creates the asset in pending_upload and returns a signed URL valid for 10 minutes. PUT the file bytes there with the declared Content-Type, then call complete.
API keymedia.write
GET/api/v1/workspaces/{workspaceId}/media/{mediaId}
Get media asset
Poll after completing an upload: status becomes ready or rejected (see rejectionReason).
API keymedia.read
POST/api/v1/workspaces/{workspaceId}/media/{mediaId}/complete
Complete an upload
Marks the object uploaded and queues verification (type sniffing, size limits, checksum, malware scan when configured).
API keymedia.write

Drafts

Channel-agnostic content with optional per-channel variants.

MethodPathSummaryAuthPermission
GET/api/v1/workspaces/{workspaceId}/drafts
List drafts
API keydrafts.read
POST/api/v1/workspaces/{workspaceId}/drafts
Create a draft
API keydrafts.write
GET/api/v1/workspaces/{workspaceId}/drafts/{draftId}
Get a draft with variants
API keydrafts.read
PATCH/api/v1/workspaces/{workspaceId}/drafts/{draftId}
Update a draft
Bumps the version and clears stored validations; schedule again to re-validate.
API keydrafts.write
DELETE/api/v1/workspaces/{workspaceId}/drafts/{draftId}
Archive a draft
API keydrafts.write
PUT/api/v1/workspaces/{workspaceId}/drafts/{draftId}/variants/{channel}
Set channel overrides
Replaces the overrides for one channel (text, media, channel settings).
API keydrafts.write
POST/api/v1/workspaces/{workspaceId}/drafts/{draftId}/validate
Validate for a channel
Runs the channel adapter's validation on the effective content and stores the result on the variant.
API keydrafts.write

Publications

Scheduling a draft on a connected account, status history and controls.

MethodPathSummaryAuthPermission
GET/api/v1/workspaces/{workspaceId}/publications
List publications
API keypublications.read
POST/api/v1/workspaces/{workspaceId}/publications
Schedule a publication
Validates the draft for the account's channel, snapshots the content, records usage against the plan and queues delivery. Workspaces that require approval create the publication in needs_attention until approved.
Supports Idempotency-Key
API keypublications.schedule
GET/api/v1/workspaces/{workspaceId}/publications/{publicationId}
Get a publication
API keypublications.read
POST/api/v1/workspaces/{workspaceId}/publications/{publicationId}/cancel
Cancel a publication
Allowed until delivery starts. A publication already publishing answers 409.
API keypublications.cancel
POST/api/v1/workspaces/{workspaceId}/publications/{publicationId}/retry
Retry a publication
Re-queues a failed or needs_attention publication for immediate delivery. The account must be active.
API keypublications.retry
POST/api/v1/workspaces/{workspaceId}/publications/{publicationId}/approve
Approve a publication
Approvals are attributed to a person: console sessions only. The approver cannot be the person who scheduled it.
Console sessionpublications.approve

API keys

Scoped keys for programmatic access. Managed from a console session.

MethodPathSummaryAuthPermission
GET/api/v1/organizations/{orgId}/api-keys
List API keys
Console sessionorg.api_keys.manage
POST/api/v1/organizations/{orgId}/api-keys
Create an API key
The plaintext key is returned once in this response.
Console sessionorg.api_keys.manage
DELETE/api/v1/organizations/{orgId}/api-keys/{keyId}
Revoke an API key
Console sessionorg.api_keys.manage

Webhooks

Signed event delivery to your HTTPS endpoints with secret rotation.

MethodPathSummaryAuthPermission
GET/api/v1/organizations/{orgId}/webhooks
List webhook endpoints
API keywebhooks.manage
POST/api/v1/organizations/{orgId}/webhooks
Create a webhook endpoint
The signing secret is returned once. Deliveries are POST requests with the WebhookEvent body and the X-SotialMedia-Signature header.
API keywebhooks.manage
GET/api/v1/organizations/{orgId}/webhooks/{webhookId}
Get a webhook endpoint
API keywebhooks.manage
DELETE/api/v1/organizations/{orgId}/webhooks/{webhookId}
Disable a webhook endpoint
Stops deliveries; the delivery history stays readable.
API keywebhooks.manage
POST/api/v1/organizations/{orgId}/webhooks/{webhookId}/rotate-secret
Rotate the signing secret
Deliveries carry two v1 signatures for 24 hours so consumers can switch without downtime.
API keywebhooks.manage
GET/api/v1/organizations/{orgId}/webhooks/{webhookId}/deliveries
List deliveries
Delivery attempts for one endpoint, newest first, with the last response status and error.
API keywebhooks.manage