Developer docs

Payment intents

Create a provider-agnostic payment intent for a reservation's deposit — what you send, what comes back, and why no card data ever touches this API.

A payment intent records that a deposit is owed for a reservation and hands you what a payment provider needs to collect it. The API never sees card numbers: the intent carries a clientSecret for the provider's own client-side flow, or a checkoutUrl to send the guest to. It follows the same key rules as the rest of /api/venues/**. The embeddable widget calls it from its confirmation's "Pay deposit" step, with an optional gift voucher code (Booking flow); your own page may call it with a publishable key after a reservation with depositRequired: true, exactly as shown below.

Endpoints

POST /api/venues/{venueSlug}/payment-intents

Request body (Content-Type: application/json)

Field Required Meaning
reservationReference yes The reservation's reference (BDP-XXXXXX)
amount yes Exactly the deposit the booking owes: the reservation's depositAmount (for a group booking, the whole group's). Any other amount is refused with 400
currency yes Three-letter ISO 4217 code, the reservation's currency
provider no Reserved for choosing a provider when more than one is configured; today it is ignored — the provider is decided by server configuration (fake by default, stripe once Stripe:SecretKey is set)
voucherCode no A gift voucher of this venue to pay the deposit with, fully or partly (With a voucher). Send it here only, never in a URL, and never log it

Response 201 Created

Field Type Meaning
id GUID The intent
reservationReference string What it pays for
amount, currency decimal, string What is owed
status string The provider's status — provider-specific, e.g. RequiresConfirmation for fake, a Stripe Checkout Session status such as open for stripe
provider string Which provider created it
clientSecret string Hand this to the provider's client library on the guest's device — never log it
checkoutUrl string or null When set, redirect the guest there instead
createdAt ISO 8601 instant When the intent was created
voucherAmount decimal or null What the voucher pays; null when the request carried no voucher
cardAmount decimal or null What the card pays: amount less voucherAmount. 0 means the voucher paid everything; null without a voucher
{
  "id": "79501bb3-1e05-4827-82ed-1086e889b3bd",
  "reservationReference": "BDP-KSQS7M",
  "amount": 20.00,
  "currency": "EUR",
  "status": "RequiresConfirmation",
  "provider": "fake",
  "clientSecret": "pi_fake_156d81370b0445619159a5028cc87bff_secret_82d75f634cbb4beaaf530982b18e492c",
  "createdAt": "2026-09-15T12:55:15.2187185+00:00",
  "checkoutUrl": null
}

A deposit can be paid once, and only while the booking is Pending and waiting for it. The amount is always the booking's own deposit, so a client never decides what the guest is charged.

With a voucher

Add voucherCode and the voucher pays what it can of the deposit; the card pays the rest through the same Checkout as above. Only an amount voucher pays a deposit. The voucher's value is held while the guest is on Stripe's page and taken when the payment lands, so it cannot be spent twice; if the guest gives up, the hold lapses by itself. The card part is at least €0.50: when less would be left, the voucher pays a little less so the card pays exactly €0.50 (Paying with a voucher).

A voucher that covers the whole deposit opens no payment at all: the booking is confirmed at once, provider is voucher, cardAmount is 0 and checkoutUrl is the booking's confirmation page. status is succeeded, or paid_but_unavailable when the slot was taken in the meantime — the venue then resolves the booking, and its refund puts the value back on the voucher.

{
  "id": "0b6d2c51-9a7e-4f3b-8c1d-2e4f6a8b0c13",
  "reservationReference": "BDP-KSQS7M",
  "amount": 20.00,
  "currency": "EUR",
  "status": "succeeded",
  "provider": "voucher",
  "clientSecret": "",
  "createdAt": "2026-10-09T12:55:15.2187185+00:00",
  "checkoutUrl": "https://app.bookdineplay.com/booking/confirmed?ref=BDP-KSQS7M",
  "voucherAmount": 20.00,
  "cardAmount": 0.00
}

With a voucher, the venue must have deposits switched on and a plan that includes them; online payments and a payout account are needed only while a card part is left. A refund — by the venue, on a guest's own cancel when the venue's policy refunds, or in the venue's Stripe dashboard — gives the voucher part back to the voucher and the card part back to the card.

Errors

Status When
400 A field fails validation (errors names it), or amount/currency is not exactly the booking's deposit
403 feature-not-in-plan: the tenant's plan does not include online payments or deposits. requiredPlan is "Premium"
404 No venue with that slug, or no reservation with that reference at this venue
409 The venue has not enabled online payments or deposits itself — skip the deposit step and treat the reservation as confirmed by the venue
409 payouts-not-connected: the plan and the venue's switches allow it, but the venue has not connected (or not finished connecting) its Stripe payout account yet
409 The booking is not waiting for a deposit — cancelled, confirmed by the venue, or finished (reason deposit-not-payable) — or its deposit is already paid (reason deposit-already-paid)
404, 409 With a voucher: one of the gift voucher problems, or 409 with reason below-card-minimum when the deposit is €0.50 or less and the voucher does not cover it

The venue's own switches, the tenant's plan, and the payout account are checked in that order — a venue with payments switched off answers the switch problem first, even on a plan and payout account that would otherwise allow it.

curl

curl -X POST "https://api.bookdineplay.com/api/venues/your-venue/payment-intents" \
  -H "X-BookDinePlay-Key: bdp_pk_your_publishable_key" \
  -H "Origin: https://www.your-venue.example" \
  -H "Content-Type: application/json" \
  -d '{ "reservationReference": "BDP-7K2Q9H", "amount": 20.00, "currency": "EUR" }'

JavaScript

const intent = await (await fetch('https://api.bookdineplay.com/api/venues/your-venue/payment-intents', {
  method: 'POST',
  headers: { 'X-BookDinePlay-Key': 'bdp_pk_your_publishable_key', 'Content-Type': 'application/json' },
  body: JSON.stringify({ reservationReference: reservation.reference, amount: reservation.depositAmount, currency: reservation.currency, voucherCode }) // voucherCode optional
})).json();
if (intent.checkoutUrl) location.assign(intent.checkoutUrl); // with cardAmount 0 this is the confirmation page

C#

var intent = await client.CreatePaymentIntentAsync("your-venue", new CreatePaymentIntentRequest
{
    ReservationReference = reservation.Reference,
    Amount = reservation.DepositAmount ?? 0m,
    Currency = reservation.Currency,
    VoucherCode = voucherCode // optional
}, cancellationToken);

Next steps

  • Reservations — where depositAmount comes from.
  • Vouchers — the rules every voucher payment shares.
  • Errors — feature-not-in-plan and payouts-not-connected in detail.
  • .NET SDK — CreatePaymentIntentAsync and the exceptions it throws on 403/409.