● SANDBOX · TEST MODE

Form 1 · Card only

Your page already has the buyer. The frame draws the card fields only; the billing details you pass ride on the charge, so address verification still runs.

Two halves, as always. Your server names the price and gets a client secret; this page mounts the form against it. What is different here is fields: { billingDetails: 'never' } plus defaultValues.billingDetails: the buyer sees no billing field, and the receipt on onSuccess still shows the address on the charge.

1 · Your test keys

The secret key is POSTed only to /api/demo/intent, never to the SDK. Allowed domains on the pk must include this host.

2 · Buyer on file (this is your page's data)

Edit these after mounting and the element picks the change up through element.update({ defaultValues }). Email is required: the demo intent has no receipt_email, and a confirm with neither fails.

3 · Pay

Test card (NMI sandbox). 4111 1111 1111 1111 · any future expiry · CVV 123. NMI answers a repeat of the same card and amount within a minute with Duplicate transaction; wait a minute between tries. Only the card fields are drawn below.

After a successful payment the green box shows charge.billing_details from the receipt: the address you passed above, on a charge whose form never asked for it.

4 · The integration

// 1. Your server, with the secret key: // POST /v1/payment_intents -> { client_secret } // 2. This page, with the publishable key: const wp = WorthyPayments('pk_test_…'); wp.mountPaymentElement('#payment', { clientSecret, fields: { billingDetails: 'never' }, // draw the card only defaultValues: { billingDetails: { // what your page already knows email: 'ada@example.com', name: 'Ada Lovelace', address: { line1: '1 Main St', city: 'Austin', state: 'TX', postal_code: '78701', country: 'US' }, }, }, onSuccess: (r) => { /* r.charge.billing_details carries that address */ }, onError: (e) => { /* e.code === 'card_declined' on a decline */ }, });

5 · Log

Waiting for a key.