Quickstart
Make your first end-to-end payment in under five minutes, without touching real money.
What you’ll do
By the end of this page you will have:
- Created a sandbox API key.
- Created a customer.
- Created a product to sell.
- Attached a card to that customer.
- Charged the card and seen a success response.
No real money moves. You can copy-paste each command and follow along.
Before you start
You need:
- An EPD Commerce account (sign up if you do not have one).
- A terminal with
curlanduuidgen. Any HTTP client works;curlis just convenient.
Step 1: Get a sandbox API key
Go to commerce.epd.com and sign in.
When you signed up, EPD also created a Demo Company alongside your real one. It is the sandbox: anything you do there moves no real money. Click your profile avatar (top right), hover the company name, and pick Demo Company from the list.
Open the gear icon (top right) → Developer & Integrations → API Keys tab → Create API Key. Give it a name like quickstart-local and (optionally) leave permissions at full access for now.
Because you created it inside the Demo Company, the key is automatically a sandbox key and starts with epd_test_sk_. It is shown once; store it somewhere safe.
export EPD_KEY="epd_test_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export EPD_VERSION="2026-02-11"
Step 2: Create a customer
EPD requires a first name, last name, and a phone number on every customer (in international format with a leading + and country code, e.g. +14155551234). Email is required too.
curl https://api.epd.com/v1/customers \
-H "Authorization: Bearer $EPD_KEY" \
-H "epd-version: $EPD_VERSION" \
-H "X-EPD-Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Doe",
"phone": "+14155551234"
}'
X-EPD-Idempotency-Key makes retries safe; see Idempotency.
You’ll get back a UUID id for the customer. Save it:
export CUSTOMER_ID="550e8400-e29b-41d4-a716-446655440000"
Step 3: Create a product
Orders charge against products you’ve defined, not free-form amounts. Create a simple $20.00 digital product (no shipping):
curl https://api.epd.com/v1/products \
-H "Authorization: Bearer $EPD_KEY" \
-H "epd-version: $EPD_VERSION" \
-H "X-EPD-Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "Quickstart Test Product",
"sku": "quickstart-test-product",
"description": "A throwaway product for the quickstart flow.",
"pricing": { "amount": 2000, "currency": "usd" },
"requires_shipping": false
}'
Save the returned product UUID id:
export PRODUCT_ID="6ba7b810-9dad-11d1-80b4-00c04fd430c8"
Step 4: Attach a card
EPD never accepts raw card numbers through this API. In your real checkout, you’d capture the card in the browser with EPD Elements (epd.js), a secure card field that keeps card numbers off your servers entirely, and attach the resulting single-use card_token:
curl https://api.epd.com/v1/customers/$CUSTOMER_ID/payment_methods \
-H "Authorization: Bearer $EPD_KEY" \
-H "epd-version: $EPD_VERSION" \
-H "X-EPD-Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"card_token": "cct_…",
"set_as_default": true
}'
Minting a real card_token requires a browser running the EPD Elements SDK, so there’s no curl-only way to do it in this quickstart. Run the command below instead. It uses Inbound Card Capture, EPD’s server-to-server capture flow, with a sandbox test card number so you can finish this walkthrough from the terminal.
curl -X POST "https://secure.epd.com" \
-H "Authorization: Bearer $EPD_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "'"$CUSTOMER_ID"'",
"card": {
"number": "4111111111111111",
"exp_month": "12",
"exp_year": "2030",
"cvc": "999"
},
"set_as_default": true
}'
Save the returned payment-method UUID id:
export PM_ID="6ba7b815-9dad-11d1-80b4-00c04fd430c8"
Step 5: Create an order
curl https://api.epd.com/v1/orders \
-H "Authorization: Bearer $EPD_KEY" \
-H "epd-version: $EPD_VERSION" \
-H "X-EPD-Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "'"$CUSTOMER_ID"'",
"payment_method_id": "'"$PM_ID"'",
"items": [
{ "product_id": "'"$PRODUCT_ID"'", "quantity": 1 }
]
}'
You should receive a 201 Created with the order in succeeded state. If you have a webhook endpoint registered, an order.succeeded event will arrive shortly after.
Want to see a decline? Redo Step 4 with card number 4000000000009995, then run Step 5 again. The order still returns 201, but comes back with status: "failed" and a failure_code (here insufficient_funds), not an error envelope. See Testing for every decline card.