# Get a customer's entitlements

> The customers.entitlements.get operation: GET /api/v1/customers/{id}/entitlements in the REST API and the customers_entitlements_get tool in the MCP server.

Returns what a customer of the brand may use, in the mode of the request: one value per feature of the brand
(`values`), where each value comes from (`sources`) and when it was resolved (`computedAt`).

Values are resolved from the customer's subscriptions (`active`, `trialing`, `past_due` during the grace
period, `paused` when the brand keeps entitlements during a pause), one-time purchases of products with
`lifetimeEntitlements`, overrides set by your team, and feature defaults, merged with each feature's combine
rule. A `perUnit` limit is multiplied by the quantity.

Ownrecord stores the result and recomputes it within one job cycle of every change; the
`customer.entitlements.updated` webhook says when it changed. A read never returns a set known to be out of
date: while a recompute is pending it resolves the values from the sources. Enforcing them is up to your
product. For one feature, `entitlements.check` is lighter.

## At a glance

- **REST:** `GET /api/v1/customers/{id}/entitlements`
- **MCP tool:** `customers_entitlements_get`
- **Operation ID:** `customers.entitlements.get`
- **Scope:** Brand
- **Permission:** `customers:read`
- **Risk tier:** `read`
- **Dry run:** Not supported
- **Idempotency:** Not needed (read only)
- **Modes:** Test and live
- **Authentication:** API key with the `customers:read` scope
- **Since:** M5

## Request

### Path parameters

| Field | Type       | Description                  |
| ----- | ---------- | ---------------------------- |
| `id`  | `cus_…` ID | The customer's ID (`cus_…`). |

### Query parameters

This operation takes no query parameters.

## Response

`200 OK` with a JSON object:

| Field                  | Type                                                     | Description                                                                                                                                                                                   |
| ---------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `object`               | `"customer_entitlements"`                                |                                                                                                                                                                                               |
| `customerId`           | `cus_…` ID                                               |                                                                                                                                                                                               |
| `brandId`              | `brd_…` ID                                               |                                                                                                                                                                                               |
| `livemode`             | boolean                                                  |                                                                                                                                                                                               |
| `values`               | object                                                   | One value per feature of the brand; defaults fill what nothing grants.                                                                                                                        |
| `sources`              | array of object                                          | Every source that granted a value, per feature in precedence order (overrides, subscriptions, purchases); the feature's combine rule merges them. A feature nothing grants lists its default. |
| `sources[].type`       | one of `override`, `subscription`, `purchase`, `default` |                                                                                                                                                                                               |
| `sources[].ref`        | string                                                   | The override (`ceo_…`), subscription (`sub_…`), payment of a lifetime purchase (`pay_…`) or, for a default, the feature (`feat_…`).                                                           |
| `sources[].featureKey` | string                                                   |                                                                                                                                                                                               |
| `sources[].value`      | boolean or number or string                              | What this source grants (per-unit limits already multiplied by the quantity).                                                                                                                 |
| `computedAt`           | date-time                                                | When the values were resolved.                                                                                                                                                                |

## Examples

### A subscriber with an override

Three seats of a plan granting 5 seats per unit (15), raised to 20 by an override (`seats.max` combines with `max`); `support.level` has its default.

```http
GET /api/v1/customers/cus_01m4ty3c2b5qx7mhd9k8w6s0aa/entitlements
Authorization: Bearer or_test_…
```

Response (`200`):

```json
{
  "object": "customer_entitlements",
  "customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0aa",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "livemode": false,
  "values": {
    "feature.export": true,
    "seats.max": 20,
    "support.level": "community"
  },
  "sources": [
    {
      "type": "subscription",
      "ref": "sub_01m4ty3c2b5qx7mhd9k8w6s0b0",
      "featureKey": "feature.export",
      "value": true
    },
    {
      "type": "override",
      "ref": "ceo_01m4ty3c2b5qx7mhd9k8w6s0b2",
      "featureKey": "seats.max",
      "value": 20
    },
    {
      "type": "subscription",
      "ref": "sub_01m4ty3c2b5qx7mhd9k8w6s0b0",
      "featureKey": "seats.max",
      "value": 15
    },
    {
      "type": "default",
      "ref": "feat_01m4tx5nj8emwbyf7y9vcf47y8",
      "featureKey": "support.level",
      "value": "community"
    }
  ],
  "computedAt": "2026-10-14T10:00:05.000Z"
}
```

### A lifetime purchase

```http
GET /api/v1/customers/cus_01m4ty3c2b5qx7mhd9k8w6s0ab/entitlements
Authorization: Bearer or_test_…
```

Response (`200`):

```json
{
  "object": "customer_entitlements",
  "customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0ab",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "livemode": false,
  "values": {
    "feature.export": true,
    "seats.max": 1,
    "support.level": "community"
  },
  "sources": [
    {
      "type": "purchase",
      "ref": "pay_01m4ty3c2b5qx7mhd9k8w6s0b1",
      "featureKey": "feature.export",
      "value": true
    },
    {
      "type": "default",
      "ref": "feat_01m4tx5nj8emwbyf7y9vcf47y6",
      "featureKey": "seats.max",
      "value": 1
    },
    {
      "type": "default",
      "ref": "feat_01m4tx5nj8emwbyf7y9vcf47y8",
      "featureKey": "support.level",
      "value": "community"
    }
  ],
  "computedAt": "2026-10-14T10:00:05.000Z"
}
```

## Errors

| Code                                                                                         | HTTP status | When                                                                                       | What to do                                                                                                                                         |
| -------------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed)       | 400         | `id` isn't a customer ID (`cus_…`).                                                        | Fix the fields listed in `details.issues` and send the request again.                                                                              |
| [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found)     | 404         | This brand has no such customer in this mode (customers belong to one brand and one mode). | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.                                               |
| [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required)             | 400         | The request names no brand (an org or entity key without `Ownrecord-Brand`).               | Call the operation with credentials or a target at its level: an organization, a legal entity, a brand or the platform (`details.required_scope`). |
| [`livemode_not_allowed`](https://ownrecord.io/docs/reference/errors.md#livemode_not_allowed) | 403         | You have no live-mode access, so you can't act on live customers.                          | Use test mode, or credentials for the target's mode. Developers need live access granted by an organization owner or admin.                        |
| [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied)       | 403         | You can't read this brand's customers (`customers:read`).                                  | Ask an organization owner or admin for a role or scope that allows this action.                                                                    |

It can also return these [common errors](https://ownrecord.io/docs/reference.md#common-errors): [`api_version_unsupported`](https://ownrecord.io/docs/reference/errors.md#api_version_unsupported), [`authentication_required`](https://ownrecord.io/docs/reference/errors.md#authentication_required), [`api_key_invalid`](https://ownrecord.io/docs/reference/errors.md#api_key_invalid), [`dry_run_not_supported`](https://ownrecord.io/docs/reference/errors.md#dry_run_not_supported), [`rate_limited`](https://ownrecord.io/docs/reference/errors.md#rate_limited), [`internal_error`](https://ownrecord.io/docs/reference/errors.md#internal_error).
