> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting: payment-mandate confirmation failures

> Triage the three customer-facing payment-mandate confirmation errors — MANDATE_CHARGE_FAILED, MANDATE_SPEND_UNVERIFIABLE, and IDEMPOTENCY_CONFLICT — on the in-call AP2 agentic-payment confirmation.

# Troubleshooting: payment-mandate confirmation failures

An AP2 payment mandate is the signed, spend-capped consent an AI agent
transacts under: a caller pre-authorizes a per-transaction maximum, a total
cap, a currency, an allow-list of merchants and categories, and an expiry,
and the agent can then charge carts against that mandate without asking
per-cart. On a live voice call the agent reads the cart (amount, currency,
merchant) back to the caller, gets explicit verbal approval, and invokes the
confirmation tool — the request this page triages. For the mandate concept
itself, read [Commerce checkout spine](/concepts/commerce-checkout-spine)
and the [Conversational Commerce Checkout](/guides/conversational-commerce-checkout)
guide first.

The confirmation has three customer-facing failure codes, and all three
**fail closed — the customer is never charged on ambiguity**. A failed
response means nothing persisted, so the whole mandate decision must be
resolved before you retry. Read the error envelope first: the `error.code`
field tells you which gate rejected the request. A typical envelope:

```json theme={null}
{
  "error": {
    "code": "MANDATE_SPEND_UNVERIFIABLE",
    "message": "Could not verify prior spend under this mandate; charge not authorized"
  },
  "request_id": "req_9c4e1d"
}
```

## Cause table

| Code                         | HTTP | The gate that rejected you                                                                                        | Fix                                                                                                                                                                                        |
| ---------------------------- | ---- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `MANDATE_CHARGE_FAILED`      | 500  | The charge was authorized but could not be committed                                                              | Verify the mandate's scope: amount within per-transaction max, merchant/category on the allow-list, mandate active and unexpired. Retry the identical cart after fixing the scope mismatch |
| `MANDATE_SPEND_UNVERIFIABLE` | 503  | Prior confirmed spend under the mandate could not be read or recorded, so the cumulative cap cannot be verified   | Do not re-authorize — the confirmation fails closed to protect the mandate cap. Retry once the read path is healthy; the customer was not charged                                          |
| `IDEMPOTENCY_CONFLICT`       | 409  | The same `charge.reference` was already confirmed for a materially different cart (amount, currency, or merchant) | Stop and reconcile — do not retry either cart under that reference. Resolve in your records which cart the reference belongs to before confirming again                                    |

## Charge commit — MANDATE\_CHARGE\_FAILED (500)

This 500 raises when the mandate decision approved the cart but the commit
step threw — the one failure where authorization succeeded and persistence
failed. Before you treat it as a platform fault, check the mandate's scope
constraints: the most common trigger is a cart the mandate should never have
approved — an amount past the per-transaction maximum, a merchant or
category outside the allow-list, or a mandate that lapsed to `expired`,
`revoked`, or `exhausted` between session-create and the confirmation call.

Check first:

1. **Amount within the per-transaction max.** Read the mandate from the
   voice session-create payload (`payment_mandate`) and compare
   `charge.amount` against `maxPerTransaction`. A cart above the max must be
   split or the mandate re-issued with a higher max — no retry of the same
   cart will pass.
2. **Merchant and category on the allow-lists.** `charge.merchant` must
   appear in `allowedMerchants` (and the agent's category in
   `allowedCategories`). Correct the catalog mapping at the agent layer and
   re-read the cart to the caller before re-confirming.
3. **Mandate status and expiry.** A mandate moves to `expired`,
   `revoked`, or `exhausted` over the course of a long call; the agent
   should re-check `mandate.status` before invoking the confirmation tool.

If the scope checks out clean and the same 500 persists with a consistent
`request_id`, escalate (below) — that is a genuine commit failure, not a
scope mismatch.

