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

# Checkout

> Create checkout sessions and initiate payments via the Embed API.

The Embed API supports two checkout modes: **authenticated checkout** (using a Sanctum token from the OTP flow) and **guest checkout** (providing customer details directly). Both modes create a checkout session and return payment options.

## Authenticated Checkout

Create a checkout session for an authenticated customer. Customer information is retrieved from the token.

```
POST /api/embed/checkout
```

### Headers

| Header          | Required | Description                                           |
| --------------- | -------- | ----------------------------------------------------- |
| `Authorization` | Yes      | `Bearer <token>` (must have `embed:checkout` ability) |
| `X-Embed-Key`   | Yes      | Your store's embed public key                         |
| `Content-Type`  | Yes      | `application/json`                                    |

### Request Body

| Field               | Type    | Required | Description                                                  |
| ------------------- | ------- | -------- | ------------------------------------------------------------ |
| `product_id`        | integer | Yes      | The product ID                                               |
| `quantity`          | integer | Yes      | Purchase quantity (min: 1)                                   |
| `coupon_code`       | string  | No       | Coupon code to apply                                         |
| `customer_note`     | string  | No       | Customer note (max 500 characters)                           |
| `notice`            | string  | No       | Alternative field for customer note                          |
| `subscription_plan` | integer | No       | Subscription variant ID (required for subscription products) |
| `fields`            | object  | No       | Custom product field values (keyed by field index)           |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://embed.rmz.gg/api/embed/checkout" \
    -H "Authorization: Bearer 1|abc123xyz..." \
    -H "X-Embed-Key: your_embed_public_key" \
    -H "Content-Type: application/json" \
    -d '{
      "product_id": 42,
      "quantity": 1,
      "coupon_code": "SAVE20"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://embed.rmz.gg/api/embed/checkout", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${token}`,
      "X-Embed-Key": "your_embed_public_key",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      product_id: 42,
      quantity: 1,
      coupon_code: "SAVE20"
    })
  });

  const { data } = await response.json();

  if (data.type === "free_order") {
    // Order created, no payment needed
    console.log("Order created:", data.order_id);
  } else {
    // Redirect to payment or show payment methods
    console.log("Payment methods:", data.payment_methods);
  }
  ```

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

  response = requests.post(
      "https://embed.rmz.gg/api/embed/checkout",
      headers={
          "Authorization": f"Bearer {token}",
          "X-Embed-Key": "your_embed_public_key",
          "Content-Type": "application/json"
      },
      json={
          "product_id": 42,
          "quantity": 1,
          "coupon_code": "SAVE20"
      }
  )

  data = response.json()["data"]
  ```

  ```php PHP theme={null}
  $response = Http::withHeaders([
      'Authorization' => "Bearer {$token}",
      'X-Embed-Key' => 'your_embed_public_key',
  ])->post('https://embed.rmz.gg/api/embed/checkout', [
      'product_id' => 42,
      'quantity' => 1,
      'coupon_code' => 'SAVE20',
  ]);

  $data = $response->json()['data'];
  ```
</CodeGroup>

### Success Response - Payment Required (200)

```json theme={null}
{
  "success": true,
  "data": {
    "type": "payment_required",
    "checkout_id": 789,
    "checkout_url": "ck_abc123",
    "payment_url": "https://store.rmz.gg/checkout/ck_abc123",
    "amount": "126.50",
    "subtotal": "149.00",
    "discount_amount": "29.80",
    "tax_amount": "17.88",
    "payment_methods": [
      {
        "id": "card",
        "name_ar": "بطاقة ائتمان",
        "name_en": "Credit Card",
        "icon": "card"
      },
      {
        "id": "mada",
        "name_ar": "مدى",
        "name_en": "Mada",
        "icon": "mada"
      },
      {
        "id": "applepay",
        "name_ar": "Apple Pay",
        "name_en": "Apple Pay",
        "icon": "applepay"
      }
    ]
  }
}
```

### Success Response - Free Order (200)

When the total is zero (e.g., 100% discount coupon), the order is created immediately:

```json theme={null}
{
  "success": true,
  "data": {
    "type": "free_order",
    "order_id": 456,
    "message": "Order created successfully"
  }
}
```

### Available Payment Methods

| ID         | Description                   |
| ---------- | ----------------------------- |
| `card`     | Credit Card (Visa/Mastercard) |
| `mada`     | Mada debit card               |
| `stcpay`   | STC Pay                       |
| `applepay` | Apple Pay                     |
| `paypal`   | PayPal                        |
| `bank`     | Bank Transfer                 |
| `coinbase` | Cryptocurrency                |

<Note>
  Available payment methods depend on the store's configuration and the order amount. Not all methods are available for every store.
</Note>

***

## Guest Checkout

Create a checkout session without OTP authentication. Customer details are provided directly in the request body.

```
POST /api/embed/guest/checkout
```

### Headers

| Header         | Required | Description                   |
| -------------- | -------- | ----------------------------- |
| `X-Embed-Key`  | Yes      | Your store's embed public key |
| `Content-Type` | Yes      | `application/json`            |

### Request Body

