Skip to content
Live in production, in shadow mode: FingerTrackID recommends, your system decides.Status →

Error catalog (Problems)

Every error comes as application/problem+json (RFC 9457), with type, title, status, retryable and, when present, correlation_id.

Download the exact Problem schema and v1 OpenAPI contract for validation.

The type is a full URI under https://fingertrackid.dev/problems/, for example https://fingertrackid.dev/problems/rate-limited.

  • It is a stable identifier. Do not fetch it at runtime and do not treat a failed lookup as a problem. Compare the full type string.
  • This page is the documentation for every type. Each one has its own section below, at https://docs.fingertrackid.com/api/errors/#<suffix> (for example #rate-limited), and opening a type URI in a browser redirects to that section.
  • Code against type and status. The title is human-readable text; it is only fixed for authentication-failed (Autenticação falhou, in Portuguese as the contract defines) and assessment-result-expired (Assessment result expired). Do not branch on title.
  • The contract allows errors[] (with pointer and code) only in validation-failed, as an optional field. Do not rely on it to find the wrong field.
type suffix HTTP retryable Routes
validation-failed 400 false Assessment, feedback
event-context-invalid 400 false Assessment
occurred-at-out-of-window 400 false Assessment
authentication-failed 401 false Assessment, feedback
timestamp-out-of-window 401 true Assessment, feedback
request-replayed 401 true Assessment, feedback
forbidden 403 false Assessment, feedback
not-found 404 false Feedback
idempotency-conflict 409 false Assessment, feedback
binding-conflict 409 false Assessment, feedback
assessment-result-expired 410 false Assessment
payload-too-large 413 false Assessment, feedback
unsupported-media-type 415 false Assessment, feedback
rate-limited 429 true Assessment, feedback
internal 500 false Assessment, feedback
assessment-unavailable 503 true Assessment, feedback

The feedback routes have their own closed Problem catalog in the feedback OpenAPI, with English titles. The Web SDK’s collection endpoint uses a few more types, listed in seen in the browser, and the types the API does not send are listed after them.

400, not retryable. The request does not match the schema, or the route is a variation of /v1/assessments (query string, trailing slash, method other than POST), or the request carries Expect/Trailer or a duplicated framing header. Fix the request against the schema.

For a v1.1 request this includes a tag outside the grammar (uppercase, hyphen, space, more than 64 characters, 11 or more digits in total) and a v1-only field (journey, action, journey_context). There is no separate Problem type for the tag.

400 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/validation-failed",
"title": "Request inválido",
"status": 400,
"correlation_id": "corr-problem-validation-0001",
"retryable": false,
"errors": [
{
"pointer": "/journey",
"code": "INVALID_ENUM"
}
]
}

400, not retryable. The event_context_token is present but invalid, expired, already used or from another scope. Nothing is stored. Under the managed production profile a token expires no later than your application’s evidence window (60 or 300 seconds) after its collection reached FingerTrackID (the evidence window). Do not retry: the same body gets the same answer, and a different body under the same operation IDs is an idempotency-conflict. To still assess the event, send it once as a new operation (new external_event_id and idempotency_key) with event_context_token: null. When the browser has no token, send null from the start (integration guidance).

400 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/event-context-invalid",
"title": "Contexto do evento inválido",
"status": 400,
"correlation_id": "corr-problem-context-invalid-0001",
"retryable": false
}

400, not retryable. The occurred_at of a new operation is outside ±300 s of the server clock. Check the clock and where the timestamp comes from; this route is not for backfill.

400 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/occurred-at-out-of-window",
"title": "Evento fora da janela online",
"status": 400,
"correlation_id": "corr-problem-occurred-at-0001",
"retryable": false
}

401, not retryable. The uniform authentication failure (see authentication): wrong bytes, headers, key_id, secret decoding, or a revoked, suspended or blocked credential. Treat it as a configuration error and alert.

401 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/authentication-failed",
"title": "Autenticação falhou",
"status": 401,
"correlation_id": "corr-problem-authentication-0001",
"retryable": false
}

401, retryable. Your clock is outside ±300 s of the server clock. Synchronize and send a new attempt.

401 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/timestamp-out-of-window",
"title": "Timestamp da assinatura fora da janela",
"status": 401,
"correlation_id": "corr-problem-timestamp-0001",
"retryable": true
}

401, retryable. A request_id was reused. Send a new attempt, and fix the ID generator.

401 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/request-replayed",
"title": "Identificador da tentativa já consumido",
"status": 401,
"correlation_id": "corr-problem-replay-0001",
"retryable": true
}

403, not retryable. The credential is valid but lacks the route’s capability. Create a server credential with that permission in the console.

403 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/forbidden",
"title": "Capability de assessment ausente",
"status": 403,
"correlation_id": "corr-problem-forbidden-0001",
"retryable": false
}

404, not retryable, feedback routes only. The target assessment does not exist or is outside the authenticated scope; both cases share this response. Check the assessment_id in the path.

409, not retryable. The idempotency key or external ID was reused with different content. Reconcile; do not invent new IDs automatically.

The tag is content: a retry with the same IDs and another tag is a conflict. So is an ID of a v1 operation sent again in a v1.1 body, or the reverse: v1 and v1.1 operations never share IDs.

409 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/idempotency-conflict",
"title": "Chave de idempotência já usada com outro conteúdo",
"status": 409,
"correlation_id": "corr-problem-idempotency-0001",
"retryable": false
}