## Cap verification — MANDATE\_SPEND\_UNVERIFIABLE (503)

The mandate's total cap is cumulative: every confirmed cart under the
mandate spends against `totalCap`, and a new cart may only be authorized if
`spent + charge.amount ≤ totalCap`. To authorize safely, the confirmation
must read the prior confirmed spend — and it refuses rather than authorize
against a position it could not read or record. That refusal is this 503.

Treat it as a temporary-unavailable response, semantics identical to the
read-path health checks elsewhere in the platform. **Do not re-authorize at
the agent layer** — do not fall back to "assume it fits under the cap" and
never retry in a tight loop. Retry with backoff once the dependency is
healthy again; the customer was not charged on any ambiguity.

If the 503 persists past a few minutes, escalate with the `request_id` — a
standing 503 here means the confirmation cannot establish the mandate's
cumulative position at all.

## Reference discipline — IDEMPOTENCY\_CONFLICT (409)

A single mandate legitimately funds many distinct carts in one call, so the
replay token is the per-charge `charge.reference` — the cart or order id the
agent read back to the caller — keyed together with the call and the
mandate. A retry of the **same** cart (a network blip, a gateway restart)
returns the stored confirmation without charging twice. A **different** cart
(amount, currency, or merchant changed) under the **same** reference
receives this 409 and is never replayed as confirmed.

The 409 is a stop-and-reconcile signal, not a retry signal:

1. Pull the confirmed charges for the call (see the audit-trail section) and
   compare the recorded cart against the cart you are trying to confirm.
2. In your order system, resolve which cart the reference actually belongs
   to. If the original cart was the right one, discard the new request. If
   the cart genuinely changed (an agent-side reprice mid-call), issue a new
   order id and re-read the full cart to the caller before confirming with
   the fresh reference.

Assign references only at cart-finalize time, and never reuse one across
agents, sessions, or reprice attempts — the conflict gate exists to catch
exactly that reuse.

## Audit trail

Every successful confirmation is stamped onto the call record: read
`GET /api/v1/voice/calls/:id` and look at
`metadata.payment_mandate_confirmation`. The stamp carries the mandate id,
the authorization id, the consent digest, the amount/currency/merchant, the
reference, whether the AP2 verifiable credential was issued, the recording
egress id, and the confirmation timestamp — the same call row the recording
lives on, so a reviewer pulling the recording sees the cryptographic
authorization alongside it. Use it to reconcile 409 conflicts and to prove
what was (and was not) charged.

## Retry-safety and escalation

All three codes converge on one rule: **a failure means the customer was not
charged**, and none resolve by retrying the identical request unchanged:

* `MANDATE_CHARGE_FAILED` — fix the mandate-scope mismatch first, then retry
  the identical cart (safe: a failed commit persisted nothing).
* `MANDATE_SPEND_UNVERIFIABLE` — retry only after the dependency recovers,
  with backoff. Never re-authorize at the agent layer.
* `IDEMPOTENCY_CONFLICT` — reconcile the reference before confirming again;
  a new cart needs a new reference.

Escalate to [Devotel support](https://devotel.io) when the cause table
points at a genuine platform fault (a persisting 500 with clean scope, or a
standing 503). Attach the `request_id` from the error envelope, the call id,
the mandate id, and the charge reference — the support team reads the same
`payment_mandate_confirmation` audit stamp on the call metadata that this
page polls.

## Cross-references

* [Commerce checkout spine](/concepts/commerce-checkout-spine) — how
  agentic payment mandates plug into the checkout architecture
* [Conversational Commerce Checkout](/guides/conversational-commerce-checkout) —
  the mandate-based end-to-end walkthrough
* [Secure payment capture](/voice/secure-payment-capture) — the
  agent-assisted DTMF card-capture flow, a different payment surface from
  AP2 mandates
* [Troubleshooting hub](/reference/troubleshooting-hub) — the index of all
  runbooks
