Requests and envelopes
This page describes local connect, publish and status requests. One request document goes in and one JSON envelope comes out; the documented shapes are what an agent or script branches on. The optional self-hosted Server has its own envelope.
The envelope
{
"protocolVersion": 1,
"operation": "publish",
"ok": true,
"result": {},
"error": null
}{
"protocolVersion": 1,
"operation": "publish",
"ok": false,
"result": null,
"error": { "code": "INPUT_INVALID", "message": "The request document is not valid." }
}For local requests, operation is one of connect, publish and status. A message is static text chosen by the code, never built from a stack, a path, a response body or an argument, so a diagnostic cannot carry a secret.
Server envelopes
Self-hosted Server. Server commands are a separate path using @syndroo/cli and @syndroo/cloudflare. Their JSON uses operation: "server", with a result.subcommand discriminator for init, doctor, deploy, connect, ci and publish.
Server request and result shapes are not the local request families below. Follow Deploy a server; its outcomes, recovery IDs and acceptance limits are summarized in the Server command reference.
connect
Four request shapes. start begins a connection, resume completes a pending step, and update and disconnect maintain a stored one.
{
"type": "start",
"provider": "bluesky",
"label": "work",
"connectionId": "conn_existing",
"options": {}
}{
"type": "resume",
"connectSessionId": "cs_...",
"stepRevision": 0,
"input": { "type": "credentials", "credentials": { "identifier": "you.bsky.social", "password": "..." } }
}{
"type": "update",
"connectionId": "conn_...",
"changes": { "label": "writing", "isDefault": true }
}A resume input is either credentials with the provider's credential object, or callback_complete for a session whose authorization callback was delivered out of band. stepRevision must match the session, so a stale step is refused rather than applied twice.
{
"status": "action_required",
"connectSessionId": "cs_...",
"stepRevision": 1,
"expiresAt": "2026-10-08T00:15:00.000Z",
"action": { "type": "credential_input", "fields": [{ "name": "password", "label": "Bluesky app password", "secret": true }] }
}An action is credential_input, open_url or wait_for_callback. A finished step answers "status": "done" with the stored connection.
publish
Three request shapes: prepare freezes the content, execute sends it, and retry re-sends only the eligible targets of an earlier operation. A document without a type is an ordinary prepare request.
{
"type": "prepare",
"content": { "text": "One document, chosen targets." },
"targets": [
{ "provider": "bluesky" },
{ "provider": "devto", "connection": "conn_...", "options": { "title": "Hello", "body_markdown": "Body" } }
]
}{ "type": "execute", "approvalToken": "<token>" }{
"type": "retry",
"retryOf": "op_...",
"targets": [{ "provider": "bluesky", "connection": "conn_..." }]
}A target names its provider, optionally a connection and optional provider options. A document carries one to twenty targets. When a target names no connection, the provider's default connection is used, and an ambiguous choice is refused rather than guessed.
{
"status": "confirmation_required",
"operationId": "op_example",
"approvalToken": "<approvalToken>",
"expiresAt": "2026-10-08T00:15:00.000Z",
"preview": [
{
"deliveryId": "dl_example",
"connectionId": "conn_example",
"account": { "provider": "bluesky", "accountId": "acct_example", "origin": "https://bsky.social" },
"provider": "bluesky",
"preview": { "content": { "text": "One document, chosen targets." }, "fields": [] },
"presentation": { "accountName": "Example account", "profileUrl": "https://bsky.app/profile/example", "label": "work" }
}
]
}{
"phase": "execution",
"operationId": "op_example",
"status": "succeeded",
"deliveries": [
{
"deliveryId": "dl_example",
"connectionId": "conn_example",
"account": { "provider": "bluesky", "accountId": "acct_example", "origin": "https://bsky.social" },
"attempts": 1,
"state": "settled",
"outcome": { "status": "succeeded", "remoteId": "at://example/post/1", "url": "https://bsky.app/profile/example/post/1" },
"presentation": { "accountName": "Example account", "profileUrl": "https://bsky.app/profile/example", "label": "work" }
}
]
}The execution status is one of pending, running, succeeded, partial, failed or unknown. Each delivery outcome is succeeded, failed with disposition not_applied, unknown, or not_started when the target never reached a call; an eligible failed outcome may carry retryable, a reason and a retryAfter time. Failed and not started mean the write is known not to have been applied, and unknown is never retryable.
A target's stable identity is its provider, origin and accountId. An optional presentation carries a readable accountName, a public profileUrl and the connection label for display only: it never changes target selection, account de-duplication or the binding, and missing optional metadata is allowed. Unsafe optional values returned by a provider are discarded before they enter the frozen snapshot; this does not relax request-schema validation.
That presentation is frozen with the rest of the intent and covered by the intent digest, so a later rename never changes this operation's history, and a profile link is displayed only when it is a safe HTTPS URL; otherwise the stable origin is shown instead. The frozen snapshot of one delivery is associated by deliveryId and the execution round that produced its state, never inferred from array position, platform name or the most recent prepared intent.
syndroo status --operation <operationId> reads the recorded result: it loads no provider, reads no input file and never rewrites history. A delivery shows the historical frozen name, label and preview of its own round rather than the current connection, and a record from an older release whose round cannot be proven from persisted evidence reports the preview as unavailable instead of guessing. Every request, well formed or not, is validated against the protocol before anything runs.
status
Five query shapes and no query language. With no selector the overview is returned.
| Request | Result |
|---|---|
{ "type": "overview" } | Whether the state is initialized, the connection count, each provider's availability and provenance, the most recent operations and the state health. |
{ "type": "provider", "provider": "bluesky" } | The provider's manifest, implementation fingerprints and observations. |
{ "type": "connections", "provider": "bluesky" } | The stored connections, optionally filtered to one provider. |
{ "type": "operation", "operationId": "op_..." } | One operation: either a prepared operation with its confirmation state and preview, or the execution result. It renders the same human result view as syndroo publish. |
{ "type": "operations", "limit": 20, "cursor": "..." } | Operation summaries, with an opaque cursor for the next page. |
Provider availability is available, untrusted, unavailable or stale, and provenance is official or third_party. Status reads stored observations; it does not refresh them by contacting a platform.
Local execution status and the exit code
A publish result maps onto the process exit code: unknown exits 4, failed and partial exit 6, and every other execution status exits 0. A preflight or usage refusal exits 2, and an explicit decline at the confirmation prompt exits 5.