409, not retryable. Person, account or session references are incompatible with bindings already stored. On the assessment route the usual cause is an account_ref that is already bound to another subject_ref: an account never changes person. No event or assessment is stored, and the same body gets the same answer, so do not retry it. Fix the mapping in your backend (keep each reference’s key and prefix unchanged over time, see person and account references), and continue your normal flow: for a login, the login goes on.

409 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/binding-conflict",
"title": "Vínculo de identidade ou sessão incompatível",
"status": 409,
"correlation_id": "corr-problem-binding-conflict-0001",
"retryable": false
}

410, not retryable, assessment route only. The authenticated logical operation exists, but its result is outside the approved history window. Stop retrying; do not create new IDs to regenerate the old operation.

410 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/assessment-result-expired",
"title": "Assessment result expired",
"status": 410,
"retryable": false
}

413, not retryable. The body is above 16384 bytes. Reduce it and sign again.

413 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/payload-too-large",
"title": "Payload excede o limite",
"status": 413,
"correlation_id": "corr-problem-payload-0001",
"retryable": false
}

415, not retryable. Content-Type is not exactly application/json, or Content-Encoding is present.

415 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/unsupported-media-type",
"title": "Representação do request não suportada",
"status": 415,
"correlation_id": "corr-problem-media-type-0001",
"retryable": false
}

429, retryable. Above your server client’s rate. Wait for Retry-After, then send a new attempt with the same body (limits).

429 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/rate-limited",
"title": "Limite de assessments atingido",
"status": 429,
"correlation_id": "corr-problem-rate-limit-0001",
"retryable": true
}

500, not retryable. A known internal failure before anything was stored. Do not retry automatically; open a support request with the correlation_id.

500 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/internal",
"title": "Falha interna não retentável",
"status": 500,
"correlation_id": "corr-problem-internal-0001",
"retryable": false
}

503, retryable. Unavailable or unknown state. Wait for Retry-After (today always 1 second; wait at least 1 second if the header is ever missing), then send a new attempt with the same body: a new request_id, current timestamp and new signature, because the request_id of the answered attempt may already be consumed. A retained assessment returns 200, an expired result returns definitive 410. Retry a bounded number of times inside your business deadline, never in a loop.

503 · application/problem+json
{
"type": "https://fingertrackid.dev/problems/assessment-unavailable",
"title": "Assessment temporariamente indisponível",
"status": 503,
"detail": "Repita a mesma operação lógica com novo request_id; o commit pode ter ocorrido.",
"correlation_id": "corr-assessment-timeout-0001",
"retryable": true
}

The Web SDK talks to your collection domain and handles these responses itself, returning a status such as UNAVAILABLE to your code. You never parse them, but they can appear in the browser’s network panel.

type suffix HTTP Meaning
origin-not-allowed 403 The page origin is not one of the application’s allowed origins under this collection domain. The response carries no CORS approval, so the browser hides it and the SDK reports TRANSPORT_ERROR
sdk-session-conflict 409 A conflict with the SDK session’s current state; the SDK handles it
event-context-conflict 409 A conflicting event context request for the same SDK event; the SDK handles it
sdk-unavailable 503 Collection is temporarily unavailable; continue with a null context

The collection endpoint also uses validation-failed, authentication-failed, not-found, idempotency-conflict, payload-too-large, unsupported-media-type, rate-limited and internal with the same meaning as above; there, internal is retryable by the SDK.

FingerTrackID’s catalog reserves a few more types. A type URI with one of these suffixes still lands here, but the assessment, feedback and collection routes never return them: code that handles the types above handles every response.

type suffix What you receive instead
signature-invalid, unknown-client, client-suspended authentication-failed. Authentication failures are uniform, so a refusal never tells a caller whether the signature, the key or the credential’s state was wrong
nonce-replayed request-replayed
external-event-conflict idempotency-conflict
assessment-timeout, assessment-state-unknown assessment-unavailable: a deadline that ran out or a state that could not be confirmed is retried with the same body
journey-key-cardinality-exceeded, assessment-profile-not-activated Nothing: they are reserved for a future request profile that is not accepted today. The v1 and v1.1 requests never return them

401, 403, 429 and 503 in one sentence each

Section titled “401, 403, 429 and 503 in one sentence each”
  • 401 — authentication of the attempt failed. authentication-failed is uniform and is not retried; timestamp-out-of-window and request-replayed are retried with a new attempt.
  • 403 — you are authenticated, but the credential lacks the route’s capability.
  • 429 — above the server client’s rate. Wait for Retry-After, then retry with a new request_id, timestamp and signature; retrying without waiting can block the credential for 10 minutes (limits).
  • 503 — unavailable or unknown state. Wait for Retry-After, then retry with the same body and a new request_id, timestamp and signature, a bounded number of times; a retained assessment returns 200; an expired result returns definitive 410.
  • On the server-to-server API (assessment and feedback), 429 and 503 carry Retry-After in whole seconds, at least 1; today they always send 1. Read the header instead of hard-coding a value, and wait at least 1 second if it is ever missing. The collection endpoint’s 429 computes its value: at the new-session rate, the time until the next session open fits; at the application’s concurrent-session limit, up to 1800 seconds. The Web SDK honours it for you.
  • Every response carries X-Correlation-Id, opaque and free of personal data. Keep it for support.
  • A POST to a path that does not start with /v1/assessments receives 404. Variations of /v1/assessments (query, trailing slash) and any method other than POST receive 400 validation-failed.