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

# Create Checkout Session

> Create a new checkout session for payment collection

# Create Checkout Session

Creates a new checkout session that your customer can use to complete payment. The session includes line items, pricing, customer information, and redirect URLs.

## Request

<ParamField header="Authorization" type="string" required>
  Bearer token with your API key (format: `Bearer mp_live_...` or `Bearer
       mp_test_...`)
</ParamField>

<ParamField body="description" type="string" required>
  A description of the checkout session (1-256 characters), shown to the
  customer during checkout.
</ParamField>

<ParamField body="customer" type="object" required>
  <Expandable title="properties">
    <ResponseField name="email" type="string" required>
      Customer's email address for receipt and notifications. Must be a valid
      email format.
    </ResponseField>
  </Expandable>
</ParamField>

<ParamField body="askShipping" type="boolean" default={false}>
  Whether to collect shipping address from the customer during checkout.
  **Optional:** Defaults to `false` if not specified.
</ParamField>

<ParamField body="urls" type="object">
  Redirect URLs for different payment outcomes. All URLs are optional and
  support null values.

  <Expandable title="properties">
    <ResponseField name="success" type="string | null">
      URL to redirect after successful payment (max 256 characters).
    </ResponseField>

    <ResponseField name="cancel" type="string | null">
      URL to redirect if customer cancels the checkout (max 256 characters).
    </ResponseField>

    <ResponseField name="failure" type="string | null">
      URL to redirect if payment fails (max 256 characters).
    </ResponseField>
  </Expandable>
</ParamField>

<ParamField body="items" type="array" required>
  List of items in the checkout. **At least one item is required, maximum 100
  items.**

  <Expandable title="item object">
    <ResponseField name="name" type="string" required>
      Name of the item (1-100 characters).
    </ResponseField>

    <ResponseField name="description" type="string | null">
      **Optional** description of the item (max 256 characters). Can be
      `null` or omitted entirely.
    </ResponseField>

    <ResponseField name="price" type="number" required>
      Price per unit in dollars (e.g., `29.99`). Must be between 0.01 and
      999,999.99.
    </ResponseField>

    <ResponseField name="quantity" type="integer" required>
      Number of units (1-1,000,000).
    </ResponseField>

    <ResponseField name="imageUrl" type="string | null">
      Optional URL to an image of the item (max 256 characters, must be
      http/https). Can be `null`.
    </ResponseField>
  </Expandable>
</ParamField>

<ParamField body="metadata" type="object | array">
  **Flexible format:** Can be either an **object** (key-value pairs) or an **array** of `{key, value}` objects.

  * Maximum 50 metadata entries
  * Keys: alphanumeric, dashes, underscores only (max 64 chars)
  * Values: string (max 255 chars), number (integer), or boolean

  **Object format (recommended for API calls):**

  ```json theme={null}
  {
    "orderId": "ORD-12345",
    "customerId": "CUST-789",
    "priority": 1,
    "isGift": false
  }
  ```

  **Array format (used by frontend forms):**

  ```json theme={null}
  [
    { "key": "orderId", "value": "ORD-12345" },
    { "key": "priority", "value": 1 }
  ]
  ```
</ParamField>

## Response

<ResponseField name="success" type="boolean">
  Whether the request was successful
</ResponseField>

