X setup
X is published through the official @xdevplatform/xdk SDK with OAuth 1.0a user authentication. That means four secrets rather than one token, and an app that is allowed to post for the account.
x-sdk
Status and evidence
Syndroo 0.2.0-rc.1 is an unpublished release candidate: prepared in the repository, not published to npm, not tagged, and not deployed. X is recorded as experimental for this candidate.
Evidence: unit tests in the core repository, including workerd coverage of the SDK path. There is no Mock SNS end-to-end coverage for X, and no live-account acceptance record exists. Experimental means the adapter is implemented and tested locally, and that live publishing through it has not been validated. See Platform readiness and the capability record.
What you need
- An X account you can post from, on the same account as the developer app you will create.
- Access to the X developer portal and an app with permission to publish for that account. The recorded requirement for this candidate is an app with Read and Write permissions; access levels and their names are X's to change, so confirm the current requirement in the portal and the official documentation.
- Four OAuth 1.0a values for that app: the consumer key and secret, plus the user access token and its secret.
- A running Worker and its API key. Either a deployment in your own Cloudflare account or a local instance. The Worker holds the platform credentials; clients hold only
SYNDROO_API_KEY. If you have not set one up yet, the first-post walkthrough covers the whole path with Bluesky.
The adapter reads all four Worker secrets:
| Secret | Required | Value |
|---|---|---|
X_API_KEY | Yes | OAuth 1.0a consumer API key for the app. |
X_API_SECRET | Yes | OAuth 1.0a consumer API secret. |
X_ACCESS_TOKEN | Yes | User access token issued for the account, after the app can post. |
X_ACCESS_TOKEN_SECRET | Yes | Secret paired with that user access token. |
All four are required. A partial set leaves X unconfigured, and selecting it returns HTTP 422 with PLATFORM_NOT_CONFIGURED.
Create the app and its keys by hand
The developer portal's layout, permission names and plan names change over time. Follow the official X documentation linked under Official sources while you work through this sequence.
-
Create or open the app
Sign in to the developer portal with the account you will publish from, then create a project and app, or open an existing one.
-
Set the app's permission level
In the app's user-authentication settings, choose the permission level that allows posting for the account. The recorded requirement for this candidate is Read and Write; if the portal offers different wording, pick the level the documentation describes as posting access.
-
Generate the user access token and secret
Generate the user access token and its secret after the permission level is set. The portal can produce the pair directly, and X also documents a three-legged OAuth 1.0a flow that ends with the same two values; that flow needs a registered callback URL, and X documents a PIN-based variant for cases where no callback UI exists. If you change the permission level later, regenerate the user credentials, because a token issued under one permission level does not gain the new one by itself.
-
Record all four values
Copy the consumer API key and secret and the user access token and secret into your secret store. Treat each value as a secret; do not paste them into a page, a chat message or an issue.
Whether an app can publish, and how many requests it may make, is decided by X and by the access level attached to your developer account. Syndroo cannot grant, buy or work around that access, and this page makes no promise about which level you need or what it costs.
Add the secrets to the Worker
Put the values where your runtime reads secrets: Worker secrets for a deployment, .dev.vars for a local instance. Cloudflare deployment and Local development cover the exact commands for each path.
X_API_KEY="your-x-consumer-api-key"
X_API_SECRET="your-x-consumer-api-secret"
X_ACCESS_TOKEN="your-x-user-access-token"
X_ACCESS_TOKEN_SECRET="your-x-user-access-token-secret"
Before accepting a post, Syndroo checks that all four values exist and are non-empty. It does not call X to test them. Revoked, expired or under-permissioned credentials pass that check and surface later as a publication failure with errorCode AUTH.
Publish and check one post
The commands below publish for real once the secrets above are configured. Set the two client variables in the terminal that will call Syndroo.
export SYNDROO_URL="https://your-worker.your-subdomain.workers.dev"
export SYNDROO_API_KEY="the-same-secret-your-worker-has"
curl -X POST "$SYNDROO_URL/v1/posts" \
-H "Authorization: Bearer $SYNDROO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: x-setup-001" \
--data '{
"content": "First post from my own Syndroo Worker.",
"platforms": ["x"]
}'
The accepted response is HTTP 202 with status queued:
{
"id": "post_...",
"status": "queued"
}
HTTP 202 means the request was accepted for processing. It does not confirm that X accepted anything, and it does not prove that the Queue has not already sent the platform request, because delivery can start immediately after acceptance. Read the stored state to learn the outcome:
curl \
-H "Authorization: Bearer $SYNDROO_API_KEY" \
"$SYNDROO_URL/v1/posts/post_..."
{
"id": "post_...",
"content": "First post from my own Syndroo Worker.",
"platforms": ["x"],
"status": "published",
"publications": [
{
"platform": "x",
"provider": "x-sdk",
"status": "published",
"attempts": 1,
"externalId": "1800000000000000000",
"errorAmbiguous": false
}
]
}
queued and publishing are not terminal; poll the same URL. published and failed are terminal. An externalUrl appears only when the platform returns a usable link; build no links by hand from the identifier.
Repeating the identical request with the same Idempotency-Key returns the stored result with HTTP 200 instead of creating a second post. See Idempotency-Key.
Limits, tokens and external dependencies
| Item | Recorded for 0.2.0-rc.1 |
|---|---|
| Text limit | 280 weighted characters, validated with twitter-text before the network call. Longer formats such as premium long posts are outside this version. |
| Content type | Text only, with SDK retries disabled so Syndroo's own retry policy is the only one. |
| Credential maintenance | Yours. X documents OAuth 1.0a user tokens as not expiring on their own but remaining revocable, so a revoked token keeps failing as AUTH until you regenerate the user credentials and replace the Worker secrets. Syndroo has no OAuth flow and does not renew credentials. |
| External dependency | X's access levels, request limits and posting rules apply. Syndroo includes no pricing of its own and promises nothing about which access level you have or need; check X's current plans and documentation. |
Check the provider's current documentation before relying on a specific permission, character-counting rule or request limit. Those facts change on the provider's schedule, not on this page; the links under Official sources are the references to re-check.
When something fails
A failed publication stores errorCode, errorMessage and errorAmbiguous in the post response. Read them before you act.
| What you see | What it means | What to do |
|---|---|---|
HTTP 422 PLATFORM_NOT_CONFIGURED | At least one of the four X secrets is missing or empty. | Add all four secrets, then send the request again. Nothing was stored or queued. |
AUTH | X rejected the credentials: revoked, expired, or issued without posting permission. | Regenerate the user credentials with the right permission level, update the Worker secrets, and check the account before resending. |
INVALID_CONTENT | The text exceeded the weighted-character limit, or failed validation, and nothing was sent. | Shorten the text and publish again with a new key. |
RATE_LIMIT | X refused the request because of its own request limits. | Syndroo retries this automatically with backoff, up to three attempts. If it still fails, your access level's limit is the constraint; wait before trying again. |
PROVIDER_UNAVAILABLE, NETWORK or UNKNOWN, with errorAmbiguous: true | The write may have reached X; the outcome is unknown. | Check the account by hand. Syndroo never resends an ambiguous publication automatically. |
Post status partial | Some selected platforms succeeded and some failed. | Never resubmit the platforms that succeeded. The failed ones need attention only after you have excluded an ambiguous outcome. |
If a publication is failed with errorAmbiguous: true, check the X account by hand first, because the post may already exist. Only when you have confirmed that nothing was published and you still want the post should you send a new request with a new Idempotency-Key. Reusing the old key replays the stored result instead of publishing. Read Ambiguous outcomes for the reasoning.
Official sources
- TypeScript XDK
- Counting characters
- Create a post
- Obtaining user access tokens (OAuth 1.0a)
- Syndroo adapter source:
@syndroo/x - Capability record, taken from the product repository at commit
87ba42band reviewed on 2026-09-18
This page follows the candidate's capability record and the product revision above. It was not verified against a live X account, so re-check the official documentation when a permission, limit or portal step differs from what you see.