One-time payments
Create a payment, choose what the payer can use, handle partial and late payments, expiry and cancellation.
Create
POST /v1/payments (SDK: payments.create). The amount is a fiat decimal string; the crypto amount is quoted when the payer picks an asset, at the current rate, and is locked for the quote's lifetime.
| Field | Notes |
|---|---|
amount, currency | "25.00", "USD" (3-letter ISO). |
merchant_order_id + return_existing | With return_existing: true an open payment with the same order id is returned instead of creating a second one. |
accepted_assets, accepted_chains | Subsets of your merchant defaults (PATCH /v1/merchant); omit to accept everything you enabled. |
allowed_payment_methods | external (connect wallet), transfer (QR / unique address), internal (payer's Cripay balance). Default ["external", "transfer"]. |
expires_in_minutes | 5 – 2880, default 30. After expiry the payment is expired; funds arriving inside the monitoring window still complete it as paid_late. |
success_url, cancel_url, description, customer_email, metadata | Returned on the payment and in every webhook. metadata is yours; it never reaches the payer. |
Always send an Idempotency-Key (the SDK generates one). Retrying with the same key replays the first response.
Fees
Your settings (PATCH /v1/merchant) decide the percentage (fee_bps), who pays it (fee_payer: merchant | payer) and the tolerance for small underpayments (underpaid_tolerance_bps). Pay-by-transfer also charges a fixed network component per chain (GET /v1/currencies → transfer_fixed_fee_usd, min_payment_usd). POST /v1/estimates previews the exact split before you create anything. Each payment snapshots its terms (fee_bps, fee_fixed_units, fee_payer) so later setting changes never alter it.
Outcomes
| Status | Webhook | What happened |
|---|---|---|
processing | payment.processing | Seen on chain (mempool / below the confirmation depth). Not final. |
confirmed | payment.confirmed | Final. gross_amount_units, fee_amount_units, net_amount_units and tx_hash are set. |
underpaid | payment.underpaid | Transfer below the quote (minus tolerance). remaining_units tells the payer what is missing; more transfers to the same address complete it. |
overpaid | payment.overpaid | More than quoted arrived; final, overpaid_units in the event. |
expired | payment.expired | Nothing arrived in time. A late transfer inside the monitoring window confirms it with paid_late: true. |
held | payment.held | A counterparty failed sanctions screening; funds frozen pending review. |
cancelled | — | You called POST /v1/payments/:id/cancel before anything arrived. |
Poll GET /v1/payments/:id only for display; act on webhooks.