Web SDKPayments

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_modeWho takes the money
drivecarsDriveCars. The widget renders a card form and charges the customer.
partner_invoicedYou. 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:

  1. Checkout creates the draft booking and emits bookingReady with { bookingReference }.
  2. You charge the customer through your own PSP, however you like.
  3. Once your PSP authorizes, you call back into the widget.
  4. 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.

<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.