Subscription API

Use the Subscription API to assign or remove developer seats, record service access, and grant or revoke analytics permissions from your own tools. These operations manage access within your organization's subscription. Purchasing seats, changing a plan, and cancelling a subscription are handled in the dashboard.

Base URL

https://platform.codity.ai/api/dashboard/subscription

The dashboard API host also accepts https://dashboard-api.codity.ai/api/subscription. Both base URLs reach the same operations. For example, append /seats/assign to either base URL to assign a seat.

Subscription operations return their result immediately as JSON. They do not return a job_id or require polling. The /v1 review and scan API has a separate base URL and request flow; see API Overview.

Enable API access

  1. Sign in to the dashboard as an organization admin and select the organization you want to manage.
  2. Open API Access and create a key, or select an existing active key.
  3. Find Subscription management in the key's details and click Enable. This permission is disabled by default for new keys.
  4. Store the key in an environment variable or your secret manager.

Send the key in X-API-Key or Authorization: Bearer. The examples use X-API-Key:

: "${CODITY_API_KEY:?Set CODITY_API_KEY to your organization API key}"
export CODITY_SUBSCRIPTION_API='https://platform.codity.ai/api/dashboard/subscription'

The key can manage only accounts linked to its own subscription organization. Supply the matching provider, account ID, and account login in every request. Creating a key does not connect a new VCS account; connect it in the dashboard first. See Connecting Your VCS.

A missing, invalid, revoked, or subscription-management-disabled key returns 401. A key targeting another organization returns 403.

Endpoints

All paths below are relative to the Subscription API base URL. All seven endpoints accept POST with Content-Type: application/json and the enabled API key.

Path Operation Defaults
/seats/assign Add or reactivate a developer seat. Sets action to add; service defaults to code_review.
/seats/revoke Deactivate a developer seat. Sets action to remove; service defaults to code_review.
/seats/action Add, remove, or record service access. Requires both action and service.
/seats/grant-permission Grant analytics access. permission defaults to analytics.
/seats/revoke-permission Revoke analytics access. permission defaults to analytics.
/analytics/grant Shortcut for granting analytics access. Sets permission to analytics.
/analytics/revoke Shortcut for revoking analytics access. Sets permission to analytics.

Request fields

Every endpoint needs provider, org, and developer. Send IDs as strings, even when the provider uses numeric IDs. The examples use fictional GitHub identities; replace them with the account and developer you want to manage.

Field Type Required Meaning
provider string Yes Provider for the linked account. Accepted values: github, gitlab, gitlab_self_hosted, azure, bitbucket, cli, codity.
org.accountExternalId string Yes Account ID from the provider, rather than Codity's internal subscription ID.
org.accountLogin string Yes Login, group path, organization name, or workspace slug for that same linked account.
org.accountType string Yes user, organization, group, or workspace, matching the account.
developer.externalId string Yes Developer's stable provider identity. See the identity guidance below.
developer.login string Yes Developer's login or username.
developer.email string or null No Developer's email. For Azure, supply the email/UPN used by the developer's Codity account.
action string On /seats/action add, remove, or touch. Assignment and revocation shortcuts set this for you.
service string On /seats/action code_review, dashboard, or analytics. Assignment and revocation shortcuts default to code_review.
requestId string No Unique identifier for a seat operation, used when retrying that operation. Applies to the three seat action endpoints.
metadata object No Additional context for a seat operation. Applies to the three seat action endpoints.
permission string No Only analytics is supported. Applies to permission endpoints.

The acting identity in the audit log comes from the API key. You do not need to send an actor field.

Provider identities

  • GitHub and GitLab: Use the numeric developer user ID encoded as a string, such as "67890". Use the organization or group ID for org.accountExternalId.
  • Azure DevOps: Use the developer's lowercased email/UPN as developer.externalId and supply the matching developer.email. This keeps API actions aligned with seats assigned through sign-in and reviews.
  • Bitbucket, CLI, and Codity accounts: Use the same stable developer ID already associated with the account's Codity seat, rather than substituting a display name.

Assign a seat

