Skip to main content
Failure, cancellation and expiry events created since this release include data.error, with a stable code and a fixed public message. Use the code for branching. Don’t match or parse the message. Look up any code in the error code tables.

The error object

  • failure_category identifies the broad event family. error.code gives the known cause.
  • Unknown causes stay generic. A generic decline never implies insufficient funds.
  • Successful and readiness events have error: null.
  • Mandate lifecycle notifications (mandate.paused, mandate.resumed, mandate.cancelled, mandate.expired) also have error: null. They describe local state, not a payment failure. See the event catalog.

Which error each event carries

Handle errors safely

  • Older retained events can omit error and failure_stage. Handle absent fields and unknown future codes safely.
  • Retries and replays keep the original event ID and bytes. They don’t add a reason discovered later.
  • A later operation outcome produces a new event, with a new resource version where applicable. It doesn’t edit an old event.
  • A new payment attempt can have a different resource ID.
  • A webhook replay retries delivery, not the underlying operation.
  • Always use status to determine the lifecycle.

Coverage boundaries

Some outcomes have limited or no webhook coverage.

Before credentials are issued

A definite failure recorded by Prava can emit payment.failed with failure_stage: credential_issuance and outcome_source: prava_observed. Supported cases include those marked Yes: For credential-fetch rejections, see Confirmed credential-fetch rejections.

Result API compatibility

The same recorded failure uses the same public error.code in the detailed payment-result or enrollment status API and in its webhook. You can reuse one error handler.
  • For payment attempts and full-enrollment results, the safe mapping is shared with the corresponding result projections.
  • failure_stage, outcome_source and failure_category add context independently of the code.

Code names and messages

  • Existing codes are preserved, including previously exposed names that mention a card network. This release doesn’t rename, remove or collapse them.
  • Historical codes that include a card-network name remain documented for compatibility, because existing integrations already receive them.
  • Any future public-code rename, including for those historical codes, needs an explicitly versioned API release. There’s no calendar cutover or automatic switch.
  • Messages come from fixed safe copy. Raw provider text is excluded.
  • Unknown codes use the family’s generic fallback.
  • Branch on codes, tolerate future codes and absent additive fields, and don’t parse messages.

Shopper reports and legacy claims

  • PAYMENT_DECLINED, USER_CANCELLED, AUTH_CANCELLED and AUTH_INCOMPLETE remain distinct.
  • Session-user reports can describe authentication or cancellation, or a generic PAYMENT_FAILED.
  • A browser-supplied issuer reason is never returned as an attested financial result. It never creates payment.failed and never supplies an issuer reason in any event.
  • Legacy financial claims with caller-controlled diagnostic metadata are also generic.
  • Known non-issuer legacy setup/provisioning aliases stay compatible. Stored diagnostics are unchanged.

Enrollment status

  • Cancelled enrollment status responses keep error: null for compatibility. Use status: cancelled.
  • The corresponding cancellation webhook provides SESSION_CANCELLED, with its unchanged null failure_category.
  • Enrollment expiry has the safe SESSION_EXPIRED reason.
  • Successful enrollment clears the error.
  • Intermediate enrollment errors retain retryable. Terminal errors use retryable: false.
  • No previous retryable error is reused as a terminal reason.

Where the shared contract applies

This shared contract applies to detailed outcome responses and newly created events. The hosted checkout request and the merchant payment-result API both keep their existing contracts:
  • Other operation wrappers/admission errors without a recorded outcome remain synchronous API errors.
  • Retained events and replay bytes are never rewritten.
  • Definite credential-issuance events describe failure to obtain credentials, not a merchant charge or final settlement result.

Confirmed credential-fetch rejections

FETCH_AGENTIC_CREDS_ERROR remains the same public code in the detailed API outcome and the webhook.
  • The event reports failure to obtain credentials. It doesn’t claim an issuer decline or a completed merchant charge.
  • Older failures aren’t backfilled.
  • The evidence Prava uses to tell these cases apart isn’t included in the payload.

Charge response messages

In Charge a Mandate responses: Unknown codes use the safe family fallback.

Error codes

Each table lists codes with their fixed messages. Keep these limits in mind:
  • A code is emitted only when its reason was actually persisted or returned at the supported request boundary.
  • These tables also cover detailed API errors. A code being listed doesn’t by itself make an outcome eligible for a webhook.
  • A listed code doesn’t mean every upstream processor can supply it.
  • Raw processor diagnostics and customer data are excluded.
Timeout, pending, malformed-response and unknown-issuance codes never produce payment.failed.

Payment attempts and mandate setup

Payment attempts and mandate setup share most codes. Used by shows whether a code belongs to payment attempts, mandate setup, or both. Codes that share a message are grouped in one row.

Full card enrollment

Quote requests