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-..."
}
FieldTypeDescription
errorstringShort code your code can switch on. Stable — safe to depend on.
detailstringHuman message. Safe to show in a UI.
requestIdstringUUID 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

Statuserror codeMeaning
400bad_requestMalformed body, missing required field, business-rule violation
401unauthorizedMissing or invalid bearer token
402payment_requiredAccount trial expired or subscription lapsed
403forbiddenToken is valid but the caller lacks the required role, or a cross-workspace boundary was hit
404not_foundResource does not exist in your workspace
409conflictUniqueness violation or state conflict
410goneResource existed but is unrecoverable
422unprocessableBody parsed but failed validation
429rate_limit_exceededRate limit hit — honor Retry-After
500internal_errorServer bug or storage failure — safe to retry
502upstream_downAn 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

StatusRetry?
4xx (except 429)No — fix the request
429Yes, after Retry-After seconds
500Yes, with exponential backoff — usually safe (writes are idempotent where the response says so)
502Yes, with backoff

Read-only endpoints (GET) are always safe to retry. Write endpoints are documented case-by-case.