Accept payments
Charge Localoy orders through your own payment gateway and report the outcome, so Localoy marks the order paid.
With Open Network payments, you collect the money with your own payment gateway and Localoy records the outcome against the order. Localoy never handles card or wallet details and never moves money.
How it works#
- Customer → Localoy: Pay for an order
- Localoy → Localoy: Open a payment session
- Localoy → Checkout page: Redirect ?session_id=…
- Checkout page → Your server: session_id
- Your server → Localoy: GET /payments/sessions/{id}
- Localoy → Your server: amountMinor, customer, returnUrl
- Your server → Your gateway: Charge amountMinor
- Your gateway → Your server: Transaction ID
- Your server → Localoy: POST …/result SUCCEEDED
- Note: The order is marked paid
- Localoy → Your server: 200 settlement record
- Localoy → Your server: Webhook: payment.updated
- Checkout page → Localoy: Redirect to returnUrl
The only call that marks an order paid is step 9, made by your server with your API key. Nothing the browser sends can change a payment.
1. Configure your checkout#
In the Partner Portal, open Open Network → Payments and set:
| Setting | Detail |
|---|---|
| Checkout URL | The page that starts your checkout, one per environment. It must be https. Any query string you add is kept, and Localoy appends session_id. |
| Session lifetime | How long a customer has to pay: 5 to 1,440 minutes, 30 by default. |
| Enabled | A production checkout is switched off until you enable it. Enabling it requires Partner+. |
Bookings wait for payment
While a production checkout is enabled, new activity bookings made through the Open Network are left pending until they are paid. A payment that succeeds confirms the booking if your confirmation policy is automatic.
2. Read the session#
Your checkout page receives only session_id. Always read the amount from the API — never from
the browser's URL.
curl "$LOCALOY_BASE_URL/payments/sessions/cm5s3ss10n00000000000001" \
-H "Authorization: Bearer $LOCALOY_API_KEY"{
"success": true,
"data": {
"id": "cm5s3ss10n00000000000001",
"status": "PENDING",
"environment": "PRODUCTION",
"amountMinor": 90000,
"currency": "BDT",
"description": "Kayak (1 hour) × 2",
"subject": { "type": "ACTIVITY_BOOKING", "id": "cm5b00k1ng0000000000001", "experienceId": "cm5act1v1ty000000000001" },
"customer": { "name": "Nusrat Jahan", "phone": "01712345678", "email": null },
"returnUrl": "https://partner.localoy.app/payments/return?session_id=cm5s3ss10n00000000000001&token=…",
"expiresAt": "2026-09-26T09:00:00.000Z",
"isExpired": false,
"isTest": false,
"providerReference": null,
"settledAt": null,
"createdAt": "2026-09-26T08:30:00.000Z"
}
}Refuse to charge if status is not PENDING or PROCESSING, or if isExpired is true.
3. Charge the customer#
Charge exactly amountMinor in currency with your gateway. Keep your gateway's transaction ID — you
will report it as providerReference.
If your gateway confirms asynchronously, you can report PROCESSING first to record that the customer
has started paying.
4. Report the result#
curl -X POST "$LOCALOY_BASE_URL/payments/sessions/cm5s3ss10n00000000000001/result" \
-H "Authorization: Bearer $LOCALOY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 7d1f0b3e-2c4a-4b9e-8f51-0a6c2d9e4b17" \
-d '{
"status": "SUCCEEDED",
"amountMinor": 90000,
"currency": "BDT",
"providerReference": "TXN-88213094"
}'| You report | Session | Order |
|---|---|---|
SUCCEEDED | Settled | Marked paid. Localoy sends payment.updated, and booking.updated if the booking is confirmed. |
FAILED | Failed; send failureCode and failureReason | Marked failed; failureReason is shown to the customer. Localoy sends payment.updated. The customer can try again. |
PROCESSING | Processing | Unchanged. |
CANCELLED | Cancelled — final | Unchanged. |
Localoy checks a SUCCEEDED result against the session. If amountMinor or currency differs, the
result is refused with 409 and the order is not marked paid. Refunds and reversals of a mismatched
charge are up to you.
See Report a result for every rule and error.
5. Send the customer back#
Redirect the browser to the session's returnUrl. Localoy's return page reads the session's status
from Localoy itself, so adding parameters such as ?status=success changes nothing.
Refunds#
When you refund a charge through your gateway, record it so the order shows as refunded:
curl -X POST "$LOCALOY_BASE_URL/payments/sessions/cm5s3ss10n00000000000001/refund" \
-H "Authorization: Bearer $LOCALOY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 0b9e4c2a-6f3d-4e1b-9a7c-5d8f2e1b3c40" \
-d '{ "providerReference": "RFD-55120", "reason": "Customer cancelled" }'A refund is always for the full session amount, and only a SUCCEEDED session can be refunded. See
Record a refund.
Session statuses#
PENDING → PROCESSING, SUCCEEDED, FAILED, CANCELLED, EXPIRED
PROCESSING → SUCCEEDED, FAILED, CANCELLED, EXPIRED
FAILED → PROCESSING, SUCCEEDED
EXPIRED → SUCCEEDED
SUCCEEDED → REFUNDED (refund endpoint only)
CANCELLED, REFUNDED finalEXPIREDis set by Localoy when the session's lifetime runs out. You cannot report it.- A charge that completes after expiry can still be reported as
SUCCEEDED; Localoy accepts it and flags the session as settled after expiry.
Rehearse in the sandbox#
- Save a sandbox checkout URL in the portal.
- On the Payments page, create a test session. It is for
10000minor units (৳100.00), with a test customer and no real order behind it. - Open the redirect URL the portal gives you, and drive the session with a sandbox key: read it, report a result, try a refund.
Test sessions change no order and fire no webhook. On them isTest is true, and the three subject
fields — type, id and experienceId — are null.
A sandbox key cannot see production sessions, and a production key cannot see sandbox ones.