Payments
Which mode applies to you is fixed by partner.mor_mode in your session, and
mirrored onto the element’s mor-mode attribute. It is a commercial setting,
not something the page chooses.
mor_mode | Who takes the money |
|---|---|
drivecars | DriveCars. The widget renders a card form and charges the customer. |
partner_invoiced | You. The widget collects no card details at all. |
drivecars — DriveCars is merchant of record
The default, and the simpler one. Checkout renders a card form inside the widget, the customer pays DriveCars, and the widget authorizes the booking itself. The card form’s publishable key arrives with the payment intent, so you pass no payment credentials at all — there is nothing of yours to configure, and nothing of yours that could leak.
You need to do exactly one thing: listen for booking.payment.authorized and
show your own confirmation.
<drivecars-checkout base-url="https://{your-base-url}"></drivecars-checkout>Nothing else is required of you. The booking is confirmed by the time that event fires.
partner_invoiced — you are merchant of record
The widget never touches card details. The sequence is:
- Checkout creates the draft booking and emits
bookingReadywith{ bookingReference }. - You charge the customer through your own PSP, however you like.
- Once your PSP authorizes, you call back into the widget.
- The widget posts the confirmation to DriveCars, advances to its terminal
screen, and emits
booking.payment.authorized.
document.addEventListener('bookingReady', async (e) => {
const { bookingReference } = e.detail;
const charge = await myPsp.charge({ orderRef: bookingReference });
DriveCars.confirmPartnerPayment(bookingReference, charge.id);
});charge.id — the second argument — is your PSP’s reference for the charge,
which is what we record against the booking.
Do not call confirmPartnerPayment before your PSP has actually authorized.
If the booking is never confirmed it simply stays a draft, which is the safe
outcome; confirming a charge that did not succeed is not.
confirmPartnerPayment(reference, paymentReference)
The first argument selects which mounted <drivecars-checkout> to call,
matched against the reference you passed to mount('checkout', el, { reference }).
With exactly one checkout element mounted, the first argument is ignored and
that single mount is used — so passing the booking reference, as above, is
harmless and reads well. With more than one, it must match a mount() label:
DriveCars.mount('checkout', flightsCheckoutEl, { reference: 'flights' });
DriveCars.mount('checkout', hotelsCheckoutEl, { reference: 'hotels' });
DriveCars.confirmPartnerPayment('flights', charge.id);If no mounted checkout matches, nothing happens beyond a console error — the booking stays a draft.
Payment links
<drivecars-payment> is a separate surface for a customer paying an existing
booking by link — typically someone with no account, who arrived from an email.
It does not use the session token. It authenticates with a payment-link-token
instead, which is why it is the only element that never asks for a session
refresh. payment-link-token is required; without it the element renders a
red error rather than an empty box. As with checkout, the card form’s
publishable key arrives with the payment intent — you pass none.
<drivecars-payment
base-url="https://{your-base-url}"
payment-link-token="…">
</drivecars-payment>It emits payment.completed with { reference, kind } when the payment
finishes.
Because the link token is the credential, treat the URL you put it in as sensitive: anyone holding it can view and pay that booking. Send it to the customer directly, and do not log it or put it in a referrer-leaking query string on a page with third-party scripts.