DineGlobeDocs

Payments (pilot posture)

How deposits are configured, what the checkout hold does, why live charging stays disabled during the pilot, and what that means for each booking.

OwnerManagerFinance

Payments in DineGlobe cover two separate things: where a venue configures the deposit it would charge for a booking, and how a paid booking moves money once a provider is connected. The machinery is fully built — holds, hosted checkout, verified webhooks, reconciliation and an append-only ledger all run as designed. What the live pilot does not have is a configured payment provider, so no charge has ever been taken, and every payment path is built to refuse visibly rather than pretend otherwise.

The pilot reality, stated plainly

DineGlobe runs as a free-booking pilot. The payment capability gates are closed, and the live environment deliberately has no payment provider configured — the provider registry names only sandbox transports, and recording a sandbox as production is refused by design (CAPABILITY_NOT_ACTIVATABLE).

What that means in practice:

  • A DEPOSIT policy cannot be activated. Activation refuses with 422 PAYMENT_NOT_READY, naming the exact block that stands closed (table below).
  • A guest who reaches a deposit offering cannot complete a paid booking online. The booking refuses with 422 PAID_BOOKING_UNAVAILABLE, and the booking screen says: “This service requires a deposit, which is not available online yet. Please book by phone.”
  • Staff payment panels answer 503 PAYMENT_PROVIDER_UNAVAILABLE for anything that would call a provider.
  • No hosted-checkout URL is faked, no capability is invented, no success is staged. When a gate stands closed, the panel says which gate it is.

Single-market pilot evidence only: one approved country and its listed capabilities do not constitute global support; unlisted countries and capabilities stay disabled.

Until an operator activates a real provider under the documented launch gates, DineGlobe will not take a charge — and it will not pretend to.

Where a deposit is configured

Deposits are policy configuration, not a per-booking toggle. Each offering is governed by a published policy version (see the Booking policies & cancellation page, /docs/setup/policies/), and the money fields live there:

Field Values Meaning
paymentMode NONE or DEPOSIT Whether the offering charges anything at all.
amountMode PER_BOOKING or PER_PERSON Deposit per booking or per guest.
amountMinor integer, exactly 0 for NONE, at least 1 for DEPOSIT Exact integer minor units — never a decimal figure.
currency three-letter code, must equal the venue currency One venue never mixes currencies.
cancellation fields freeCancelMinutes, lateRetentionBps, noShowRetentionBps, graceMinutes The same version quotes what a cancellation or no-show retains.

Policy versions are immutable. You change terms by retiring a version and publishing a new one, and a booking stores the accepted policy snapshot at booking time, so its quoted terms never drift when you publish later.

A DEPOSIT policy activates only when the venue’s connected payment account is charge-ready. Otherwise activation refuses with PAYMENT_NOT_READY and one of these blocks in the paymentMode field error:

Block Meaning What to do
NO_ACCOUNT No payment account is connected. An owner connects the account (see below).
CHARGES_DISABLED The connected account cannot take charges right now. Refresh its capability truth.
CURRENCY_MISMATCH The connected account settles in a different currency than the venue. Align the account’s settlement currency.
COUNTRY_NOT_APPROVED Payments are not approved for the venue’s country. Wait for the operator’s capability approval.

When everything lines up, the capability view reports “PAID INTAKE READY — a DEPOSIT policy may now be activated.” In the pilot it reports blocked, and that is the honest answer.

How money is represented

  • Every amount is an exact integer in minor units, stored in a bigint column and carried as a string through APIs and panels. Floating-point arithmetic never touches an amount, and there is no automatic currency conversion anywhere: an amount quoted in one currency is held, captured, refunded and reported in exactly that currency.
  • One venue, one currency. The venue’s currency is fixed at setup, and a policy’s deposit currency must equal it.
  • Rendering is separate from money. A fixed list of zero-decimal currencies (the Japanese yen among them) renders no decimals; a fixed three-decimal list (the Kuwaiti dinar among them) renders three; everything else renders two. Display formatting re-renders the stored integer — it never recomputes an amount.
  • Finance views aggregate per currency and never combine currencies into one total (the views are covered in Refunds, /docs/money/refunds/).

