> This page is for Partner API.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.getmodulate.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getmodulate.dev/_mcp/server.

# Authentication

The Modulate Partner API uses API key authentication. Include your key in every request using the `X-Partner-API-Key` header.

**`Example request`**

```bash title="Example request"
curl https://getmodulate.dev/api/partner/merchants \
  -H "X-Partner-API-Key: YOUR_API_KEY"
```

## Getting your API key

API keys are provisioned by the Aurora Payments team. To request one:

1. Log in to your [Partner Portal](https://withensemble.ai) account
2. Contact your account manager or email [it@flute.com](mailto:it@flute.com)
3. You'll receive your key via secure channel — store it somewhere safe

> **Warning**
>
> **Keep your API key private.** Do not embed it in client-side code or commit it to source control. Treat it like a password.

## Using your key

Pass your API key as a request header on every call:

```bash
X-Partner-API-Key: YOUR_API_KEY
```

#### cURL

```bash
curl https://getmodulate.dev/api/partner/merchants \
  -H "X-Partner-API-Key: YOUR_API_KEY"
```

#### Python

```python
import httpx

client = httpx.Client(
    base_url="https://getmodulate.dev",
    headers={"X-Partner-API-Key": "YOUR_API_KEY"},
)

merchants = client.get("/api/partner/merchants").json()
```

#### TypeScript

```typescript
const response = await fetch("https://getmodulate.dev/api/partner/merchants", {
  headers: {
    "X-Partner-API-Key": "YOUR_API_KEY",
  },
});

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

## Verifying your key

`GET /api/partner/me` returns the identity behind the key you just sent — your organization, the key's own prefix and environment, its scopes, and the per-minute limits that apply to it. It is the quickest way to confirm a new key works, and the only place to look up your `organization_id`.

**`Check which key you are using`**

```bash title="Check which key you are using"
curl https://getmodulate.dev/api/partner/me \
  -H "X-Partner-API-Key: YOUR_API_KEY"
```

**`Response`**

```json title="Response"
{
  "data": {
    "organization_id": "3f9a1c2e-5b7d-4e10-9c33-8ad2e6f10b44",
    "organization_name": "Example Payments",
    "key_id": "8c1d4f60-2e93-4a55-b7c1-0d9e3a5f2b18",
    "key_prefix": "pk_live_a1b2",
    "label": "Production - Main",
    "environment": "production",
    "scopes": ["partner:read"],
    "rate_limits": {
      "standard_per_minute": 120,
      "ai_per_minute": 5,
      "window_seconds": 60
    }
  },
  "meta": { "request_id": "req_abc123", "api_version": "v1" },
  "errors": []
}
```

> **Info**
>
> No endpoint asks you to supply your `organization_id` — every request is scoped automatically by the key you send. `/me` reports it for your own logging and support requests.

## Error responses

If authentication fails, you'll receive one of these responses:

| Status | Code                      | Meaning                                           |
| ------ | ------------------------- | ------------------------------------------------- |
| `401`  | `AUTHENTICATION_REQUIRED` | `X-Partner-API-Key` header is missing             |
| `401`  | `AUTHENTICATION_REQUIRED` | API key is invalid or has been revoked            |
| `403`  | `INSUFFICIENT_SCOPE`      | Key exists but lacks permission for this endpoint |

**`Example error response`**

```json title="Example error response"
{
  "error": {
    "code": "AUTHENTICATION_REQUIRED",
    "message": "Missing X-Partner-API-Key header",
    "request_id": "req_abc123"
  }
}
```

## Key scopes

API keys are scoped to control access. Currently available scope:

| Scope          | Access                                                                          |
| -------------- | ------------------------------------------------------------------------------- |
| `partner:read` | Full read access to merchants, pricing, transactions, statements, and residuals |

> **Info**
>
> Additional write scopes (e.g. merchant updates) are on the roadmap. Contact your account manager to discuss early access.

## Rotating your key

Partner admins and partner developers can manage keys themselves in the Ensemble portal at [withensemble.ai](https://withensemble.ai), under **API Keys**.

To rotate without downtime:

1. Choose **Rotate** on the key and pick a grace period: 1, 6, 24 or 48 hours.
2. Copy the new key. It is shown once and cannot be retrieved later.
3. Deploy the new key to your integration. Both keys work until the grace period ends.
4. When the grace period ends, the old key stops working and returns `401`.

Pick a grace period longer than the gap between your deploy and your next scheduled run. For a nightly job, 24 hours covers one full cycle.

**Usage & Limits** shows each key's current position against its limit (120 requests per rolling 60 seconds unless we have raised it), and **API Logs** lists your recent requests by `request_id`.

If you don't have portal access, email [it@flute.com](mailto:it@flute.com) and we will issue a second key so you can switch over before the old one is revoked.

If your key is compromised, revoke it in the portal right away (it stops working immediately), or contact [it@flute.com](mailto:it@flute.com).

## Key expiry

Keys have no fixed lifetime, but a key that goes unused is revoked automatically:

* A key with no authenticated request for **45 days** is revoked. A key that has never been used counts from the day it was created.
* **7 days before**, partner admins and partner developers in your organization get an email, and the key shows its expiry date under **API Keys**.
* Any request authenticated with the key resets the clock, whatever its response, so a key in regular use never expires.
* A revoked key cannot be restored. Create a new key in the portal if you still need access.

Keys are also revoked when your organization is deactivated, and reactivating the organization does not restore them.