Onboard and charge
Sign up a new customer and run their first payment in a single MCP tool call.
What you’ll build
An agent flow that takes a name, an email, and a card_token and produces a paid order, without juggling three separate tool calls.
Where the card comes from
create_customer_and_charge takes a single-use card_token (cct_…). Your
frontend captures the card in the browser with EPD Elements (the epd.js SDK
loaded with a publishable key), which returns the card_token. The raw card
number never reaches the agent or the API. See the
EPD Elements guide for the browser code. A card_token
is single-use and expires 15 minutes after capture.
The single call
Use create_customer_and_charge (a composite tool).
{
"name": "create_customer_and_charge",
"arguments": {
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Doe",
"phone": "+14155551234",
"card_token": "cct_3f8a1c9e7b2d4a6f0e1c3b5d7f9a1c3e5b7d9f0a2c4e6b8d",
"items": [
{ "product_id": "prod_9b2c1e7a5d3f4b6c8e0a2c4e6b8d0f1a", "quantity": 1 }
],
"currency": "usd",
"description": "Welcome order",
"idempotency_key": "onboard-2026-04-21-abc123"
}
}
The order total comes from the product catalog: you pass items, not an
amount. Update the product’s price first if you need a different total.
What EPD does internally:
Equivalent to create_customer with the customer fields.
Equivalent to add_payment_method with the card_token and set_as_default: true.
Builds and charges an order from items behind the scenes.
Returns the customer, payment_method, and order objects together.
Why use the composite tool
| Doing it yourself | create_customer_and_charge |
|---|---|
| 3 MCP round-trips (≥ 3× latency) | 1 round-trip |
| Partial-failure recovery you write yourself | EPD orchestrates the flow and returns a consolidated outcome |
| 3 idempotency keys to track | One key per intent |
3 request_ids to correlate | One logical trace by request_id |
Handling outcomes
On success the response contains the three objects:
{
"customer": { "id": "550e8400-e29b-41d4-a716-446655440000" },
"payment_method": { "id": "6ba7b815-9dad-11d1-80b4-00c04fd430c8" },
"order": { "id": "6ba7b811-9dad-11d1-80b4-00c04fd430c8", "status": "succeeded", "total": 2999 }
}
The order’s charged amount is total (in cents). If the charge declines, the
order still comes back in the normal response with order.status: "failed" and a
failure_reason: the customer and payment method are kept, so your agent can
prompt for a different card and call create_order directly without re-creating
the customer:
{
"customer": { "id": "550e8400-e29b-41d4-a716-446655440000" },
"payment_method": { "id": "6ba7b815-9dad-11d1-80b4-00c04fd430c8" },
"order": { "id": "6ba7b811-9dad-11d1-80b4-00c04fd430c8", "status": "failed", "failure_reason": "insufficient funds", "failure_code": "insufficient_funds" }
}
Only a genuine failure before the charge (e.g. the customer is created but the
card can’t be attached) rolls the customer back and returns an error envelope. If
that rollback itself fails, you get error.code: "partial_rollback_failed" with
the orphaned customer_id in the message. Surface it and clean up manually.
Sandbox example
To exercise a decline through this tool in sandbox, capture one of the declining
test cards (e.g. the insufficient-funds card) with EPD Elements against your
sandbox publishable key; that yields a card_token, which you then pass here:
{
"name": "create_customer_and_charge",
"arguments": {
"email": "test@example.com",
"first_name": "Decline",
"last_name": "Test",
"phone": "+14155550100",
"card_token": "cct_<captured from the insufficient-funds sandbox test card>",
"items": [
{ "product_id": "prod_9b2c1e7a5d3f4b6c8e0a2c4e6b8d0f1a", "quantity": 1 }
],
"currency": "usd"
}
}
You’ll see the customer get created and the order come back with
status: "failed", failure_code: "insufficient_funds" (with failure_reason as the human-readable companion).
There is no server-only sandbox card_token for this composite tool. A
cct_… is minted only by a real EPD Elements browser capture (sandbox or
live). For pure server-to-server sandbox testing without a browser, use
Inbound Card Capture with a sandbox test card
number to save the payment method directly, then charge it with the
primitive create_order tool instead of
this composite. See the testing reference.