PaymentIntent that includes payment_method_data and setup_future_usage.PCI-DSS scope notice
Posting PAN/CVC directly to your servers places you in SAQ D scope. If you want to minimize PCI burden, use Drop-in or Checkout instead.
| Item | Notes |
|---|---|
| Secret key | Use server-side only. |
| Customer ID | Reuse an existing customer or create one with POST /v1/customers (email recommended). |
| Return URL | A page to receive the user after 3-D Secure (return_url). |
| Webhooks | Expose an HTTPS endpoint. Treat payment_intent.succeeded as the authoritative payment-success signal (and that the card is saved to the customer). |
{
"amount": 100,
"currency": "USD",
"confirm": true,
"customer": "cus_1760950869144109056",
"payment_method_data": {
"type": "card",
"card": {
"exp_month": "01",
"exp_year": "2027",
"number": "4111111111111111",
"cvc": "022",
"name": "XX XXX"
}
},
"setup_future_usage": "on_session",
"return_url": "https://yourwebsite.com"
}status: "succeeded" (no 3DS).status: "requires_action" with a next_action.status: "requires_payment_method" (invalid card, insufficient funds, etc.).requires_action){
"id": "pi_XXXX",
"status": "requires_action",
....
"next_action": {
"type": "challenge_redirect",
"challenge_redirect": {
"url": "https://jstest.wooshpay.com/v1/3ds/index.html?...",
"return_url": "https://yourwebsite.com"
}
},
"customer": "cus_1760950869144109056",
"payment_method": "pm_XXXX",
.....
}next_action.challenge_redirect.url.return_url.Optional: You may poll GET /v1/payment_intents/{id}, but rely on the webhook for final state.
| Event | Purpose | What to store |
|---|---|---|
| payment_intent.succeeded | Authoritative indicator that the payment completed and the card was saved to the customer (because setup_future_usage was set and customer supplied). | Persist (customer_id, payment_method_id) for future charges. You can read event.data.object.payment_method. |
{
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_XXXX",
"status": "succeeded",
....
"customer": "cus_XXXXXXXXXX",
"payment_method": "pm_XXXXXXXXXXXX",
....
}
}
}{
"amount": 2500,
"currency": "USD",
"confirm": true,
"off_session": false, // true if no user present
"customer": "cus_1953770230215868416",
"payment_method": "pm_123123123",
"return_url": "https://example.com/pay/complete"
}| Key point | Value |
|---|---|
customer | ID from Step 1. |
payment_method | Saved card’s ID from webhook or listing API. |
off_session | falseto attempt and on-session charge(user present now)true to attempt an off-session charge (recurring / unsupervised). |
payment_intent.status | Meaning | Your next step |
|---|---|---|
requires_payment_method | Card entry/processing failure | Show error; allow new card. |
requires_action | 3-D Secure step-up required | Redirect to next_action.XXXX.XXXX. |
processing | Bank/network is processing | Wait for webhook; avoid duplicate submissions. |
succeeded | Paid and card saved to customer | Persist mapping; fulfill the order. |
| Action | Test card number | Notes |
|---|---|---|
| Successful save + charge | 4111 4111 41111 4111 | Any future date, any CVC |
| 3-D Secure required | 4462030000000000 | Checkout will prompt for 3DS challenge |
| Task | API |
|---|---|
| Create customer | POST /v1/customers |
| Pay & save (Direct API) | POST /v1/payment_intents (with payment_method_data + setup_future_usage) |
| Authoritative success | payment_intent.succeeded |
| Charge later | POST /v1/payment_intents (with customer + saved payment_method) |