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

# Digital Product Cart Checkout

> Multi-item cart checkout for digital products, gift cards, and downloadable content

# Digital Product Cart Checkout

Sell multiple digital products in a single checkout. No shipping, no address collection, instant fulfillment.

<Info>
  **Supported Product Types:** `digital`, `gift_card`, `others`

  These product types share a simplified checkout flow - no cart validation step, no shipping address required.
</Info>

***

## Quick Start

### 1. Build Your Payload

```json theme={null}
{
  "product_type": "digital",
  "product_title": "Design Assets Bundle",
  "order_total_charge": 4500,
  "cart": [
    {
      "product_id": 3553,
      "quantity": 1,
      "price": 2000,
      "product_image": "",
      "has_variation": false,
      "product_variant_data": "none"
    },
    {
      "product_id": 3570,
      "quantity": 1,
      "price": 2500,
      "product_image": "",
      "has_variation": false,
      "product_variant_data": "none"
    }
  ],
  "email": "customer@example.com",
  "first_name": "John",
  "last_name": "Doe",
  "currency": "USD",
  "payment_type": "one",
  "is_coupon_used": false,
  "is_second_time_payment": false,
  "payment_by": "customer"
}
```

### 2. Call Payment Intent API

```bash theme={null}
curl -X POST https://api.khaime.com/api/v1/payment/intent \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ ... payload above ... }'
```

### 3. Use the Token

```json theme={null}
{
  "status": true,
  "message": "Payment Intent Successful",
  "data": {
    "token": "eyJtZXJjaGFudF9pZCI6MTc5MCwi...",
    "amount": 4500,
    "currency": "USD",
    "cart_identifier": "digital-1234567890-abc123"
  }
}
```

Pass `token` to `<KhaimeCheckout />` - payment gateway is handled automatically.

***

## How It Works

```
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  Your Frontend  │────▶│  Your Backend   │────▶│   Khaime API    │
│                 │     │                 │     │                 │
│  Cart Items     │     │  POST /checkout │     │  POST /payment  │
│  + Customer     │     │  (your route)   │     │  /intent        │
└─────────────────┘     └─────────────────┘     └─────────────────┘
                                                        │
                                                        ▼
                              ┌─────────────────────────────────────┐
                              │  Returns token with gateway config  │
                              │  (Stripe, Paystack, StartButton)    │
                              └─────────────────────────────────────┘
                                                        │
                                                        ▼
                        ┌─────────────────────────────────────────────┐
                        │  <KhaimeCheckout token={token} />           │
                        │  Renders correct payment UI automatically   │
                        └─────────────────────────────────────────────┘
```

**Key points:**

* Your backend calls Khaime API and gets a `token`
* Token contains everything needed for payment (gateway, keys, amount)
* Your code never touches Stripe/Paystack/etc directly
* Gateway is selected automatically based on currency

***

## Request Reference

### Top-Level Fields

| Field                    | Type    | Required | Description                                         |
| ------------------------ | ------- | -------- | --------------------------------------------------- |
| `product_type`           | string  | Yes      | `"digital"`, `"gift_card"`, or `"others"`           |
| `product_title`          | string  | Yes      | Display name (e.g., `"Cart (3 items)"`)             |
| `order_total_charge`     | number  | Yes      | Total in cents (sum of price × quantity)            |
| `cart`                   | array   | Yes      | Array of cart items                                 |
| `email`                  | string  | Yes      | Customer email                                      |
| `first_name`             | string  | Yes      | Customer first name                                 |
| `last_name`              | string  | Yes      | Customer last name                                  |
| `currency`               | string  | Yes      | ISO currency code (`"USD"`, `"NGN"`, `"GHS"`, etc.) |
| `payment_type`           | string  | Yes      | Must be `"one"` for cart checkout                   |
| `is_coupon_used`         | boolean | Yes      | Set `false` if no coupon                            |
| `is_second_time_payment` | boolean | Yes      | Set `false` for new purchases                       |
| `payment_by`             | string  | Yes      | Must be `"customer"`                                |

