Kyndex
API Conventions

Error Handling

The format, the status codes, and the zero-knowledge guarantees that shape how errors are returned.

Endpoint schemas and parameter details live in the API Reference. This page covers error behavior — the format, the status codes, and the zero-knowledge guarantees that shape how errors are returned.

RFC 7807 Problem Details

All errors are returned as RFC 7807 Problem Details objects with Content-Type: application/problem+json.

Every error response includes these fields:

FieldTypeDescription
typestring (URI)Machine-readable error identifier. Always follows the pattern https://api.kyndex.co/errors/{ERROR_CODE}
titlestringHuman-readable summary (e.g. "Bad Request", "Forbidden")
statusintegerHTTP status code
codestringMachine-readable error code from the ErrorCode enum — use this for programmatic error handling
instancestring (opt)The request path that triggered the error

Example:

{
  "type": "https://api.kyndex.co/errors/INVALID_REQUEST",
  "title": "Bad Request",
  "status": 400,
  "code": "INVALID_REQUEST",
  "instance": "/v1/documents"
}

Error Code Reference

The type URI always follows the pattern:

https://api.kyndex.co/errors/{ERROR_CODE}

400 Bad Request

CodeWhenRecovery
MISSING_PARAMETERA required parameter is absent from the request.Check the endpoint documentation and include all required fields.
INVALID_PARAMETERA parameter value is malformed or outside allowed bounds.Validate the parameter format against the endpoint schema.
INVALID_REQUESTRequest body or query parameters failed schema validation.Fix your request against the endpoint schema.
VALIDATION_ERRORRequest failed one or more validation rules (e.g. constraints, format).Adjust the request to pass all validation rules.

401 Unauthorized

CodeWhenRecovery
UNAUTHORIZEDAccess token is missing, expired, or invalid.Refresh via /auth/tokens/refresh. If refresh fails, re-authenticate from login.
INVALID_TOKENSession token failed cryptographic verification or is malformed.Same as UNAUTHORIZED — refresh or re-authenticate.
TOKEN_EXPIREDAccess token has expired.Refresh via /auth/tokens/refresh.
SESSION_LOCKEDValid token, but session lacks owner_token / user_member_token — data access denied.Pass owner_token and user_member_token in the next /auth/tokens/refresh call. See Session Lifecycle.

403 Forbidden

CodeWhenRecovery
FORBIDDENValid token, but insufficient permissions for this resource or action.Check your role and membership. You may not have access to this resource.
INSUFFICIENT_PERMISSIONSOperation requires elevated permissions you do not have.Check the code field. You may need a different role or entity ownership.
CSRF_REQUIREDX-Kyndex-Request: 1 header is missing on a mutation request.Add X-Kyndex-Request: 1 to the request headers.

404 Not Found

CodeWhenRecovery
NOT_FOUNDRoute path does not match any endpoint (catch-all).Check the URL path and HTTP method.
USER_NOT_FOUNDUser ID does not exist or is not accessible.Verify the user ID. On authenticated endpoints, returns 404 for both missing and inaccessible resources.
DOCUMENT_NOT_FOUNDDocument ID does not exist or is not accessible.Verify the document ID. On authenticated endpoints, returns 404 for both missing and inaccessible resources.
GRANT_NOT_FOUNDGrant ID does not exist or is not accessible.Verify the grant ID. On authenticated endpoints, returns 404 for both missing and inaccessible resources.

409 Conflict

CodeWhenRecovery
CONFLICTResource is in a conflicting state or operation violates a constraint.Check the code field for the specific conflict.
EMAIL_EXISTSEmail address is already registered.Use a different email or recover the existing account.
GRANT_CLAIM_LIMIT_EXCEEDEDGrant has been claimed the maximum number of times.Create a new grant if you need additional claims.

413 Payload Too Large

CodeWhenRecovery
PAYLOAD_TOO_LARGEDocument upload exceeds the 100 MB size limit.Reduce file size before encrypting and uploading.

415 Unsupported Media Type

CodeWhenRecovery
UNSUPPORTED_MEDIA_TYPEContent-Type header is missing or not supported for this endpoint.Use application/json for JSON requests or application/octet-stream for binary uploads.

429 Too Many Requests

CodeWhenRecovery
RATE_LIMITEDRequest rate limit exceeded.Read the Retry-After response header. Back off exponentially. See Rate Limiting page.

500 Internal Server Error

CodeWhenRecovery
INTERNAL_ERRORUnexpected server error (catch-all).Retry with exponential backoff. If the error persists, contact support.
DATABASE_ERRORDatabase operation failed (connection, query, constraint).Retry with exponential backoff. If persistent, contact support.
KMS_ERRORKey management service call failed.Retry with exponential backoff. If persistent, contact support.
STORAGE_ERRORObject storage operation failed (upload, download, deletion).Retry with exponential backoff. If persistent, contact support.
VERIFICATION_FAILEDThird-party identity verification service returned an error.Retry with exponential backoff. If persistent, contact support.

503 Service Unavailable

CodeWhenRecovery
SERVICE_UNAVAILABLEA required upstream dependency is temporarily down.Retry with exponential backoff. If persistent, contact support.

Anti-Oracle Guarantee: Why You See 404 For Both Cases

This is the most important behavioral difference from typical REST APIs.

Literal never reveals whether a resource exists. When you request a resource you cannot access, the server returns 404 Not Found with the message "not found or access denied" — regardless of whether the resource actually exists. Both missing resources and permission failures produce the same status code and the same response shape.

This is deliberate. In a zero-knowledge system, distinguishing "doesn't exist" from "you can't access it" is an information leak. An attacker could probe resource IDs to learn which documents, grants, or entities are real.

The guarantee: the server's response to GET /documents/{id} is identical whether {id} is a real document you can't access or a completely fabricated UUID.

This pattern extends beyond resource lookups:

  • OPRF challenge (POST /auth/challenges) — evaluates a blinded ristretto255 point without learning the input email. The server's response is indistinguishable regardless of whether the email is registered.
  • Grant discovery (GET /grants) — uses view tags that produce ~1/256 collisions, so the server cannot distinguish the intended recipient from noise.
  • Public key lookup (GET /users/{userId}/public-keys) — returns 404 only because the user ID namespace is random UUIDs with no sequential pattern to enumerate.

Status Code Summary

StatusWhen you'll see itWhat to do
400Request body or query params fail schema validationFix your request against the endpoint schema.
401Token missing, expired, or revokedRefresh via /auth/tokens/refresh. If that fails, re-authenticate.
403Valid token, but insufficient permissionsCheck your role and entity membership.
404Resource not found or access denied on authenticated endpointsCheck the URL path and your authorization.
409Duplicate resource or invalid state transitionCheck the code field for the specific conflict.
413Upload exceeds 100 MBReduce file size before encrypting.
415Wrong or missing Content-TypeUse application/json or application/octet-stream.
429Rate limit exceededRead Retry-After header. Back off.
500Unexpected server errorRetry with exponential backoff. If persistent, contact support.
503Upstream dependency temporarily unavailableRetry with exponential backoff. If persistent, contact support.

On this page