The checkout flow as designed

When the gates are open and a guest books a DEPOSIT offering, the flow is:

  1. Hold. The booking command creates the payment attempt and moves the reservation to HELD; both commit before any provider call. The hold lasts 10 minutes.
  2. Hosted checkout. Staff open the provider’s hosted checkout from the Payment holds and checkout panel. The URL is the provider’s own page, shown once, and the state line always names AWAITING_GUEST — a checkout session is never presented as a payment.
  3. Verification, not the browser. The provider calls POST /api/webhooks/payments. The signature is verified over the raw body before anything is parsed or stored, and a valid event is stored once in an idempotent inbox (a redelivery answers an idempotent DUPLICATE). A stored receipt is pending truth only — money effects belong to reconciliation, never to the receipt.
  4. Reconciliation confirms. The reconciliation pass drains verified events into money truth: the capture is written to an append-only ledger, and only a live HELD reservation is confirmed. A browser return or a provider session state can never confirm a booking — payment is confirmed only by provider reconciliation.
  5. Expiry. If the guest never pays, the expiry sweep — run opportunistically inside every booking mutation and staff-fired from the panel — expires the attempt and the reservation, releases the held tables and queues a booking.expired event (PAYMENT_HOLD_EXPIRED). A lapsed hold never blocks a replacement booking.
  6. Late money never resurrects a booking. If a capture arrives after the hold died, reconciliation records it and schedules a full-amount compensation refund intent; the booking stays non-confirmed and the tables were already released.

A payment attempt moves CREATED → AWAITING_GUEST → EXPIRED, with the capture recorded in the ledger only when a verified provider event lands.

If the provider does not answer during checkout, the error is 503 PAYMENT_CHECKOUT_TIMEOUT and the remedy is to retry the same action: the stable idempotency key continues the SAME checkout, so a retry can never create a second charge.

The payment panels

All money surfaces live in the operator console at /app/panels (sign in at /app/login):

  • Payment account connection — owner/org-admin only. Begins the provider-hosted onboarding (credentials live with the provider; the URL is shown once and never stored) and refreshes capability truth — charges, payouts, settlement currency, country and route approval.
  • Payment holds and checkout — start or recover a hosted checkout with the booking’s request key, and run the hold-expiry sweep. An empty sweep is a normal outcome.
  • Provider event inbox — the webhook surface and its staff-side envelope view. Encrypted payloads never leave the database; the panel shows envelopes and checkpoints only.
  • Payment reconciliation — drains pending verified events into money truth, sweeps a provider account window, and lists refund intents.
  • Payment status and finance views — per-reservation money status and settled finance totals. Host and door sessions are refused here: money views belong to the money roles (see the Finance guide, /docs/roles/finance/).

Error codes

Code Meaning and remedy
PAID_BOOKING_UNAVAILABLE The offering charges a deposit but the gates refuse right now. Book as a free or request booking if offered, or by phone.
PAYMENT_NOT_READY A deposit policy cannot be activated; the field error names the block (NO_ACCOUNT, CHARGES_DISABLED, CURRENCY_MISMATCH, COUNTRY_NOT_APPROVED). Fix the named problem and retry.
PAYMENT_PROVIDER_UNAVAILABLE No payment provider is configured for this deployment. Expected during the pilot; retry after a provider is connected.
PAYMENT_COUNTRY_NOT_APPROVED The venue’s country has no approved payment capability. Waits on an operator decision.
PAYMENT_ROUTE_NOT_APPROVED The approved capability names a different provider than the one in use. The operator aligns the capability row.
PAYMENT_CHECKOUT_TIMEOUT The provider did not answer. Retry the same action — it recovers the same checkout, never a second charge.
PAYMENT_HOLD_EXPIRED The hold expired; the reservation is EXPIRED and its tables were released. Rebook.
PAYMENT_WEBHOOK_REJECTED Signature verification failed on the raw bytes, or the event names an account nobody owns. Nothing was stored; check provider configuration.

Full code reference: Error codes & fixes. For what happens to money after a capture — refunds, thresholds and approvals — see Refunds.