> ## Documentation Index
> Fetch the complete documentation index at: https://docs.afriex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Checkout Session

> Creates a hosted checkout session for a customer and returns a `checkoutUrl` that the customer should be redirected to in order to complete payment. The session captures the merchant intent (amount, currency, merchant reference, customer details, and allowed payment channels) and is identified end-to-end by the merchant-supplied `merchantReference`.

<Warning>
  **Coming soon.** Hosted checkout is not yet generally available in production, but you can already try it end-to-end in the **sandbox/staging** environment today. Use sandbox to call this endpoint, see how it works, and validate your integration while we finish the production rollout, which we expect to ship in the coming weeks.
</Warning>

Create a hosted checkout session for a customer. Afriex returns a `checkoutUrl` that you redirect the customer to so they can complete payment on Afriex's hosted page.

<Note>
  **Testing in sandbox?** A checkout session's underlying transaction settles automatically, usually within about 5-6 minutes, and triggers the same webhook and redirect behavior as a real payment (see **How it works** below). Control the outcome through `merchantReference`: include `fail` for a **FAILED** result, or add `SIMULATE_INSTANT` to settle in about 30 seconds instead of waiting. For mobile money, `SIMULATE_OTP` / `SIMULATE_NO_OTP` control whether the payment requires the OTP step shown on the hosted page. See [Testing transaction outcomes in sandbox](/development#testing-transaction-outcomes-in-sandbox).
</Note>

## How it works

1. Call this endpoint with the amount you want to collect, the customer's details, your `merchantReference`, and a `redirectUrl`.
2. Afriex returns a `checkoutUrl`.
3. Redirect the customer to that URL.
4. After payment, Afriex redirects the customer back to your `redirectUrl` and fires a `CHECKOUT_SESSION.CREATED` [webhook](/api-reference/endpoint/webhooks/introduction) to your configured callback URL.

## Identifying the session

The `merchantReference` you supply is the end-to-end identifier. Use it to look up the session, match webhook deliveries, and reconcile any resulting transaction in your system. It must be unique per session.

## Amounts are in minor units

`amount` is denominated in the smallest unit of the currency. For example, kobo for `NGN` or cents for `USD`. To charge ₦5,000.00, pass `500000`. Minimum value is `100` (one major unit).

## Choosing payment channels

`channels` is **required** and lists the deposit rails you are willing to offer the customer. Supported values are `VIRTUAL_BANK_ACCOUNT`, `MOBILE_MONEY`, and `CARD`; pass at least one.

**Treat it as a cap, not an exact list.** Channels the session's `currency` cannot collect on are dropped silently, so you can send the same list on every corridor and let Afriex offer the right subset. For example, `["VIRTUAL_BANK_ACCOUNT", "MOBILE_MONEY", "CARD"]` becomes mobile money for a KES session and cards for a USD session, all from one integration.

The response echoes what the payer will actually be shown as `channels`, in the order you sent them.

<Warning>
  If none of the requested `channels` are supported for the `currency` (or the currency has no deposit channel at all), the request is rejected with `422 Unprocessable Entity`.
</Warning>


## OpenAPI

