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

# Checkout Sessions

> Create an Axra Pay hosted checkout page in one API call. Customers enter card details on Axra's secure page — no PCI DSS scope added to your integration.

Checkout Sessions let you redirect customers to an Axra-hosted payment page instead of collecting card details yourself. You create a session with a single API call, redirect the customer to the returned URL, and Axra handles card entry, validation, 3D Secure authentication, and the post-payment redirect — all without any card data touching your servers. Because Axra absorbs the card data handling, you are not in PCI DSS scope for card storage or transmission.

<Note>
  If you need full control over the payment UI or want to charge cards programmatically from your server, use the [Payments API](/payments/overview) instead. Both approaches support 3DS and webhooks.
</Note>

***

## How checkout sessions work

<Steps>
  <Step title="Create a session">
    Call `POST /business/payment/session` from your server with the payment amount, currency, and redirect URLs. Axra returns a `checkoutUrl` and a `sessionId`.
  </Step>

  <Step title="Redirect the customer">
    Send the customer's browser to the `checkoutUrl`. You can do this with a server-side redirect or by opening the URL in a new window, but a full-page redirect gives the best experience.
  </Step>

  <Step title="Customer completes payment">
    The customer enters their card on Axra's hosted page. If the card requires 3DS, Axra handles the challenge entirely within the checkout experience — the customer never leaves the Axra-hosted page.
  </Step>

  <Step title="Customer is redirected">
    On success, Axra redirects the customer to your `successUrl`. If the customer clicks "Cancel" or the session expires, they are sent to your `cancelUrl`. The `successUrl` supports a `{SESSION_ID}` placeholder that Axra replaces with the actual session ID.
  </Step>

  <Step title="Confirm via webhook">
    After the redirect, verify the payment by waiting for the `payment.completed` webhook event. Do not fulfil orders based on the URL redirect alone — the webhook is the authoritative confirmation.
  </Step>
</Steps>

<Warning>
  Always confirm payment completion via the `payment.completed` webhook. A customer can reach your `successUrl` without a successful payment (e.g., by navigating directly to the URL). Only the webhook guarantees the charge succeeded.
</Warning>

***

## Create a checkout session

`POST /business/payment/session`

Creates a new hosted checkout session and returns a URL to redirect your customer to.

### Authentication

Pass your API key in the `x-api-key` header, or include a valid JWT `Authorization: Bearer <token>` header.

### Request parameters

<ParamField body="amount" type="number" required>
  Payment amount in major currency units (e.g., `25.00`). Minimum value is `0.50`.
</ParamField>

<ParamField body="currency" type="string" required>
  ISO 4217 currency code in lowercase (e.g., `"usd"`, `"eur"`, `"ngn"`).
</ParamField>

<ParamField body="successUrl" type="string" required>
  URL to redirect the customer to after a successful payment. You can include the `{SESSION_ID}` placeholder — Axra will replace it with the actual session ID on redirect. Example: `"https://yourapp.com/payment/success?session={SESSION_ID}"`.
</ParamField>

<ParamField body="cancelUrl" type="string" required>
  URL to redirect the customer to if they cancel the checkout or if the session expires.
</ParamField>

<ParamField body="description" type="string">
  Short description displayed on the Axra-hosted checkout page (e.g., `"Subscription — Pro Plan"`). Helps customers recognize what they are paying for.
</ParamField>

<ParamField body="customerEmail" type="string">
  Customer email address. Pre-fills the email field on the checkout page so the customer does not have to type it.
</ParamField>

<ParamField body="expiresIn" type="number" default="3600">
  How long the session remains valid, in seconds. Minimum `300` (5 minutes). After expiry, customers visiting the `checkoutUrl` are redirected to your `cancelUrl`.
</ParamField>

<ParamField body="metadata" type="object">
  Arbitrary key-value pairs attached to the session and included in the `payment.completed` webhook payload. Use this to store your internal order ID, user ID, or any other reference.
</ParamField>

### Response fields

<ResponseField name="sessionId" type="string" required>
  Unique identifier for the checkout session. Use this to look up the associated payment later.
</ResponseField>

<ResponseField name="checkoutUrl" type="string" required>
  The fully-formed URL to redirect your customer to. Valid until `expiresAt`.
</ResponseField>

<ResponseField name="expiresAt" type="string" required>
  ISO 8601 timestamp indicating when the session expires.
</ResponseField>

<ResponseField name="amount" type="number" required>
  The session amount in major currency units, confirming what was set.
</ResponseField>

