DocsGuides

Charge lodging via your MSP

Charge the room on your own merchant service provider and report the payment to Coastly. Coastly never touches the card.

Hotels that already run their own payment stack can keep charging the lodging on their own merchant service provider (MSP) — Square, Stripe, PayU, Adyen, or any gateway — and simply report the payment to Coastly. Coastly never touches the guest's card and holds none of the lodging funds.

Coastly charges the guest nothing and never touches the lodging funds. No ledger or commission entry is ever recorded for the lodging.

You keep the money. The guest's room charge settles directly into your MSP account. This endpoint only records that the lodging was paid, so Coastly can confirm the reservation and show the guest the right status.

The flow

  1. A guest books a stay. Coastly creates the reservation with status requested or pending_payment.
  2. Coastly fires a reservation.created webhook to your endpoint.
  3. Your system charges the guest's card on your own MSP and receives a payment reference (for example a Square payment.id or a Stripe pi_...).
  4. Your system calls POST /v1/reservations/{id}/lodging-payment to report that payment.
  5. Coastly marks the lodging as paid and, if the reservation was pending_payment, transitions it to confirmed and emits reservation.confirmed.
guest books ─▶ reservation.created ─▶ you charge the card on YOUR MSP
     ▲                                        │
     │                                        ▼
 confirmed ◀── reservation.confirmed ◀── POST /lodging-payment (report)

1 · The reservation.created webhook

Subscribe to reservation.created and read the reservation id from the event.

{
  "id": "evt_c1d2e3f4",
  "type": "reservation.created",
  "created": 1751760000,
  "api_version": "v1",
  "data": {
    "object": {
      "id": "res_9Fq2c8",
      "status": "pending_payment",
      "property_id": "prop_1a2b3c",
      "check_in": "2026-07-12",
      "check_out": "2026-07-15",
      "guests": 2,
      "total_cents": 42000
    }
  }
}

Verify the webhook signature exactly as described in the webhooks guide before acting on it.

2 · Report the lodging payment

After you have charged the card on your MSP, report the payment.

POST /v1/reservations/{id}/lodging-payment · scope reservations:write

Field Type Required Notes
amount_cents integer yes Lodging amount you captured, in the smallest currency unit. Must be a positive integer.
external_ref string yes The payment id from your MSP. Also acts as a dedupe key (see below).
currency string no ISO code, e.g. USD. Defaults to the reservation currency.
provider string no Your gateway name, e.g. square. Defaults to msp.
method string no Optional method label, e.g. card.

Writes require an Idempotency-Key header.

curl -X POST https://coastly.surf/api/v1/reservations/res_9Fq2c8/lodging-payment \
  -H "Authorization: Bearer $COASTLY_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8b1f0c92-6d4a-4f2e-9a1c-2e7d4b5a0f31" \
  -d '{
    "amount_cents": 42000,
    "currency": "USD",
    "external_ref": "sq_pmt_AbC123XyZ",
    "provider": "square",
    "method": "card"
  }'
{
  "reservation": {
    "id": "res_9Fq2c8",
    "status": "confirmed",
    "lodging_status": "paid",
    "lodging_paid_cents": 42000,
    "lodging_payment_ref": "sq_pmt_AbC123XyZ",
    "lodging_payment_provider": "square",
    "lodging_paid_at": "2026-07-05T18:22:10.000Z"
  }
}

The reservation's lodging_status (unpaid | paid | refunded) and lodging_paid_cents are also returned on every reservation read, so you can poll payment state at any time.

Idempotency and the external_ref dedupe key

Two independent safeguards prevent a double charge from ever being double-recorded:

  • Idempotency-Key header — retrying with the same key and the same body replays the stored response verbatim. Retrying the same key with a different body is a 409 idempotency_conflict.
  • external_ref — even with a fresh Idempotency-Key, reporting the same external_ref against a reservation whose lodging is already paid replays the existing result without applying it twice. Reporting a different external_ref against an already-paid reservation is a 409 reservation_conflict — the lodging can only be paid once.

Together this means it is always safe to retry a report on a timeout: the same payment reference will never be applied twice.

Errors

Status Code When
403 forbidden_scope The reservation belongs to another vendor.
404 not_found No reservation with that id.
409 reservation_conflict The reservation is cancelled, or lodging is already paid under a different external_ref.
422 validation_error external_ref missing, or amount_cents is not a positive integer.

What Coastly does — and does not — do

  • Does record lodging_status, the amount, your external_ref, the provider, and the paid-at timestamp.
  • Does confirm the reservation when it was pending_payment, and emit reservation.confirmed.
  • Does not touch the guest's card, hold the lodging funds, or record any ledger or commission entry for the lodging.

Coastly charges the guest nothing on the lodging and collects none of the lodging funds; the lodging payment is entirely between you and the guest.