<ResponseField name="data" type="object">
  <Expandable title="properties">
    <ResponseField name="id" type="string">
      Unique identifier for the session (UUID format)
    </ResponseField>

    <ResponseField name="status" type="string">
      Session status: `pending`, `processing`, `completed`, `failed`,
      `cancelled`, `refunded`
    </ResponseField>

    <ResponseField name="checkoutUrl" type="string">
      The URL where the customer can complete the payment
    </ResponseField>

    <ResponseField name="businessId" type="string">
      Your business identifier
    </ResponseField>

    <ResponseField name="currency" type="string">
      Three-letter ISO currency code (always `USD`)
    </ResponseField>

    <ResponseField name="total" type="integer">
      Total amount in cents (item totals + fees)
    </ResponseField>

    <ResponseField name="customerEmail" type="string">
      Customer email address
    </ResponseField>

    <ResponseField name="description" type="string">
      Session description
    </ResponseField>

    <ResponseField name="askShipping" type="boolean">
      Whether shipping address collection is enabled
    </ResponseField>

    <ResponseField name="successUrl" type="string | null">
      Success redirect URL
    </ResponseField>

    <ResponseField name="cancelUrl" type="string | null">
      Cancel redirect URL
    </ResponseField>

    <ResponseField name="failureUrl" type="string | null">
      Failure redirect URL
    </ResponseField>

    <ResponseField name="metadata" type="object">
      Custom metadata (always returned as object format)
    </ResponseField>

    <ResponseField name="items" type="array">
      Array of line items with pricing details
    </ResponseField>

    <ResponseField name="createdAt" type="string">
      ISO 8601 timestamp when session was created
    </ResponseField>

    <ResponseField name="updatedAt" type="string">
      ISO 8601 timestamp when session was last updated
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.swiftpay.cx/api/checkout/sessions \
    -H "Authorization: Bearer mp_live_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "description": "Coffee Subscription - Premium Package",
      "customer": {
        "email": "customer@example.com"
      },
      "askShipping": true,
      "urls": {
        "success": "https://yoursite.com/success",
        "cancel": "https://yoursite.com/cancel",
        "failure": "https://yoursite.com/payment-failed"
      },
      "items": [
        {
          "name": "Premium Coffee Beans",
          "description": "Ethiopian Yirgacheffe - Light Roast",
          "price": 24.99,
          "quantity": 2,
          "imageUrl": "https://yoursite.com/images/coffee.jpg"
        },
        {
          "name": "Shipping",
          "description": null,
          "price": 5.00,
          "quantity": 1,
          "imageUrl": null
        }
      ],
      "metadata": {
        "orderId": "ORD-2026-12345",
        "subscriptionId": "sub_premium_monthly",
        "customerTier": "gold",
        "isFirstOrder": true,
        "referralCode": "FRIEND20"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  // Using object metadata (recommended)
  const response = await fetch("https://api.swiftpay.cx/api/checkout/sessions", {
     method: "POST",
     headers: {
        Authorization: "Bearer mp_live_your_api_key",
        "Content-Type": "application/json",
     },
     body: JSON.stringify({
        description: "Coffee Subscription - Premium Package",
        customer: {
           email: "customer@example.com",
        },
        askShipping: true,
        urls: {
           success: "https://yoursite.com/success",
           cancel: "https://yoursite.com/cancel",
           failure: "https://yoursite.com/payment-failed",
        },
        items: [
           {
              name: "Premium Coffee Beans",
              description: "Ethiopian Yirgacheffe - Light Roast",
              price: 24.99,
              quantity: 2,
              imageUrl: "https://yoursite.com/images/coffee.jpg",
           },
           {
              name: "Shipping",
              description: null,
              price: 5.0,
              quantity: 1,
              imageUrl: null,
           },
        ],
        metadata: {
           orderId: "ORD-2026-12345",
           subscriptionId: "sub_premium_monthly",
           customerTier: "gold",
           isFirstOrder: true,
           referralCode: "FRIEND20",
        },
     }),
  });

  const session = await response.json();

  // Redirect customer to checkout
  window.location.href = session.data.checkoutUrl;
  ```

  ```javascript Array Metadata Format theme={null}
  // Alternative: Using array metadata format
  const response = await fetch("https://api.swiftpay.cx/api/checkout/sessions", {
     method: "POST",
     headers: {
        Authorization: "Bearer mp_live_your_api_key",
        "Content-Type": "application/json",
     },
     body: JSON.stringify({
        description: "Coffee Subscription - Premium Package",
        customer: {
           email: "customer@example.com",
        },
        askShipping: false,
        urls: {
           success: "https://yoursite.com/success",
           cancel: null,
           failure: null,
        },
        items: [
           {
              name: "Premium Coffee Beans",
              description: "Ethiopian Yirgacheffe",
              price: 24.99,
              quantity: 1,
              imageUrl: null,
           },
        ],
        // Metadata as array (useful for dynamic forms)
        metadata: [
           { key: "orderId", value: "ORD-12345" },
           { key: "priority", value: 1 },
           { key: "isGift", value: false },
        ],
     }),
  });

  const session = await response.json();
  ```

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

  response = requests.post(
      'https://api.swiftpay.cx/api/checkout/sessions',
      headers={
          'Authorization': 'Bearer mp_live_your_api_key',
          'Content-Type': 'application/json'
      },
      json={
          'description': 'Coffee Subscription - Premium Package',
          'customer': {
              'email': 'customer@example.com'
          },
          'askShipping': True,
          'urls': {
              'success': 'https://yoursite.com/success',
              'cancel': 'https://yoursite.com/cancel',
              'failure': 'https://yoursite.com/payment-failed'
          },
          'items': [
              {
                  'name': 'Premium Coffee Beans',
                  'description': 'Ethiopian Yirgacheffe - Light Roast',
                  'price': 24.99,
                  'quantity': 2,
                  'imageUrl': 'https://yoursite.com/images/coffee.jpg'
              },
              {
                  'name': 'Shipping',
                  'description': None,
                  'price': 5.00,
                  'quantity': 1,
                  'imageUrl': None
              }
          ],
          'metadata': {
              'orderId': 'ORD-2026-12345',
              'subscriptionId': 'sub_premium_monthly',
              'customerTier': 'gold',
              'isFirstOrder': True,
              'referralCode': 'FRIEND20'
          }
      }
  )

  session = response.json()
  checkout_url = session['data']['checkoutUrl']

  # Redirect user to checkout_url
  print(f"Checkout URL: {checkout_url}")
  ```

  ```php PHP theme={null}
  <?php

  $ch = curl_init('https://api.swiftpay.cx/api/checkout/sessions');

  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      'Authorization: Bearer mp_live_your_api_key',
      'Content-Type: application/json'
  ]);

  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
      'description' => 'Coffee Subscription - Premium Package',
      'customer' => [
          'email' => 'customer@example.com'
      ],
      'askShipping' => true,
      'urls' => [
          'success' => 'https://yoursite.com/success',
          'cancel' => 'https://yoursite.com/cancel',
          'failure' => 'https://yoursite.com/payment-failed'
      ],
      'items' => [
          [
              'name' => 'Premium Coffee Beans',
              'description' => 'Ethiopian Yirgacheffe - Light Roast',
              'price' => 24.99,
              'quantity' => 2,
              'imageUrl' => 'https://yoursite.com/images/coffee.jpg'
          ],
          [
              'name' => 'Shipping',
              'description' => null,
              'price' => 5.00,
              'quantity' => 1,
              'imageUrl' => null
          ]
      ],
      'metadata' => [
          'orderId' => 'ORD-2026-12345',
          'subscriptionId' => 'sub_premium_monthly',
          'customerTier' => 'gold',
          'isFirstOrder' => true,
          'referralCode' => 'FRIEND20'
      ]
  ]));

  $response = curl_exec($ch);
  $session = json_decode($response, true);

  curl_close($ch);

  // Redirect to checkout
  header('Location: ' . $session['data']['checkoutUrl']);
  ?>
  ```
</RequestExample>

<ResponseExample>
  ```json 201 Success theme={null}
  {
    "success": true,
    "data": {
      "id": "01936d2e-8f4a-7b3c-9e5f-2a1c8d9b6e3f",
      "businessId": "01936d2e-7a5b-7c8d-9e2f-3a4b5c6d7e8f",
      "userId": "01936d2e-6b4c-7d5e-8f9a-1b2c3d4e5f6a",
      "status": "pending",
      "currency": "USD",
      "total": 5998,
      "description": "Coffee Subscription - Premium Package",
      "customerEmail": "customer@example.com",
      "askShipping": true,
      "successUrl": "https://yoursite.com/success",
      "cancelUrl": "https://yoursite.com/cancel",
      "failureUrl": "https://yoursite.com/payment-failed",
      "checkoutUrl": "https://swiftpay.cx/checkout/01936d2e-8f4a-7b3c-9e5f-2a1c8d9b6e3f",
      "metadata": {
        "orderId": "ORD-2026-12345",
        "subscriptionId": "sub_premium_monthly",
        "customerTier": "gold",
        "isFirstOrder": true,
        "referralCode": "FRIEND20"
      },
      "items": [
        {
          "id": "01936d2e-9a8b-7c6d-5e4f-3a2b1c0d9e8f",
          "sessionId": "01936d2e-8f4a-7b3c-9e5f-2a1c8d9b6e3f",
          "name": "Premium Coffee Beans",
          "description": "Ethiopian Yirgacheffe - Light Roast",
          "price": 2499,
          "quantity": 2,
          "imageUrl": "https://yoursite.com/images/coffee.jpg",
          "subtotal": 4998
        },
        {
          "id": "01936d2e-9b7c-8d5e-6f4a-3b2c1d0e9f8a",
          "sessionId": "01936d2e-8f4a-7b3c-9e5f-2a1c8d9b6e3f",
          "name": "Shipping",
          "description": null,
          "price": 500,
          "quantity": 1,
          "imageUrl": null,
          "subtotal": 500
        }
      ],
      "createdAt": "2026-01-10T16:30:00.000Z",
      "updatedAt": "2026-01-10T16:30:00.000Z",
      "completedAt": null
    }
  }
  ```

  ```json 400 Validation Error theme={null}
  {
     "success": false,
     "error": {
        "type": "validation_error",
        "message": "Validation failed",
        "errors": [
           {
              "path": ["items", 0, "price"],
              "message": "Price must be between 0.01 and 999999.99"
           }
        ],
        "requestId": "req_01936d2e9c5b7d8e"
     }
  }
  ```

  ```json 400 Missing Items theme={null}
  {
     "success": false,
     "error": {
        "type": "validation_error",
        "message": "At least one item is required",
        "errors": [
           {
              "path": ["items"],
              "message": "At least one item is required"
           }
        ],
        "requestId": "req_01936d2e9d6c8e9f"
     }
  }
  ```

  ```json 400 Invalid Metadata theme={null}
  {
     "success": false,
     "error": {
        "type": "validation_error",
        "message": "Too many metadata fields (max 50)",
        "errors": [
           {
              "path": ["metadata"],
              "message": "Too many metadata fields (max 50)"
           }
        ],
        "requestId": "req_01936d2e9e7d9f0a"
     }
  }
  ```

  ```json 401 Unauthorized theme={null}
  {
     "success": false,
     "error": {
        "type": "authentication_error",
        "message": "Invalid API key",
        "requestId": "req_01936d2e9f8e0a1b"
     }
  }
  ```
</ResponseExample>

## Notes

* **Pricing**: All prices in the request are in **dollars** (e.g., `24.99`), but returned amounts are in **cents** (e.g., `2499`)
* **Metadata Formats**: Both object and array formats are accepted. The API automatically normalizes array format to object format
* **URL Validation**: All URLs are validated for security (only `http://` and `https://` schemes allowed, internal IPs blocked)
* **Rate Limiting**: Standard tier allows 100 requests per minute
* **Idempotency**: Not currently supported - each request creates a new session
* **Expiration**: Sessions remain active until completed, failed, or cancelled (no automatic expiration)
