Skip to content

Errors

Every error the platform returns is stable, actionable, and documented here. Errors include the structured details you need to understand what went wrong and how to fix it.

Every error response has this structure:

{
"error": {
"code": "enrollment_identity_incomplete",
"message": "Required verified identity evidence is missing.",
"request_id": "req_8Fq2LmVw9dKpRt4X",
"details": [
{
"field": "identity_evidence.issuing_office",
"code": "required",
"message": "Issuing office is required alongside the document number."
}
]
}
}
Field Meaning
code Machine-stable error code. Your code should handle known codes; tolerate unknown ones.
message Human-readable explanation. Safe for developers; contains no secrets or personal data.
request_id The canonical request identifier for this request. Use this in support requests.
details Zero or more specific problems. Empty where there are no details.

Each detail in the details array specifies:

Field Meaning
field JSON path to the offending value, where applicable (e.g., identity_evidence.issuing_office)
code Machine-stable detail code (e.g., required)
message Additional context for the problem
Status Cause Retryable
200 Success —
201 Created —
202 Accepted for asynchronous processing —
204 No content —
304 Not modified (cached) No
400 Malformed request or schema validation failed No
401 Missing, invalid, or expired credentials No*
403 Authenticated but not permitted No
404 Resource not found or not visible No
409 Resource state prevents operation, or idempotency key reused with different payload No
410 Resource content is gone (delivery expired, report archived, attempt limit reached) No
413 Request body too large No
414 Request URI too long No
415 Unsupported Content-Type No
422 Well-formed but rejected by policy No
429 Rate limited Yes, with Retry-After
500 Unexpected server error Yes, with same idempotency key
502 Gateway error Yes, with backoff
503 Service temporarily unavailable Yes, with Retry-After
504 Gateway timeout Yes, with backoff

*A 401 should be retried only once to refresh credentials. If it fails again, stop retrying.

Every response includes these headers:

Header Meaning
Request-Id The canonical identifier for this request. Always returned. Use this to reference the request in logs or support tickets.
RateLimit-Limit Your rate limit quota for this endpoint
RateLimit-Remaining Requests remaining in this window
RateLimit-Reset Unix timestamp when the window resets
Retry-After (On 429 and 503 only) Seconds to wait before retrying

Every mutating operation (POST, PUT, PATCH) requires an Idempotency-Key header:

POST /enrollments HTTP/1.1
Idempotency-Key: abc123def456

Idempotency key rules:

  1. Generate once per logical operation. Create a key when you begin a request and reuse it if you retry.
  2. Same key, same payload → original outcome. If you send the same key and payload twice, the second request returns the original response (not a second resource).
  3. Same key, different payload → 409 Conflict with idempotency_key_reused. The platform rejected the second request to prevent accidental overwrites.
  4. Key format: Alphanumeric, 16–128 characters. A UUID or a hash of your transaction ID works well.
Code Status Cause Resolution
unauthenticated 401 Credentials missing, invalid, or expired Verify your API credentials are correct and not expired. Refresh OAuth tokens or rotate mTLS certificates.
credential_binding_mismatch 401 Your access token and client certificate resolve to different applications Make sure the token and the mTLS certificate presented on the same connection belong to the same application.
capability_not_granted 403 Operation requires a capability your organization has not been granted Contact Radiant InfoTech to request the missing capability. The error message names it.
Code Status Cause Resolution
not_found 404 The resource does not exist, or exists but is not visible to your organization Verify the ID is correct and belongs to your organization. The platform returns the same code either way, so existence cannot be probed for a resource you cannot see.
conflict 409 The resource is not in a state permitting this operation, or the idempotency key was reused with a different payload Check the resource’s current status and refer to its lifecycle. For example, you cannot cancel an enrollment that has already been issued.
idempotency_key_reused 409 Same idempotency key sent with a different payload Use a new idempotency key for a genuinely new request, or resend the original payload unchanged.
delivery_expired 410 The delivery window elapsed before the subscriber retrieved the package Create a new delivery to issue a fresh package.
delivery_attempts_exhausted 410 The subscriber exceeded the allowed retrieval attempts Create a new delivery.
delivery_retired 410 The delivery’s material has already been retired, with destruction evidence recorded Create a new delivery if a fresh copy is needed.
Code Status Cause Resolution
bad_request 400 Malformed JSON, a schema violation, or an internally inconsistent request Check your request body against the API reference.
enrollment_identity_incomplete 400 Required identity evidence is missing Refer to the details array to see which fields are required. National ID, passport, or citizenship document with issuing office is required.
Code Status Cause Resolution
enrollment_not_found 404 Enrollment does not exist or is not visible to your organization Verify the enrollment ID is correct and belongs to your organization.
policy_rejected 422 The request is well-formed but rejected by policy Refer to the message and details for the specific policy ground (e.g., the confirmed certificate details differ from what the applicant confirmed, or the suspension ground is not one the Act or Rules contain).

