Payment Intents
A payment intent is an approval your backend grants before a customer's card is ever
collected. Your server creates the intent with your secret key, fixing the amount
and currency, and gets back a single-use client_secret. Your frontend then submits the
card with your publishable key plus that client_secret, completing the one payment
you approved.
This splits payment creation into two steps across two different keys. The publishable key that ships in your frontend can no longer originate a payment of its own — it can only fulfill an intent your backend already authorized, for the amount your backend set.
The two steps
| Step | Endpoint | Key | Who calls it |
|---|---|---|---|
| Create an intent | POST /v1/payment_intents | Secret key | Your backend |
| Fulfill an intent | POST /v1/payment_intents/{id}/fulfill | Publishable key | The browser |
| Read an intent | GET /v1/payment_intents/{id} | Secret key | Your backend |
| Cancel an intent | POST /v1/payment_intents/{id}/cancel | Secret key | Your backend |
What the intent locks
Four fields are set once, at intent creation, and cannot be changed at fulfillment:
amount, currency, description and callback_url. If the fulfillment request
sends different values for any of them, the intent's values are used instead.
Everything else about the payment — the source, metadata, save_card, manual,
3ds and so on — is supplied at fulfillment, because those are properties of the card
the customer chose, not of the charge you approved.
What does not change
A fulfillment produces an ordinary payment. The response is the same object
Create Payment returns, with the same
statuses and the same 3D Secure challenge in source.transaction_url. Everything
downstream — payment operations, webhooks,
tokenization, invoices, splits — works exactly as it
does for a directly created payment.
Every payment method is supported: card, Apple Pay, Samsung Pay, STC Pay, and saved card tokens.
The intent flow is available alongside the existing single-step Create Payment. Nothing you have today stops working, and adopting intents is a change you make when you are ready.
When you do not need it
Payments your backend creates directly with the secret key — recurring charges on a saved token, MOTO payments, invoices — are already authorized by your server. There is no publishable key involved and no intent to add.
Payment intents are for the case where a customer's payment details are collected in a browser or app.
Reference
- Payment Intents API — the
/v1/payment_intentsendpoints. - Create Payment API — the
sourcefields used at fulfillment. - Payment Errors — payment failure reasons.
Amounts throughout are in the currency's smallest unit (e.g. 10000 is 100.00 SAR).