Error codes
Every API failure returns an RFC 9457
application/problem+json body with two stable extensions: a numeric code and
a dotted codeName.
{ "status": 403, "title": "Forbidden by policy", "detail": "Activation is blocked by the entitlement's activation policy.", "code": 2011, "codeName": "license.forbidden_by_policy"}Branch on code or codeName, never on detail or title — those are
human-facing prose and may change; the codes are contract. New codes may be added
over time (an additive, backward-compatible change), so treat unknown codes as a
generic failure of the given HTTP status.
What a refused activation needed
Section titled “What a refused activation needed”When an activation is refused because something it needed was missing, the problem
also carries a requires member, so your application can act without reading the
message:
requires |
What to do |
|---|---|
sign_in |
Sign the user in and activate again. |
verified_email |
Activate again with the user’s email address; they confirm it from the link they receive. |
assigned_user |
The code was issued to another user. Sign in as that user, or ask your software provider for a code of your own. |
organization_member |
The license is limited to one organization the signed-in user isn’t a member of. |
verified_user |
Your software provider hasn’t verified this user yet. |
hardware_key |
Activate with a YubiKey, through the hardware-key add-on. |
hardware_key_touch |
Activate with a YubiKey set up to ask for a touch. |
A caller with no signed-in user only ever sees sign_in or verified_email, with
status 401, code license.authentication_required and a WWW-Authenticate header:
Bearer when no token was sent, or Bearer error="insufficient_user_authentication"
(RFC 9470) when the token has no user behind
it. The other values go to a signed-in caller, with status 403. An unknown, expired or
used activation code is refused before anything else, as before, and carries no
requires.
Codes are globally unique and grouped in ranges: general platform errors are 1000–1999, licensing 2000–2999, account/directory 3000–3999, webhooks 4000–4999, organizations and environments 5000–5999, hardware keys 7000–7999.
General (1000–1999)
Section titled “General (1000–1999)”Cross-cutting errors any endpoint can return.
| Code | Code name | HTTP | Meaning |
|---|---|---|---|
| 1001 | validation.empty |
400 | A required value was missing or empty. |
| 1002 | validation.duplicate |
409 | The value collides with an existing record. |
| 1003 | validation.failed |
400 | The request failed validation. |
| 1010 | resource.not_found |
404 | The resource doesn’t exist. |
| 1011 | resource.expired |
410 | The resource existed but has expired. |
| 1012 | resource.limit-exceeded |
429 | A plan or capacity limit was reached. |
| 1020 | operation.invalid |
400 | The operation isn’t valid in the current state. |
| 1021 | operation.pending |
409 | A conflicting operation is already in flight. |
| 1030 | auth.forbidden |
403 | The caller lacks the required scope or role. |
| 1040 | service.unavailable |
503 | Temporarily unavailable — retry with backoff. A request that has to look a user or an organization up, such as an activation or the caller’s own licenses, activation codes, plans and usage, answers it while the user directory can’t be reached, and changes nothing. |
| 1041 | service.failure |
500 | Unexpected failure. |
| 1042 | service.too-many-requests |
429 | Rate limit exceeded — honor Retry-After. |
Licensing (2000–2999)
Section titled “Licensing (2000–2999)”Returned by activation, session and usage endpoints. These can also answer
service.unavailable (1040, under General above).
| Code | Code name | HTTP | Meaning |
|---|---|---|---|
| 2001 | license.no_active_license |
403 | No active license backs this request. |
| 2002 | license.no_such_entitlement |
404 | The entitlement doesn’t exist. |
| 2003 | license.no_active_session |
409 | No active session for this operation. |
| 2004 | license.not_found |
404 | The activation code doesn’t map to anything, or has expired. |
| 2005 | license.invalid_operation |
400 | The operation isn’t valid for this license’s state. |
| 2006 | license.no_permission |
403 | The caller doesn’t own this session or entitlement. |
| 2007 | license.no_such_product |
404 | The product doesn’t exist. |
| 2008 | license.no_such_provider |
404 | The provider doesn’t exist. |
| 2009 | license.validation_error |
400 | The request body or activation code is invalid. |
| 2010 | license.no_credit |
400 | The credit balance can’t cover the requested consumption. |
| 2011 | license.forbidden_by_policy |
403 | Blocked by the entitlement’s activation policy, for example offline activation turned off, a code issued to another user, or a YubiKey required. When something specific was missing, requires names it. |
| 2012 | license.operation_pending |
409 | A pending step (e.g. email verification) must complete first. |
| 2013 | license.expired |
409 | The license or credit balance has expired. |
| 2014 | license.spending_disabled |
403 | The balance holds credits, but its owner has switched extra-credit spending off. Distinct from license.no_credit: nothing needs buying. |
| 2015 | license.billing_events_not_included |
403 | Posting billing events isn’t included in your plan. |
| 2016 | license.reserved_scheme |
403 | A billing event names a reference under a scheme a built-in connector owns (stripe, sfdc, oclavex, manual, none, operator). Use your billing system’s own. |
| 2017 | license.platform_environment |
403 | The environment can’t take billing events. |
| 2018 | license.billed_elsewhere |
409 | Another provider bills the entitlement through a live subscription; it can take yours once that one is cancelled. |
| 2019 | license.provider_owns_end_date |
400 | A billing provider bills the entitlement or offer as a subscription and decides when it ends, so it takes no subscription policy or time restriction that ends it. Set its billing to managed by vendor to use one. |
| 2020 | license.offer_not_orderable |
409 | The offer isn’t Published, so it takes no orders: a Draft offer isn’t open yet, and a Disabled or Archived one no longer is. Publish a Draft offer to take orders from it. |
| 2021 | license.metric_not_tracked |
404 | A consume, or a preview of one, named a metric the entitlement doesn’t track, so nothing could be charged. Check the metric name, or add the metric to the plan behind the entitlement. |
| 2022 | license.session_token_rejected |
401 | The license token a session call presented is no longer accepted: its signing key, audience or lifetime doesn’t validate. Activate the license again; the SDK does this once on its own. |
| 2023 | license.hardware_keys_not_licensed |
403 | Hardware keys aren’t included in your plan: requiring one on an entitlement or offer, or activating a license that doesn’t require one with a hardware key. Licenses that already require a key keep activating. |
| 2024 | license.usage_metering_not_licensed |
403 | Your plan doesn’t include usage metering, so a new monitored asset, usage uploads, consumes and pre-allocations are refused and nothing is recorded. Monitored assets and credit balances are kept, and recording resumes once your plan includes usage metering again. |
| 2025 | license.unknown_user |
403 | The caller is signed in, but no user on your environment matches its sign-in, so it has no licenses, activation codes or entitlements of its own, and an activation that needs a user (useInteractiveUser, or a code issued to a user or an organization) is refused. Signing in again doesn’t change this: the user must exist under Customers → Users, and a user added after the refusal can take up to five minutes to be recognized. |
| 2027 | license.product_end_of_life |
403 | Every product the application may use is past its End of life, and the device has never activated the license, so it can’t start now, online or offline. Devices activated before keep activating and renewing. Clear the End of life on the product to let new devices activate again. |
| 2028 | license.authentication_required |
401 | The activation needs a signed-in user or a confirmed email address, and the caller has neither. requires says which (sign_in or verified_email); WWW-Authenticate carries the challenge. An offline request needing one is refused with license.forbidden_by_policy instead, since your operator who uploads it is signed in. |
Account & directory (3000–3999)
Section titled “Account & directory (3000–3999)”Returned by user and organization endpoints.
| Code | Code name | HTTP | Meaning |
|---|---|---|---|
| 3001 | organization.not_found |
404 | The user or organization doesn’t exist. |
| 3002 | organization.duplicate |
409 | Already exists (e.g. email in use). |
| 3003 | organization.invalid_operation |
400 | Not valid in the current state. |
| 3004 | organization.no_permission |
403 | The caller lacks directory permission. |
| 3005 | organization.validation_error |
400 | The request failed validation. |
| 3006 | organization.no_credit |
400 | A seat or capacity limit was reached. |
Webhooks (4000–4999)
Section titled “Webhooks (4000–4999)”Returned by the webhook subscription and delivery-management endpoints.
| Code | Code name | HTTP | Meaning |
|---|---|---|---|
| 4001 | subscription.tenant_required |
400 | The request lacks an active environment context. |
| 4002 | subscription.client_id_required |
400 | An OAuth client identity is required. |
| 4003 | subscription.tenant_mismatch |
403 | The subscription belongs to a different environment. |
| 4010 | subscription.not_found |
404 | The subscription doesn’t exist. |
| 4020 | subscription.invalid_state |
409 | Not allowed in the subscription’s current state (e.g. test-fire on an inactive subscription). |
| 4021 | subscription.invalid_transition |
409 | The requested state change isn’t allowed. |
| 4022 | subscription.not_applicable |
400 | The action has no meaning for this kind of subscription (e.g. rotating the secret of a capture subscription, which has no receiver). |
| 4030 | subscription.invalid_secret |
400 | The signing secret isn’t a Standard Webhooks secret: whsec_ followed by the base64 of 24 to 64 random bytes. |
| 4031 | subscription.invalid_overlap |
400 | The rotation overlap window is invalid. |
| 4032 | subscription.invalid_callback_scope |
400 | A requested callback scope isn’t allowed. |
| 4033 | subscription.invalid_url |
400 | The receiver URL is not allowed. |
| 4034 | subscription.invalid_filter |
400 | An attribute filter can never match: its field name is empty, its value is null, or no subscribed event type carries the field it names. |
| 4035 | subscription.invalid_event_type |
400 | An event-type pattern is not * or an exact type from the event catalog: family wildcards such as Entitlement.* are not accepted. |
| 4040 | subscription.challenge_failed |
422 | The endpoint failed the registration challenge. |
| 4050 | subscription.not_licensed |
403 | Webhooks aren’t included in your plan. |
| 4060 | replay.invalid_selection |
400 | A replay needs either envelopeIds or a from/to window — not both and not neither. |
| 4061 | replay.too_many_envelopes |
400 | The selection matches more envelopes than one replay request may carry; narrow the window or replay in batches. |
| 4062 | replay.rate_limited |
429 | The replay would exceed the hourly envelope quota. |
| 4070 | testfire.unknown_event_type |
400 | The requested event type isn’t in the event catalog. |
| 4071 | testfire.event_type_not_subscribed |
400 | The event type doesn’t match any of the subscription’s event-type patterns. |
| 4072 | testfire.event_type_not_allowed |
400 | The event type can’t be test-fired (the registration challenge is the platform’s own handshake). |
| 4073 | testfire.rate_limited |
429 | The subscription has used its test-fires for this hour. |
| 4080 | delivery.ambiguous_envelope |
400 | The envelope reached more than one subscription; pass subscriptionId to choose one. |
Organizations and environments (5000–5999)
Section titled “Organizations and environments (5000–5999)”Returned by the organization onboarding endpoints.
| Code | Code name | HTTP | Meaning |
|---|---|---|---|
| 5001 | onboarding.tenant_create_operator_only |
403 | During the private preview, new organizations are created by the Oclavex operator on request; an administrator of an existing organization can’t create one. Adding an environment to your own organization isn’t affected. |
Hardware keys (7000–7999)
Section titled “Hardware keys (7000–7999)”Returned by the hardware-key activation routes, online and offline.
| Code | Code name | HTTP | Meaning |
|---|---|---|---|
| 7001 | hardware_key.attestation_refused |
403 | The YubiKey’s attestation did not hold, so nothing was activated: it isn’t a genuine YubiKey 5, its firmware is older than 5.7, or it attests a different key than the one the device activates with. detail says which. |
| 7002 | hardware_key.proof_refused |
403 | An online activation’s proof that the device holds the YubiKey’s key did not hold, so nothing was activated: the proof is missing, signed by another key, made for another request, or its nonce has expired. detail says which. |
Validation errors
Section titled “Validation errors”Model-binding failures (malformed JSON, wrong types, missing required fields)
return the standard ASP.NET validation problem — a 400 with an errors
dictionary keyed by field name:
{ "status": 400, "title": "One or more validation errors occurred.", "errors": { "activationCode": ["The activationCode field is required."] }}