Payment sessions
A payment session is one payment you intend to take, for an exact amount and currency. Your server opens it with a secret key; the customer's page completes it with a publishable key. Because the amount is fixed when the session is opened, nothing in the browser can change it.
The flow
- Your server calls
POST /payment-sessionswith a secret key and gets backidandclient_secret. - Your page receives those two values and passes them to the checkout widget, together with your publishable key.
- The widget collects the card with Stripe and calls
POST /payment-sessions/{id}/confirm. - The charge is created. It shows in your dashboard and in
GET /charges.
Create a session
POST /payment-sessions, secret key only. In live mode your email must be verified and your business verification approved.
- Name
amount- Type
- integer
- Description
Required. Smallest currency unit. Below the currency's minimum the API answers
amount_too_small.
- Name
currency- Type
- string
- Description
Required. A currency the platform supports:
usd,eur,gbporcadunless the platform was set up differently.
- Name
description- Type
- string
- Description
Up to 255 characters.
- Name
customer- Type
- string | object
- Description
A customer id (
cus_...) of yours, or{ name, email, phone? }.
- Name
receipt_email- Type
- string
- Description
Where the receipt goes.
- Name
success_url- Type
- string
- Description
An
https://URL. In test modehttp://localhostis also accepted.
- Name
metadata- Type
- object
- Description
Up to 20 keys; values are strings (500 characters at most), numbers or booleans.
Request
curl https://api.cari.finance/payment-sessions \
-H "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"amount": 2500, "currency": "usd"}'
Response (shape)
{
"id": "ps_...",
"client_secret": "ps_..._secret_...",
"amount": 2500,
"currency": "usd",
"livemode": false,
"status": "open",
"expires_at": "2026-10-11T12:30:00+00:00"
}
A session expires after 30 minutes unless the platform was configured otherwise. An expired session cannot be confirmed; open a new one.
Read and confirm
GET /payment-sessions/{id}?client_secret=...returns the status, amount, currency andlivemode. A publishable key may call it.POST /payment-sessions/{id}/confirmwith{ client_secret, payment_method_token, receipt_email? }. A publishable key may call it. You do not normally call it yourself: the widget does.
A confirmation answers one of:
200with{ "status": "complete", "charge_id": "ch_..." }: paid.202with{ "status": "processing" }: the card network has not given a final answer yet. Do not retry the payment. CheckGET /chargesor the dashboard for the outcome.402with a message from the card network: the card was declined. The session stays open, so the customer can try another card.
A session can be confirmed once. Two simultaneous confirmations produce one charge.
A publishable key can call these two routes and nothing else. Any other route answers 403 with error_code: "forbidden_key_type".