Create the intent without a method. Give a return_url and a cancel_url for where the customer is sent back to and, if you have it, their customer_email. The Idempotency-Key header is required. Every parameter is in Create a payment intent in the reference.
curl https://api.example.com/v1/payment_intents \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Idempotency-Key: order-1042-1" \ -H "Content-Type: application/json" \ -d '{ "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" }'An intent created without a method is requires_action and comes back with next_action.type redirect_to_url, the same shape a card's payment page has: a url on our checkout page, and your return_url. Redirect your customer to the url. The page shows your business's name, the amount and how long the page has left, and offers the methods in payment_method_types, as they stand when the customer opens it. You can still confirm a method yourself over the API instead.
The page: framing and language
Section titled “The page: framing and language”Send the customer to the page itself: it refuses to be shown in a frame on any other site, so a browser shows nothing of it inside yours. It is in your checkout's default language, from Settings → Checkout in your dashboard, or the platform's where you set none or the page has no words in yours: English and Filipino today. Amounts are shown in the intent's currency, written the way that language writes them, and times in the platform's time zone. The page can be used with a keyboard alone and with a screen reader.
How long the link lasts
Section titled “How long the link lasts”The link is good for one checkout session, 30 minutes by default; the page says when it ends. Once that session is over — expired, or the intent canceled or paid — the link shows a page saying the checkout is no longer available, and the intent no longer carries the next_action. An intent whose link expired unpaid stays requires_action until you cancel it or confirm a method over the API. Read the intent to get the link while it is open: webhooks never carry it. The link is the customer's credential for this one payment, so send it only to them.
Paying on the page
Section titled “Paying on the page”The customer pays on the page:
- QR Ph: the page shows a code to scan with any bank or e-wallet app, and how long it has left; it updates on its own once the payment is captured. A code that expires unpaid is replaced by a new one on the customer's request.
- Cash: the page shows a reference to pay at a cash collection location, the amount and until when. The customer's visit is over once they have it, while the intent stays
requires_actionuntil the cash arrives. Opening the link again shows the same reference until it expires. - Card: the customer types their card on our checkout page itself, into secure card fields that send it straight to our card processor: it never passes through your servers, or the page's. Most cards complete there. When the customer's bank asks them to confirm, the page takes them to their bank's step and back to our page, which shows how it went. A declined card, or one the bank did not confirm, can be tried again there, or another method chosen.
Trying again, and another way
Section titled “Trying again, and another way”After a payment that did not go through, the customer can try the same method again or choose another, on the same intent. While a QR code is shown or a card has not been typed and paid, they can also switch to another method: the payment they had in hand fails as one they turned back on, with payment_intent.payment_failed, and the new one starts. Not while a payment is processing. A checkout session allows 3 payments in all; a new QR code for one that expired unpaid does not count. After the third has failed, the page says so and offers only cancelling.
Cancelling
Section titled “Cancelling”The customer can cancel on the page, while they have not paid and nothing is processing. The intent is canceled with cancellation_reason requested_by_customer, and you get payment_intent.canceled.
Sending the customer back
Section titled “Sending the customer back”Give a return_url when you create the intent, and the page sends the customer back to it once they are done — after a payment, with a cash reference, or when it is still pending. Give a cancel_url, and a customer who cancels is sent there instead; without one, they go to your return_url. Either way payment_intent and checkout_session are added to it, and never a status. Coming back proves nothing: retrieve the intent, or wait for its webhook, to know how it went. While the customer pays, the intent moves as it does over the API, and you get the same webhooks.
A receipt
Section titled “A receipt”Above the methods, the page offers an optional field for the customer's email, for their receipt. Give a customer_email when you create the intent and the field is filled in with it, so your customer is not asked again; they can change it or clear it. Nobody has to give one to pay. Once the payment succeeds, we send one receipt to the address given, naming you: the amount, the method, when it was paid, the payment intent's id and where to ask about the order. A cash reference is not a receipt: for cash, it is sent once the cash is paid. The address is kept for the receipt only. It is not shown on the intent, nor in any event or webhook.
Where next
Section titled “Where next”- A failed attempt does not end the intent: see Payment intents.
- To show the same checkout inside your own page, see Embedded checkout.