Using the REST API
Every endpoint follows the same conventions, so learning them once covers the whole surface. Per-endpoint request and response schemas are in the generated REST API reference; this page is the contract around them.
URL structure and audiences
Section titled “URL structure and audiences”Routes are api/v1/provision/... and split by audience:
| Area | Audience | Credential |
|---|---|---|
admin/* |
Back-office: catalog authoring, entitlement management, reporting | Admin-scoped client credentials |
operational/* |
Your backend automating lifecycle operations — issue codes, renew, top up | Operational-scoped client credentials |
| unmarked | The runtime surface your shipped application calls | Anonymous (activation) or license session token |
The split is deliberate: runtime endpoints never require an API secret, so nothing secret ships inside your application.
The runtime surface
Section titled “The runtime surface”What a shipped application (or the .NET SDK on its behalf) calls:
Activation & sessions
POST /activations/jwt— activate, returns the license token only.POST /activations/license— activate, returns token plus metadata (the entitlement description and license terms link, the licensed products and their Public custom properties, feature names and descriptions).POST /activations/{sessionId}/renew— extend the lease without re-activating.POST /activations/{sessionId}/check-in//release— heartbeat and seat release for floating and inactivity-based licenses.
Session calls present the session’s license token. A token the server no
longer accepts, because its signing key, audience or lifetime doesn’t
validate, is refused with 401 license.session_token_rejected. A session
that no longer exists, deleted or revoked, is refused with 409
license.no_active_session on every session call; a usage upload under it
is answered entitlementResolved: false and records nothing. Either way,
activate again. The .NET SDK does this once on its own.
Usage & metering
POST /usage/sessions/{sessionId}/transactions— batch usage upload.POST /usage/preview-consume/{sessionId}/{metric}and/usage/consume/{sessionId}/{metric}?amount=— ask, then charge metered consumption where overuse must be blocked. The first changes nothing and reserves nothing; the second is the decision that binds. A metric the entitlement doesn’t track is refused with404license.metric_not_tracked, and a session that no longer exists is refused with409license.no_active_session; nothing is charged either way.GET /usage/{sessionId}/{metric}/usageand/consumption— current usage snapshot and remaining balance;204for a metric the entitlement doesn’t track.GET /usage/sessions/{sessionId}/rating-prompt— the next feature-rating prompt to show, if any.
Signed-in user self-service (/consumer/me/..., user token)
GET /consumer/me/sessions— the user’s active license sessions.GET /consumer/me/activation-codes— codes issued to the user.GET /consumer/me/entitlements/{entitlementId}/plansand/sessions/{sessionId}/plans— the plans behind a license, for in-app display.
Collections and paging
Section titled “Collections and paging”Collection endpoints return a shared envelope:
{ "items": [ … ], "pageNumber": 1, "pageSize": 25, "totalCount": 112, "totalPages": 5, "hasNextPage": true, "hasPreviousPage": false}Page with pageNumber (1-based) and pageSize (max 100). A pageSize above
the maximum is silently clamped to it, not rejected.
filter and sortOrder take Sieve expressions:
filter—Field==Valuefor equality,Field@=textfor contains; comma-separate terms and they are ANDed (name@=acme,status==Active).sortOrder—Fieldascending,-Fielddescending, comma-separated (-createdAt,name).
Filterable and sortable fields are whitelisted per endpoint — see the
REST API reference. An expression that doesn’t parse or
names a non-whitelisted field returns 400 license.validation_error.
Updates: PATCH vs PUT
Section titled “Updates: PATCH vs PUT”PATCH <collection>/{id}is a merge: send only the fields you’re changing; absent ornullfields stay untouched. Where a field must be explicitly cleared, the DTO documents a sentinel (e.g.clearExpirationDate).PUTreplaces the full editable representation — send everything.- Toggles and anything needing a payload on delete are
POST .../{id}/<action>(e.g.enable-activations/disable-activations).
Success responses
Section titled “Success responses”A request that returns something answers 200 with it. A request that changes
something and has nothing to return answers either 200 or 204 No Content
with an empty body; the REST API reference names which
for each endpoint. Treat any 2xx as success.
Retries and idempotency
Section titled “Retries and idempotency”- Activation is retry-safe: re-activating with the same code and fingerprint returns the existing session, never a duplicate seat.
Idempotency-Keyheader (up to 200 characters) — send one on any mutating request you might retry. On the activation endpoints the key is durable: it persists on the session, a replay of an identical request returns the same session, and reusing the key with different parameters is rejected with409. On the operational balance mutations and the consumer credit grant the key is honored for 24 hours — a retry returns the original response.- Usage transactions carry their own ids and timestamps; upload batches can be retried after a network failure, under the same session or another session of the same license. A record already uploaded is acknowledged and not counted again. A record captured more than 90 days before it is uploaded is acknowledged but not counted.
- Metered consumption (
consume) accepts anidempotencyKeyquery parameter — a retried consume with the same key returns the original decision instead of consuming twice. A key is remembered for 24 hours. Once it is older than that, it is forgotten within the hour, and a consume that sends it again counts as a new consume. - Pass
X-Correlation-Idon any request to correlate it across your logs and Oclavex’s — echo one id through a whole business operation. - When consuming webhooks, dedupe on the
webhook-idheader — delivery is at-least-once.
Errors
Section titled “Errors”Failures return application/problem+json with a stable numeric code and
dotted codeName:
{ "status": 404, "title": "Not Found", "detail": "The activation code does not map to an entitlement.", "code": 2004, "codeName": "license.not_found"}Branch on code or codeName — never on detail, which is human-facing prose
and may change. The full catalog is in
Error codes.