Documentation Index
Fetch the complete documentation index at: https://docs.truthlocks.com/llms.txt
Use this file to discover all available pages before exploring further.
Canonical error codes and verdicts used across the Truthlocks platform. These codes are stable and can be used for programmatic error handling.
Verification Verdicts
| Verdict | CLI Exit | Description |
|---|
| VALID | 0 | Attestation verified successfully |
| ALTERED | 10 | Payload hash does not match |
| REVOKED | 11 | Attestation has been revoked |
| KEY_COMPROMISED | 12 | Signing key marked as compromised |
| KEY_EXPIRED | 13 | Signing key has expired |
| LOG_PROOF_FAILED | 14 | Transparency log proof verification failed |
| SIGNATURE_INVALID | 15 | Cryptographic signature verification failed |
Verification reasons
When you call the Verify endpoint, the response includes a reasons array with additional context. These reason codes are informational and appear alongside the verdict:
| Reason | Verdict | Description |
|---|
document_hash_mismatch | ALTERED | The document_hash_hex you provided does not match the hash stored at mint time |
document_hash_not_stored | (any) | The attestation was minted without a document hash, so the document hash check was skipped |
API error codes
General
| Code | HTTP | Description |
|---|
INVALID_INPUT | 400 | Request validation failed |
INVALID_REQUEST | 400 | Request body or parameters are malformed |
INVALID_ID | 400 | Identifier is not a valid UUID |
NOT_FOUND | 404 | Resource not found |
UNAUTHORIZED | 401 | Authentication required |
FORBIDDEN | 403 | Permission denied |
CONFLICT | 409 | Resource state conflict |
INTERNAL_ERROR | 500 | An unexpected server error occurred |
DB_ERROR | 500 | A database operation failed |
Attestations and issuers
| Code | HTTP | Description |
|---|
ISSUER_NOT_TRUSTED | 403 | Issuer must be in trusted status to mint attestations |
KEY_INACTIVE | 400 | Signing key is not active |
API keys
| Code | HTTP | Description |
|---|
NAME_REQUIRED | 400 | A key name is required |
KEY_ID_REQUIRED | 400 | Key ID parameter is missing |
KEY_NOT_FOUND | 404 | API key not found |
KEY_LIMIT | 409 | Maximum number of active API keys reached (5 per consumer) |
Consumer
| Code | HTTP | Description |
|---|
CONSUMER_REQUIRED | 400 | A consumer email reference is required |
Identity and DID
| Code | HTTP | Description |
|---|
MISSING_DID | 400 | DID parameter is required |
DID_NOT_FOUND | 404 | DID not found or the associated issuer has been revoked |
MISSING_ID | 400 | Issuer ID parameter is required |
EMAIL_NOT_VERIFIED | 403 | Email address has not been verified |
SSO
| Code | HTTP | Description |
|---|
DISCOVERY_FAILED | 400 | OIDC discovery configuration could not be loaded |
METADATA_FETCH_FAILED | 400 | SAML IdP metadata could not be fetched |
CRYPTO_ERROR | 500 | An encryption operation failed |
TEST_FAILED | 400 | SSO connection test did not succeed |
AUTH_FAILED | 401 | SSO authentication failed |
INVALID_STATE | 401 | OAuth or SAML state parameter is invalid |
EXPIRED_SESSION | 401 | SSO login session has expired |
REPLAY_DETECTED | 401 | OAuth or SAML state token has already been used |
CONFIG_ERROR | 500 | SSO configuration is missing or invalid |
Policy and governance
| Code | HTTP | Description |
|---|
POLICY_VIOLATION | 403 | Request violates an active policy |
Billing and limits
| Code | HTTP | Description |
|---|
BILLING_LIMIT | 402 | Billing quota exhausted for the current cycle |
LIMIT_REACHED | 429 | Monthly protection limit reached |
SEAT_LIMIT | 402 | Team seat limit reached — upgrade your plan or remove an existing member |
Data residency
| Code | HTTP | Description |
|---|
REGION_MISMATCH | 409 | Tenant is pinned to a different region than the one processing the request |
Retryable vs. terminal errors
When deciding whether to retry a failed request, use the HTTP status code to determine if the error is transient or permanent.
Retryable (transient)
These errors are automatically retried by the SDKs when MaxRetries (or equivalent) is configured:
| HTTP status | Code | When to retry |
|---|
408 | Request Timeout | Immediately — the server did not receive the request in time |
429 | RATE_LIMITED | After the duration specified in the Retry-After header |
500 | INTERNAL_ERROR | With exponential backoff — transient server issue |
502 | Bad Gateway | With exponential backoff — upstream service unavailable |
503 | Service Unavailable | With exponential backoff — service temporarily overloaded |
504 | Gateway Timeout | With exponential backoff — upstream service timed out |
Terminal (do not retry)
These errors indicate a problem with the request that won’t resolve by retrying:
| HTTP status | Example codes | Action |
|---|
400 | INVALID_INPUT, INVALID_REQUEST | Fix the request payload |
401 | UNAUTHORIZED | Check your API key or authentication token |
403 | FORBIDDEN, ISSUER_NOT_TRUSTED, POLICY_VIOLATION | Check permissions or issuer status |
404 | NOT_FOUND | Verify the resource ID exists |
409 | CONFLICT | Resolve the state conflict before retrying |
All three SDKs handle retryable errors automatically with exponential backoff and jitter. You only need manual retry logic if you’ve disabled automatic retries or want custom behavior on top of the SDK defaults.
Every error response returns a JSON object with two fields:
{
"code": "ISSUER_NOT_TRUSTED",
"message": "Issuer must be in trusted status to mint attestations"
}
code — a stable, machine-readable error code from the tables above. Use this for programmatic error handling.
message — a human-readable description of what went wrong. Messages may change between releases; do not match on them programmatically.
Error messages that would expose infrastructure details (such as database connection strings or internal hostnames) are automatically replaced with a generic message before being returned to the client. The original details are logged server-side only.
Gateway errors (RFC 7807)
When a request reaches the API gateway but does not match any valid route, the gateway returns a structured error response following the RFC 7807 Problem Details specification. This applies to 404 Not Found and 405 Method Not Allowed errors at the gateway level.
Gateway errors use application/problem+json as the content type and include four fields:
{
"type": "https://docs.truthlocks.com/ops/errors",
"title": "Not Found",
"status": 404,
"detail": "The requested path does not match any API route."
}
| Field | Description |
|---|
type | A URI reference that identifies the error type. Points to this documentation page. |
title | A short summary of the error. Either Not Found or Method Not Allowed. |
status | The HTTP status code — 404 or 405. |
detail | A human-readable explanation of the specific error. |
When you see these errors
404 Not Found — The request path does not match any API route. Double-check the URL, including the /v1/ version prefix and resource name.
405 Method Not Allowed — The request path exists, but the HTTP method you used (for example, DELETE on a read-only endpoint) is not supported. Check the API reference for the correct method.
Handling gateway errors in code
If you parse error responses programmatically, check the Content-Type header to distinguish gateway errors from application errors:
application/problem+json — Gateway-level error (RFC 7807). Use the status and title fields.
application/json — Application-level error. Use the code and message fields.
const res = await fetch("https://api.truthlocks.com/v1/nonexistent");
const contentType = res.headers.get("content-type");
if (contentType?.includes("application/problem+json")) {
// Gateway error — RFC 7807 format
const problem = await res.json();
console.error(`${problem.status} ${problem.title}: ${problem.detail}`);
} else {
// Application error — standard format
const error = await res.json();
console.error(`${error.code}: ${error.message}`);
}
The Truthlocks SDKs handle both error formats automatically. You only need to distinguish between them if you are calling the API directly.
Canonical Enums
Algorithm
* Ed25519 * P-256 * P-384
Issuer Status
pending * trusted * suspended * revoked
Trust Tier
self_issued * verified_org * regulated_issuer
Key Status
ACTIVE * DISABLED * EXPIRED * COMPROMISED
Attestation Status
* ACTIVE * REVOKED * SUPERSEDED
Risk Rating
unknown * low * medium * high * critical