SuperCoolDocs Get an API key

Reference

Rate limits & errors

Every SuperCool API error code, what it means and how to fix it, plus rate limits, rate-limit headers, request ids and the request inspector.

View as Markdown

#Error shape

Every error has the same JSON shape and an HTTP status that matches it:

json
{
  "error": "idempotency_conflict",
  "message": "That Idempotency-Key was already used for a different message. Use a new key for a new request.",
  "request_id": "req_6c2f0e1d9a8b7c6d5e4f3a2b",
  "docs": "https://supercool.com/docs/api/errors#idempotency_conflict"
}
Field Meaning
error A stable, machine-readable code. Branch on this, never on message.
message What went wrong, written for people. It may change.
request_id The request's id, also in the Request-Id header.
docs A link to the code's entry on this page.

Some errors add fields: invalid_request lists its problems, and poll_in_progress includes the cursor to use when you call again.

Outcomes of the work itself, like running out of credits, hitting the running-jobs cap, a failed job or a question from the agent, are not errors. They come back as a message with a status.

#Request ids and the inspector

Every response, success or error, has a Request-Id header (req_…). Log it. The API dashboard's request inspector shows every request from the last 30 days: time, key, method, path, status, error code, latency, and the request and response bodies (redacted and capped). Search it by request id or message id, and filter by key, status, path or error code.

If you contact support, include the request id.

#Rate limits

Limit Value Applies to
Requests 600 per minute Each API key, every request
Messages 120 per hour, 1,000 per day Each account, POST /v1/messages
Waits 1,500 per hour Each account, long-polls (?wait= and /events)
Work reads 600 per hour Each account, GET /v1/work/{work_id}
Running jobs 5 at once Each account. Not an HTTP error: see below.

The per-key budget means one busy or leaked key can't use up the whole account. The account limits are generous, and are there to stop runaway loops.

#Running jobs

Up to 5 jobs can run at once per account. The cap never refuses a request: POST /v1/messages always gets through, so you can always stop work or follow up on it. Instead, if the agent tries to start new work while 5 jobs are running, that start is refused. The message comes back as usual (201) with a job whose status is blocked and reason is too_many_running, and the message lists the work that's running in running. See At capacity.

#Headers

Every authenticated response reports the per-key budget:

Header Meaning
RateLimit-Limit Requests this key may make per minute (600).
RateLimit-Remaining Requests left in the current window.
RateLimit-Reset Seconds until the oldest counted request leaves the window.
Retry-After On every 429, seconds to wait before retrying.

Every 429 carries Retry-After. For the per-key budget it's the exact number of seconds until a request frees up. For the account limits (messages, waits, work reads) it's 60.

#Handling 429s

python
import random
import time

import requests

def call(method, url, **kwargs):
    for attempt in range(6):
        r = requests.request(method, url, timeout=60, **kwargs)
        if r.status_code not in (429, 500, 503):
            return r
        wait = float(r.headers.get("Retry-After", 2 ** attempt)) + random.random()
        time.sleep(wait)
    return r

Always send an Idempotency-Key on POST /v1/messages, so a retry can never start work twice.

#Status codes

Status Meaning
200 OK. Also returned when an Idempotency-Key replays an existing message.
201 Created: a new message, upload or webhook endpoint.
400 The request can't be processed as sent, including requests that don't match the schema (invalid_request). Fix it before retrying.
401 The API key is missing, unknown, expired or revoked.
404 Nothing with that id for this key or account.
409 Conflicts with the current state.
413 A file is too large.
422 An uploaded file was refused (executable_refused).
429 A rate limit. Always has Retry-After.
500 Something broke on our side. Retry with backoff.
503 The API is temporarily switched off. Retry later.

#Error codes

#400: Bad request

#bad_request

The request is invalid in a way not covered by a more specific code, for example an unusable webhook setting. Read message for details.

#invalid_request

The request doesn't match what the endpoint expects: a required field is missing, a field has the wrong type, a query parameter is out of range (like wait above 45), or the body isn't valid JSON. The response lists what's wrong in problems, up to 10 entries:

