---
title: "Check an unsigned payment against the order's deposit before sending"
method: POST
path: "/agent/swap/payment-check"
tags: ["agent", "swap"]
---

# Check an unsigned payment against the order's deposit before sending

`POST /agent/swap/payment-check`

## Request

- Base URL: `https://xmrtousdc.xyz/api/v1`
- URL: `https://xmrtousdc.xyz/api/v1/agent/swap/payment-check`
- Auth: none declared

Body { orderId, payment }. payment is what the wallet will sign, UNSIGNED: the transaction JSON {to, data, value, chainId} (data.deposit.payment.tx), an ethereum: (EIP-681) or monero: URI, the calldata, or an unsigned raw transaction. Never a signed transaction: one is refused with 400 signed_transaction and never stored or broadcast. Swapper reads the live order and compares the payment with its deposit (token, chain, recipient, exact amount). Send only if data.paymentCheck.safeToSend is true (it also requires data.payable true); data.paymentCheck.mismatches lists what differs. Reads only: creates nothing and moves no funds. Offline alternative: /swapper-verify.js (the same checks with Node, no dependencies).

## Request body

- object
  - `orderId` string, required: data.order.orderId from create.
  - `payment` union, required: Unsigned only: tx JSON {to, data, value, chainId} (object or JSON string), an ethereum:/monero: URI, calldata (0x...), or an unsigned raw transaction (hex). Never a signed transaction.
    - string
    - object
      - `to` string
      - `data` string
      - `value` string
      - `chainId` union
        - integer
        - string

## Response `200`

The check

- PaymentCheckResponse
  - `ok` true
  - `operation` 'swap.payment_check'
  - `data` object
    - `orderId` string
    - `payable` boolean: The live payable gate (same as status).
    - `payableReason` 'null' | 'replay_check_status' | 'deposit_seen' | 'not_waiting' | 'expiry_unknown' | 'expired' | 'expiring' | 'reconfirm_required' | 'status_unavailable' | 'upstream_mismatch' | 'unverified_origin' | 'queued', nullable: Why payable is false (null while payable). queued: a 202 create waiting in the order line (no order exists yet). On create and status, the first failing check names it: status_unavailable (the live order could not be read, e.g. on a replay or recovery, or a long-poll ended on cached data; read the status again without waitSec), upstream_mismatch (the provider's order did not match the request; deposit is null), unverified_origin (the order was not created through this API from a quote: origin other, e.g. one made by the removed raw POST /orders route or one Swapper has no record of; never fund it, create your own order from a quote), deposit_seen (a deposit was already seen; never send again), not_waiting (the order no longer waits for funding), reconfirm_required (the provider's expected output differs materially from the quote; nothing clears it: next.action requote_and_create_new_order), expiry_unknown (the deposit expiry is unknown), expired (the deposit window has closed while the provider still shows the order waiting), expiring (less than 600 s to expiry). On lists: replay_check_status (a list never offers a payment; read the order's status).
    - `destination` string, nullable: The payout address recorded with the order: fund only if it is the user's own.
    - `paymentCheck` object
      - `safeToSend` boolean, required: true only when the order is payable and the payment sends exactly the deposit (token, chain, recipient, amount). Send only if true.
      - `matches` boolean: Whether the payment matches the deposit, whatever the payable state.
      - `txMatchesDeposit` boolean, nullable: For a transaction: whether its recipient, token, amount and chain match the deposit; null for a URI-only check.
      - `mismatches` string[]: What differs (for example chainId, token, recipient, amount).
      - `decoded` object, nullable: What Swapper read from the payment (kind, chainId, token, recipient, amountAtomic).
      - `note` string

## Other responses

- `400`: invalid_request (details.field orderId | payment: missing, unreadable or too long), or signed_transaction: the payment is a signed transaction; pass the unsigned one.
- `404`: not_found: unknown orderId.
- `415`: unsupported_media_type: the body must be JSON (content-type: application/json).
- `429`: Rate limited. Honor Retry-After.
- `502`: upstream_* while reading the live order; retry later. Send nothing until a check returns safeToSend true.
- `503`: upstream_unavailable or upstream_unreachable (retryable).

---

[API](https://skmtc.dev/xmrtousdc/apis/swapper-agent-api.md) · [All operations](https://skmtc.dev/xmrtousdc/apis/swapper-agent-api/llms.txt) · [OpenAPI document](https://skmtc.dev/xmrtousdc/apis/swapper-agent-api/revisions/9f4252126907?raw)
