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

# Authentication

> API key authentication, idempotency, and entity-level data scoping

## API Key Authentication

All requests require an API key passed as a bearer token in the `Authorization` header:

```bash theme={null}
curl 'https://api.sbx.moduluslabs.io/ecom/v1/checkout' \
  -H 'Authorization: Bearer sk_test_your_api_key_here'
```

API keys are provisioned during merchant onboarding. Contact your account manager to request keys.

| Environment | Key Prefix | Description                        |
| ----------- | ---------- | ---------------------------------- |
| Production  | `sk_live_` | Live transactions, real money      |
| Sandbox     | `sk_test_` | Test transactions, no real charges |

<Warning>
  Keep your API keys secret. Do not expose them in client-side code, public repositories, or browser applications. Requests without a valid key receive a `401 invalid_api_key` response.
</Warning>

## Entity Scoping

Every API key is scoped to an entity in the organization hierarchy. Data access is automatically restricted based on your key's level.

| Key Level    | Access                                       |
| ------------ | -------------------------------------------- |
| **Partner**  | All merchants and branches under the partner |
| **Merchant** | All branches under the merchant              |
| **Branch**   | Only that branch                             |

When you create a payment link, partner- and merchant-scoped keys must specify a `merchant_branch_reference_number`. Branch-scoped keys can omit it — the link is created against that branch automatically.

## Idempotency

The `Idempotency-Key` header is a unique client-generated identifier using letters, digits, dot (`.`), hyphen (`-`), and underscore (`_`), 8–64 characters. Clients often reuse their own `order_reference` as the key.

* `POST /checkout` (create a payment link) — **required**
* `POST /checkout/{id}/cancel` (cancel a payment link) — **optional**; cancel is idempotent by nature, so a key is accepted but not required

If you send the same idempotency key with the same request body, you receive the original response without creating a duplicate. If you send the same key with a **different** body, you receive a `409 idempotency_mismatch` error.

<Note>
  Idempotency keys expire after 24 hours. Generate a fresh key for each distinct operation.
</Note>

## Request headers

| Header            | Required                                                               | Description                                                                 |
| ----------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `Authorization`   | Always                                                                 | `Bearer sk_live_...` or `Bearer sk_test_...`                                |
| `Content-Type`    | `POST`, `PATCH`                                                        | `application/json`                                                          |
| `Idempotency-Key` | Required on `POST /checkout`; optional on `POST /checkout/{id}/cancel` | Unique client-generated ID. Letters, digits, `.`, `-`, `_`; 8–64 characters |

## Response headers

Every response includes:

| Header                  | Description                                                            |
| ----------------------- | ---------------------------------------------------------------------- |
| `x-correlation-id`      | Unique request identifier (UUID v4). Include this in support requests. |
| `X-RateLimit-Limit`     | Maximum requests allowed per minute for this endpoint                  |
| `X-RateLimit-Remaining` | Requests remaining in the current window                               |
| `X-RateLimit-Reset`     | Unix timestamp when the rate limit window resets                       |

## Rate limits

Requests are rate-limited per API key per endpoint.

| Endpoint                     | Limit               |
| ---------------------------- | ------------------- |
| `POST /checkout`             | 60 requests/minute  |
| `GET /checkout`              | 120 requests/minute |
| `GET /checkout/{id}`         | 120 requests/minute |
| `PATCH /checkout/{id}`       | 60 requests/minute  |
| `POST /checkout/{id}/cancel` | 60 requests/minute  |

When rate limited, the API returns a `429 rate_limited` response. Check the `Retry-After` header for the number of seconds to wait before retrying.
