---
title: "POST /user/invoices/{invoice_id}/payment-session"
method: POST
path: "/user/invoices/{invoice_id}/payment-session"
---

# POST /user/invoices/{invoice_id}/payment-session

`POST /user/invoices/{invoice_id}/payment-session`

## Request

- Base URL: `https://developers.whmcs.com/api/v2`
- URL: `https://developers.whmcs.com/api/v2/user/invoices/{invoice_id}/payment-session`
- Auth: none declared

Start a headless payment for an invoice that already exists, without sending the shopper to a WHMCS payment page. Instead, this renders and confirms the payment from within your integration. A payment method may still redirect the shopper to their bank and then back to a URL that you own (see **Redirect methods** below).

**Behavior**
- This endpoint returns the session as the `data.payment_session` value. The `POST /cart/{cart_id}/checkout` endpoint only returns the same `PaymentSession` object as the `data.payment.next_action.session` value when its `next_action.type` value is `payment_session`.
- Issuing a session is not a payment. This endpoint does not place the order, change the invoice status, or record a transaction, so you can safely abandon and repeat the call.
- Unlike checkout, this endpoint refuses a gateway that cannot handle headless payment with a `422` error instead of returning a redirect. To avoid this, check the `supports_headless_payment_session` value on the `GET /store/billing/gateways` endpoint in advance.

**Choosing a Gateway**
This endpoint uses the invoice's own `payment_method` value unless you provide a `gateway` value, which pays with that gateway instead and records it on the invoice.

**Redirect Methods**
With the `stripe_dynamic` gateway, an issued session offers the same redirect methods that WHMCS's own invoice payment pages offer, such as iDEAL or Bancontact, where the merchant enabled them. A session that the `POST /cart/{cart_id}/checkout` endpoint issues does not offer them, because the order form does not.

- For sessions that include a redirect, give the SDK a return URL of your own when you confirm. The shopper returns to your own page, not to WHMCS.
- Redirect methods update the invoice status asynchronously. As a result, expect the invoice to still be unpaid when they return.

**Do Not Trust Input from the Return URL**
Never mark an order paid, grant access, or provision a service because a `redirect_status` value is `succeeded`. Instead, confirm the invoice status with WHMCS directly.

- For more information, see the `settlement` value's description on the `PaymentSession` schema.

Whether webhook handling recovers a confirmation you never make depends on the gateway, so read the per-gateway behavior on the confirmation endpoint before relying on it. Where it does apply, treat it as a backstop rather than as your settlement path, because it reports no outcome to your integration.

## Path parameters

- `invoice_id` integer, required

## Response `200`

The session to render. Pass the `params` value to the SDK that the `provider` value lists, and then follow the `settlement` value.

- object
  - `data` object, required
    - `payment_session` PaymentSession, required: A gateway-specific object of client-side parameters. The `params` keys depend on the `provider` value.
      - `provider` string, required: A discriminator that tells your integration which gateway SDK to drive.
      - `params` object, required: The keys that the provider's SDK accepts.
      - `settlement` 'async_webhook' | 'sync_confirm', required: The method to use to settle payment. Branch on the value you receive rather than assuming one: - `sync_confirm` — Call the confirmation endpoint (`POST /user/invoices/{invoice_id}/payment-session/confirm`), which records the outcome in WHMCS. - `async_webhook` — Do not call the confirmation endpoint. The gateway module records the outcome when the provider's signed webhook arrives, so poll the `GET /user/invoices/{invoice_id}` endpoint until the status reaches `Paid`. After a `pending` result, poll regardless of this value. Success does not indicate that payment cleared.
      - `sdk` object, required: The method to use to load the SDK that renders this session.
        - `scriptUrl` string, required: The provider CDN URL your integration loads the SDK from.
        - `apiVersion` string: The gateway API version your integration must use so that the browser and WHMCS agree. The system returns this value for providers that accept it.

## Other responses

- `401`: Access Not Authorized
- `403`: The caller is authenticated but does not have permission to use this resource (the _View & Pay Invoices_ permission).
- `404`: Entity Not Found
- `422`: The system cannot issue a session for this invoice due to one of the following reasons: - The invoice is not awaiting payment. Only `Unpaid` and `Collections` status invoices are collectable. The `Payment Pending` status is excluded to avoid duplicating in-progress payments. - The gateway cannot start a headless session. - A named gateway cannot pay this invoice. - The system refused the gateway because the `gateway` value was not a string. - The body was not valid JSON. - There is no `gateway` value and the invoice does not include a `payment_method` value. Set a `gateway` value to issue the session. The system will not return a hand-off `url` value and no invoice changes will occur.
- `429`: Too many payment session requests have occurred (more than 30 within five minutes). This error prevents unbounded callers from exceeding the merchant's API quota, which could block valid orders. The system counts these requests per client IP address. Because of this, integrations that proxy shoppers server-side will reach this limit quickly. The system will not return a hand-off `url` value and no invoice changes will occur.
- `default`: General Error

---

[API](https://skmtc.dev/whmcs/apis/whmcs-api.md) - [All operations](https://skmtc.dev/whmcs/apis/whmcs-api/llms.txt) - [OpenAPI document](https://skmtc.dev/whmcs/apis/whmcs-api/revisions/bd3848ddbc3f?raw)
