Core concepts
Errors
KYA Pro returns the same error format for every non-2xx response.
Envelope shape
json response
{
"error": "bad_request",
"detail": "toTs must be after fromTs",
"requestId": "3f2a1c-..."
}| Field | Type | Description |
|---|---|---|
error | string | Short code your code can switch on. Stable — safe to depend on. |
detail | string | Human message. Safe to show in a UI. |
requestId | string | UUID matching the X-Request-Id response header. Include it when you report issues. |
The X-Request-Id header is always set on the response and matches the requestId in the body. If your client sends its own X-Request-Id, KYA echoes it back.
HTTP status codes
| Status | error code | Meaning |
|---|---|---|
| 400 | bad_request | Malformed body, missing required field, business-rule violation |
| 401 | unauthorized | Missing or invalid bearer token |
| 402 | payment_required | Account trial expired or subscription lapsed |
| 403 | forbidden | Token is valid but the caller lacks the required role, or a cross-workspace boundary was hit |
| 404 | not_found | Resource does not exist in your workspace |
| 409 | conflict | Uniqueness violation or state conflict |
| 410 | gone | Resource existed but is unrecoverable |
| 422 | unprocessable | Body parsed but failed validation |
| 429 | rate_limit_exceeded | Rate limit hit — honor Retry-After |
| 500 | internal_error | Server bug or storage failure — safe to retry |
| 502 | upstream_down | An upstream service is unavailable |
Structured error details
Some errors return a structured detail object instead of a string, so the client gets machine-readable fields alongside the human message.
Rate limit exceeded (429)
json response
{
"error": "rate_limit_exceeded",
"message": "Rate limit exceeded for this surface. Retry after the interval indicated by the Retry-After header."
}The response includes a Retry-After header (seconds to wait before the next call is accepted). Clients should back off at least that long before retrying.
Account gated (402)
json response
{
"error": "account_gated",
"status": "trial_expired",
"reason": "Trial period ended on 2026-07-15",
"upgrade_url": "https://app.veldtlabs.ai/billing",
"message": "Ingest is paused for this account. Upgrade or renew to resume."
}status is one of trial_expired, sub_lapsed, sub_canceled.
Admin required (403)
json response
{
"error": "admin_required",
"message": "This action requires the 'admin' role."
}Retry guidance
| Status | Retry? |
|---|---|
| 4xx (except 429) | No — fix the request |
| 429 | Yes, after Retry-After seconds |
| 500 | Yes, with exponential backoff — usually safe (writes are idempotent where the response says so) |
| 502 | Yes, with backoff |
Read-only endpoints (GET) are always safe to retry. Write endpoints are documented case-by-case.