API Reference

API Reference

Base URL, authentication, response format, errors, limits and the full list of Relaycast REST endpoints.

The Relaycast API is a JSON REST API. You can call it with any HTTP client: the examples use cURL, fetch in Node.js, and Python requests. There is no official SDK.

Base URL

https://social-publish-api.onrender.com

All resource endpoints are versioned under /v1. The health endpoints (/health, /ready) are at the root and need no authentication.

Authentication

Every /v1 request needs an API key. Create one in the dashboard under API Keys. Send it in either header:

HeaderExample
x-access-keyx-access-key: sp_live_…
AuthorizationAuthorization: Bearer sp_live_…

A key belongs to one project; everything you create with it (posts, accounts) is scoped to that project. Revoked keys stop working immediately. See Authentication.

curl https://social-publish-api.onrender.com/v1/accounts \
  -H "x-access-key: $RELAYCAST_API_KEY"
const res = await fetch("https://social-publish-api.onrender.com/v1/accounts", {
  headers: { "x-access-key": process.env.RELAYCAST_API_KEY! },
});
const { data } = await res.json();
import os, requests

res = requests.get(
    "https://social-publish-api.onrender.com/v1/accounts",
    headers={"x-access-key": os.environ["RELAYCAST_API_KEY"]},
)
data = res.json()["data"]

Requests

  • Send JSON bodies with content-type: application/json.
  • Request bodies are limited to 1 MB. Media is never uploaded in the request body: pass a public https URL or a media library reference (media://<id>). See Media & Uploads.
  • Timestamps are ISO 8601 strings. scheduledFor must include a time zone (Z or an offset such as +02:00).
  • IDs are UUIDs.

Responses

Successful responses wrap the result in a data field, for single objects and lists alike:

Response 200
{
  "data": [
    { "id": "6f1c2a7e-4b8d-4f7a-9a51-2d3c4b5a6e7f", "platform": "twitter", "handle": "acme" }
  ]
}

Errors

Errors use a single envelope with a machine-readable code, a human-readable message, and sometimes details:

Response 400
{
  "error": {
    "code": "validation_error",
    "message": "Content is not valid for some platforms",
    "details": {
      "6f1c2a7e-4b8d-4f7a-9a51-2d3c4b5a6e7f": [
        { "field": "content", "message": "X posts allow 280 characters (links count as 23, emoji/CJK as 2); turn on Long post for Premium accounts; this is 312" }
      ]
    }
  }
}
StatusCodeMeaning
400invalid_jsonThe body isn't valid JSON.
400validation_errorThe body doesn't match the schema, or content isn't valid for a platform.
400unknown_accountAn accountId doesn't exist in this project.
400account_inactiveAn account needs reconnecting.
400unknown_mediaA media:// reference doesn't exist in this project's media library.
400invalid_credentialsBluesky rejected the handle or app password.
401unauthorizedMissing or invalid API key.
402insufficient_creditsNot enough credits for the post.
404not_foundThe resource or route doesn't exist.
413payload_too_largeThe request body is larger than 1 MB.
429rate_limitedToo many requests for this API key.
500internal_errorUnexpected server error.

validation_error has two details shapes:

  • Schema errors (wrong types, missing fields): an array of issues, each with path (for example ["targets", 0, "accountId"]), message and code.
  • Platform errors: an object keyed by account ID, each holding a list of { field, message }.

See Errors for handling advice.

Rate limits

Each API key may make 120 requests per minute by default (fixed one-minute window; self-hosted deployments set RATE_LIMIT_PER_MINUTE). Responses include:

HeaderMeaning
X-RateLimit-LimitRequests allowed per minute
X-RateLimit-RemainingRequests left in the current minute

Over the limit, the API returns 429 with code rate_limited; retry after the minute rolls over. See Rate Limits.

Lists and limits

GET /v1/posts returns the most recent posts first. Use limit (1–100, default 20). There is no cursor pagination; to browse or filter older posts, use Posts in the dashboard.

LimitValue
Accounts per post (targets)1–20
Media items per post10
content1–10,000 characters (platforms have lower limits)
Media URL2,048 characters
Request body1 MB

Idempotency

POST /v1/posts accepts an Idempotency-Key header. Retrying with the same key returns the post created by the first request (200) instead of creating and charging for a new one (201). See Idempotency & Retries.

Credits

Each post costs 1 credit per target account, charged when the post is created. Targets that fail permanently are refunded. See Credits & Usage.

Endpoints

MethodPathDescription
GET/v1/accountsList connected social accounts
POST/v1/accounts/connect-linksCreate a hosted link your user opens to connect an OAuth account
GET/v1/accounts/connect-links/{id}Check a connect link's result
POST/v1/accounts/blueskyConnect a Bluesky account with an app password
POST/v1/postsCreate a post (publish now or schedule)
GET/v1/postsList recent posts
GET/v1/posts/{id}Get a post and its per-platform targets
POST/v1/liveStart or schedule a live stream
GET/v1/liveList live streams
GET/v1/live/usageLive minutes used this month
GET/v1/live/{id}Get a live stream and its destinations
POST/v1/live/{id}/stopStop (or cancel) a live stream
POST/v1/live/{id}/relaunchGo live again with the same setup
GET/healthLiveness check
GET/readyReadiness check (database and queue)

Events are delivered to your server as webhooks.

Some operations are only available in the dashboard: connecting OAuth platforms (Integrations), uploading files to the media library, deleting or cancelling posts, post analytics, managing API keys, and configuring notifications.

Request logs

Every authenticated /v1 request is recorded in the dashboard under Logs, including requests rejected by the rate limiter. See Request Logs.

This page is also available as Markdown.