---
title: "Exchange online license key for entitlement"
method: POST
path: "/api/v1/licenses/entitlement"
tags: ["internal"]
---

# Exchange online license key for entitlement

`POST /api/v1/licenses/entitlement`

## Request

- Base URL: `https://app.scanopy.net`
- URL: `https://app.scanopy.net/api/v1/licenses/entitlement`
- Auth: none declared

Called by self-hosted Scanopy servers. The key is the credential, so the
endpoint takes no session or API key. Every success records the check-in
and returns an entitlement minted from the organization's current plan and
paid-through date.

## Request body

- EntitlementRequest: Body the instance POSTs to [`ENTITLEMENT_PATH`].
  - `instance_id` string, uuid, nullable: The random id this server's database holds (`server_instance`), shared by every container on that database. Absent from servers older than instance counting; those share one instance slot.
  - `key` string, required: The online key configured via `SCANOPY_LICENSE_KEY`.
  - `non_production` boolean, nullable: Whether the server was started with `SCANOPY_NON_PRODUCTION`. Absent from servers older than the setting: they count as production, and the cloud never refuses them a slot.

## Response `200`

Entitlement for the key's organization

- ApiResponseEntitlementResponse: Envelope for a successful response. Failures are sent with a non-2xx status and an `ApiErrorResponse` body instead.
  - `data` object: Data returned inside `ApiResponse` by [`ENTITLEMENT_PATH`].
    - `entitlement` string, required: An offline-format license key (claims: [`super::types::LicenseClaims`]) with `org_id` and `plan` set from the organization's current state.
    - `instances` InstanceUsage: Server instances an online key has checked in from within the last `LICENSE_SILENCE_THRESHOLD_DAYS`, and how many the organization's licence covers (`None` when the plan has no cap), for production and non-production servers. A server past its class's limit is refused an entitlement.
      - `active` integer, required: Production servers.
      - `limit` integer, nullable: Production servers the key covers. `None` is no cap.
      - `non_production_active` integer, required: Servers started with `SCANOPY_NON_PRODUCTION`. Absent from clouds older than the setting.
      - `non_production_limit` integer, nullable, required: Non-production servers the key covers. `None` is no cap.
  - `error` string, nullable: Not sent on a successful response. Failure messages arrive in an `ApiErrorResponse`.
  - `meta` ApiMeta, required: API metadata included in all responses
    - `api_version` integer, required: API version (integer, increments on breaking changes)
    - `server_version` string, required: Server version (semver)
  - `success` boolean, required: Always `true` on a successful response.

## Other responses

- `400`: Malformed key, bad signature, or not an online key
- `403`: Key was regenerated, the organization is not on a self-hosted plan, or the key already runs on as many servers as the plan covers
- `429`: Too many requests for this organization

## Changes

- **2026-10-26** `c9d9d46d1ae8`: 1 info
  - api tag `billing` removed
- **2026-10-14** `29b77b6b0404`: 3 info
  - added the new optional request property `non_production`
  - added the required property `data/instances/oneOf[#/components/schemas/InstanceUsage]/non_production_active` to the response with the `200` status
  - added the required property `data/instances/oneOf[#/components/schemas/InstanceUsage]/non_production_limit` to the response with the `200` status
- **2026-10-14** `a68a9285f72d`: 2 breaking
  - the response property `data/instances/oneOf[#/components/schemas/InstanceUsage]/limit` became nullable for the status `200`
  - the response property `data/instances/oneOf[#/components/schemas/InstanceUsage]/limit` became optional for the status `200`
- **2026-10-14** `9461f5876538`: 2 info
  - added the new optional request property `instance_id`
  - added the optional property `data/instances` to the response with the `200` status
- **2026-09-24** `7ff37ad8c4cc`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/scanopy/apis/scanopy-api/changes/api/v1/licenses/entitlement/post.md)

---

[API](https://skmtc.dev/scanopy/apis/scanopy-api.md) - [All operations](https://skmtc.dev/scanopy/apis/scanopy-api/llms.txt) - [OpenAPI document](https://skmtc.dev/scanopy/apis/scanopy-api/revisions/966ba786bdb5?raw)
