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

  1. Your server calls POST /payment-sessions with a secret key and gets back id and client_secret.
  2. Your page receives those two values and passes them to the checkout widget, together with your publishable key.
  3. The widget collects the card with Stripe and calls POST /payment-sessions/{id}/confirm.
  4. 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, gbp or cad unless 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 mode http://localhost is 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 and livemode. A publishable key may call it.
  • POST /payment-sessions/{id}/confirm with { 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:

  • 200 with { "status": "complete", "charge_id": "ch_..." }: paid.
  • 202 with { "status": "processing" }: the card network has not given a final answer yet. Do not retry the payment. Check GET /charges or the dashboard for the outcome.
  • 402 with 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".

Was this page helpful?