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

# What you have promised this customer

> Requires `billing:read`. Every override on this customer, **expired ones included** — which is deliberately not the same question as what they are entitled to. That read applies expiry and this one does not: "they had unlimited seats until March" is a question support gets asked, and a list that hid the answer would be a list that only knows the present.

`expired` says which are still in force.



## OpenAPI

````yaml /api-reference/openapi.json get /v1/organization/customers/{id}/entitlement-overrides
openapi: 3.1.0
info:
  title: UserKit API
  version: 1.0.0
  description: >-
    The HTTP surface of UserKit.


    Two planes share one API. The **staff plane** is what a human uses in the
    panel: users, organizations, roles, members, keys. The **customer plane** is
    what a developer's own product uses: contacts, identities, hosted or
    federated sign-in.


    Every error answers the same envelope — `{"error": {"code", "message"}}`.
    The `code` is a stable contract to branch on; the `message` is for a person
    and may change.
servers:
  - url: '{baseUrl}'
    description: The API host.
    variables:
      baseUrl:
        default: https://api.userkit.dev
        description: Base URL of the API, no trailing slash.
security:
  - sessionToken: []
tags:
  - name: Authentication
    description: >-
      Public sign-up, sign-in, two-factor and password recovery for staff
      accounts.
  - name: Session
    description: >-
      The active session: who the caller is, which organization they are in, and
      signing out.
  - name: Account
    description: The caller's own account — profile, password, sessions, avatar.
  - name: Two-factor
    description: >-
      TOTP setup, activation and recovery codes. Returns 501 when two-factor is
      unavailable on the server.
  - name: Organizations
    description: The organizations a user belongs to, and the active one.
  - name: Environments
    description: >-
      The live and test environments seeded with every organization, and their
      identity settings.
  - name: Members
    description: Memberships and invitations.
  - name: Roles
    description: Roles and the permission catalogue they draw from.
  - name: Audit log
    description: >-
      What staff did inside an organization. Append-only, and read behind its
      own permission.
  - name: API keys
    description: Secret keys (`uk_sk_…`) and publishable keys (`uk_pk_…`).
  - name: Contacts (staff session)
    description: >-
      The staff view of the customer plane, opened by a staff session. Reads
      take `?environment=` as an explicit view parameter.
  - name: Contacts (API key)
    description: >-
      The machine surface, authenticated by an API key. The environment is the
      key's environment and cannot be named by the caller.
  - name: Customer plane
    description: >-
      Called from the developer's own pages with a publishable key: boot, magic
      link, and the contact's own session.
  - name: Hosted auth
    description: >-
      Sign-up, sign-in, verification and recovery for contacts, when UserKit
      owns the account.
  - name: Customer teams
    description: >-
      A customer is a team. Its roster, its invitations and its two roles —
      owner and member — administered by the contact's own session. The active
      customer travels in `X-Customer-Id`.
  - name: Webhooks
    description: >-
      Outbound webhooks: endpoints, the published event catalogue, the delivery
      log, replay and test sends. Never gated by a plan — webhooks are a
      developer primitive.
  - name: Catalogue
    description: >-
      The plans, prices and features **you** sell to your own customers. Per
      environment, a price per currency, and `recurring` or `one_time`. Distinct
      from the plan you are on with UserKit, which is `GET
      /v1/organization/entitlements`.
  - name: Subscriptions
    description: >-
      What one of **your** customers is paying you, mirrored from the gateway
      that charges them. The gateway is the truth about money — it holds the
      schedule, runs the retries and decides what a proration is worth — so
      these routes ask it to change something and answer with what it then said.
      `provider_synced_at` is how stale the copy admits to being.
  - name: Provider webhooks
    description: >-
      Where a payment provider delivers to. Not a surface you call — it is a URL
      you paste into the provider's dashboard, which is why it sits outside
      `/v1`: a version bump must never mean editing a setting in somebody else's
      product. Signed with the secret of the connection named in the path, and
      safe to retry.
  - name: Entitlements
    description: >-
      What one of **your** customers may do, resolved: the plan their
      subscription carries, plus the overrides you promised them on top. This is
      the read your own gate calls, so it is cached and answers in one round
      trip. It is a different question from `GET /v1/organization/entitlements`,
      which is the plan **you** are on with UserKit — two catalogues, same word,
      different money.
