> This page is for Gateway.

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

# Customers

> Create, look up, update, deactivate, and delete Customer objects, the end customers you scope Embedded Routing requests to.

A **Customer** represents one of your end customers. Create one per tenant, store its `id`, and send it as `customer` on requests, or skip storing anything and [address it by your own ID](#address-customers-by-your-own-id). Its policies, keys, and budget are separate sub-resources.

## Create a customer

`name` and `origin_id` are required, and `key_usage_default` is optional. `origin_id` is your identifier for the tenant, unique in your organization and immutable.

**`cURL`**

```bash title="cURL"
curl -X POST https://api-gateway.merge.dev/v1/customers \
  -H "Authorization: Bearer $MERGE_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Acme", "origin_id": "acme-corp", "key_usage_default": "PREFER_BYOK" }'
```

The response includes the `id`. A duplicate `origin_id` returns `409`.

## Address customers by your own ID

Send your `origin_id` in the `X-Merge-Customer-Origin-Id` header instead of the Customer's `id`. It works on every endpoint that accepts `customer` and needs no mapping table on your side.

**`cURL`**

```bash title="cURL"
curl https://api-gateway.merge.dev/v1/responses \
  -H "Authorization: Bearer $MERGE_GATEWAY_API_KEY" \
  -H "X-Merge-Customer-Origin-Id: acme-corp" \
  -H "Content-Type: application/json" \
  -d '{ "input": [{"type": "message", "role": "user", "content": "Hello"}] }'
```

If no customer has that `origin_id` yet, Gateway creates one with your organization's defaults (`name` set to the `origin_id`) and serves the request. Later requests reuse it. A deleted customer's `origin_id` stays blocked with `403` rather than being created again; create it explicitly with `POST /v1/customers` to reuse it.

To give the customer its own key by `origin_id`, see [Mint by your own ID](/merge-gateway/embedded-routing-stack/customer-api-keys#mint-by-your-own-id).

Sending both `customer` and the header is allowed only when they name the same customer. With a [customer API key](/merge-gateway/embedded-routing-stack/customer-api-keys), the header must name the key's own customer and never creates one.

## Sync customers in bulk

`PUT /v1/customers/batch` creates or updates up to 100 customers by `origin_id` in one call. Each item takes `origin_id` and optional `name` (defaults to the `origin_id` on create) and `key_usage_default`. Fields you omit are left unchanged on existing customers.

**`cURL`**

```bash title="cURL"
curl -X PUT https://api-gateway.merge.dev/v1/customers/batch \
  -H "Authorization: Bearer $MERGE_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "customers": [
        { "origin_id": "acme-corp", "name": "Acme" },
        { "origin_id": "globex", "key_usage_default": "BYOK_ONLY" }
      ] }'
```

```json
{
  "results": [
    { "origin_id": "acme-corp", "id": "9f8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d", "status": "created" },
    { "origin_id": "globex", "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "status": "updated" }
  ]
}
```

`status` is `created`, `updated`, `unchanged`, or `error`. Items are independent: an `error` item carries `error.status_code`, `error.code` (such as `customer_limit_reached` or `origin_id_conflict`), and `error.message`, and doesn't undo the others. A duplicate `origin_id` within one batch, an empty list, or more than 100 items returns `422`.

## Look up a customer

Resolve an `origin_id` with `GET /v1/customers?origin_id=acme-corp`, which returns the list envelope (`results`, `next`, `previous`) with the one match or empty `results`. Without the filter it lists every customer, paginated with `limit` and `cursor`. `GET /v1/customers/{customer_id}` returns one customer.

## Update, deactivate, or delete

`PATCH /v1/customers/{customer_id}` changes `name`, `key_usage_default`, or `status`. `INACTIVE` stops serving the customer's traffic but keeps its configuration; `ACTIVE` resumes.

**`cURL`**

```bash title="cURL"
curl -X PATCH https://api-gateway.merge.dev/v1/customers/{customer_id} \
  -H "Authorization: Bearer $MERGE_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "status": "INACTIVE" }'
```

`DELETE /v1/customers/{customer_id}` is permanent: it revokes the customer's API keys, policies, and vendor keys, and later requests naming its ID return `403` instead of falling back to your organization's defaults.

## Reference

| Field                                                | Type          | Description                                                                                                                                                                                        |
| ---------------------------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                                                 | UUID          | Send as `customer` on requests                                                                                                                                                                     |
| `origin_id`                                          | string        | Your ID for the customer, 1 to 255 characters, unique, can't be changed. Send it in `X-Merge-Customer-Origin-Id` to address the customer.                                                          |
| `name`                                               | string        | Display name, up to 255 characters                                                                                                                                                                 |
| `key_usage_default`                                  | enum          | `USE_ANY`, `PREFER_BYOK`, `BYOK_ONLY`, or `CUSTOMER_ONLY`. Unset inherits your organization's default. See [key usage modes](/merge-gateway/embedded-routing-stack/customer-keys#key-usage-modes). |
| `status`                                             | enum          | `ACTIVE` or `INACTIVE`. Requests for an inactive customer return `403`.                                                                                                                            |
| `routing_policies`, `budgets`, `byok_configurations` | list of UUIDs | IDs of the customer's sub-resources. Read each from its own endpoint.                                                                                                                              |
| `created_at`, `modified_at`                          | datetime      | Timestamps                                                                                                                                                                                         |

A [customer API key](/merge-gateway/embedded-routing-stack/customer-api-keys) can read its own customer and change only `name`; any other field returns `403` `customer_scoped_key_forbidden_field`.

An organization can have up to 100,000 customers. Creating one past that returns `409` `customer_limit_reached` from the customers API, and `403` `customer_limit_reached` when `X-Merge-Customer-Origin-Id` would create it.

## Next steps

#### [Routing policies](/merge-gateway/embedded-routing-stack/routing-policies)

Give the customer a default policy

#### [Customer keys](/merge-gateway/embedded-routing-stack/customer-keys)

Add the customer's own vendor credentials