Documentation Index
Fetch the complete documentation index at: https://docs.reflecto.dev/llms.txt
Use this file to discover all available pages before exploring further.
Most Reflecto errors return JSON with a stable error.code you can switch on
in client code; authentication failures (401) use a flat shape instead — see
the auth shape below. The human-readable message may
evolve; the codes will not.
Error shape
Most endpoints return:
{
"error": {
"code": "payload_too_large",
"message": "Payload exceeds 2048 byte limit",
"details": { "size": 3104, "max": 2048 }
}
}
details is currently populated only for payload_too_large (413). The
byte-length 400 errors (message_too_long, invalid_title, invalid_url,
invalid_url_title, invalid_action) returned details: { bytes, max }
in earlier API revisions but no longer do — the field is missing entirely
on those responses. A future revision will restore it.
Message-text changes from earlier API revisions
The error code values are stable wire contracts and have not changed.
The human-readable error.message strings, however, were rewritten when
validation moved to Zod schemas. Clients that match on .code are
unaffected; clients that display .message verbatim will see new wording:
.code | When | Previous .message | Current .message |
|---|
invalid_action | invalid action URL | must be a valid URL | is not a valid URL |
invalid_title | empty title | title must be 1–100 bytes (shared with the over-limit branch) | title must not be empty (now distinct) |
invalid_title | over-limit title | title must be 1–100 bytes (shared with the empty branch) | title must be ≤ 100 bytes (now distinct) |
invalid_message | message key omitted | message is required | Invalid input: expected string, received undefined |
invalid_action | action url missing | each action requires label + url | Schema default for the missing required field |
Auth failure shape
Auth failures use a flat shape so token problems don’t get masked behind
nested structure. The full shape — both fields — is shown below:
{
"error": "missing_token",
"message": "Authorization: Bearer rfk_live_… required"
}
message is optional. The invalid_token variant omits it (the code alone
is actionable):
{
"error": "invalid_token"
}
Status codes
| Status | When |
|---|
| 200 | Accepted and enqueued. Check warnings in the body for non-fatal notes. |
| 400 | Body malformed or a field failed validation. |
| 401 | Missing, invalid, or revoked bearer token. |
| 403 | Token exists but lacks scope (e.g. priority above priority_cap). |
| 413 | Serialized envelope > 2048 bytes. |
| 429 | Rate limit hit on one of the layers; Retry-After is set. |
| 5xx | Server error. Retry with exponential backoff. |
Codes
Validation (400)
| Code | Meaning |
|---|
invalid_body | Body wasn’t JSON, form-encoded, or text. |
invalid_message | message missing or not a string. |
message_too_long | message exceeds 1500 bytes (UTF-8). |
invalid_title | title is 0 bytes or > 100 bytes (UTF-8). |
invalid_priority | Not one of min, low, default, high, urgent. |
invalid_url | Not http(s), invalid URL, or > 512 bytes. |
invalid_url_title | url_title > 32 bytes. |
invalid_action | Missing label/url, oversized, or non-http(s) scheme. |
invalid_device | device parameter > 256 chars. |
Auth (401)
| Code | Meaning |
|---|
missing_token | No Authorization: Bearer … header sent. |
invalid_token | Token format invalid, unknown, or revoked. |
Scope (403)
| Code | Meaning |
|---|
priority_capped | Token’s priority_cap is below the requested priority. |
Size (413)
| Code | Meaning |
|---|
payload_too_large | Serialized envelope > 2048 bytes. |
Rate limit (429)
| Code | Meaning |
|---|
rate_limit_exceeded | One of the rate-limit layers tripped. See X-RateLimit-Resource for which one. |
Server errors (5xx)
| Code | Meaning |
|---|
internal_error | Catch-all for unhandled exceptions on the server (Redis unavailable, FCM dispatch failure, etc.). Retry with exponential backoff. |
Warnings vs errors
Some conditions are surfaced as warnings on a 200 response rather than
errors, to keep long-running automations alive:
unknown device label: '…' — one of the names in device didn’t match any
paired device.
device fallback: all entries unknown, delivering to every paired device —
every entry was unknown; the send fell back to broadcast.
tags truncated to first 5 (got 7) — excess tags dropped.
tag #N truncated to 32 bytes — a tag exceeded the per-tag byte cap.
actions truncated to first 3 (got 5) — excess action buttons dropped.
no paired devices for this token's owner — the request succeeded but
produced no enqueues. Useful for cron jobs run during transient unpairing.
token scope '…' dropped out-of-scope device(s): … — caller’s device
parameter referenced devices outside the token’s scopeDevices.