paths:
  /v1/organization/customers/{id}/entitlement-overrides:
    get:
      tags:
        - Entitlements
      summary: What you have promised this customer
      description: >-
        Requires `billing:read`. Every override on this customer, **expired ones
        included** — which is deliberately not the same question as what they
        are entitled to. That read applies expiry and this one does not: "they
        had unlimited seats until March" is a question support gets asked, and a
        list that hid the answer would be a list that only knows the present.


        `expired` says which are still in force.
      operationId: listCustomerEntitlementOverrides
      parameters:
        - $ref: '#/components/parameters/OrganizationHeader'
        - $ref: '#/components/parameters/EnvironmentQuery'
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The customer.
      responses:
        '200':
          description: The overrides, by feature key.
          content:
            application/json:
              schema:
                type: object
                properties:
                  overrides:
                    type: array
                    items:
                      $ref: '#/components/schemas/EntitlementOverride'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  parameters:
    OrganizationHeader:
      name: X-Organization-Id
      in: header
      required: false
      schema:
        type: string
      description: >-
        The organization the caller is acting on — the `org_…` code that appears
        in the panel URL. It *identifies*; the membership JOIN is what
        *authorizes*, so a forged code reads nothing. Absent, the session's
        default organization answers.
    EnvironmentQuery:
      name: environment
      in: query
      required: false
      schema:
        type: string
        enum:
          - live
          - test
        default: live
      description: >-
        Which environment to act in. A view parameter, valid only on the staff
        surface — a machine credential never chooses its environment, it is
        resolved from the key.
  schemas:
    EntitlementOverride:
      type: object
      description: >-
        A promise made to one customer on top of their plan — "we agreed to give
        this account unlimited seats" — or one made against it: `"enabled":
        false` withholds a feature the plan carries.


        It REPLACES the plan's answer for that feature and never adds to it. Not
        a maximum: a downward override is as real as an upward one, and a merge
        rule that could only grant more would refuse half of its own use cases.
        Additive grants are a credit top-up, which is a ledger rather than this.
      properties:
        customer_id:
          type: string
          format: uuid
        feature_id:
          type: string
          format: uuid
        feature_key:
          type: string
        feature_name:
          type: string
          description: >-
            The feature's display name, so a list of overrides reads as
            sentences rather than as keys.
        unit_name:
          type: string
          description: >-
            What one unit of the feature is called. Empty on a `boolean`
            feature.
        feature_kind:
          type: string
          enum:
            - boolean
            - metered
            - credit
          description: >-
            Taken from the feature rather than from the request, so it cannot
            disagree with it.
        enabled:
          type: boolean
          description: >-
            Whether this override grants the feature or withholds it. Removing
            the override is a different act from withholding it: removing hands
            the feature back to whatever the plan says.
        limit:
          type:
            - integer
            - 'null'
          format: int64
          description: >-
            The ceiling this customer gets instead of the plan's, on a `metered`
            feature. `-1` is unlimited; `0` is a real limit — none at all.
        included_quantity:
          type:
            - integer
            - 'null'
          format: int64
          description: >-
            The credits this customer is granted per period instead of the
            plan's.
        note:
          type: string
          description: >-
            What was agreed. Required and never blank: an override outlives the
            conversation, the deal and frequently the person who made it, and a
            row nobody can explain is a row nobody dares remove.
          example: >-
            Migration deal, agreed with Ana on the 12th — unlimited seats
            through Q1.
        expires_at:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            When the promise runs out; `null` when it does not. An expired
            override stops applying on its own and the row is kept, so "they had
            unlimited seats until March" is still answerable.
        expired:
          type: boolean
          description: >-
            Whether `expires_at` has passed, stated rather than left to your
            clock — resolution compares against the server's.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    Error:
      type: object
      description: Every error in this API answers this envelope.
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: Stable. Branch on this.
            message:
              type: string
              description: For a person. May change.
          required:
            - code
            - message
      required:
        - error
      example:
        error:
          code: forbidden
          message: your role does not allow this action
  responses:
    Unauthorized:
      description: >-
        `unauthorized` — missing, malformed or expired credential. A well-formed
        credential from the wrong family says so: "this endpoint expects a staff
        session token, not an organization API key".
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: '`forbidden` — your role does not allow this action.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: >-
        `not_found`. Also the answer for a resource that exists in another
        organization or environment — the 404 never reveals which.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    sessionToken:
      type: http
      scheme: bearer
      description: >-
        A staff session token, `uk_st_…`. Minted by sign-up, sign-in or the
        two-factor exchange.

````