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.
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 field | When | Example |
|---|---|---|
reason | Quota and plan limits (429) | {"error":"Quota exceeded","reason":"credit_count"} |
code | Guardrail and data-residency blocks on run endpoints | {"error":"...","code":"SENSITIVE_DATA_BLOCKED"} |
error_code | Sensitive-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
| Status | Meaning | Typical body |
|---|---|---|
200 / 201 / 204 | Success | The resource, or nothing for 204 |
400 | Invalid JSON or a field failed validation; also restricted models, residency and guardrail blocks on run endpoints | {"error":"<binding error text>"} |
401 | No valid API key | {"error":"Invalid API key"}, or an empty body when no key was recognised |
403 | Key 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: ..."} |
404 | Not found, or not visible to the key’s owner | {"error":"Conversation not found"} (some routes return an empty body) |
429 | Workspace quota or plan limit reached | {"error":"Quota exceeded","reason":"..."} |
500 / 503 | The 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"}
reason | Meaning |
|---|---|
credit_count | The workspace has used its credits. An admin can top up in the app. |
user_count | A limit on the number of users in the workspace’s plan. |
subscription | The workspace’s subscription does not allow it. |
trial_expired | The trial has ended. |
unknown | The 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:
| Query | Default | Meaning |
|---|---|---|
page | 1 | Page number, starting at 1. |
size | 10 | Items per page. |
The page metadata is in the response headers, not the body. The body is a plain JSON array.
| Header | Meaning |
|---|---|
X-Page | The page you received. |
X-Page-Size | The page size used. |
X-Total-Count | Total 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: 137import 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 += 1const 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
slugin place of the ID; the reference pages say where. - Most records include four base fields with capitalised keys:
ID,CreatedAt,UpdatedAtandDeletedAt. The rest of the fields are snake_case, and a few are camelCase (for exampleisUseron messages,userIdandprojectIdon conversations). - Some hand-written responses, such as prompt run results, use lowercase
idandcreated_atinstead. - 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.