Dashboard API reference llms.txt
Quick start

Publish your first post in five minutes.

Four calls: authenticate, create a profile, connect an account, publish. Every example below is copy-pasteable — replace the host and key with your own.

1 Authenticate

Every request carries your API key as a bearer token. Keys are created in the dashboard under API keys and shown exactly once.

# Store it once in your shell
export SOCAPI_KEY="sk_live_..."
export SOCAPI_URL="http://localhost:8000"

# Confirm it works — this returns your organization
curl "$SOCAPI_URL/v1/me" -H "Authorization: Bearer $SOCAPI_KEY"
A 401 means the key is wrong or revoked. Every error response is {"success": false, "error": "...", "requestId": "..."} — quote the requestId if you need to trace a request in the logs.

2 Create a profile

A profile groups the accounts one brand publishes through. Most integrations need only one to start.

curl -X POST "$SOCAPI_URL/v1/profiles" \
  -H "Authorization: Bearer $SOCAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "My Brand"}'

# => { "success": true, "profile": { "_id": "prof_CMqLDdWut7M", ... } }

3 Connect an account

Starting a connection returns an authUrl. If the platform has provider credentials configured, that URL is the real OAuth screen — send your user to it. If not, it points back at this API's development stub.

curl "$SOCAPI_URL/v1/connect/twitter?profileId=prof_CMqLDdWut7M" \
  -H "Authorization: Bearer $SOCAPI_KEY"

# => { "success": true, "authUrl": "https://twitter.com/i/oauth2/authorize?...", ... }
Development stubs. A platform without credentials publishes to a local stub: the call succeeds, but nothing reaches the network. Stubbed accounts carry metadata.mode == "development" and the dashboard labels them, so a test is never mistaken for a real post.

Connecting is easier from the dashboard — it handles both the OAuth redirect and the stub for you.

4 Publish

One request fans out to every target. platforms is required, and each account must match its declared platform.

curl -X POST "$SOCAPI_URL/v1/posts" \
  -H "Authorization: Bearer $SOCAPI_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Hello from SendFlow",
    "publishNow": true,
    "platforms": [
      { "platform": "twitter",  "accountId": "acc_7Kd2p" },
      { "platform": "linkedin", "accountId": "acc_Q1muv" }
    ]
  }'
Read the per-target results, not just the status. A post can be partial_failure — accepted by one platform and rejected by another. The results array carries the outcome and reason for each target.

5 Schedule, draft and edit

Send scheduledFor instead of publishNow to schedule. Omit both to save a draft.

GoalRequest
Publish now"publishNow": true
Schedule"scheduledFor": "2026-09-01T09:00:00Z"
Save a draftomit both
Edit a draftPATCH /v1/posts/{id}
Cancel a scheduled postDELETE /v1/posts/{id}
Retry a failurePOST /v1/posts/{id}/publish
Only draft, scheduled and failed posts can be edited or deleted. Anything that reached a platform is part of the delivery record and is refused with a 422.

6 Get told what happened

Rather than polling, subscribe to events. Deliveries are signed, retried with backoff, and kept in a delivery log you can inspect in the dashboard.

curl -X POST "$SOCAPI_URL/v1/webhooks" \
  -H "Authorization: Bearer $SOCAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.example/hooks/socapi",
    "events": ["post.published", "post.failed", "account.needs_reconnect"]
  }'

Verify every delivery before trusting it:

expected = "sha256=" + hmac.new(
    secret.encode(),
    f"{timestamp}.".encode() + raw_body,
    hashlib.sha256,
).hexdigest()
assert hmac.compare_digest(expected, received_signature)
account.needs_reconnect is the one to wire up first. Access tokens are refreshed automatically, but when a refresh finally fails the account stops publishing — this event is how you find out before your users do.

7 Where to go next