Skip to main content

Embed secure card fields

Use @peakgateway/web-sdk to place Peak-hosted card fields in your checkout. Card numbers and security codes go directly to Peak; your page and merchant server do not receive them. This does not eliminate your responsibility to secure your checkout or meet applicable PCI requirements.

Server: create the payment context

Authenticate on your server and create either:

  • POST /api/v1/checkout/sessions for a payment. Persist its Idempotency-Key and original body before sending. Use the returned checkoutUrl.
  • POST /api/v1/setup-intents to save a card without charging it. Bind the customer, location and consent required by the request. For a ready-to-use hosted link, use POST /api/v1/setup-intents/issue-link with deliveryMode: "IFRAME" and use hostedUrl.

The hosted context URL has a /c/{sessionId} or /setup/{setupIntentId} path. Preserve the returned URL, including its authorization parameters; do not manufacture a client secret or use an API URL as the iframe URL.

Browser: mount the fields

npm install @peakgateway/web-sdk
import { mountSecureCardFields } from '@peakgateway/web-sdk'

// These elements belong to your checkout form.
const submitButton = document.querySelector<HTMLButtonElement>('#submit-payment')!
submitButton.disabled = true
let ready = false
let complete = false

const fields = mountSecureCardFields({
  container: document.getElementById('card-fields')!,
  url: hostedUrl, // returned by your server for this checkout or setup intent
  style: { fontFamily: 'system-ui', fontSize: '16px', color: '#172033' },
  onEvent(event) {
    if (event.type === 'ready') ready = true
    if (event.type === 'change') complete = event.complete
    submitButton.disabled = !ready || !complete
    if (event.type === 'succeeded') {
      // Ask your server to read the authoritative session/setup-intent state.
      refreshPaymentState()
    }
  },
})

// In your form's submit handler, after ready and complete:
const context = { cardHolderName, billingStreet, billingCity, billingState, billingCountry, billingZip }
const result = await fields.confirm({
  amount, // authoritative checkout amount supplied by your server, in minor units
  currency,
  context,
})
// For a setup intent, use fields.confirm({ context }) without amount/currency.
// Destroy only when removing the fields from the page:
// fields.destroy()

hostedUrl, amount and currency come from your application's server response. Collect cardHolderName and the billing-address values in ordinary form inputs; never create merchant-owned card-number or security-code inputs. The context object supplies this non-card billing information. refreshPaymentState is your application's authenticated status refresh. Handle result.type without equating submission or a browser event with authoritative payment success. See card setup for the separate Elements setup flow.

Server: use the saved card

Read the completed setup intent or checkout session with authenticated server credentials. Setup intents expose paymentMethodId; use that identifier as savedPaymentMethodId when creating a subscription or card-on-file payment. Browser events are a prompt to refresh, not proof of payment or authority to attach a customer's card. Validate the customer, location and final status on your server.

ACH is a different flow

There are no embeddable bank-account fields in the web SDK. To keep bank entry off your server, redirect to hosted checkout and set allowedPaymentMethods: ["ach"] (or include "card" as well) when creating the session. ACH must be enabled for the location and currency.

Alternatively, POST /api/v1/saved-payment-methods/bank-accounts accepts customerId, accountHolderName, accountNumber, routingNumber, accountType, mandateAccepted and mandateVersion; isDefault is optional. This option sends bank details through your server. Obtain the customer's authorization and supply mandateAccepted: true and the supported customer authorization version ach-mandate-v1. Protect bank data and never log it. Use the reference for account-type values and validation.

ACH acceptance is not settlement; see checkout lifecycle.