### Cart Item Fields

| Field                    | Type    | Required | Description                        |
| ------------------------ | ------- | -------- | ---------------------------------- |
| `product_id`             | number  | Yes      | Khaime product ID                  |
| `quantity`               | number  | Yes      | Number of units                    |
| `price`                  | number  | Yes      | Per-unit price in **cents**        |
| `product_image`          | string  | Yes      | Image URL or empty string `""`     |
| `has_variation`          | boolean | Yes      | Set `false` for standard products  |
| `product_variant_data`   | string  | Yes      | Set `"none"` for standard products |
| `additional_information` | object  | No       | Custom form fields (see below)     |

<Warning>
  **Digital cart items use a SIMPLER schema than physical products.**

  Do NOT include: `product_title`, `product_thumbnail`, `main_variant`, `least_sub_variant_id`, `shipping_rate`
</Warning>

***

## Currency & Gateway Routing

Khaime automatically selects the payment gateway based on currency:

| Currency           | Gateway        | Payment UI         |
| ------------------ | -------------- | ------------------ |
| USD, EUR, GBP, CAD | Stripe         | Embedded card form |
| NGN                | Paystack       | Popup / redirect   |
| GHS                | StartButton    | Redirect           |
| KES                | Paystack Kenya | Popup / redirect   |
| ZAR                | Paystack       | Popup / redirect   |

Your code doesn't need to know about gateways - just pass the currency and Khaime handles the rest.

***

## Complete Examples

### USD Checkout (Stripe)

```json theme={null}
{
  "product_type": "digital",
  "product_title": "Premium Template Pack",
  "order_total_charge": 4900,
  "cart": [
    {
      "product_id": 1001,
      "quantity": 1,
      "price": 2900,
      "product_image": "https://example.com/template1.jpg",
      "has_variation": false,
      "product_variant_data": "none"
    },
    {
      "product_id": 1002,
      "quantity": 1,
      "price": 2000,
      "product_image": "https://example.com/template2.jpg",
      "has_variation": false,
      "product_variant_data": "none"
    }
  ],
  "email": "buyer@example.com",
  "first_name": "Sarah",
  "last_name": "Connor",
  "currency": "USD",
  "payment_type": "one",
  "is_coupon_used": false,
  "is_second_time_payment": false,
  "payment_by": "customer"
}
```

### NGN Checkout (Paystack)

```json theme={null}
{
  "product_type": "digital",
  "product_title": "E-book Collection",
  "order_total_charge": 1500000,
  "cart": [
    {
      "product_id": 2001,
      "quantity": 1,
      "price": 500000,
      "product_image": "",
      "has_variation": false,
      "product_variant_data": "none"
    },
    {
      "product_id": 2002,
      "quantity": 2,
      "price": 500000,
      "product_image": "",
      "has_variation": false,
      "product_variant_data": "none"
    }
  ],
  "email": "buyer@example.ng",
  "first_name": "Chidi",
  "last_name": "Okonkwo",
  "currency": "NGN",
  "payment_type": "one",
  "is_coupon_used": false,
  "is_second_time_payment": false,
  "payment_by": "customer"
}
```

### Gift Cards with Recipient Info

```json theme={null}
{
  "product_type": "gift_card",
  "product_title": "Gift Cards (2)",
  "order_total_charge": 10000,
  "cart": [
    {
      "product_id": 5001,
      "quantity": 1,
      "price": 5000,
      "product_image": "",
      "has_variation": false,
      "product_variant_data": "none",
      "additional_information": {
        "recipient_name": "John Smith",
        "recipient_email": "john@example.com",
        "gift_message": "Happy Birthday!"
      }
    },
    {
      "product_id": 5001,
      "quantity": 1,
      "price": 5000,
      "product_image": "",
      "has_variation": false,
      "product_variant_data": "none",
      "additional_information": {
        "recipient_name": "Jane Doe",
        "recipient_email": "jane@example.com",
        "gift_message": "Congratulations!"
      }
    }
  ],
  "email": "purchaser@example.com",
  "first_name": "Mike",
  "last_name": "Wilson",
  "currency": "USD",
  "payment_type": "one",
  "is_coupon_used": false,
  "is_second_time_payment": false,
  "payment_by": "customer"
}
```

