Skip to main content

Payment on arrival

With payment on arrival (PoA), a customer books without paying online and pays at the venue. The booking is confirmed straight away; its payment stays open until staff record it.

This page explains how a PoA booking moves through its life and which API calls touch it. For the staff side, see Today and check-in and Payments and refunds.

When PoA is offered​

PoA is a product setting. A product offers it when Allow pay on arrival is on (isPoaAllowed on the product in the admin API).

Even then, the product's booking policy can refuse it:

Booking policyPoA allowed?
Default (no policy)Yes
payment_requiredNo
instant_confirm_with_paymentNo
requires_approvalNo. Every booking needs staff approval first (APPROVAL_REQUIRED).

A refused PoA confirmation returns 409 with the error code POA_NOT_ALLOWED or PAYMENT_REQUIRED.

Status​

A booking has two statuses: a lifecycle status (where the booking is) and a payment status (what has been paid). PoA uses both:

StepLifecyclePayment
Customer picks a timeholdpending
Customer confirms with PoAconfirmedpending
Customer arrivesarrivedpending, or paid if collected at check-in
Staff record the paymentunchangedpaid (or part_paid for a partial amount)
Visit endscompletedpaid

See Status field conventions for all values.

A plain PoA booking has no payment deadline. It is not reminded or cancelled automatically; staff settle it on the day.

Deposit bookings​

Pay on arrival is not offered for a product with a deposit, even if the product has pay on arrival turned on. The customer pays the deposit (or the full price) online, by Paytrail or card, and the booking becomes confirmed + part_paid. The rest is then collected one of two ways, set on the product's deposit:

  • Online before the event (default): the customer gets a reminder email with a payment link before the balance is due.
  • On arrival (balanceDueMode: "on_arrival"): no reminder; staff collect the rest at the venue. Use this when you want a deposit up front and the rest paid on the day.

Staff can send the payment link again with POST /api/v1/admin/bookings/{bookingId}/resend-payment-link.

An API request for pay on arrival on a deposit product returns 409 DEPOSIT_REQUIRED. The former "pay later" option (payment_mode: "deposit_later"), which confirmed a deposit booking without any payment, has been removed.

API touchpoints​

Confirm a hold with PoA​

POST /api/v1/bookings/{id}/confirm
x-tenant-id: t_demo
{
"expected_pricing_hash": "…",
"payment_mode": "poa",
"guest_email": "customer@example.com",
"guest_name": "Alex Example",
"guest_phone": "+358401234567"
}

payment_mode is stripe (default) or poa; any other value returns 400 PAYMENT_MODE_NOT_SUPPORTED. The pricing hash comes from the hold; a changed price returns 409. See Bookings API for the hold and confirm flow.

Staff operations​

These need a staff token with one of the listed permissions.

TaskCallPermissions
Find bookingsGET /api/v1/admin/bookings/searchadmin:read
Check a customer inPOST /api/v1/bookings/{bookingId}/mark-arrivedbookings:checkin or bookings:write
Undo a check-inPOST /api/v1/bookings/{bookingId}/undo-arrivalbookings:checkin or bookings:write
Record a paymentPOST /api/v1/bookings/{bookingId}/mark-paidbookings:write or payments:record
Mark a no-showPOST /api/v1/bookings/{bookingId}/mark-no-showbookings:checkin or bookings:write
CancelPOST /api/v1/bookings/{bookingId}/cancelStaff or the booking's customer
Resend a deposit payment linkPOST /api/v1/admin/bookings/{bookingId}/resend-payment-linkadmin:write

GET /api/v1/admin/bookings/search filters on lifecycle status (status=confirmed), dates, site, product and customer. It has no payment-status filter; read paymentStatus in the results to find unpaid bookings.

Check in and collect in one step. mark-arrived takes an optional body:

{
"collectPayment": true,
"paymentMethod": "manual_cash",
"notes": "Paid at the desk"
}

paymentMethod is manual_cash, stripe_card_present or pos_integration. For a late arrival past the product's grace period, send "acknowledgeLateness": true.

Record a payment later. mark-paid takes an optional body:

{
"paymentMethod": "card_terminal",
"transactionId": "T-12345",
"amountPaid": 60.0,
"notes": "Paid after the session"
}

Cancel. cancel takes an optional reason and notes. Nothing was charged, so there is nothing to refund.