json
{
  "error": "invalid_request",
  "message": "The request doesn't match what this endpoint expects; see `problems`.",
  "request_id": "req_6c2f0e1d9a8b7c6d5e4f3a2b",
  "docs": "https://supercool.com/docs/api/errors#invalid_request",
  "problems": [
    { "field": "files", "problem": "Input should be a valid list" },
    { "field": "wait", "problem": "Input should be less than or equal to 45" }
  ]
}

field is the dotted path to the field (like files.0.url or size), or null when the problem is with the body as a whole. Fix the request; retrying it unchanged won't help.

#empty_message

POST /v1/messages had no message, files or upload_ids. Send at least one.

#too_long

The message text is over 20,000 characters. Send the long part as a file instead.

#bad_cursor

The cursor on GET /v1/messages/{id}/events isn't valid for this API key: it's malformed, or it came from another key. Use the cursor from your last page, or leave it out to start from the beginning of the message.

#bad_url

A webhook endpoint URL was refused. It must be a public https URL on port 443 or 8443, with no username or password in it, and at most 2,000 characters. Private and internal addresses aren't allowed.

#bad_events

A webhook endpoint listed an unknown event. Use "*" or events from the list.

#bad_size

POST /v1/uploads needs size: the file's exact size in bytes, as a positive whole number.

#too_many

A message named more than 10 upload_ids. Split the files across messages, or combine them (for example, into a zip).

#401: Unauthorized

#unauthorized

The Authorization header is missing, or the key is unknown, expired or revoked. Send Authorization: Bearer sc_key_… with an active key from the dashboard. See Authentication.

#404: Not found

#not_found

Nothing with that id is available to you:

  • Messages belong to the API key that sent them, and are kept for at least 14 days after their last job's deadline. Check you're using the same key, or read the work instead.
  • Work, files, uploads and webhook endpoints belong to your account. Check the id, and that the chat wasn't deleted.
  • webhook_endpoint_id on a message must name an endpoint on your account.

#409: Conflict

#idempotency_conflict

The Idempotency-Key was already used, within 7 days and with this API key, for a message with a different body. Use a new key for a new request. See Idempotency.

#poll_in_progress

Another GET /v1/messages/{id}/events wait is already running for this message. Only one runs at a time. Wait for it to return, then call again with the cursor from the error.

#too_many_endpoints

The account already has 10 webhook endpoints. Delete one you don't need, or use one endpoint for several purposes with per-message routing.

#not_pending

The upload can't be completed because it was rejected or already attached to a message. Create a new upload.

#not_uploaded

You completed an upload before the file reached storage, or its 15-minute presigned POST expired. POST the file to the upload's url first, or create a new upload.

#changed

The uploaded file was replaced while it was being completed. Upload it again with a new upload.

#upload_not_ready

A message named an upload that isn't ready: not completed yet, or not on your account. Call POST /v1/uploads/{id}/complete first.

#413: Too large

#too_large

A file is over the limit: 500 MB per upload, or 1 GB of uploads per message. For inline files, oversized files are skipped and listed in the message's notes instead.

#422: Unprocessable

#executable_refused

The uploaded file is an executable program, which can't be attached. POST /v1/uploads/{id}/complete refuses it and deletes it. This is the only 422 the API returns. (An executable sent inline in files doesn't fail the message: it's skipped and listed in the message's notes.)

#429: Too many requests

#rate_limited

A rate limit was hit: this key's 600 requests per minute, or one of the account's limits on messages, waits or work reads. Wait the Retry-After seconds (exact for the per-key budget, 60 for account limits), then retry. See Rate limits.

#500 and 503

#internal

Something went wrong on our side. Nothing you sent was lost. Retry with backoff, using the same Idempotency-Key. If it keeps happening, contact support with the request_id.

#unavailable

The API is temporarily switched off, for example during an incident. message says why. Retry later.

Last updated