Errors and status handling
Use this page to decide what to retry, what to trust, and what counts as a terminal answer.Typical error shape
Most Hilt route failures come back as one of these shapes:detail.code, thencode, thenerrordetail.message, thendetail, thenmessage- the request id header, usually
X-Hilt-Request-IdorX-Request-Id
HiltApiError.code, statusCode or status_code, requestId or request_id, retryable, and docsUrl or docs_url.
Public error-code catalog
Use the error code as the durable branch in your integration. Human-readable messages can become more specific over time.payment_failed
The payment did not complete successfully. Example:subscription_expired
The paid-through period has ended. Example:invalid_authorization
The API key, bearer token, or permission scope is missing or invalid for the route. Example:X-Hilt-Key, and that the key has the required scope.
webhook_signature_failed
The webhook payload could not be verified against the endpoint signing secret. Example:X-Hilt-Signature as t=<unix_timestamp>,v1=<hex_hmac_sha256>, reject stale timestamps, and use the signing secret returned when the webhook endpoint was created or rotated.
rate_limited
The client is sending too many requests. Example:Retry-After when present, and avoid retry loops that create new payment sessions before reading current Hilt state.
setup_not_ready
The product, rail, webhook, billing, or live configuration needs attention before the requested live action can proceed. Example:GET /v1/access/setup/readiness, complete the returned customer-facing actions, and retry the live request only after readiness is clear.
entitlement_missing
Hilt does not have an active entitlement for the customer and product. Example:402 Payment Required from the protected resource, create a Hilt payment session, and re-check entitlement after payment.
subscription_cancelled
The native subscription authorization has been cancelled. Example:subscription_requires_reapproval
The subscription needs buyer reapproval before future automatic renewals can continue. Example:request_timeout
The SDK did not receive a response before its local timeout. Example:Idempotency-Key and read current Hilt state before creating a replacement object.
Idempotency errors
Hilt Pay API write routes require anIdempotency-Key header so retries do not create duplicate live objects.
idempotency_key_required
The write request did not include a usable idempotency key. Example:idempotency_key_too_long
The idempotency key is longer than Hilt accepts. Example:session-cust-123-pro-api-001.
idempotency_key_invalid
The idempotency key contains whitespace, control characters, or non-visible ASCII. Example:invalid_idempotency_key
Some SDK and integration layers use this broader client-side code when an idempotency key fails local validation before a request is sent. Example:idempotency_in_progress
Another request with the same idempotency key and request body is still processing. Example:idempotency_conflict
The same idempotency key was already used with a different request body. Example:idempotency_race
Hilt could not yet read the idempotency record that another concurrent request just created. Example:Common HTTP meanings
| Status | Meaning | Typical action |
|---|---|---|
400 | The request shape is valid enough to parse, but the action itself is not allowed | Fix the request |
401 | Session or API key is not valid | Re-authenticate or replace the key |
403 | Caller is authenticated but not allowed to do that action | Check workspace ownership or access level |
404 | Object does not exist or does not belong to that workspace | Re-check the identifier and workspace context |
408 | The chain has not confirmed quickly enough for the current confirm attempt | Keep the same payment_id and retry later |
409 | The object state conflicts with the requested action | Read current state before retrying |
410 | The active session is no longer usable | Start a fresh buyer session |
422 | Payload shape is valid JSON, but not valid for this operation | Fix the request body or query parameters |
429 | You are sending too many requests | Back off and retry more slowly |
503 | A required runtime dependency is unavailable | Retry later and surface a temporary error |
Payment states that matter most
| Status | Meaning | What your app should do |
|---|---|---|
PENDING_SIGNATURE | Buyer session exists but the transaction is not signed yet | Wait for buyer action |
PENDING_CONFIRMATION | The transaction is signed or broadcast but not yet final in Hilt | Poll until a terminal state appears |
CONFIRMED | Payment is final in Hilt | Continue into memberships, receipts, and post-payment logic |
FAILED | Payment did not complete successfully | Stop and show a recovery path |
Expiry handling
Expiry usually appears one of two ways:410during the active buyer sessionFAILEDwith an expiry-style failure reason when Hilt later finalises the payment record
Payment behavior that is normal
Treat these as normal:- a payment taking time to settle
- repeated polling before a terminal state appears
- the buyer seeing wallet success before your backend sees final Hilt status
- asking the buyer to sign again while the first payment is still pending
- building business logic from screenshots instead of Hilt state
Edge cases worth handling deliberately
Duplicate payment attempts
If your checkout flow already has a livepayment_id, keep using it until that payment reaches a terminal state.
Do not start a second payment just because:
- the buyer refreshed the page
- the wallet popup closed late
- confirmation is still catching up
Duplicate confirm calls
If your own app callsPOST /v1/pay/confirm more than once for the same transaction, read the current payment state before trying again.
The right recovery pattern is:
- read
GET /v1/payments/{payment_id} - if the payment is already
CONFIRMED, continue - if the payment is still transitional, wait and poll
- if the payment is terminal and failed, start a clean new checkout
Expired sessions
If a checkout session has expired:- treat it as closed
- create a fresh session
- do not ask the buyer to sign the old one again
Identity handoff expiry
If a signed handoff link is no longer valid, create a fresh handoff token and send the buyer back through a new checkout URL. Do not patch around this by manually guessing the buyer identity on the backend.Good polling pattern
Use a simple progression:- poll quickly just after payment starts
- slow down once the payment is clearly in
PENDING_CONFIRMATION - stop polling once the payment is
CONFIRMEDorFAILED
payment_id. Do not create a second payment just because confirmation is still catching up.
Safe retry guidance
Safe retries usually mean:- retrying reads
- retrying lookups
- retrying your own app-side automation after reading current Hilt state
- starting a second payment before the first one is clearly failed or expired
- mutating access state without checking the current payment, membership, or receipt trail
Timeout and backoff guidance
Use calmer retry behavior as a payment ages:| Situation | Good behavior |
|---|---|
| Fresh checkout just started | retry reads quickly |
Payment has moved to PENDING_CONFIRMATION | slow down |
| Payment is older than expected | keep the same payment_id, log the case, and continue with wider intervals |
| Payment is terminal | stop polling |
Good retry candidates
GET /v1/productsGET /v1/products/{product_id}GET /v1/payments/{payment_id}GET /v1/membershipsGET /v1/memberships/lookupGET /v1/receiptsPOST /v1/memberships/{membership_id}/retry-delivery
Routes that deserve more care
POST /v1/productsPATCH /v1/products/{product_id}POST /v1/pay/confirmPOST /v1/support/tickets
Practical recovery sequence
When something looks wrong:- read
GET /v1/payments/{payment_id} - inspect the related membership if access is involved
- inspect the related receipt if proof is involved
- open or append a support ticket if a human conversation is needed
A strong correlation habit
Even without a separate idempotency header, you can keep your integration safe by treatingpayment_id as the canonical correlation key for:
- retries
- queue jobs
- buyer progress tracking
- post-payment automation
A good developer rule
Use Hilt states for:- payment truth
- access truth
- receipt truth