| Field                   | Type    | Required | Description                        |
| ----------------------- | ------- | -------- | ---------------------------------- |
| `product_id`            | integer | Yes      | The product ID                     |
| `quantity`              | integer | Yes      | Purchase quantity (min: 1)         |
| `customer_first_name`   | string  | Yes      | Customer first name (max 100)      |
| `customer_last_name`    | string  | Yes      | Customer last name (max 100)       |
| `customer_email`        | string  | Yes      | Customer email address             |
| `customer_phone`        | string  | Yes      | Customer phone number (max 20)     |
| `customer_country_code` | string  | Yes      | Phone country code (max 10)        |
| `coupon_code`           | string  | No       | Coupon code to apply               |
| `customer_note`         | string  | No       | Customer note (max 500 characters) |
| `fields`                | object  | No       | Custom product field values        |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://embed.rmz.gg/api/embed/guest/checkout" \
    -H "X-Embed-Key: your_embed_public_key" \
    -H "Content-Type: application/json" \
    -d '{
      "product_id": 42,
      "quantity": 1,
      "customer_first_name": "Ahmed",
      "customer_last_name": "Ali",
      "customer_email": "ahmed@example.com",
      "customer_phone": "501234567",
      "customer_country_code": "966"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://embed.rmz.gg/api/embed/guest/checkout", {
    method: "POST",
    headers: {
      "X-Embed-Key": "your_embed_public_key",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      product_id: 42,
      quantity: 1,
      customer_first_name: "Ahmed",
      customer_last_name: "Ali",
      customer_email: "ahmed@example.com",
      customer_phone: "501234567",
      customer_country_code: "966"
    })
  });

  const { data } = await response.json();
  ```
</CodeGroup>

The response format is identical to the authenticated checkout response above.

***

## Initiate Payment

After creating a checkout session, initiate the actual payment with the customer's chosen payment method.

### Authenticated Payment

```
POST /api/embed/payment/initiate
```

Requires `Authorization: Bearer <token>` with `embed:checkout` ability.

### Guest Payment

```
POST /api/embed/guest/payment/initiate
```

No authentication required.

### Request Body (Both Endpoints)

| Field            | Type   | Required | Description                                                                |
| ---------------- | ------ | -------- | -------------------------------------------------------------------------- |
| `checkout_url`   | string | Yes      | The `checkout_url` from the checkout response                              |
| `payment_method` | string | Yes      | One of: `card`, `mada`, `stcpay`, `applepay`, `paypal`, `bank`, `coinbase` |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://embed.rmz.gg/api/embed/payment/initiate" \
    -H "Authorization: Bearer 1|abc123xyz..." \
    -H "X-Embed-Key: your_embed_public_key" \
    -H "Content-Type: application/json" \
    -d '{
      "checkout_url": "ck_abc123",
      "payment_method": "card"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://embed.rmz.gg/api/embed/payment/initiate", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${token}`,
      "X-Embed-Key": "your_embed_public_key",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      checkout_url: "ck_abc123",
      payment_method: "card"
    })
  });

  const { data } = await response.json();

  if (data.type === "redirect") {
    window.location.href = data.redirect_url;
  } else if (data.type === "bank_transfer") {
    // Show bank details to customer
    console.log("Bank:", data.bank_details);
  }
  ```
</CodeGroup>

### Response Types

The response varies by payment method:

**Card, Mada, STC Pay, Apple Pay, Coinbase, PayPal (with PayPal.me link)**

```json theme={null}
{
  "success": true,
  "data": {
    "type": "redirect",
    "redirect_url": "https://..."
  }
}
```

Redirect the customer to `redirect_url` to complete payment.

**PayPal (manual, email only)**

```json theme={null}
{
  "success": true,
  "data": {
    "type": "paypal_manual",
    "paypal_email": "merchant@paypal.com",
    "amount": 149.00,
    "checkout_url": "ck_abc123"
  }
}
```

**Bank Transfer**

```json theme={null}
{
  "success": true,
  "data": {
    "type": "bank_transfer",
    "bank_details": {
      "bank_name": "Al Rajhi Bank",
      "account_name": "Store Owner Name",
      "account_number": "1234567890",
      "iban": "SA1234567890123456789012"
    },
    "amount": 149.00,
    "checkout_url": "ck_abc123"
  }
}
```

### Error Responses

| Status | Description                                  |
| ------ | -------------------------------------------- |
| 404    | Checkout session expired or not found        |
| 400    | Order already created for this checkout      |
| 400    | Payment method not configured for this store |
| 422    | Invalid payment method                       |

<Warning>
  Checkout sessions expire after a period of time. If a customer takes too long, you may need to create a new checkout session.
</Warning>

***

## Product Fields

Products can have custom fields that customers fill in during checkout. Pass field values in the `fields` object, keyed by the field's array index from the product data.

### Field Types

| Type       | Value Format | Notes                                                                 |
| ---------- | ------------ | --------------------------------------------------------------------- |
| `text`     | string       | Free text input                                                       |
| `number`   | number       | Numeric input                                                         |
| `date`     | string       | Date string                                                           |
| `datetime` | string       | Date and time string                                                  |
| `color`    | string       | Color value                                                           |
| `select`   | integer      | Index of the selected option (may add to price)                       |
| `image`    | file         | Upload via `field_files.{index}` (JPG, PNG, GIF, max 10MB)            |
| `file`     | file         | Upload via `field_files.{index}` (PDF, DOC, DOCX, TXT, ZIP, max 20MB) |

<Tip>
  Select fields can include price add-ons. The add-on amount is added to the unit price before calculating the total. Check the product info response to see if options have prices.
</Tip>