***

## Merchant Backend Example

Your backend receives cart data from your frontend, transforms it to Khaime format, and returns the token.

### Next.js API Route

```typescript theme={null}
// app/api/checkout/route.ts
import { NextResponse } from 'next/server';

const KHAIME_API_KEY = process.env.KHAIME_API_KEY;
const KHAIME_API_URL = 'https://api.khaime.com/api/v1';

export async function POST(request: Request) {
  const body = await request.json();
  const { items, currency, email, firstName, lastName } = body;

  // Transform to Khaime format
  const cart = items.map((item: any) => ({
    product_id: Number(item.productId),
    quantity: item.quantity,
    price: item.price,
    product_image: item.productImage || '',
    has_variation: false,
    product_variant_data: 'none',
  }));

  const totalAmount = items.reduce(
    (sum: number, item: any) => sum + item.price * item.quantity,
    0
  );

  const productTitle = items.length === 1
    ? items[0].productTitle
    : `Cart (${items.length} items)`;

  // Call Khaime API
  const response = await fetch(`${KHAIME_API_URL}/payment/intent`, {
    method: 'POST',
    headers: {
      'X-API-Key': KHAIME_API_KEY!,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      product_type: 'digital',
      product_title: productTitle,
      order_total_charge: totalAmount,
      cart,
      email,
      first_name: firstName,
      last_name: lastName,
      currency,
      payment_type: 'one',
      is_coupon_used: false,
      is_second_time_payment: false,
      payment_by: 'customer',
    }),
  });

  const data = await response.json();

  if (!data.status) {
    return NextResponse.json(
      { ok: false, error: data.message },
      { status: 400 }
    );
  }

  // Return token to frontend
  return NextResponse.json({
    ok: true,
    data: {
      token: data.data.token,
      amount: data.data.amount,
      currency: data.data.currency,
    },
  });
}
```

### Frontend Component

```tsx theme={null}
import { useState } from 'react';
import { KhaimeCheckout } from '@khaime/react';

interface CartItem {
  productId: number;
  productTitle: string;
  productImage: string;
  price: number;
  quantity: number;
}

export function DigitalCheckout({ items, currency }: {
  items: CartItem[];
  currency: string;
}) {
  const [token, setToken] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);

  const handleCheckout = async () => {
    setLoading(true);

    const response = await fetch('/api/checkout', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        items,
        currency,
        email: 'customer@example.com',
        firstName: 'John',
        lastName: 'Doe',
      }),
    });

    const result = await response.json();
    setLoading(false);

    if (result.ok) {
      setToken(result.data.token);
    }
  };

  if (token) {
    return (
      <KhaimeCheckout
        token={token}
        onSuccess={(result) => {
          console.log('Payment successful!', result);
          window.location.href = '/success';
        }}
        onError={(error) => {
          console.error('Payment failed:', error);
          setToken(null);
        }}
        onClose={() => setToken(null)}
      />
    );
  }

  return (
    <button onClick={handleCheckout} disabled={loading}>
      {loading ? 'Processing...' : `Pay Now`}
    </button>
  );
}
```

***

## Response Structure

### Success Response

```json theme={null}
{
  "status": true,
  "message": "Payment Intent Successful",
  "data": {
    "token": "eyJtZXJjaGFudF9pZCI6MTc5MCwicGF5bWVudF9nYXRld2F5Ijoic3RyaXBlIi...",
    "cart_identifier": "digital-1788636780073-tcvplc8s0",
    "amount": 4500,
    "currency": "USD"
  }
}
```