````yaml POST /api/v1/checkout-session
openapi: 3.1.0
info:
  title: Afriex Business API
  version: 1.0.8
  description: >-
    Welcome to the Afriex Business API. This API allows you to manage customers,
    process payments, handle payouts, and receive real-time notifications via
    webhooks.


    For detailed guidance on authentication, pagination, error handling, and
    webhooks, please refer to the [dedicated guides](https://docs.afriex.com) in
    the top bar. The guide provides a step-by-step instructions to help you
    integrate seamlessly.
  termsOfService: https://www.afriex.com/terms-and-condition
  contact:
    name: Afriex API Support
    email: support@afriex.com
    url: https://docs.afriex.com
  license:
    name: Proprietary
    url: https://www.afriex.com/terms-and-condition
servers:
  - url: https://sandbox.api.afriex.com
    description: Staging Base URL
  - url: https://api.afriex.com
    description: Production Base URL
security:
  - ApiKey: []
tags:
  - name: Customers
    description: Create and manage your customers.
  - name: Payment Methods
    description: Register and resolve customer payout and collection methods.
  - name: Transactions
    description: Create and track deposits, withdrawals, and swaps.
  - name: Balance
    description: View and top up your business wallet balances.
  - name: Rates
    description: Fetch real-time exchange rates.
  - name: Checkout Sessions
    description: Create hosted checkout sessions.
  - name: Webhooks
    description: Webhook event payloads and sandbox webhook testing.
  - name: Media
    description: Generate presigned URLs for secure file uploads.
paths:
  /api/v1/checkout-session:
    parameters:
      - $ref: '#/components/parameters/x-api-version'
    post:
      tags:
        - Checkout Sessions
      summary: Create a checkout session
      description: >-
        Creates a hosted checkout session for a customer and returns a
        `checkoutUrl` that the customer should be redirected to in order to
        complete payment. The session captures the merchant intent (amount,
        currency, merchant reference, customer details, and allowed payment
        channels) and is identified end-to-end by the merchant-supplied
        `merchantReference`.
      operationId: createCheckoutSession
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - amount
                - currency
                - merchantReference
                - redirectUrl
                - customer
                - channels
              properties:
                amount:
                  type: integer
                  minimum: 100
                  description: >-
                    The transaction amount in **minor currency units** (e.g.
                    kobo for NGN, cents for USD). Minimum 100 (equivalent to 1
                    major currency unit).
                  examples:
                    - 500000
                currency:
                  type: string
                  description: >-
                    Uppercase 3-letter ISO 4217 currency code (e.g. NGN, GHS).
                    Must be a currency enabled for checkout sessions on the
                    business.
                  examples:
                    - NGN
                merchantReference:
                  type: string
                  minLength: 1
                  description: >-
                    Unique merchant-supplied reference for this session. Used
                    end-to-end to look up the session and any resulting
                    transaction.
                  examples:
                    - order-2026-05-12-001
                redirectUrl:
                  type: string
                  format: uri
                  description: >-
                    HTTPS URL the customer is redirected to after the hosted
                    checkout flow completes.
                  examples:
                    - https://merchant.example.com/checkout/return
                customer:
                  $ref: '#/components/schemas/CheckoutSessionCustomer'
                channels:
                  type: array
                  minItems: 1
                  description: >-
                    The payment channels you are willing to offer the customer,
                    at least one. **This is a cap, not an exact list: you do not
                    need to vary it per country.** Channels the `currency` does
                    not support are dropped and the session is created with the
                    rest, so the same list works for every corridor (send
                    `["VIRTUAL_BANK_ACCOUNT", "MOBILE_MONEY", "CARD"]` and a KES
                    session offers mobile money while a USD one offers cards).
                    The channels the customer will actually be shown come back
                    as `channels` on the response. The request is rejected
                    (`422`) only when none of the requested channels are
                    supported for the currency, or when the currency supports no
                    deposit channel at all.
                  items:
                    type: string
                    enum:
                      - VIRTUAL_BANK_ACCOUNT
                      - MOBILE_MONEY
                      - CARD
                metadata:
                  type: object
                  maxProperties: 50
                  description: >-
                    Optional flat key/value metadata to attach to the session.
                    Both keys and values must be strings. At most 50 entries;
                    keys up to 128 characters, values up to 1024 characters.
                  additionalProperties:
                    type: string
                    maxLength: 1024
            examples:
              minimal:
                summary: One channel list for every corridor
                value:
                  amount: 500000
                  currency: NGN
                  merchantReference: order-2026-05-12-001
                  redirectUrl: https://merchant.example.com/checkout/return
                  customer:
                    name: John Doe
                    email: john.doe@example.com
                    phone: '+2348192837465'
                    countryCode: NG
                  channels:
                    - VIRTUAL_BANK_ACCOUNT
                    - MOBILE_MONEY
                    - CARD
              withChannelsAndMetadata:
                summary: Narrowing to specific channels, plus metadata
                value:
                  amount: 500000
                  currency: NGN
                  merchantReference: order-2026-05-12-002
                  redirectUrl: https://merchant.example.com/checkout/return
                  customer:
                    name: John Doe
                    email: john.doe@example.com
                    phone: '+2348192837465'
                    countryCode: NG
                  channels:
                    - VIRTUAL_BANK_ACCOUNT
                    - CARD
                  metadata:
                    orderId: '12345'
                    source: web
      responses:
        '201':
          description: Checkout session created successfully.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/CreateCheckoutSessionResponse'
              examples:
                created:
                  summary: Session created
                  value:
                    data:
                      checkoutUrl: >-
                        https://pay.afriex.com/pay/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
                      channels:
                        - VIRTUAL_BANK_ACCOUNT
                        - CARD
        '400':
          description: Invalid request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized - Invalid business API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: >-
            None of the requested `channels` are supported for the `currency`,
            or the currency has no deposit channel available at all.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      x-codeSamples:
        - lang: TypeScript
          label: Afriex SDK
          source: >
            const session = await afriex.checkout.createSession({
              amount: 500000,
              currency: "NGN",
              merchantReference: "order-2026-05-12-001",
              redirectUrl: "https://yourapp.com/checkout/return",
              customer: {
                name: "John Doe",
                email: "john@example.com",
                phone: "+2348192837465",
                countryCode: "NG",
              },
              // Send the same list everywhere; unsupported ones are dropped
              channels: ["VIRTUAL_BANK_ACCOUNT", "MOBILE_MONEY", "CARD"],
              metadata: { orderId: "order-456", cartId: "cart-123" },
            });


            // Redirect customer to session.checkoutUrl

            console.log(session.checkoutUrl);

            // What the payer will be shown, e.g. ["VIRTUAL_BANK_ACCOUNT",
            "CARD"]

            console.log(session.channels);
