What this is and who needs it

To bill a customer more than once, or to charge them later without making them re-enter their card, you have to store the card somewhere safe. Storing card data yourself means PCI compliance, audits, and risk you do not want.

EPD handles this for you, and the payoff is immediate: raw card data never reaches your servers, which keeps your PCI compliance at its lightest tier: PCI SAQ A (a short self-check, not a full audit). Under the hood, the card is captured in a secure field and stored in EPD’s PCI-scoped vault; EPD Commerce keeps a display copy (last four digits, brand, expiry) that points back to the stored card.

If you charge customers more than once (subscriptions, top-ups, win-backs, saved-card checkout), this is the flow you need.

The recommended way to capture a card for vaulting is EPD Elements, the epd.js browser SDK. No browser in the loop (phone/MOTO orders where an agent keys the card in by hand, a back-office tool, or a migration)? Use Inbound Card Capture instead. Both produce the same vaulted payment method.

How it works

Vaulting uses two keys with two different jobs. Keep them straight.

Publishable key

epd_live_pk_… / epd_test_pk_…. Lives in the browser. Capture-only: it tokenizes a card and nothing else. Safe to ship in client-side code.

Secret key

epd_live_sk_… / epd_test_sk_…. Server-side only. Attaches the captured card to a customer, then charges it. Never expose it in the browser.

EPD Commerce does not accept a raw PAN (the card number itself), CVV, or expiry over its API. Raw card data reaches EPD only through a PCI-scoped capture layer that tokenizes it first: the EPD Elements secure field in the browser, or the server-to-server Inbound Card Capture proxy. The API itself only ever receives the resulting token.

The flow

Capture the card

Client-side

Your checkout page loads epd.js and mounts a secure card field with your publishable key. The shopper enters their card; your pages and servers never see the raw PAN. See EPD Elements for the full SDK reference (combined and split fields, styling, events).

Tokenize

Client-side

On submit, the SDK tokenizes the card and returns a single-use card_token (cct_…).

A card_token is single-use and expires 15 minutes after capture. Attach it promptly; if the attach fails, capture a fresh one. Never resend a spent token.

Send the token to your backend

Client-side → your server

Your frontend POSTs the card_token to your own server. It is bound to your merchant and useless to anyone else, but route it only to your backend.

Attach to a customer

Server-side → EPD Commerce

Your backend attaches the token to a customer with your secret key. EPD vaults the card, stores the mirror, and returns a UUID id for the payment method.

curl https://api.epd.com/v1/customers/$CUSTOMER_ID/payment_methods \
  -H "Authorization: Bearer $EPD_KEY" \
  -H "epd-version: 2026-02-11" \
  -H "X-EPD-Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "card_token": "cct_3f8a1c9e7b2d4a6f0e1c3b5d7f9a1c3e5b7d9f0a2c4e6b8d",
    "set_as_default": true
  }'

Don’t have the customer yet? Create one first with POST /v1/customers, then attach. Some processors require a billing address to vault: if yours does, pass an optional billing_details object on the same request. See Add Payment Method.

Charge using the payment-method id

Pass payment_method_id: "<uuid>" on POST /v1/orders or POST /v1/subscriptions. The card never has to be entered again.

Key identifiers

A few identifiers move through this flow. Keep them straight.

IdentifierSourceLifetimeWhat it identifies
card_tokenEPD Elements15 minutesOne-time, single-use token representing the captured card
payment_method_idEPD CommercePermanentThe vaulted payment method on an EPD Commerce customer

payment_method_id is the only id that must be a bare UUID on input; don’t prefix it with pm_.

Sandbox

A test publishable key (epd_test_pk_…) tokenizes against your sandbox; the SDK behaves identically; only the key’s environment differs. Type a test card (e.g. 4111 1111 1111 1111 for a Visa success) into the field and the resulting card_token works against the sandbox attach endpoint. Sandbox is keyed off your API key: same base URL, no separate environment.

Why this matters

Without a vaultWith EPD’s vault
Card data flows through your serversCard data never reaches your servers
Full PCI DSS audit (SAQ D)Reduced PCI scope (SAQ A)
You store sensitive card dataEPD stores it; you store a token only
Re-entry required for each chargeCharge stored cards on demand

Security

Never log, store, or transmit raw card numbers. Capture cards only through the EPD Elements secure field; never build your own input that touches the PAN.

  • Keep your secret key server-side only; never ship it to the browser. Only the publishable key belongs in client code.
  • Use HTTPS for every API call.
  • Rotate keys periodically from the EPD Commerce dashboard.

Common questions