Understand the sale lifecycle
Related
- Sale Statuses
- Sale Types
- Callback types reference
- Callbacks
- List sales
- List transactions
- Capture an authorized sale
- Refund a sale
- Void an authorization
- Idempotency and Retries
A sale is PayMe's record of one order. It starts as initial when you create it, and its sale_status changes as the buyer pays and as you capture, refund or void it. This page shows every transition, what causes it, the callback PayMe sends for it, how long the payment link stays open, and how to read a sale's current state.
The status values are listed on Sale Statuses. The callbacks are described on Callback types reference.
The states at a glance
Charge now (sale_type: sale)
initial ──► completed ──► refunded
│ ▲ ├───────► partial-refund
│ │ └───────► chargeback / partial-chargeback ──► completed (reversed)
▼ │
failed (the buyer can pay again on the same sale)
Authorize now, capture later (sale_type: authorize)
initial or failed ──► authorized ──► completed (captured)
├────────► failed (capture declined; capture again)
├────────► voided
└────────► partial-void
Transitions
| From | To | What causes it | Callback (notify_type) |
|---|---|---|---|
| — | initial |
You create the sale with generate-sale |
sale-create, only if you sent sale_send_creation_callback: true |
initial, failed |
completed |
The buyer pays | sale-complete |
initial, failed |
authorized |
The buyer pays a sale created with sale_type: authorize |
sale-authorized |
initial, failed |
failed |
A payment attempt fails: a decline, or a failed 3D Secure check | sale-failure, once per failed attempt |
authorized, or failed after a declined capture |
completed |
capture-sale succeeds. A capture for less than the authorized amount sets the sale price to the captured amount |
sale-complete |
authorized |
failed |
capture-sale is declined. You can capture again while the authorization is still valid |
sale-failure |
authorized |
voided |
refund-sale releases the whole hold |
refund |
authorized, partial-void |
partial-void |
refund-sale releases part of the hold. A partial-void sale can't be captured, and further voids keep it partial-void |
refund |
completed |
refunded |
refund-sale refunds the full amount at once |
refund |
completed, partial-refund |
partial-refund |
refund-sale refunds part of the amount. The sale stays partial-refund even after the parts add up to the full amount |
refund |
| A paid sale | chargeback or partial-chargeback |
The card issuer charges the payment back, in full or in part | sale-chargeback |
chargeback, partial-chargeback |
completed |
Every chargeback on the sale is reversed in the seller's favor | sale-chargeback-refund |
initial (template sales only) |
canceled |
cancel-template closes the template's link |
None |
Some sales are created by PayMe rather than by your generate-sale call, and then follow the same statuses:
- Each payment on a template sale (one link that many buyers pay) creates its own sale,
sale_type4. The template itself only moves frominitialtocanceled. - Each subscription charge creates a sale,
sale_type3, which sends its ownsale-completeorsale-failure. - An Israeli direct-debit payment sends
sale-paidwhen the debit is submitted to the bank, thensale-complete, orsale-failureif the bank returns it. See Israeli Direct Debit.
Capturing in several parts creates child sales; see multi-capture.
Failures aren't final
failed means the last attempt failed, not that the sale is closed. The buyer can try again on the same payment page, and you can call pay-sale again on a failed sale. Each failed attempt sends another sale-failure with its own payme_transaction_id. The attempts stop when the sale completes.
So:
- Don't cancel the order on the first
sale-failure. Wait forsale-complete, or for your own deadline. - If you create a new sale for a retry, the old
sale_urlstays payable too, and the buyer could pay twice. Reuse the same sale, or setsale_expiry_secondson each sale. - Once a sale is
completed, a late failure can't move it back tofailed.
How long the payment link stays open
sale_url has no fixed expiry. The payment page opens while the sale is initial or failed; once the sale has any other status, the page no longer takes a payment.
To set a deadline, send sale_expiry_seconds when you create the sale. The time counts from the sale's creation. After it:
- the payment page answers HTTP 403;
pay-salereturns error367("the sale has expired");sale_statusdoesn't change. An expired sale still readsinitialorfailedinget-sales, so track the deadline on your side too.
sale_should_be_opened_once: true works only on a sale with layout: token-capture: the page then opens only once.
There is no call to cancel an ordinary open sale. To stop a buyer from paying, rely on sale_expiry_seconds. cancel-template works only on template sales.
Callbacks at each step
The last column of the table above is the callback each transition sends. Three rules matter when you handle them:
sale-createis opt-in: PayMe sends it only when you create the sale withsale_send_creation_callback: true.sale-failureis sent once per failed attempt, andrefundonce per refund or void. Each carries its ownpayme_transaction_id.- Callbacks can arrive more than once and out of order. Never let a later callback overwrite a final state you already recorded.
The payloads, the signature and the delivery rules are on Callbacks. Who receives each type, and its key fields, is on Callback types reference.
Read the current state
Callbacks can be lost after their retries, so confirm a sale with get-sales before you fulfil the order, and when a request timed out.
POST https://sandbox.payme.io/api/get-sales (production: https://live.payme.io/api/get-sales)
{
"seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567",
"sale_payme_id": "SALE1655-3843870J-NTPYLJNW-SOWRLK9X",
"sale_status": ["initial", "completed", "failed", "authorized", "refunded", "partial-refund", "voided", "partial-void", "chargeback", "partial-chargeback"]
}
Send sale_status. Without it, get-sales leaves out initial sales, so an unpaid sale comes back as an empty items list, as if it didn't exist.
The response (other fields omitted):
{
"status_code": 0,
"items_count": 1,
"items": [
{
"seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567",
"sale_payme_id": "SALE1655-3843870J-NTPYLJNW-SOWRLK9X",
"transaction_id": "order-1002",
"sale_type": 1,
"sale_status": "completed",
"sale_currency": "ILS",
"sale_price": 1000,
"sale_paid_date": "2026-11-09 12:30:05",
"sale_error_code": null,
"sale_is_3ds": false
}
]
}
Before you fulfil the order, check that:
sale_statusiscompleted(orauthorized, if you capture later);sale_priceandsale_currencymatch your order.sale_priceis the amount charged, in minor units;transaction_idis your own order ID for this order.
On a failed sale, sale_error_code and sale_error_text give the reason of the failed payment. sale_type tells you where the sale came from, for example 3 for a subscription charge and 4 for a payment on a template sale's link; see Sale Types.
To see each money movement on its own row (the payment, the capture, every refund and chargeback), use get-transactions. There, transaction_error_code is null on a successful transaction. A sale that is authorized and not yet captured appears only when you send transaction_type: 40.
If a request timed out and you don't know whether it ran, read the sale before you retry. See Idempotency and Retries.