Pagination and errors
Conventions every Roxels REST endpoint follows. Read this once; it applies everywhere.
Base URL
All endpoints are under https://api.roxels.ai/v1/.
Content type
Requests and responses use application/json. Set the header on every POST/PATCH:
curl https://api.roxels.ai/v1/templates \
-H "Authorization: Bearer sk-your-key-here" \
-H "Content-Type: application/json" \
-d '{"name": "..."}'Pagination
List endpoints return a paginated response:
{
"items": [
/* ... */
],
"next_cursor": "eyJpZCI6Li4ufQ==",
"has_more": true
}To fetch the next page, pass the cursor:
curl "https://api.roxels.ai/v1/conversations?cursor=eyJpZCI6Li4ufQ==&limit=50" \
-H "Authorization: Bearer sk-your-key-here"Common query parameters on list endpoints:
| Param | Description |
|---|---|
cursor |
Opaque cursor returned by the previous page. |
limit |
Page size. Defaults to a reasonable value per endpoint; can be raised up to a documented maximum. |
| Filter-specific params | Each endpoint documents its own filters (e.g. template_id, status, since). |
When has_more is false, you've reached the end.
Error shape
Errors return a non-2xx status and a JSON body with a stable shape:
{
"error": {
"code": "validation_error",
"message": "Field 'name' is required.",
"field": "name"
}
}| Field | Meaning |
|---|---|
error.code |
A machine-readable code. Stable across versions. Switch on this in code. |
error.message |
Human-readable explanation. Safe to show to admin users; don't show to end users without translation. |
error.field |
Optional. The request field that caused the error, if applicable. |
Common error codes
| Code | HTTP | Meaning |
|---|---|---|
unauthorized |
401 | Missing or invalid bearer token. |
forbidden |
403 | Token is valid but lacks permission. |
not_found |
404 | Resource doesn't exist. |
validation_error |
400 | Request body or params failed validation. |
conflict |
409 | Resource state conflicts with the request (e.g. version mismatch). |
rate_limited |
429 | Too many requests; back off and retry. |
internal_error |
500 | Something went wrong on our side. Retry with backoff; if persistent, contact support. |
Switch on error.code, not on error.message. Messages may be reworded; codes are part of the contract.
Idempotency
Endpoints that create resources accept an optional Idempotency-Key header. Same key + same body within 24 hours returns the original response; same key + different body returns 409 conflict. Use a UUID per request from your application.
curl https://api.roxels.ai/v1/conversations \
-H "Authorization: Bearer sk-your-key-here" \
-H "Idempotency-Key: 5b1e2c3d-..." \
-d '{"template_id": "tpl_..."}'This is the safe way to retry a network-failed POST.
Request IDs
Every response includes an X-Request-Id header:
HTTP/1.1 200 OK
X-Request-Id: req_a1b2c3d4When something unexpected happens, include the request id when you reach out to support. We use it to find the exact request in our logs.
Rate limits
Rate limits apply per API key. When you exceed them, you get 429 rate_limited. Back off and retry — see the Retry-After response header for the recommended wait.
CORS
The REST API is not CORS-enabled — it's intended to be called from your backend, not from browsers. For browser-side flows, use the embed (which calls a CORS-enabled subset of endpoints internally) or proxy calls through your own server.
Read next
- Authentication — Key types and how to send them.
- Templates — Manage templates programmatically.
- Conversations — Start and inspect conversations.
- Persons — Persistent identity for resumption.