The following examples use Bash, curl, and jq. Define the shared identity payload once:

SEAT_PAYLOAD='{
  "provider": "github",
  "org": {
    "accountExternalId": "12345",
    "accountLogin": "acme-corp",
    "accountType": "organization"
  },
  "developer": {
    "externalId": "67890",
    "login": "alex-example"
  }
}'

curl --fail-with-body -sS -X POST "$CODITY_SUBSCRIPTION_API/seats/assign" \
  -H "X-API-Key: $CODITY_API_KEY" \
  -H 'Content-Type: application/json' \
  --data-binary "$SEAT_PAYLOAD"

This creates or reactivates a manual seat. Assigning an already active developer updates that seat without consuming an additional slot. An active subscription at its seat limit returns 409; increase the purchased seat count in the dashboard or free an existing seat before trying again. Assigning a developer does not purchase additional seats or start a code review.

Example 200 OK response:

{
  "status": "success",
  "result": "manual_add",
  "entitlementId": "550e8400-e29b-41d4-a716-446655440000",
  "provider": "github",
  "seat": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "isActive": true,
    "firstAccessAt": "2026-10-23T16:30:00.000Z",
    "firstAccessService": "code_review",
    "lastAccessAt": "2026-10-23T16:30:00.000Z",
    "lastAccessService": "code_review",
    "accessCount": 1,
    "provider": "github",
    "developerExternalId": "67890",
    "developerLogin": "alex-example",
    "developerEmail": null,
    "seatSource": "manual",
    "removedAt": null,
    "removedBy": null,
    "accessLevel": 1
  },
  "usage": {
    "purchasedSeats": 10,
    "usedSeats": 4,
    "remainingSeats": 6
  },
  "subscriptionStatus": "active",
  "trialDaysRemaining": null,
  "planId": null
}

The example values are illustrative. usage reports seat counts across the subscription, and remainingSeats never falls below zero. It is separate from the monthly review, scan, and navigation pools. entitlementId identifies the subscription entitlement; planId and trialDaysRemaining can be null. A seat can also be null, for example when removing a developer who has no seat.

Remove a seat

Using the same identity payload:

curl --fail-with-body -sS -X POST "$CODITY_SUBSCRIPTION_API/seats/revoke" \
  -H "X-API-Key: $CODITY_API_KEY" \
  -H 'Content-Type: application/json' \
  --data-binary "$SEAT_PAYLOAD"

Success returns 200 with result: "manual_remove". An active seat becomes inactive and the used-seat count decreases. Removing an already inactive or nonexistent seat also succeeds without reducing the count again. Removal remains available when the subscription is expired, cancelled, or suspended.

Removing a seat frees access capacity; it does not reduce your purchased seat count or change billing. Future service activity may reactivate the seat if access is allowed. See Managing Seats.

Record service access

Use /seats/action when an integration needs the consolidated action interface. touch records access and may create or reactivate an automatic seat if allowed; it is a write operation, rather than a read-only permission check.

jq '. + {action: "touch", service: "code_review"}' <<< "$SEAT_PAYLOAD" | \
  curl --fail-with-body -sS -X POST "$CODITY_SUBSCRIPTION_API/seats/action" \
    -H "X-API-Key: $CODITY_API_KEY" \
    -H 'Content-Type: application/json' \
    --data-binary @-

Success returns touch_existing, touch_created, or touch_reactivated in result. To add or remove through this endpoint, set action to add or remove and supply a service. The results are manual_add and manual_remove, respectively.

Using service: "analytics" requires an explicit analytics grant. Calling touch or add with that service does not grant analytics permission. A code-review touch can also be blocked by an applicable starter allowance. Recording access does not submit a review, scan, or analytics job.

Grant or revoke analytics access

Grant analytics permission to the same developer:

jq '. + {permission: "analytics"}' <<< "$SEAT_PAYLOAD" | \
  curl --fail-with-body -sS -X POST "$CODITY_SUBSCRIPTION_API/seats/grant-permission" \
    -H "X-API-Key: $CODITY_API_KEY" \
    -H 'Content-Type: application/json' \
    --data-binary @-

