Authentication & Scopes
One API key per TrustPager workspace, with scope-based permissions and optional approval gating.
API key format
- Prefix: all keys start with
tp_live_ - Header:
Authorization: Bearer tp_live_... - Create or rotate: https://app.trustpager.com/settings/api
- Visibility: the full key is shown only once at creation. Lose it and you must create a new one.
Scopes
Scopes are stamped on the key at creation and follow you across both MCP and REST surfaces. Format: <resource>:<action>.
contacts:read,contacts:write,contacts:delete— and similar per resourceopportunities:read,opportunities:write,opportunities:deleteadmin— superscope; grants everything
Full list of per-resource scopes: see the OpenAPI spec under each endpoint's x-scopes.
Approval queue
Keys with -approval scope variants (e.g. contacts:write-approval) queue write operations for human review instead of executing
immediately. Use these when an AI agent should be able to PROPOSE changes that a human ratifies.
- Write operations return HTTP 202 with an
approval_idin the response body. - The action is queued, NOT executed. Do not retry.
- Check status:
GET /approvals/:id - Humans approve / reject at https://app.trustpager.com/settings/api?tab=approvals
You can also opt IN to review per request: add "require_approval": true to the body of any write, and it queues for
approval (HTTP 202 + approval_id) even when your key has permission to execute it directly. Useful when an agent wants a human
to confirm a specific action. Approving it later runs the action exactly as sent.
Pagination
List endpoints return a cursor-paginated envelope:
{ data, pagination: { has_more, next_cursor } }. Pass the next_cursor value back as the
?after= query parameter to fetch the next page. Default page size is 25, maximum 100 (?limit=).
Idempotency
Send an Idempotency-Key header on write requests (POST/PATCH/PUT/DELETE) to prevent duplicate records if a
request is retried. For 24 hours the same key replays the original successful (2xx) response instead of
executing the operation again. Error responses are not remembered, so retrying a write that failed with a 5xx runs it
again: see Retrying safely.
Credit costs
Reads are free. Writes are billed; AI generation and sends (email, SMS, voice) are billed more. The MCP surface is ~10× cheaper per call than REST and is the recommended surface for interactive AI work — see Using AI.
Error responses on auth failure
401 and 403 responses are AI-friendly — they tell the caller exactly what to do:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="trustpager", error="invalid_token", error_description="Missing Authorization header"
Link: <https://docs.trustpager.com>; rel="help", <https://docs.trustpager.com/openapi.json>; rel="describedby"
Content-Type: application/json
{
"error": {
"code": "UNAUTHORIZED",
"message": "Missing Authorization header",
"details": {
"docs": "https://docs.trustpager.com",
"api_base_url": "https://api.trustpager.com/functions/v1/api/v1",
"auth_scheme": "Authorization: Bearer tp_live_...",
"fix": "Include a valid API key in the Authorization header..."
}
}
} Rate limits
Default: 60 requests per minute, 10,000 per day per key. Configurable per key. On limit hit you'll see HTTP 429 with a
Retry-After header and a RATE_LIMITED error code.
Retrying safely
Whether a failed request is safe to send again depends on whether it could have run before it failed.
- Platform busy (always safe): an HTTP 503 whose
sb-error-coderesponse header containsSERVICE_DEGRADED(the body has noerrorobject) means the platform was momentarily too busy to start your request. It never ran, so retry it, writes included: wait about half a second, then a second or so, and stop after two or three tries. These cluster in the first seconds after each quarter hour. - Rate limited (always safe): an HTTP 429 was refused before it ran. Wait for
Retry-After, then retry. - Reads (always safe): a
GETthat failed with any 5xx or a network error can be retried. - Writes after any other 5xx or a dropped connection (check first): a POST, PATCH, PUT or DELETE may have
completed before the error. Check whether it took effect (for example
GETthe record, or list by a value you set) before sending it again, or you may create a duplicate or send something twice. AnIdempotency-Keydoes not cover this case, because only successful responses are replayed.
IP allowlist (optional)
You can restrict a key to specific IP addresses on the key creation form. Requests from other IPs return HTTP 403 with
error.code: "FORBIDDEN" and message "IP address not allowed". Leave the allowlist empty to allow any IP.
Error codes
Every error response carries a stable error.code alongside the HTTP status, a human message, and a
details.fix hint. Branch on the code, not the message text.
| HTTP | code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | A field is missing or invalid. Fix the request body and retry. |
| 400 | AMBIGUOUS_REFERENCE | A name was given where a UUID is required and it matches existing records. Retry with the UUID. |
| 401 | UNAUTHORIZED | Missing or invalid API key. |
| 402 | INSUFFICIENT_CREDITS | Not enough credits for this operation. Reads are free. |
| 403 | FORBIDDEN | The key lacks the required scope, or the caller IP is not allowed. |
| 404 | NOT_FOUND | The record does not exist, or belongs to a different workspace. This is a genuine miss, not a transient error. |
| 409 | CONFLICT | The write conflicts with an existing record (e.g. a value that must be unique is already in use). |
| 413 | SOURCE_TOO_LARGE | The payload or source content exceeds the allowed size. |
| 429 | RATE_LIMITED | Too many requests. Wait for the Retry-After header, then retry. |
| 500 | INTERNAL_ERROR | Unexpected server-side error. A read is safe to retry; a write may have completed, so check before retrying (see Retrying safely). |
| 503 | TEMPORARILY_UNAVAILABLE | A transient database or connection issue (timeout, dropped connection). This is not a problem with your request or IDs. Wait a moment (a Retry-After header is included) and retry a read as is; for a write, check it did not take effect first (see Retrying safely). |
| 503 | no error object; sb-error-code header contains SERVICE_DEGRADED | The platform was momentarily too busy to start the request. It never ran: retry the same request after a short wait, writes included. |