Skip to content

Create a payment intent

POST
/v1/payment_intents
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.

Idempotency-Key
required
string
<= 255 characters

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-1
Media typeapplication/json
object
amount
required

In the currency’s minor unit, at most 18 digits.

integer
>= 1
currency
required

A three-letter ISO 4217 code, in either case.

string
/^[A-Za-z]{3}$/
payment_method_data

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
type
required

A payment method type, such as qrph, card or cash.

string
payment_method_types

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.

Array<string>
>= 1 items unique items
description

Your own text, such as an order number. Never shown to the customer.

string
<= 1000 characters
metadata

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
<= 50 properties
key
additional properties
string
<= 500 characters
confirm

true creates and confirms the intent in one call. payment_method_data[type] is then required.

boolean
return_url

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.

string format: uri
<= 2048 characters
cancel_url

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.

string format: uri
<= 2048 characters
customer_email

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.

string format: email
<= 254 characters
checkout_mode

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.

string
default: hosted
Allowed values: hosted embedded
risk_signals

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
ip_address

The customer’s IP address, IPv4 or IPv6, as your server saw it.

string
device_id

Your identifier for the customer’s device or browser session.

string
<= 64 characters /^[A-Za-z0-9._:-]{1,64}$/
email

The customer’s email address.

string format: email
<= 254 characters
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"
}

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.

Media typeapplication/json
object
id
required
string
object
required
string
Allowed value: payment_intent
amount
required

In the currency’s minor unit.

integer
amount_received
required

The amount paid: amount once succeeded, and 0 until then.

integer
currency
required

A three-letter ISO 4217 code, in lower case.

string
/^[a-z]{3}$/
payment_method_types
required

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.

Array<string> | null
channel
required

Where the payment is taken: ecommerce for every intent your server creates. Payments taken on terminals will say pos (Pending).

string
status
required
string
Allowed values: requires_payment_method requires_confirmation requires_action processing succeeded canceled
next_action
required
One of:
object
type
required
string
Allowed value: qrph_display_qr_code
qrph_display_qr_code
required
object
data
required

The QR payload. Render it as a QR code for the customer to scan with their banking app.

string
expires_at
required

When the code stops being payable, as a Unix timestamp.

integer | null
last_payment_error
required
One of:
object
code
required

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.

string
Allowed values: card_declined expired_card payment_intent_authentication_failure payment_intent_payment_attempt_failed payment_intent_payment_attempt_expired
decline_code

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.

string
Allowed values: insufficient_funds do_not_honor expired_card
message
required

Words you can show the customer. May be reworded, so never branch on it.

string
cancellation_reason
required

The reason given when it was canceled, if any.

string | null
Allowed values: requested_by_customer duplicate fraudulent abandoned
canceled_at
required

When it was canceled, as a Unix timestamp.

integer | null
description
required
string | null
metadata
required

The metadata you gave it. {} if none.

object
key
additional properties
string
livemode
required
boolean
created
required

When it was created, as a Unix timestamp.

integer
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
}
X-Request-ID
string

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.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
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.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
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.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
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.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
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.
Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
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.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure"
}
}