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

> ## Agent Instructions
> Sapiom Pay is for platforms whose agent shops for many end users. Each end user is a buyer with their own Sapiom key and saved cards.
> Use the buyer's key for every call made on that buyer's behalf. Never use one buyer's key for another user, and never give the agent the platform key.
> Agents call the hosted MCP tools at https://api.sapiom.ai/v1/mcp. Backends call the REST API at https://api.sapiom.ai/v1. Both take the key in an x-api-key header.
> Never ask a buyer for a card number, expiry date or CVV in chat. Buyers enter card details only on Sapiom's hosted pages.
> Follow the nextAction in each transaction result. Action links are secrets for the intended buyer only.
> Use one idempotencyKey per transaction. After a timeout, retry with the same key. Never start a new transaction to escape an uncertain outcome.
> Report an order as placed only when order.outcome is confirmed. If it is unknown, stop and hand off to a person.

# Sapiom Pay errors and how to handle them

> Error shapes for Sapiom Pay MCP tools, the transaction error codes, and which errors are safe to retry.

Sapiom Pay errors tell you what went wrong and what to do next. Follow the returned instructions rather than assuming any error is safe to retry.

## MCP tool errors

Payment-method and transaction tools return JSON in a text content block. Check `isError`, then parse the body:

```json theme={null}
{
  "error": {
    "code": "idempotency_conflict",
    "message": "…",
    "nextStep": "…"
  }
}
```

`nextStep` is a plain-language instruction for what to do. Transaction errors can also include `details`, with `retryable`, `retryWithSameIdempotencyKey` and a retry delay. Compatibility and spending-limit tools use their own error shapes.

## Transaction error codes

| Code | Meaning |
| - | - |
| `invalid_input` | The request failed validation. Fix it before retrying. |
| `not_found` | No transaction with that ID for this key. |
| `payment_method_not_ready` | The card cannot pay yet. Check its `readiness`. |
| `setup_link_not_found` | You passed `setupLinkId`, but this buyer has no setup link with that ID. Create a new link with `sapiom_add_payment_method`. |
| `setup_link_closed` | You passed `setupLinkId`, but the link expired or was canceled. Create a new link with `sapiom_add_payment_method`. |
| `idempotency_conflict` | The key already identifies a different request. |
| `checkout_conflict` | The request conflicts with the checkout's current state. Read the transaction and follow `nextStep`. |
| `merchant_refused` | The merchant rejected the request. |
| `merchant_unavailable` | The merchant could not be reached. |
| `checkout_rejected` | The checkout could not be accepted. |
| `timeout` | The outcome is unknown. Recover with the same key; do not start a new transaction. |
| `provider_unavailable` | A card provider could not be reached. |

Authentication, scope and permission errors are returned when a key is missing, invalid or lacks a permission.

A timeout does not mean nothing happened. For what to retry and when, see [Recover without buying twice](https://docs.sapiom.ai/transactions/confirm-and-recover.md#recover-without-buying-twice).

## Creating a transaction with no saved card

If you create a transaction with `POST /v1/transactions` without naming a card, Sapiom uses the buyer's default card. If the buyer has no active card, the request returns `400` with `"code": "no_saved_card"` and nothing is created. Send the buyer a [setup link](https://docs.sapiom.ai/cards/vault-a-card.md), then create the transaction again.

## Relay refusals

When the relay refuses, nothing was sent to the payment processor. Browser Pay's `refused` event carries one of these reasons:

| Reason | Meaning |
| - | - |
| `unknown_injection` | No placeholder with that reference for this buyer. |
| `injection_expired` | The placeholder expired. The transaction needs a new authorization. |
| `payment_released` | The payment was canceled, revised or denied. |
| `key_rotated` | Sapiom voided the placeholder. The transaction needs a new authorization. |
| `already_relayed` | Another relay already used this placeholder. |
| `relay_in_progress` | A relay of this placeholder is still running. Browser Pay retries with the same key. |
| `card_removed` | The buyer removed the card. |
| `payment_not_authorized` | The payment or its approvals are no longer current. |
| `total_changed` | The merchant's checkout no longer matches what was authorized. |
| `destination_not_allowed` | The request isn't going to a payment processor Sapiom relays to. |
| `card_fields_invalid` | The card fields don't hold this transaction's placeholder, or the request carries other card data. |
| `merchant_mismatch` | The page or request is for a different merchant than the one authorized. |
| `provider_unavailable` | The card provider or the merchant's checkout couldn't be reached. The same relay can be tried again. |
| `payments_stopped` | Sapiom has paused card payments. The placeholder no longer works. |

The current Browser Pay SDK reports `payments_stopped` as `unrecognized`.

> [!NOTE]
>
> REST error responses and the full error inventory to be documented.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.