### Token Security

The token is **signed with HMAC-SHA256** and **expires after 15 minutes**.

Format: `base64(payload).signature`

```json theme={null}
{
  "merchant_id": 1790,
  "payment_gateway": "stripe",
  "publishable_key": "pk_test_...",
  "client_secret": "pi_xxx_secret_xxx",
  "amount": 4500,
  "currency": "USD",
  "payment_type": "one_time",
  "iat": 1699900000,
  "exp": 1699900900,
  "metadata": {
    "stripe_account_id": "acct_xxx",
    "is_direct_charge": true
  },
  "product": {
    "name": "Design Assets Bundle",
    "type": "digital",
    "currency": "USD"
  }
}
```

<Note>
  You don't need to decode the token - just pass it to `<KhaimeCheckout />` and it handles everything.

  **Important:** Tokens expire after 15 minutes. If a customer waits too long, create a new payment intent.
</Note>

***

## After Payment

### Order Structure

After successful payment, the Order contains all cart items:

```json theme={null}
{
  "id": 91234,
  "status": "completed",
  "payment_status": "paid",
  "cart_items": {
    "cart_details": [
      {
        "product_id": 1001,
        "quantity": 1,
        "price": 2900,
        "product_title": "Premium Template",
        "product_type": "digital",
        "downloadable_links": [
          {
            "name": "template.zip",
            "url": "https://storage.example.com/signed-url"
          }
        ]
      }
    ]
  },
  "cart_item_identifier": "digital-1788636780073-tcvplc8s0"
}
```

### Customer Receives

* Confirmation email with all purchased items
* Download links for each digital product
* Order accessible in their account

***

## Pricing

### All Amounts in Cents

| Display Price | API Value | Currency |
| ------------- | --------- | -------- |
| \$15.00       | `1500`    | USD      |
| \$149.99      | `14999`   | USD      |
| N15,000.00    | `1500000` | NGN      |
| GH₵100.00     | `10000`   | GHS      |

### Total Calculation

```
line_total = price × quantity
cart_total = sum(all line_totals)
final_charge = cart_total + platform_fees
```

***

## vs Physical Products

| Aspect             | Physical Products           | Digital Products |
| ------------------ | --------------------------- | ---------------- |
| Cart validation    | Required (`/cart/validate`) | **Not required** |
| `cart_unique_id`   | Required                    | Auto-generated   |
| Shipping address   | Required                    | **Not required** |
| `delivery_details` | Required                    | **Not required** |
| Shipping fees      | Calculated                  | None             |
| Fulfillment        | Manual shipping             | Instant download |

***

## Error Codes

| Code                     | Description            | Fix                    |
| ------------------------ | ---------------------- | ---------------------- |
| `VALIDATION_ERROR`       | Missing/invalid fields | Check required fields  |
| `PRODUCT_NOT_FOUND`      | Invalid `product_id`   | Verify product exists  |
| `PAYMENT_INTENT_FAILED`  | Gateway error          | Check API keys/config  |
| `CURRENCY_NOT_SUPPORTED` | Unsupported currency   | Use supported currency |

***

## Related

<CardGroup cols={2}>
  <Card title="Physical Product Checkout" icon="truck" href="/api-reference/checkout-integration-guide">
    Checkout with shipping and cart validation
  </Card>

  <Card title="Payment Intent API" icon="credit-card" href="/api-reference/commerce/payment-intent">
    Full API reference
  </Card>

  <Card title="React SDK" icon="react" href="/sdks/react/overview">
    `<KhaimeCheckout />` component
  </Card>

  <Card title="Webhooks" icon="webhook" href="/webhooks/overview">
    Payment event notifications
  </Card>
</CardGroup>