Certificate lifecycle conflicts (revoked, suspended, already in a live batch, no open hold, and similar) share the generic conflict (409) code above rather than a code per state. Two grounds are specific to the statutory explanation window:

Code Status Cause Resolution
explanation_window_required 422 This suspension ground was formed by the authority, so the subscriber must be given an explanation window before the certificate can be suspended Open the explanation window and wait for it to close or for a response before suspending.
explanation_window_still_open 422 The subscriber’s period to explain has not yet elapsed Wait for the explanation window to close before proceeding.
predecessor_revoked — Returned on reissuance flows where the predecessor certificate is already revoked Check the predecessor certificate’s status before requesting reissuance.

Note: explanation_window_required and explanation_window_still_open fall back to policy_rejected if the code fails to parse against the published catalogue — treat policy_rejected with a matching message as equivalent.

Code Status Cause Resolution
package_digest_mismatch 422 The retrieved package’s digest does not match the one recorded for the delivery Do not import the package. Retry the retrieval; if the mismatch persists, contact support.
certificate_thumbprint_mismatch 422 The certificate thumbprint confirmed at import does not match the one issued Do not treat the import as confirmed. Contact support.
certificate_revoked 422 The certificate named in a transfer or delivery is revoked Check the certificate status; a revoked certificate cannot be transferred or delivered.
certificate_suspended 422 The certificate named in a transfer or delivery is suspended Check the certificate status to see whether it will be released or revoked.
certificate_not_active 422 The certificate is not in a state from which a credential may be copied Check the certificate status.
target_application_not_permitted 422 The receiving application is not permitted to hold credentials Verify the target application is registered and authorized for your organization.
transfer_request_expired 422 The transfer request’s window elapsed before it was completed Open a new transfer request.
transfer_request_consumed 422 The transfer request has already been completed Do not retry; the original transfer already completed.
package_code_not_accepted — The retrieval code presented for a delivery package was rejected Verify the code was entered correctly and has not expired.
Code Status Cause Resolution
rate_limited 429 You have exceeded the rate limit Wait for the window to reset. Retry-After header says how long to wait. Use RateLimit-Remaining to stay below the limit.

Safe to retry with backoff:

  • 408 (request timeout)
  • 429 (rate limited) — honor Retry-After
  • 502, 503, 504 (gateway errors)
  • 500 (internal error) — use the same idempotency key to guarantee the original outcome

Not safe to retry (same result):

  • 400 (bad request)
  • 401 (unauthorized) — retry once to refresh credentials
  • 403 (forbidden)
  • 404 (not found)
  • 409 (conflict)
  • 410 (gone)
  • 413 (payload too large)
  • 415 (unsupported media type)
  • 422 (policy rejection)

Paginated responses use cursor-based pagination, not offsets. Cursors are opaque and must never be constructed by the client.

{
"items": [...],
"cursor": "next_cursor_value",
"next": "https://api.example.invalid/v1/resource?cursor=next_cursor_value"
}

Pagination rules:

  1. Use limit and cursor query parameters. Limit defaults to 25; maximum 100.
  2. Cursors are opaque. Never construct one. Use the cursor from the previous response.
  3. Iteration is safe. Cursor pagination cannot skip or repeat records under concurrent writes, unlike offset pagination.
  4. Page when needed. Do not fetch all records if you only need a few.

Example request:

GET /certificates?limit=50&cursor=prev_page_cursor

The platform supports entity tags for cheap polling. Every resource response carries an ETag header:

ETag: "abc123"

On subsequent requests, send If-None-Match:

GET /certificates/cert_abc123 HTTP/1.1
If-None-Match: "abc123"

If the resource has not changed, you receive 304 Not Modified with no body. If it has changed, you receive 200 with the new representation.

This lets you poll certificate status cheaply; the platform does not send the full certificate body on every request if nothing changed.

Best practices:

  1. Log the request ID. When an error occurs, log the Request-Id from the response. This unique identifier lets you trace the request in the platform’s logs.

  2. Handle error codes, not just status codes. Two different errors may return the same HTTP status. Check error.code to determine the appropriate action.

  3. Retry appropriately. Use the status code and Retry-After header to decide whether to retry and when.

  4. Expose details safely. The error message is safe to log or show to developers. Do not assume a user-facing message is safe.

  5. Do not retry blindly. If an idempotency key fails because the payload changed, retrying with a different key is the right move, but retrying the same key with a different payload is not.

  6. Deduplicate webhook events. Events carry an id field. Deduplicate by event ID, including across redeliveries.

  7. Catch unknown errors. The code field may contain values not documented here. Catch and log unknown codes rather than treating them as success.


See Concepts for entity definitions, Events for lifecycle notifications, and the API Reference for every operation’s possible error codes.