<ResponseField name="currency" type="string" required>
  ISO 4217 currency code confirming the session currency.
</ResponseField>

### Example

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.useaxra.com/api/v1/business/payment/session \
    --header 'x-api-key: YOUR_API_KEY' \
    --header 'Content-Type: application/json' \
    --data '{
      "amount": 25.00,
      "currency": "usd",
      "description": "Subscription — Pro Plan",
      "customerEmail": "amara@example.com",
      "successUrl": "https://yourapp.com/payment/success?session={SESSION_ID}",
      "cancelUrl": "https://yourapp.com/payment/cancelled",
      "expiresIn": 1800,
      "metadata": {
        "orderId": "sub_pro_9982",
        "userId": "usr_abc123"
      }
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    'https://api.useaxra.com/api/v1/business/payment/session',
    {
      method: 'POST',
      headers: {
        'x-api-key': process.env.AXRA_API_KEY,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        amount: 25.00,
        currency: 'usd',
        description: 'Subscription — Pro Plan',
        customerEmail: 'amara@example.com',
        successUrl: 'https://yourapp.com/payment/success?session={SESSION_ID}',
        cancelUrl: 'https://yourapp.com/payment/cancelled',
        expiresIn: 1800,
        metadata: {
          orderId: 'sub_pro_9982',
          userId: 'usr_abc123',
        },
      }),
    }
  );

  const session = await response.json();

  // Redirect the customer to the hosted checkout page
  res.redirect(session.checkoutUrl);
  ```

  ```python Python theme={null}
  import os, requests

  response = requests.post(
      "https://api.useaxra.com/api/v1/business/payment/session",
      headers={
          "x-api-key": os.environ["AXRA_API_KEY"],
          "Content-Type": "application/json",
      },
      json={
          "amount": 25.00,
          "currency": "usd",
          "description": "Subscription — Pro Plan",
          "customerEmail": "amara@example.com",
          "successUrl": "https://yourapp.com/payment/success?session={SESSION_ID}",
          "cancelUrl": "https://yourapp.com/payment/cancelled",
          "expiresIn": 1800,
          "metadata": {
              "orderId": "sub_pro_9982",
              "userId": "usr_abc123",
          },
      },
  )

  session = response.json()
  # Flask example: redirect(session["checkoutUrl"])
  print(session["checkoutUrl"])
  ```
</CodeGroup>

**201 Created — session created successfully**

```json theme={null}
{
  "sessionId": "cs_01HABC987654",
  "checkoutUrl": "https://checkout.useaxra.com/pay/cs_01HABC987654",
  "expiresAt": "2026-04-14T11:23:45.000Z",
  "amount": 25.00,
  "currency": "usd"
}
```

***

## Handling the post-payment redirect

When Axra redirects to your `successUrl`, the URL will contain the session ID if you included the `{SESSION_ID}` placeholder. You can read this value from the query string to associate the redirect with the correct order.

```javascript Node.js (Express) theme={null}
app.get('/payment/success', async (req, res) => {
  const sessionId = req.query.session;

  // Do NOT fulfil the order yet — wait for the webhook instead.
  // Use sessionId to show a "processing" screen to the customer.
  res.render('payment-processing', { sessionId });
});
```

<Tip>
  Show a "payment processing" message on your success page and fulfil the order only after receiving the `payment.completed` webhook. This avoids fulfilling orders for redirects that do not correspond to a completed payment.
</Tip>

***

## Listening for payment confirmation

Configure a webhook URL in your Axra Pay dashboard and handle the `payment.completed` event. The payload includes the `sessionId` in the `metadata` object alongside any custom metadata you provided when creating the session.

```javascript Node.js (Express) theme={null}
app.post('/webhooks/axra', express.raw({ type: 'application/json' }), (req, res) => {
  const event = JSON.parse(req.body);

  if (event.type === 'payment.completed') {
    const { paymentId, metadata } = event.data;
    const orderId = metadata.orderId;

    // Safe to fulfil the order now
    fulfillOrder(orderId);
  }

  res.sendStatus(200);
});
```

See [Webhooks](/manage/webhooks) for signature verification and the full event schema.

***

## Session expiry

If a customer does not complete payment before the session expires, Axra redirects them to your `cancelUrl`. The expired session cannot be reactivated — create a new session if the customer wants to try again.

<Note>
  The minimum session duration is 300 seconds (5 minutes). For checkout flows with multiple steps before payment, set `expiresIn` to at least 900 seconds (15 minutes) to avoid premature expiry.
</Note>
