Errors, pagination and quotas

The error body, the status codes you will see, quota responses, how list endpoints paginate, the mixed ID casing in responses, and how API usage is counted.

4 min read · Updated 28 September 2026

These conventions apply across the whole REST API. MCP has its own error behaviour, covered in MCP overview.

The error body

Almost every error is a JSON object with a single human-readable message:

{"error": "Conversation not found"}

There are no general machine-readable error codes. A few error families add one extra field:

Extra fieldWhenExample
reasonQuota and plan limits (429){"error":"Quota exceeded","reason":"credit_count"}
codeGuardrail and data-residency blocks on run endpoints{"error":"...","code":"SENSITIVE_DATA_BLOCKED"}
error_codeSensitive-data blocks and MCP server errors on conversation endpoints{"error":"...","error_code":"..."}

The data-residency codes are EU_INFERENCE_REQUIRED, ZERO_RETENTION_REQUIRED, NO_PROVIDER_ASSIGNED and NO_ENDPOINT_AVAILABLE. Some authentication failures return a bare status with an empty body, so do not assume every error response parses as JSON.

Status codes

StatusMeaningTypical body
200 / 201 / 204SuccessThe resource, or nothing for 204
400Invalid JSON or a field failed validation; also restricted models, residency and guardrail blocks on run endpoints{"error":"<binding error text>"}
401No valid API key{"error":"Invalid API key"}, or an empty body when no key was recognised
403Key lacks a permission, the route is not open to keys, the account is not active, or the request comes from an unsupported region{"error":"This api key does not have any of the required permissions. You need at least one of: ..."}
404Not found, or not visible to the key’s owner{"error":"Conversation not found"} (some routes return an empty body)
429Workspace quota or plan limit reached{"error":"Quota exceeded","reason":"..."}
500 / 503The operation failed, for example no model selected or a provider error{"error":"<message>"}

The exact statuses per endpoint are listed on each REST reference page. The authentication errors are explained in API keys and authentication.

Quotas

Routes that start paid work - runs, conversations, media generation, transcription, knowledge-base uploads and file processing - check the workspace’s plan and credits first. When the check fails they return:

HTTP 429
{"error": "Quota exceeded", "reason": "credit_count"}
reasonMeaning
credit_countThe workspace has used its credits. An admin can top up in the app.
user_countA limit on the number of users in the workspace’s plan.
subscriptionThe workspace’s subscription does not allow it.
trial_expiredThe trial has ended.
unknownThe limit could not be classified.

A 429 here is not a rate limit, so retrying straight away will not help. Surface it to a person who can act on it. Credits and plans are covered in Usage, credits and billing.

Rate limits

There is no published per-key or per-user request rate limit. Throughput is governed by your workspace’s plan and credits, reported through the 429 Quota exceeded response above. Long synchronous calls (a slow model, a long transcription) are bounded by how long the work takes, so give your HTTP client a generous timeout.

Pagination

List endpoints that paginate take two query parameters:

QueryDefaultMeaning
page1Page number, starting at 1.
size10Items per page.

The page metadata is in the response headers, not the body. The body is a plain JSON array.

HeaderMeaning
X-PageThe page you received.
X-Page-SizeThe page size used.
X-Total-CountTotal number of items across all pages.

Some list endpoints return everything when you send no paging parameters (for example GET /ai_model). Each endpoint’s reference says which.

curl -i "https://api.stickyprompts.com/api/v1/conversation?page=2&size=25" \
  -H "Authorization: Bearer $STICKY_API_KEY"
# X-Page: 2
# X-Page-Size: 25
# X-Total-Count: 137
import os
import requests

BASE = "https://api.stickyprompts.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['STICKY_API_KEY']}"}

def all_conversations(size=50):
    page = 1
    while True:
        r = requests.get(f"{BASE}/conversation", headers=HEADERS,
                         params={"page": page, "size": size})
        r.raise_for_status()
        yield from r.json()
        if page * size >= int(r.headers["X-Total-Count"]):
            break
        page += 1
const BASE = "https://api.stickyprompts.com/api/v1";
const headers = { Authorization: `Bearer ${process.env.STICKY_API_KEY}` };

async function* allConversations(size = 50) {
  for (let page = 1; ; page++) {
    const res = await fetch(`${BASE}/conversation?page=${page}&size=${size}`, { headers });
    if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
    yield* await res.json();
    if (page * size >= Number(res.headers.get("X-Total-Count"))) break;
  }
}

MCP tools page differently, with limit and offset arguments and a total_count in the result. See MCP tool reference.

IDs and field casing

  • Most resources use numeric IDs. Many endpoints also accept an 8-character slug in place of the ID; the reference pages say where.
  • Most records include four base fields with capitalised keys: ID, CreatedAt, UpdatedAt and DeletedAt. The rest of the fields are snake_case, and a few are camelCase (for example isUser on messages, userId and projectId on conversations).
  • Some hand-written responses, such as prompt run results, use lowercase id and created_at instead.
  • Credit and money values typed as decimals (for example credits_used, multiplier) arrive as JSON strings like "0.4213". Parse them with a decimal type, not a float.
{
  "ID": 5120,
  "CreatedAt": "2026-09-28T09:13:58Z",
  "DeletedAt": null,
  "slug": "aB3dE5gH",
  "userId": 77,
  "next_message_ai_model_id": 42,
  "credits_used": "0.4213"
}

Map fields explicitly in your client rather than relying on one naming convention.

Correlation ID

Every response carries an X-Correlation-ID header. Log it with your own request logs. If you need help with a specific call, include it when you write to hello@stickyprompts.com.

Geographic restriction

Requests from a region the service does not serve are refused, for REST and MCP alike:

HTTP 403
{"error": "access from your region is not supported"}

How usage is counted

API and MCP calls go through the same execution, quota and billing path as the web app. Usage is attributed to the key’s owner and their workspace, exactly as if they had done the same thing in the app, and draws on the same credits. There is no separate API price list and API usage is not reported separately from app usage. Individual run responses do not include token counts or cost; workspace admins see usage in Usage, credits and billing.