Payments and their statuses
The payment object, its payment methods and destination, the unique amount, how receipts and deposits complete it, and every status a payment can be in.
A payment is one amount you want to receive, for one order. Your customer pays it card to card or by bank transfer, straight to your card or account, and sends a receipt. Money that your team approves from a receipt, or that a bank SMS shows arrived, is a deposit. A payment collects deposits until they reach its amount, which is why a wrong transfer is never a dead end.
Creating a payment
POST /v1/payments takes:
| Parameter | Description |
|---|---|
amount | Required. Integer rial, from 10,000 to 2,000,000,000. |
reference | Your order id, up to 100 characters. Shown on the checkout and searchable in the dashboard. |
description | Up to 500 characters. |
customer or customer_details | An existing customer id (cus_…), or { name, phone, email }. |
return_url, cancel_url | Where the checkout sends the customer back, with a signed status. See hosted checkout. |
expires_in | Seconds the checkout stays open, 300 to 86,400. Defaults to your checkout setting (30 minutes). |
allow_partial | Track several deposits toward the amount. Defaults to your payments setting (on). |
card | A destination id (card_…): a card or an account that takes one of your enabled payment methods. Defaults to your routing (your default destination, round robin or least used). |
metadata | Up to 50 string keys of 40 characters, values up to 500. |
curl https://a.bezanbecard.com/v1/payments \
-H "Authorization: Bearer sk_test_…" \
-H "Idempotency-Key: order-1042" \
-H "Content-Type: application/json" \
-d '{"amount":12500000,"reference":"1042","customer_details":{"name":"Test Customer","phone":"09900001234"},"metadata":{"order_id":"1042"}}'Methods and destination
payment_method_types says how the customer may pay: card (card to card) and transfer (Pol, Paya, Satna or a same-bank transfer to the IBAN). It is fixed when the payment is created, from the methods you enabled that its destination takes.
destination names where the money goes: card (the destination's id), type (card or account), bank, last4 (null for an account), iban_last4 and holder_name. With a secret key it also carries the full pan and iban for a custom checkout. Bank transfers has the details.
The unique amount
A receipt or a bank SMS says how much arrived on which card or account, and little else. To keep transfers apart, every payment asks for an amount no other open payment on the same destination is asking for: expected_amount. It is amount plus a small unique sum (by default between 1,000 and 99,990 rial, in steps of 10; you can choose to subtract it instead in the payments settings).
The customer pays exactly expected_amount, and paying it in full counts as paying amount in full: the unique sum never shows up as an overpayment. The hosted checkout shows the figure and copies it with one tap. If you build your own checkout, show expected_amount (never amount) and the exact rial figure.
You can turn unique amounts off in the payments settings. expected_amount then equals amount: simpler for the customer, but a bank SMS can no longer tell apart two open payments of the same amount. See unique amounts on or off.
How a payment is completed
- The customer pays from their bank app and sends a receipt on the checkout. The payment becomes Awaiting approval
processing. - A member of your team approves the receipt in Receipts. The approval puts a deposit of that amount on the payment.
- The payment is recomputed from its deposits: Succeeded
succeededwhen they reachamount, Partially paidpartially_paidwith a top-up when they fall short, an overpayment when they pass it.
Your team can also reject the receipt (the payment waits for another), approve a payment directly, or attach a deposit by hand. See receipts and review and corrections.
How a bank deposit is matched
A deposit also arrives without a receipt: from the optional SMS app, when you record one by hand, or when you simulate one in test mode. Bezanbecard then looks at the open payments on that card or account, in this order, and stops at the first rule that finds exactly one:
- Exact amount. A payment whose current
expected_amountequals the deposit. - An earlier amount. A payment that asked for this amount before a top-up replaced it.
- Payer card and claim. The SMS names the payer's card, and one payment had a customer report a card-to-card transfer with the same last four digits in the last two hours. This is how wrong amounts are caught: less becomes a partial payment, more an overpaid success.
- A single recent claim. One payment is waiting with a recent claim and the deposit is within half of its amount either way. A Paya or Satna claim stays recent longer. This is only a suggestion: the payment goes to review and a person confirms it.
A rule that finds two candidates never guesses. A deposit no rule matches waits in the dashboard's Review and fix inbox with suggestions, where you attach it by hand. When a receipt on the payment fits the deposit, the SMS corroborates the receipt instead of counting a second time.
With automatic approval off (the default), a deposit these rules match in full does not complete the payment by itself: the payment goes to review with auto_disabled and a person approves it.
Statuses
| Status | Meaning |
|---|---|
Awaiting transferrequires_payment | Waiting for the customer to pay expected_amount and send a receipt. |
Awaiting approvalprocessing | The customer sent a receipt, or said they paid. Waiting for your team's review. |
Partially paidpartially_paid | Deposits so far are below amount. amount_remaining is still due, with a fresh unique amount for it. |
Needs reviewrequires_review | A person needs to decide. review.reason says why. |
Succeededsucceeded | Deposits reached amount, or a member approved the payment. |
Canceledcanceled | You canceled it before it succeeded. |
Expiredexpired | Nothing arrived and no receipt was sent before the checkout closed. |
A payment with a pending receipt stays processing until your team decides; no timer moves it. A canceled or expired payment still catches a late transfer until the grace period after its checkout's expiry ends (60 minutes by default, and longer after a Paya or Satna claim: see the transfer wait window), and reopens. After that only a manual attach reaches it.
Review reasons
review.reason | Why the payment waits for a person |
|---|---|
no_sms | Only for an "I have paid" claim stored before receipts: no matching bank SMS arrived in the time such a transfer usually takes, or by the end of grace. A receipt without a file, from the checkout or /claim, waits in your Receipts queue (the payment stays Awaiting approvalprocessing) until a member decides. |
expired_partial | Part of the money arrived and the checkout closed before the rest did. |
partial_disabled | A deposit below the amount arrived while partial payments are off for this payment. |
payer_mismatch | The deposit was matched automatically, but the payer's card is not one the customer claimed. |
amount_mismatch | Rule 4 above: a suggested deposit waits for your confirmation. |
auto_disabled | A deposit the rules matched covers the full amount; with automatic approval off (the default), a person approves it. |
detached | A correction took every deposit off a payment that had succeeded. |
Corrections covers what you can do about each.
Amount fields
| Field | Description |
|---|---|
amount | What you asked for. Never changes. |
amount_received | The money matched to the payment (approved receipts and bank deposits), summed from its deposits. |
amount_remaining | What is still due. |
amount_overpaid | What arrived beyond amount. See overpayments. |
amount_shortfall | What you forgave when you approved the payment without the full amount. |
expected_amount | The exact amount to transfer (unique on the destination); null once the payment is terminal or past grace. It stays set while a receipt is under review (processing) and in requires_review, so ask for a transfer by status (requires_payment, partially_paid). |
These are recomputed from the matched deposits on every change, never added up step by step, so a correction always leaves them right.
Reading, listing and updating
GET /v1/payments/:id returns one payment; add expand[]=deposits for the full deposit objects, expand[]=receipts for its receipts and expand[]=customer for the customer. GET /v1/payments lists them newest first and filters by status, customer, reference and created (see pagination).
POST /v1/payments/:id changes description, metadata and customer_details while the payment is open. POST /v1/payments/:id/cancel cancels an open payment, with an optional reason of 3 to 500 characters; if money had already arrived, the payment records it as owed back to the customer.
Events
Every status change emits an event your webhook endpoints receive: payment.created, payment.processing, payment.partially_paid, payment.requires_review, payment.succeeded, payment.overpaid, payment.overpayment_resolved, payment.canceled, payment.expired and payment.updated. Receipts emit their own: receipt.created, receipt.approved and receipt.rejected.