A grant upgrades an existing active seat to access level 2 without using another slot. If the developer has no active seat, it can create or reactivate one and consume a slot; an enforced seat limit can block this with 409.

warning

Analytics access level 2 also grants subscription and seat-management admin privileges in the dashboard. Grant it only to developers who should have that access.

Revoke the permission:

jq '. + {permission: "analytics"}' <<< "$SEAT_PAYLOAD" | \
  curl --fail-with-body -sS -X POST "$CODITY_SUBSCRIPTION_API/seats/revoke-permission" \
    -H "X-API-Key: $CODITY_API_KEY" \
    -H 'Content-Type: application/json' \
    --data-binary @-

Revocation downgrades an active seat to access level 1 and keeps it active. It does not free a seat. If no seat exists, revocation succeeds with seat: null.

Both permission operations return 200 with status: "success", a result of permission_granted or permission_revoked, the seat object, and usage. They do not include the seat-action response's entitlementId, provider, subscriptionStatus, trialDaysRemaining, or planId fields at the top level.

Retry a seat operation

For /seats/action, /seats/assign, and /seats/revoke, you can supply a unique requestId in the JSON body. Generate a fresh identifier, such as a UUID, for each new logical operation and reuse it only when retrying that same operation with the same payload.

When an event for that identifier has already been recorded, the API returns its outcome without applying the seat action again. Seat details and usage can reflect their current state, so the response need not be byte-for-byte identical. A recorded blocked outcome is also replayed: after resolving the block, use a new identifier for the new attempt.

Permission endpoints do not support requestId replay. Repeated grants or revocations may produce additional audit entries.

Errors and blocked requests

HTTP status Meaning Action
200 Operation succeeded. Read result, seat, and usage.
400 Missing identity fields, an invalid action, service, provider, or permission, or an invalid numeric developer ID. Correct the payload.
401 Authentication failed, including a key with subscription management disabled. Check the key is active and enable Subscription management for it.
403 The API key is not authorized for the target organization. Use the key and linked account identities for the same subscription organization.
409 Seat or service access is blocked. Inspect the JSON code and resolve the block before making a new attempt.
500 The operation failed unexpectedly. Retry with backoff; reuse the seat operation's requestId if supplied. Contact contact@codity.ai if the error persists.

Validation and authentication errors use this shape:

{
  "status": "error",
  "message": "Developer context is required"
}

A blocked request returns 409, for example:

{
  "status": "blocked",
  "code": "SEAT_LIMIT_EXCEEDED",
  "message": "Purchased seat limit exceeded for this organization",
  "usage": {
    "purchasedSeats": 10,
    "usedSeats": 10,
    "remainingSeats": 0
  },
  "notification": {
    "alertCreatedOrUpdated": true
  }
}
Block code Meaning
SEAT_LIMIT_EXCEEDED There is no capacity for another active seat. Free a seat or increase purchased seats.
ACCESS_NOT_GRANTED The developer needs an explicit analytics permission grant.
TRIAL_EXPIRED The trial has ended. Activate a subscription in the dashboard.
SUBSCRIPTION_CANCELLED The subscription has been cancelled.
SUBSCRIPTION_SUSPENDED The subscription is suspended. Resolve its status in the dashboard.
SUBSCRIPTION_EXPIRED The subscription or its billing period has expired. Renew in the dashboard.
STARTER_REVIEW_LIMIT_REACHED The developer has used the applicable starter review allowance.
STARTER_PERIOD_ELAPSED The developer's starter allowance window has ended.

Some blocked responses also include reason, subscriptionStatus, or trialDaysRemaining. Starter allowance blocks include starterQuota with reviewLimit, reviewsUsed, periodDays, and periodEndsAt. Use code for programmatic handling and message for the explanation.

Billing and subscription details

Use the dashboard's Subscription page to view your plan, list seats and members, view transactions, purchase capacity, or cancel. Those dashboard routes require a signed-in session; the subscription-management API key grants access to the seven seat and permission endpoints documented above.

For billing behavior, see Billing and Plans. For monthly service allowances, see Usage and Limits.