components:
  parameters:
    x-api-version:
      name: x-api-version
      in: header
      required: false
      description: >-
        API version in ISO 8601 format (e.g. 2025-12-28). Defaults to latest
        stable.
      schema:
        type: string
  schemas:
    CheckoutSessionCustomer:
      type: object
      required:
        - name
        - email
        - phone
        - countryCode
      properties:
        name:
          type: string
          description: The full name of the customer.
          examples:
            - John Doe
        email:
          type: string
          format: email
          description: The email address of the customer.
          examples:
            - john.doe@example.com
        phone:
          type: string
          description: The phone number of the customer in E.164 format.
          examples:
            - '+2348192837465'
        countryCode:
          type: string
          description: >-
            The ISO 3166-1 alpha-2 country code of the customer (e.g., 'NG',
            'GH'). Case-insensitive; values are normalized to uppercase.
          examples:
            - NG
    CreateCheckoutSessionResponse:
      type: object
      properties:
        checkoutUrl:
          type: string
          format: uri
          description: >-
            The URL the customer should be redirected to in order to complete
            the hosted checkout flow.
          examples:
            - https://pay.afriex.com/pay/eyJhbGciOiJI...
        channels:
          type: array
          description: >-
            The payment channels the customer will actually be offered on the
            checkout page: the request's `channels`, in the order you sent them,
            minus any the currency cannot collect on. Never empty.
          items:
            type: string
            enum:
              - VIRTUAL_BANK_ACCOUNT
              - MOBILE_MONEY
              - CARD
          examples:
            - - MOBILE_MONEY
    ErrorResponse:
      type: object
      properties:
        code:
          type: string
          description: Machine-readable error code.
        error:
          type: string
          description: Human-readable error message.
        details:
          $ref: '#/components/schemas/ErrorDetails'
    ErrorDetails:
      type: object
      properties:
        errorMessage:
          type: string
          description: Detailed/technical error message.
        friendlyMessage:
          type: string
          description: User-facing error message safe to display.
        data:
          type: object
          description: >-
            Optional caller-safe context for the error. On a customer-create
            uniqueness conflict (EMAIL_ALREADY_EXISTS /
            PHONE_NUMBER_ALREADY_EXISTS) this carries the existing customer's
            id, so you can adopt it without a follow-up lookup.
          properties:
            customerId:
              type: string
              description: Id of the existing customer (on a create conflict).
  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Static business API key issued from the dashboard. A business can
        provision **multiple API keys**, each scoped to a configurable set of
        **permissions** (e.g. read transactions, create deposits, etc).
        Permissions are chosen per key at creation time in the dashboard and may
        be revoked by deleting the key. Requests made with a key that does not
        include the permission required by the target endpoint will be rejected
        with a `403 Forbidden` response; an unrecognised, malformed or revoked
        key returns `401 Unauthorized`. Manage your keys and their permissions
        under **Developer → API keys** in the dashboard.

````