---
title: "POST /cart/{cart_id}/checkout"
method: POST
path: "/cart/{cart_id}/checkout"
---

# POST /cart/{cart_id}/checkout

`POST /cart/{cart_id}/checkout`

## Request

- Base URL: `https://developers.whmcs.com/api/v2`
- URL: `https://developers.whmcs.com/api/v2/cart/{cart_id}/checkout`
- Auth: none declared

Begin the checkout process.

The request body determines the behavior:

- An empty or omitted body preserves the legacy `cart.php` redirect response (no changes).
- A non-empty JSON body runs the gateway-agnostic checkout: it places the order, resolves or registers the client, screens for fraud, and dispatches to the payment strategy for the gateway.

The payment strategies are:
- Already paid.
- Fraud hold.
- Nothing payable, when the order created no invoice.
- Stored-token capture.
- Offline or pending.
- A headless payment session, when the request sets the `payment.mode` value to `headless` and the gateway supports it.
- A hand-off that requires the shopper to complete payment using the returned `next_action.url` value.

## Path parameters

- `cart_id` string, required

## Response `200`

Success. An empty request body returns the legacy redirect `url` value. A non-empty body returns the full `CheckoutResult` object when the checkout is finished and needs nothing further from you: either it resolved as immediately paid, or it created no invoice and so has nothing payable.

- object
  - `data` union, required
    - object
      - `url` string, required
    - CheckoutResult
      - `order_id` integer, required
      - `invoice_id` integer, required: `0` when the order created no invoice. Do not treat `0` as an error and do not request the invoice. A `payment.status` of `not_required` is the ordinary case; a free-cycle order held for fraud review reports `pending` with the same `0`.
      - `client_id` integer, required
      - `service_ids` integer[]
      - `addon_ids` integer[]
      - `domain_ids` integer[]
      - `domain_renewal_ids` integer[]: The domains the checkout renewed. A renewal reuses the client's existing domain, so these identifiers are not new.
      - `service_renewal_ids` integer[]: The services the checkout renewed. A renewal reuses the client's existing service, so these identifiers are not new.
      - `addon_renewal_ids` integer[]: The addons the checkout renewed. A renewal reuses the client's existing addon, so these identifiers are not new.
      - `upgrade_ids` integer[]: The upgrades the checkout created.
      - `order_status` string, required
      - `payment` CheckoutPayment, required
        - `method` string, required
        - `status` 'paid' | 'pending' | 'action_required' | 'not_required' | 'failed', required: `not_required` means the order created no invoice and there is nothing to collect, so `invoice_id` is `0` and `next_action` is `null`. A free billing cycle produces no invoice; an order discounted to zero is invoiced and answers `paid`. `failed` means the capture of the stored payment method did not succeed: the gateway declined it, or the attempt did not complete. Under a `payment.mode` value of `headless`, `next_action` carries a `payment_session` so that another method can be collected in place, and the request answers a `422` error status instead when no session can be minted; otherwise it carries a `redirect` to the hosted pay page. `failed` describes the attempt that did not succeed. Checking the same cart out again answers `paid` if the invoice settled in the meantime, `pending` once a payment is in flight, `action_required` with a freshly minted session while it is neither, and a `422` error status if a session cannot be minted again.
        - `next_action` union: How to proceed with payment. - `redirect` returns a single-use hand-off `url` value (the default). - `payment_session` returns a `session` object that your integration passes to the matching gateway SDK and carries no `url` value.
          - NextActionRedirect
            - `type` 'redirect', required
            - `url` string, required
          - NextActionPaymentSession: Returned when the checkout set the `payment.mode` value to `headless` for a gateway that supports it.
            - `type` 'payment_session', required
            - `session` PaymentSession, required: A gateway-specific object of client-side parameters. The `params` keys depend on the `provider` value.
              - …
      - `url` string, nullable: Mirrors the `payment.next_action.url` value, for single-page application compatibility.

## Other responses

- `202`: Accepted. The checkout completed but it requires follow-up: a payment hand-off, a fraud hold, or an offline or pending gateway. A checkout with nothing to pay needs no follow-up and answers `200` instead.
- `400`: Cart validation failure
- `401`: Access Not Authorized
- `404`: Entity Not Found
- `409`: The request conflicts with the current state of the resource (for example, cart-lock contention, or an item-mutating operation on a cart that has already checked out).
- `422`: Invalid checkout request. This status indicates one of the following scenarios: - An inactive or unknown `paymentmethod` value. - An invalid promotion code. - A structurally impossible client and payment combination (for example, a new customer referencing a stored payment method). - A `payment.mode` value of `headless`. - Before order creation, if the gateway can neither start a session nor capture a supplied `paymethod_id` value, the system does not create an order or an invoice. - After order creation, if no payment session can be offered — a supported gateway fails to start one, or a stored `paymethod_id` value is declined and no session can then be minted — the order and its invoice already exist, and the invoice remains payable through the `GET /user/invoices/{invoice_id}` endpoint.
- `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)
