Payment Flow
Authorize a Payment Order, collect the card, cancel, and chain several sales.
Take a payment
Each sale is one Payment Order:
- Your backend creates the Payment Order and returns its
idandobjectSecret. authorizePaymentOrder()prepares the payment on the phone.collectPayment()asks the customer to tap, then confirms the payment.
import { LemonwayTerminal, type LemonwayTerminalError } from '@lemonway/terminal';
async function charge(cartId: string) {
const { id, objectSecret } = await myBackend.post('/terminal/payment-orders', { cartId });
try {
const authorized = await LemonwayTerminal.authorizePaymentOrder({ id, objectSecret });
const payment = await LemonwayTerminal.collectPayment(authorized);
showSuccess(payment.amount, payment.currency);
} catch (error) {
handlePaymentError(error as LemonwayTerminalError);
}
}The phone must be connected before collectPayment().
collectPayment() resolves a PaymentResult:
| Field | Description |
|---|---|
paymentOrderId | The Payment Order id (po_…). |
paymentIntentId | The payment id (pi_…). |
status | Payment status, succeeded for a captured payment. |
amount | Amount in cents. |
currency | Currency code, lowercase (eur). |
The result is for the UIDeliver the goods or close the order from the webhook on your backend, never from
collectPayment()orpayment.success.
Cancel a payment
Call cancelCollectPayment() until the card is read, for example from a Cancel button:
await LemonwayTerminal.cancelCollectPayment();collectPayment() then rejects with PAYMENT_CANCELED and the SDK emits payment.canceled. Once the card is read, the payment can no longer be canceled and cancelCollectPayment() throws.
After a failure
What to do depends on the error code:
| Code | Next step |
|---|---|
PAYMENT_DECLINED, PAYMENT_CANCELED | The Payment Order is closed. Create a new Payment Order for the next try. |
CARD_READ_ERROR | The card was not read. Ask the customer to tap again and call collectPayment() again with the same authorized object. |
NETWORK_ERROR, UNKNOWN | The card may have been charged. Check the Payment Order status on your backend before creating a new one. |
Avoid charging twiceA network failure during
collectPayment()does not mean the payment failed. Always check the Payment Order on your backend before asking the customer to pay again.
See Error handling for every code.
Several payments
- One payment at a time. A second
collectPayment()while one is running throwsPAYMENT_IN_PROGRESS. - Keep the phone connected between sales. Do not reconnect for each payment.
- Safe retries. Calling
authorizePaymentOrder()twice on the samependingPayment Order returns the same payment, unless its amount changed. - Split payments. Create one Payment Order per card and group them with your own reference.
- Several phones. Each phone is its own reader. All phones of a shop share the same location.
Updated 11 days ago