Meet the new Scripe, live on October 7.Register

OpenAPI reference · Posts

Create a draft (or scheduled) post

POST/posts

Creates a tPost row in draft status (or scheduled if scheduledFor is set). Always pairs the post with an empty tTranscription placeholder for parity with the dashboard.

With scheduledFor set, the post is scheduled at that timestamp and the project's LinkedIn connection is verified first: no access token on file is an immediate refusal, and otherwise a live /me ping + token refresh for personal brands (non-empty admin set for company pages). If LinkedIn isn't usable the request fails 409 conflict and nothing is created. The 409 body carries details.reason (not_connected | token_invalid | no_company_page_admin), details.retryable: false — only a human can repair a connection — and details.reconnectUrl, the page they open to do it (null for no_company_page_admin, whose repair is on a different project). The post-scheduler cron handles the publish itself; if that later fails, the post moves to failed_to_publish (same path as the dashboard).

Required scope: posts:write.

Authorization

  • Authorizationstringrequired

    Bearer token in the Authorization header.

    Pass Authorization: Bearer scripe_sk_live_<...> (or scripe_sk_test_<...> for test keys) on every request. Keys are scoped to a single workspace and can be revoked from the Scripe dashboard.

    The same header also accepts an OAuth 2.1 access token (scripe_oat_*); both credentials share one scope vocabulary and every operation below documents the scope it requires. An API key can hold every scope named on this surface except webhooks:manage, which is grantable to OAuth tokens only today — the webhook-endpoint operations answer 403 scope_missing to every API key. Operations that name no scope accept any valid token of the workspace.

Header parameters

  • Scripe-Api-Versionstring

    Pin the API version. Format YYYY-MM-DD. Omit to receive the currently rolling default. Unknown versions return 400 version_unsupported.

  • Idempotency-Keystring

    Opaque string (1–64 chars, [A-Za-z0-9_-]) used to dedup retried writes. Within 24h of the first request, the same key

    • same body returns the original response (Idempotent-Replayed: true). Same key + different body returns 409 idempotency_key_conflict.

    Strongly recommended for every write — see /docs/api/v1/idempotency.

Request bodyapplication/json

  • projectIdstringrequired
  • contentstring

    Post body. Defaults to a single space (TipTap rejects truly-empty content).

  • titlestring

    The post's INTERNAL name — shown in the dashboard and in teammates' notifications. It is not published as post copy, with one exception: on a post whose attached media asset (a document or an image) carries no filename of its own, a title YOU set is used as that asset's display title on LinkedIn. Only a title you set is eligible — a title Scripe derived is never published, and such a post's asset goes out titled Document.

    Omitting it and sending "" do the same thing here: Scripe names the post after its own opening line, so a post created with content is never nameless. Send a real title and the name is yours: nothing overwrites it afterwards, not a later PATCH of content and not the AI passes that rewrite the draft.

  • contentTypestring

    Allowed values: PERSONAL, BUSINESS_INTERNAL, BUSINESS_EXTERNAL, EDUCATIONAL, UNKNOWN

    Default: "PERSONAL"

  • scheduledForstring <date-time> | null

    Future ISO timestamp at which the post should publish. If omitted/null, the post stays in draft.

    A timestamp WITHOUT an offset (2026-08-18T09:00:00) is resolved in the project's calendar timezone — not UTC and not the server's zone — because that is what "9am" means to the person asking. Send an offset or Z when you mean an absolute instant. A date alone (2026-08-18) is rejected with 422: it would schedule the post at midnight.

Responses

  • 200

    Post created (or replayed via Idempotency-Key).

  • 400

    Malformed request (bad cursor, bad limit, etc.).

  • 401

    Missing, malformed, expired, or revoked API key.

  • 403

    Plan not eligible, scope missing, or workspace mismatch.

  • 404

    Resource not found in this workspace.

  • 409

    Either an Idempotency-Key conflict, or LinkedIn is not connected for the project — a post cannot be created already scheduled against a dead connection.

  • 413

    Request body exceeds the size cap.

  • 422

    Body shape was JSON but failed validation (unprocessable).

  • 429

    Sliding-window rate limit exceeded.

Example request

bash
curl --request POST \
  --url 'https://api.scripe.io/v1/posts' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
  "projectId": "proj_a1b2c3d4e5f6g7h8",
  "content": "string",
  "title": "string",
  "contentType": "PERSONAL",
  "scheduledFor": "2026-08-18T09:00:00+02:00"
}'

Example response (200)

json
{
  "data": {
    "id": "post_a1b2c3d4e5f6g7h8",
    "projectId": "string",
    "status": "waitingProcessing",
    "statusId": "string",
    "statusTitle": "string",
    "statusCategory": "suggested",
    "platform": "string",
    "contentType": "string",
    "funnelStage": "REACH",
    "title": "string",
    "content": "string",
    "contentTruncated": true,
    "scheduledAt": "2026-08-10T09:00:00Z",
    "publishedAt": "2026-08-10T09:00:00Z",
    "lastPublishError": "string",
    "lastPublishAttemptAt": "2026-08-10T09:00:00Z",
    "delivery": {
      "state": "not_scheduled",
      "willRetry": true,
      "retryUntil": "2026-08-10T09:00:00Z",
      "detail": "string"
    },
    "review": {
      "state": "not_requested",
      "awaitingDecision": true,
      "reviewerUserId": "string",
      "deadline": "2026-08-10T09:00:00Z",
      "overdue": true,
      "decidedAt": "2026-08-10T09:00:00Z",
      "notes": "string",
      "requiredByWorkspace": true,
      "detail": "string"
    },
    "media": {},
    "createdAt": "2026-08-10T09:00:00Z",
    "updatedAt": "2026-08-10T09:00:00Z"
  }
}