What this is and who needs it

Inbound Card Capture lets you save a card server-to-server, without a browser. Your backend POSTs the raw card to EPD’s inbound capture URL; the proxy tokenizes the PAN (the card number itself) in a PCI-certified environment and creates a payment method on the customer. The PAN never reaches EPD’s API; only an opaque token does.

Reach for this when there’s no browser to run EPD Elements in:

  • Phone / MOTO orders (mail-order/telephone-order): an agent keys the card into your own system.
  • Back-office tools: an operator saves a card on a customer’s behalf.
  • Migrations: moving an existing book of cards onto EPD from your own PCI-compliant store.

For web and app checkout, use EPD Elements instead: it keeps the PAN out of your servers entirely.

This flow puts the raw card number on your backend. Unlike EPD Elements, where the card goes straight from the shopper’s browser into the vault and keeps your servers out of the cardholder-data path, here your server handles the PAN on its way to the proxy, which brings it into your PCI DSS scope. Handling raw card data carries materially heavier PCI obligations than a browser capture flow, and your exact validation requirements depend on your full payment channel and your acquirer. Confirm your obligations with your acquirer or a QSA before using this flow, and prefer EPD Elements whenever a browser is involved.

What EPD provisions for you

To capture cards inbound you authenticate with two things:

Inbound capture URL

https://secure.epd.com: a single EPD endpoint, the same for every merchant. It tokenizes the PAN before it reaches the EPD API; EPD resolves your account from your secret key (below), not from the URL.

Secret key

epd_live_sk_… / epd_test_sk_…. Sent as a normal Authorization: Bearer header and forwarded to EPD untouched: it’s how EPD resolves your account and saves the card under it.

The card is bound to your account by your secret key, server-side, and is guarded against cross-account replay: a token captured under one account can never be saved to another.

The flow

Collect the card

Your backend obtains the raw card details (e.g. an agent enters them for a phone order).

POST it to the inbound capture URL

Send the card and the target customer_id to the inbound capture URL, authenticated with your secret key.

The proxy tokenizes the PAN

The capture proxy vaults the card in a PCI-certified environment and forwards only an opaque token to EPD. The PAN never reaches the EPD API.

EPD saves the payment method

EPD vaults the card under your account and returns a standard payment method.

Save a card

POST the card to the inbound capture URL with your secret key:

curl -X POST "https://secure.epd.com" \
  -H "Authorization: Bearer epd_test_sk_…" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "550e8400-e29b-41d4-a716-446655440000",
    "card": {
      "number": "4111111111111111",
      "exp_month": "12",
      "exp_year": "2029",
      "cvc": "999"
    },
    "billing_details": {
      "name": "Jane Doe",
      "address": {
        "line1": "1 Main St",
        "city": "Austin",
        "state": "TX",
        "postal_code": "78701",
        "country": "US"
      }
    },
    "set_as_default": false
  }'

Request fields

FieldRequiredDescription
customer_idyesThe customer the card is saved to (cus_… or a bare UUID). Must exist for your account.
card.numberyesThe card number (PAN). Tokenized by the proxy; never stored by EPD.
card.exp_monthyesExpiry month, 112.
card.exp_yearyesExpiry year, 4-digit (2029). A 2-digit year (29) is also accepted and normalized to 4 digits.
card.cvcnoCard security code. Forwarded to the vault only when present.
billing_detailsnoCardholder name + billing address. See below.
set_as_defaultnoMake this the customer’s default payment method. Defaults to false.
update_subscriptionsnoWhen set_as_default is true, also switch active subscriptions to this card. Defaults to false.

billing_details mirrors the object used elsewhere: name, email, phone, company, and an address (line1, line2, city, state, postal_code, country as ISO 3166-1 alpha-2). Every field is optional. Supplying a complete address also enables network-token provisioning: the card networks (Visa, Mastercard, …) issue a device-specific replacement number behind the scenes, so charges keep working automatically after the physical card is reissued or its number changes, with no action needed from your integration. This is unrelated to card_token (the one-time EPD Elements capture token); network tokens are a separate, card-network-level mechanism applied to the card you’ve already saved. An unrecognized country is skipped silently rather than failing the capture. If you omit the cardholder name, it falls back to the customer’s name so the saved card never shows as a bare “Credit Card”.

Some processors require a billing address before they will vault a card. If yours does, include billing_details.address with line1, city, state, postal_code, and country.

Response

On success you get back the same payment method object as Add Payment Method, 201 Created:

{
  "id": "6ba7b815-9dad-11d1-80b4-00c04fd430c8",
  "type": "card",
  "card": { "brand": "visa", "last4": "1111", "card_expires": "12/2029" },
  "customer": "550e8400-e29b-41d4-a716-446655440000",
  "is_default": false,
  "created_at": "2024-01-15T10:30:00.000Z"
}

From here the card behaves exactly like any vaulted payment method; use its id for orders and subscriptions.

Errors

All errors use the standard error envelope. Branch on code, not message.

WhentypecodeparamWhat to do
card.number / exp_month / exp_year missinginvalid_request_errorN/AN/ASend all required card fields.
Expiry out of rangeinvalid_request_errorN/AN/Aexp_month must be 112 and exp_year a valid year.
Card couldn’t be read or verifiedinvalid_request_errorinvalid_requestruntime_tokenRe-capture the card and submit it again.
Processor requires a billing addressinvalid_request_errorinvalid_requestbilling_detailsResend with billing_details.address (line1, city, state, postal_code, country).
Customer doesn’t exist for your accountinvalid_request_errorresource_not_foundN/ACheck the customer_id.

Card data is never echoed back in an error; re-capture and retry rather than logging or inspecting the value you sent.

You send card.number / exp_month / exp_year / cvc, but a card-read error reports param: runtime_token. That’s the internal, tokenized form the proxy turns your PAN into before it reaches EPD’s API; EPD never sees the raw card fields, so it names the tokenized value. Treat it as “the card you captured” and re-capture.

Sandbox

Use a test secret key (epd_test_sk_…) against the inbound capture URL and a test card (e.g. 4111 1111 1111 1111 for a Visa success, or 4000 0000 0000 0002 to simulate a decline). The saved payment method works against the sandbox orders and subscriptions endpoints exactly as in production.

How it protects you

  • The PAN is tokenized in a PCI-certified environment and never reaches EPD’s API; EPD only ever sees an opaque token.
  • The captured card is bound to your account server-side from your secret key, and is guarded against cross-account replay.
  • Capture is rate-limited per account to blunt card-testing.

Capturing cards in a browser? EPD Elements keeps the PAN out of your servers entirely (PCI SAQ A). Both produce the same payment method.