Auto Schedule API
Errors
Seven codes, one envelope. The endpoint has no request body, so almost every failure is about the key, the id or the plan rather than about what you sent.
The error envelope
{
"success": false,
"error_code": "web_page_not_found",
"error_message": "Web page not found."
}| Field | Type | Default | Description |
|---|---|---|---|
success | boolean | — | Always false on an error. |
error_code | string | — | A stable token. Branch on this, never on the message. |
error_message | string | — | Human-readable. Its wording is not part of the contract. |
retry_after_seconds | integer | — | Present on rate_limited. Mirrored in the Retry-After header. Absent on every other code. |
Nothing internal travels with it: no wrapper object, no internal code, no details and no stack trace. It is the same envelope the Instant Snap API uses, so one error handler can serve both.
Every code
| Field | Type | Default | Description |
|---|---|---|---|
api_key_invalid | 401 | Do not retry | Missing, malformed, deleted or unknown key. All four answer identically, so the endpoint cannot be used to discover which keys exist. |
web_page_id_invalid | 400 | Do not retry | The path segment is not a UUID. A malformed id is a client mistake, so it is a 400 rather than a 404. |
web_page_not_found | 404 | Do not retry | No such scheduled page for this key’s account — including a page that exists but belongs to somebody else. See below. |
no_trigger_allowance | 403 | Do not retry | The subscription has no capture allowance left, or is not permitted to start one right now. |
feature_not_available | 403 | Do not retry | The plan does not include API triggering. Not a 402: no amount of waiting or usage turns it into a yes, only a different plan does. |
sitemap_schedule_not_triggerable | 409 | Do not retry | The web page is a sitemap schedule. Sitemap schedules run only on their schedule - a run captures up to 1,000 pages over hours - so they cannot be triggered. |
rate_limited | 429 | Retry | Past your plan's API rate limit, or too many requests from your address — or the bad-key lockout, which answers with a fifteen-minute Retry-After. |
service_unavailable | 503 | Retry | The trigger could not be handed to the capture service. Temporary; retry_after_seconds says when to try again. The same token and status as on the Instant Snap API. |
Why 404 and not 403
Not an existence oracle
web_page_not_found, exactly as an id that never existed does. Answering 403 instead would confirm that the id is real, and anyone could then map out which ids exist by trying them.So a 404 means one of three things, and the API will not tell you which:
- The id is wrong — a typo, or an id from a different environment.
- The schedule was deleted.
- The key belongs to a different account from the schedule.
The third is the one worth checking first when a call that used to work stops working after a key rotation.
Answers that are not errors
already_pending is a success
200 with "success": true. Code that treats any answer other than triggered as a failure will report errors that never happened — and, worse, will often retry into a capture that is already running.const result = await response.json();
if (!result.success) {
if (result.error_code === "rate_limited") return retryAfter(result);
throw new Error(result.error_code);
}
if (result.status === "already_pending") {
// Not an error. A capture is already running.
return;
}Read success first to separate failures from successes, then read status to tell the two successes apart.
What to retry
| Value | Meaning |
|---|---|
Retry: 429, 503 | Throttling and an unreachable capture service both clear on their own. Honour retry_after_seconds where it is given, cap your attempts, add jitter. |
Never retry: 400, 401, 403, 404 | The identical call will fail identically. The id, the key or the plan has to change first. |
Codes this page does not list
Every refusal this service can produce is in the table above; a code outside it would be reported as internal_error. If you meet one, treat it as a transient fault — log it, retry once, and do not branch on it.
Did this page answer your question?
Tell us what is missing