Create a payment intent
const url = 'https://api.example.com/v1/payment_intents';const options = { method: 'POST', headers: { 'Idempotency-Key': 'order-1042-attempt-1', Authorization: 'Bearer <token>', 'Content-Type': 'application/json' }, body: '{"amount":10000,"currency":"php","description":"Order 1042","return_url":"https://shop.example.com/orders/1042/paid","cancel_url":"https://shop.example.com/cart","customer_email":"maria@example.com"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.example.com/v1/payment_intents \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: order-1042-attempt-1' \ --data '{ "amount": 10000, "currency": "php", "description": "Order 1042", "return_url": "https://shop.example.com/orders/1042/paid", "cancel_url": "https://shop.example.com/cart", "customer_email": "maria@example.com" }'Starts a payment of amount in currency. Name the method now in
payment_method_data[type], and the intent is requires_confirmation with its method and
price fixed. Leave it out, and the intent is requires_action with the methods it can be paid
by in payment_method_types, and next_action.redirect_to_url: send your customer to its
url, our hosted checkout page, or choose a method yourself when you confirm. Without a
method, a return_url is where our hosted checkout page sends the customer back to, a
cancel_url where it sends one who cancels, and a customer_email where it offers to send
the receipt.
With checkout_mode embedded, the intent is paid in embedded checkout, on your own page,
instead: its next_action is mount_embedded_checkout, with the client token your page
mounts it with. A return_url is then where the customer is sent after paying by card, and a
cancel_url is refused. See Embedded checkout.
With confirm: true, the intent is created and confirmed in one call, and comes back
requires_action with next_action. Name the method, and a return_url for a card.
payment_method, the id of a saved payment method, is not supported yet and is refused with
validation_failure.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”A value unique to this operation, such as your order number and attempt, of 1 to 255 characters. A retry with the same key and body is done at most once; see Idempotency.
Example
order-1042-attempt-1Request Bodyrequired
Section titled “Request Bodyrequired”object
In the currency’s minor unit, at most 18 digits.
A three-letter ISO 4217 code, in either case.
The method to pay with. Its price is fixed with it until an attempt fails. A method that is
missing or not valid is
refused with validation_failure and param payment_method_data[type].
object
A payment method type, such as qrph, card or cash.
The methods this intent may be paid by. Leave it out to allow any your account
can take. A method in payment_method_data[type] must be one of them.
Your own text, such as an order number. Never shown to the customer.
Your own key-value pairs, returned as given and carried in webhooks: up to 50 keys of up to 40 characters without square brackets, each with a text value of up to 500 characters.
object
true creates and confirms the intent in one call. payment_method_data[type] is
then required.
Where the customer comes back to after a payment page, such as a card’s. Required to confirm
a card payment; one given here replaces an earlier one. https in live mode, http or
https in test mode. On create, only with confirm: true — or with no payment method, when
it is where our hosted checkout page sends the customer back to once they are done, or, with
checkout_mode embedded, where our return page sends them after paying by card; embedded
checkout offers card only when the intent has one.
The customer comes back with payment_intent=<id> added to it, and from the hosted checkout
page with checkout_session=<id> too, never a status. Coming back proves nothing: retrieve
the intent, or wait for its webhook, to know how it went.
Where our hosted checkout page sends a customer who cancels. Only on create, and only with no
payment method and without confirm; refused with checkout_mode embedded, where a
customer who cancels stays on your page. https in live mode, http or https in test mode, as
for return_url. Without one, a customer who cancels goes to your return_url.
The customer comes back with payment_intent=<id> and checkout_session=<id> added to it,
never a status. It is not shown on the intent.
Your customer’s email, if you have it: our hosted checkout page, or embedded checkout, fills
its optional receipt field with it, and the customer can change or clear it. Once the payment succeeds, one
receipt is sent to the address the customer leaves there. Only on create, and only with no
payment method and without confirm; anything that is not an email address is refused
with param customer_email.
It is used for the receipt and, hashed, for our risk checks. It is not shown on the intent, nor sent in any event or webhook.
Where the customer pays an intent created without a method: hosted, on our hosted checkout
page, which next_action.redirect_to_url links to; or embedded, in embedded checkout on
your own page, which next_action.mount_embedded_checkout gives the client token for. Only
on create, and only with no payment method and without confirm; anywhere else, or any
other value, is refused with param checkout_mode. With embedded, a cancel_url is
refused.
What you know of the customer paying, for the platform’s risk checks. Each is optional; send
what you have. The email is hashed before it is checked and is never stored. Send these with
the confirmation: on create only with confirm: true.
object
The customer’s IP address, IPv4 or IPv6, as your server saw it.
Your identifier for the customer’s device or browser session.
The customer’s email address.
Examples
{ "amount": 10000, "currency": "php", "description": "Order 1042", "return_url": "https://shop.example.com/orders/1042/paid", "cancel_url": "https://shop.example.com/cart", "customer_email": "maria@example.com"}{ "amount": 10000, "currency": "php", "description": "Order 1042", "checkout_mode": "embedded", "return_url": "https://shop.example.com/orders/1042/paid", "customer_email": "maria@example.com"}{ "amount": 10000, "currency": "php", "payment_method_data": { "type": "qrph" }}{ "amount": 10000, "currency": "php", "payment_method_data": { "type": "card" }, "confirm": true, "return_url": "https://shop.example.com/orders/1042/paid", "metadata": { "order_id": "1042" }}Responses
Section titled “Responses”The intent: requires_action with next_action.redirect_to_url to our hosted checkout
page when created without a method, or next_action.mount_embedded_checkout with
checkout_mode embedded; requires_confirmation with a method; or requires_action
with next_action when created with confirm: true.
object
In the currency’s minor unit.
The amount paid: amount once succeeded, and 0 until then.
A three-letter ISO 4217 code, in lower case.
The chosen method, such as [qrph], once there is one. Until then, the methods that can
take this payment now: confirm with one. In an event for an intent with no method, the
methods you allowed at creation, or null if you allowed any.
Where the payment is taken: ecommerce for every intent your server creates. Payments
taken on terminals will say pos (Pending).
object
object
The QR payload. Render it as a QR code for the customer to scan with their banking app.
When the code stops being payable, as a Unix timestamp.
object
object
The payment reference, unique to this attempt. Give it to the customer to pay at a cash collection location.
The exact amount to pay, in the currency’s minor unit.
A three-letter ISO 4217 code, in lower case.
When the reference stops being payable, as a Unix timestamp. After it the attempt fails as expired.
Words to show the customer. May be reworded, so never branch on it.
object
object
The payment page: a card’s, or our hosted checkout page for an intent created without a method. Send the customer there.
Where the customer comes back to, or null when you gave none: your return_url, or our hosted checkout page when
the customer chose card there, which then sends them on to yours. For the hosted
checkout page itself, the return_url you gave on create.
An intent created with checkout_mode embedded, waiting for the customer in embedded
checkout on your page. See Embedded checkout.
object
object
What your page mounts embedded checkout with, beside your publishable key, from one of your registered origins. The same on every read while it is here. It opens this one payment’s checkout: give it only to the customer paying.
When the checkout session ends, as a Unix timestamp. After it, the client token opens nothing.
object
card_declined: the card was declined. expired_card: the card has expired (test mode
only today). payment_intent_authentication_failure: the customer did not complete the
card’s authentication. payment_intent_payment_attempt_failed: the attempt failed, or the
customer left without paying. payment_intent_payment_attempt_expired: the customer did
not pay in time.
Why the card was declined, when the decline names a reason. Test mode only today: it
appears when you simulate a decline with a decline_reason (see Simulate a payment’s
outcome), and a live decline does not carry it yet, so
never depend on it there.
Words you can show the customer. May be reworded, so never branch on it.
The reason given when it was canceled, if any.
When it was canceled, as a Unix timestamp.
The metadata you gave it. {} if none.
object
When it was created, as a Unix timestamp.
Examples
Created without a method
{ "id": "pi_01j9x2m8k4q7r5t3v6w8y0z2a4", "object": "payment_intent", "amount": 10000, "amount_received": 0, "currency": "php", "payment_method_types": [ "card", "qrph" ], "channel": "ecommerce", "status": "requires_action", "next_action": { "type": "redirect_to_url", "redirect_to_url": { "url": "https://checkout.example.com/pay/q3Jx8m1Vw0b_Zc4N-7pLkTfYs2HdRa9uEoGiW6nBvXy", "return_url": "https://shop.example.com/orders/1042/paid" } }, "last_payment_error": null, "cancellation_reason": null, "canceled_at": null, "description": "Order 1042", "metadata": { "order_id": "1042" }, "livemode": false, "created": 1790411400}Created without a method, for embedded checkout
{ "id": "pi_01j9x2m8k4q7r5t3v6w8y0z2a4", "object": "payment_intent", "amount": 10000, "amount_received": 0, "currency": "php", "payment_method_types": [ "card", "qrph", "cash" ], "channel": "ecommerce", "status": "requires_action", "next_action": { "type": "mount_embedded_checkout", "mount_embedded_checkout": { "client_token": "ct_6QYI9milpE_Q7-uM7wvlj7fwyKooT2868Dm45Wwigcs", "expires_at": 1790413200 } }, "last_payment_error": null, "cancellation_reason": null, "canceled_at": null, "description": "Order 1042", "metadata": {}, "livemode": false, "created": 1790411400}Confirmed with card
{ "id": "pi_01j9x2p4d6f8h0k2m4n6q8s0t2", "object": "payment_intent", "amount": 10000, "amount_received": 0, "currency": "php", "payment_method_types": [ "card" ], "channel": "ecommerce", "status": "requires_action", "next_action": { "type": "redirect_to_url", "redirect_to_url": { "url": "https://pay.example.com/checkout/7c2e9a41", "return_url": "https://shop.example.com/orders/1042/paid" } }, "last_payment_error": null, "cancellation_reason": null, "canceled_at": null, "description": null, "metadata": { "order_id": "1042" }, "livemode": false, "created": 1790411400}Headers
Section titled “Headers”This request’s id. Quote it when you contact support.
validation_failure: invalid_parameter for a parameter missing or not valid, named in param; invalid_json for a body that is not JSON; unsupported_media_type for a body that is not sent as JSON; not_acceptable when the request will not accept JSON; method_not_allowed for an HTTP method the path does not take.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure", "code": "invalid_parameter", "message": "A whole number of minor units, from 1 to 999999999999999999.", "param": "amount", "request_id": "req_4f1c0b2e9a7d" }}authentication_failure: access_token_required when no token was sent, invalid_access_token when it is not valid, has expired, or is a client secret. Sent with a WWW-Authenticate: Bearer header, which adds error="invalid_token" when a token was sent.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure" }}authorization_failure with merchant_mismatch: a Merchant-Id header, query parameter or body field names a merchant or tenant other than the key’s.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure" }}conflict: intent_state when the intent is not in a state that allows this; idempotency_key_reused when the Idempotency-Key was used for a different request. timeout_or_in_progress with idempotency_key_in_use while a request with the same key is still running, or with refund_in_progress for a refund while another refund of the same payment is still being processed.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure" }}policy_rejection: this payment cannot be taken now. code says why:
code |
Meaning |
|---|---|
account_inactive |
Your account is not active. |
not_permitted_for_account |
Your account may not use this method yet. |
method_not_enabled |
The method is not enabled for your account. |
method_not_set_up |
The method is enabled but its setup is not finished. |
method_suspended |
The method is suspended for your account. |
pricing_unavailable |
No price is set for this method and amount. |
payment_method_unavailable |
The method cannot take this payment on this channel yet. |
no_payment_method_available |
None of your methods can take this payment now. |
test_mode_unavailable |
Confirming only: this method cannot be simulated in test mode. |
limit_exceeded |
Confirming only: this payment would take your account past its limit. |
restricted |
Confirming only: payments are restricted for your account, store or terminal at the moment. |
risk_declined |
Confirming only: this payment was declined by a risk check. |
not_available |
Unavailable for another reason. |
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "policy_rejection", "code": "method_suspended", "message": "This payment method is suspended for your account.", "param": null, "request_id": "req_4f1c0b2e9a7d" }}dependency_failure with service_unavailable: something on our side, or a payment network behind it, did not answer, or failed part-way. Whether the call took effect is not known, so do not assume it did not. Retry the same request with the same Idempotency-Key, and never make a new key for the retry: if the first call took effect, you are answered with its result (the payment intent or refund it made, or the intent as it now is) and nothing is done a second time. A retry refused with conflict and intent_state means the intent is no longer in a state that allows the call: the first call may have taken effect, or the customer may have acted since. Read the intent. If the failure came while the answer was being stored, the key is held for five minutes and a retry in that time answers 409 with idempotency_key_in_use: retry shortly. See When a write answers 503.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure" }}