Responses and errors
Every action answers the same way on REST, MCP and the CLI.
Success
Section titled “Success”{ "ok": true, "summary": "Scheduled for Tue 28 Oct, 10:00 (America/New_York) on @yourhandle.", "data": { "postId": "…", "scheduledAt": "2026-10-28T14:00:00.000Z" }, "ids": { "postId": "…" }}| Field | Meaning |
|---|---|
summary |
One or two readable sentences. Read it first; models can relay it as is. |
data |
The result. Its shape depends on the action. |
ids |
IDs worth acting on next, such as postId. |
next |
Suggested next calls, by MCP tool name. |
creditsCharged |
AI credits actually spent, when any. |
dryRun |
true when nothing was changed because you passed dryRun. |
Errors
Section titled “Errors”{ "ok": false, "error": { "code": "SCOPE_MISSING", "message": "This connection isn't allowed to post, send and change what goes out on X yet. Give the user this link to allow it (one click in Xholic), then try again: https://app.xholic.ai/oauth/allow?connection=…&scope=publish", "scope": "account", "details": { "missingScope": "publish", "allowUrl": "https://app.xholic.ai/oauth/allow?connection=…&scope=publish" } }}code is stable; branch on it, not on the message. scope says whose problem it is: account means something you or the account can fix, platform means Xholic or X is having trouble and a retry later should work. retryAfterSeconds is set when waiting helps, and details carries more (validation issues, a credit quote).
On MCP the same object comes back as a tool result with isError: true, and the text starts with CODE: message.
| Code | HTTP | Scope | Meaning |
|---|---|---|---|
UNAUTHENTICATED |
401 | account | No credential was sent, or the action needs an account. |
INVALID_CREDENTIAL |
401 | account | The API key or token is wrong, revoked or expired. |
SCOPE_MISSING |
403 | account | The connection lacks the write or publish scope this action needs. details.allowUrl lets the person allow it in one click. |
ROLE_NOT_PERMITTED |
403 | account | Your role on a shared account doesn’t allow this action. |
ACCOUNT_NOT_FOUND |
404 | account | The account isn’t one this login can use. |
SUBSCRIPTION_REQUIRED |
402 | account | The subscription isn’t active. Keys and connections are kept. |
FEATURE_NOT_INCLUDED |
403 | account | The plan doesn’t include this feature. |
APP_ONLY |
403 | account | This change can only be made in the Xholic app. |
INVALID_INPUT |
400 | account | The input failed validation; details lists each field. |
NOT_FOUND |
404 | account | The thing you referenced doesn’t exist, or the endpoint doesn’t. |
CONFLICT |
409 | account | The change clashes with the current state (for example an old article version). |
CREDITS_CONFIRMATION_REQUIRED |
402 | account | The action uses Xholic AI. details.quote has the estimate and a quoteId; call again with confirmCredits and quoteId. |
INSUFFICIENT_CREDITS |
402 | account | Not enough AI credits left for this action. |
RATE_LIMITED |
429 | account | Too many requests in this bucket. Wait retryAfterSeconds. |
IDEMPOTENCY_KEY_REUSED |
409 | account | The key was already used for a different request. |
IDEMPOTENCY_IN_PROGRESS |
409 | account | A request with this key is still running. Retry with the same key shortly. |
X_DATA_LIMIT_REACHED |
429 | account | The plan’s live X data allowance is used up for now. |
UPSTREAM_UNAVAILABLE |
503 | platform | X or another service Xholic depends on is unavailable. Retry later. |
INTERNAL_ERROR |
500 | platform | Something failed on Xholic’s side. Retry later. |
Control fields
Section titled “Control fields”Every surface adds these to an action’s own input:
| Field | Type | Applies to | What it does |
|---|---|---|---|
account |
string | Every action that acts on an X account | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | Every change | Return exactly what would happen without doing it. |
idempotencyKey |
string | Every change (required on publish_now) |
A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
confirmCredits |
number | Actions that use Xholic AI | Xholic AI credits the user agreed to spend. Call first without it to get the quote, show the quote to the user, and pass the amount only after they say yes. |
quoteId |
string | Actions that use Xholic AI | The quoteId from the quote the user agreed to. Send it with confirmCredits. |
Headers (REST)
Section titled “Headers (REST)”| Header | Meaning |
|---|---|
X-RateLimit-Limit |
Requests allowed per minute in this action’s bucket. |
X-RateLimit-Remaining |
Requests left this minute. |
X-RateLimit-Reset |
Seconds until the bucket refills. |
X-Xholic-Credits-Remaining |
AI credits left, on actions that quote credits. |
Retry-After |
Seconds to wait, on 429 and some 409/503 errors. |
Responses are Cache-Control: no-store. The API takes bearer credentials only and never reads cookies.
