Skip to content

Errors

Errors

All API errors use RFC 7807 Problem+JSON. Every error response includes a request_id for support triage.

Error response format

{
"type": "https://docs.verbitas.io/api/errors#verbitas.sign.invalid_recipe",
"title": "Invalid recipe",
"status": 400,
"detail": "Recipe 'my-recipe-v99' not found for tenant t_01j...",
"request_id": "req_01j...",
"code": "verbitas.sign.invalid_recipe"
}
FieldDescription
typeURI identifying the error type; links to this page
titleShort human-readable title
statusHTTP status code
detailSpecific detail about this instance of the error
request_idUnique request ID; include this in all support requests
codeMachine-readable dot-separated error code

Stack traces are never included in API responses. Use request_id to correlate with server logs when contacting support.

Error codes by category

Authentication

CodeHTTPDescription
verbitas.auth.invalid_key401API key does not exist or has been revoked
verbitas.auth.key_expired401API key has passed its expiry date
verbitas.auth.insufficient_scope403Key scope does not permit this operation
verbitas.auth.tenant_suspended403Tenant account is suspended (e.g. failed payment)

Sign

CodeHTTPDescription
verbitas.sign.invalid_recipe400Recipe ID not found or validation failed
verbitas.sign.unsupported_mime400File type not allowed by this recipe
verbitas.sign.missing_idempotency_key400Idempotency-Key header is missing
verbitas.sign.invalid_metadata400Metadata JSON is malformed or contains unknown assertion keys
verbitas.sign.file_too_large413File exceeds 100 MB direct upload limit
verbitas.sign.idempotency_conflict409Same Idempotency-Key, different payload

Verify

CodeHTTPDescription
verbitas.verify.no_input400No file, asset_id, or manifest_uri provided
verbitas.verify.unsupported_file_type415File format not in supported set
verbitas.verify.asset_not_found404asset_id not found in tenant’s records
verbitas.verify.manifest_not_found404Manifest URI could not be fetched

Lookup

CodeHTTPDescription
verbitas.lookup.no_input400No asset or fingerprint provided
verbitas.lookup.unsupported_file_type415File format not supported
verbitas.lookup.invalid_algorithm400algorithm value not in allowed set

Recipes

CodeHTTPDescription
verbitas.recipes.invalid_schema400YAML fails schema validation; detail includes field errors
verbitas.recipes.unknown_step_kind400step.kind outside closed enum
verbitas.recipes.invalid_extends400Base preset not found
verbitas.recipes.byok_plan_required402kms_mode: byok requires Enterprise BYOK plan
verbitas.recipes.conflict409Recipe ID + version already exists
verbitas.recipes.immutable409Recipe has been used; cannot modify

Billing

CodeHTTPDescription
verbitas.billing.quota_exceeded402Monthly operation quota reached for current plan
verbitas.billing.spending_cap_reached402Tenant spending cap has been hit

Audit

CodeHTTPDescription
verbitas.audit.invalid_date_range400from after to, or range too large

Rate limiting

CodeHTTPDescription
verbitas.ratelimit.exceeded429Per-tenant or per-IP rate limit exceeded

Rate limit responses include:

Retry-After: 12
X-RateLimit-Limit: 5
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1715248800

Infrastructure

CodeHTTPDescription
verbitas.signer.unavailable503KMS signer temporarily unavailable; retry with backoff
verbitas.internal_error500Unexpected internal error; include request_id in support ticket

SDK error handling

SDKs map error codes to typed exceptions:

Python

import verbitas
from verbitas.exceptions import (
AuthError,
QuotaExceededError,
RateLimitError,
SignerUnavailableError,
VerbtiasAPIError,
)
try:
result = client.sign("image.png", recipe="image-genai-v1")
except AuthError as e:
# e.code = "verbitas.auth.invalid_key"
print(f"Auth failed: {e.message}")
except QuotaExceededError:
print("Monthly quota reached; upgrade plan")
except RateLimitError as e:
print(f"Rate limited; retry after {e.retry_after}s")
except SignerUnavailableError:
# Retry with backoff; SDK retries automatically (max 3 attempts)
pass
except VerbtiasAPIError as e:
print(f"API error {e.code}: {e.detail} (request_id={e.request_id})")

TypeScript

import { VerbitasClient, VerbtiasAPIError, AuthError, RateLimitError } from "@verbitas/sdk";
try {
const result = await client.sign("image.png", { recipe: "image-genai-v1" });
} catch (e) {
if (e instanceof AuthError) {
console.error("Auth failed:", e.code);
} else if (e instanceof RateLimitError) {
console.error("Rate limited; retry after", e.retryAfter, "s");
} else if (e instanceof VerbtiasAPIError) {
console.error(`${e.code}: ${e.detail} (requestId=${e.requestId})`);
}
}

Retries

SDKs automatically retry on 429 and 5xx responses with exponential backoff (max 3 attempts). The retry logic respects the Retry-After header. Idempotency keys ensure retried sign calls do not create duplicate records.

Manual retry guidance:

  • 429: back off per Retry-After header
  • 503 verbitas.signer.unavailable: back off 2–30 seconds; the signer recovers quickly in most cases
  • 500 verbitas.internal_error: do not retry more than 3 times; contact support with request_id