Deactivate Device
Release (revoke) a device activation so its seat is freed. There are two ways to do this, for two different callers:
- App self-service release (Integration API) — the licensed application releases the seat it activated (e.g. on uninstall / deregister / hardware change). This is the recommended, automated path and the one that lets a
activations.max: 1license move to a new device without manual help. - Administrative revoke (Tenant / Admin API) — the account owner (or a ValidonX admin) force-revokes a specific activation by id from the dashboard.
Revocation is non-destructive: the activation record is preserved (status = "revoked", deactivated_at set) for audit purposes, and the seat it held no longer counts against the license's activations.max.
1. App self-service release (Integration API)
The application releases the activation it created, identified by the same license_key + instance_id it activated with — no activation id required.
Endpoint
POST /api/v1/integration/activations/deactivateHeaders
| Header | Required | Value |
|---|---|---|
X-API-Key | Yes | Your API key |
Content-Type | Yes | application/json |
Request Body
{
"license_key": "VX-ACME-abc123def456",
"instance_id": "server-prod-01",
"device_fingerprint": "sha256-hash-of-device-info"
}| Field | Required | Type | Description |
|---|---|---|---|
license_key | Yes | string | The license key the seat was activated against |
instance_id | Yes | string | The instance identifier used at activation |
device_fingerprint | No | string | If supplied, further narrows the match to a specific device |
Response (200 OK)
{
"data": {
"activation": {
"id": "9a1b7c2d-3e4f-5a6b-7c8d-9e0f1a2b3c4d",
"license_key_id": "1f2e3d4c-5b6a-7988-a0b1-c2d3e4f5a6b7",
"instance_id": "server-prod-01",
"device_fingerprint": "sha256-hash...",
"status": "revoked",
"deactivated_at": "2026-07-06T10:00:00.000000Z"
}
},
"meta": { "request_id": "uuid", "api_version": "1" }
}Idempotency
Releasing a seat that is already released returns 200 with the same revoked activation — safe to retry, and safe to call on every uninstall even if a previous attempt already succeeded.
Freeing a single-seat license
For a license with activations.max: 1, a second device is refused with ACTIVATION.LIMIT_EXCEEDED while the first seat is active. Releasing the first activation frees the seat, and the next device can then activate — the intended device-transfer flow.
Error Responses
| Code | HTTP | Description |
|---|---|---|
LICENSE.NOT_FOUND | 404 | License key not found for your tenant |
ACTIVATION.INVALID | 400 | No activation exists for that license_key + instance_id |
VALIDATION.FAILED | 422 | license_key or instance_id missing |
AUTH.INVALID_API_KEY | 401 | Invalid API key |
2. Administrative revoke (Tenant / Admin API)
The account owner force-revokes a specific activation by id — e.g. to reclaim a lost, stolen, or stuck seat. Activation ids come from GET /api/v1/tenant/activations (see the Activation Lifecycle guide).
Endpoint
DELETE /api/v1/tenant/activations/{activationId}Platform admins can revoke on behalf of a tenant at:
DELETE /api/v1/admin/tenants/{tenantId}/activations/{activationId}Headers
| Header | Required | Value |
|---|---|---|
Authorization | Yes | Bearer {token} (token needs the tenant ability) |
This path uses a tenant Bearer token, not an API key — it is an account-management action, not something the distributed application performs.
Response (200 OK)
{
"data": {
"id": "9a1b7c2d-3e4f-5a6b-7c8d-9e0f1a2b3c4d",
"status": "revoked",
"deactivated_at": "2026-07-06T10:00:00.000000Z"
},
"meta": { "request_id": "uuid", "api_version": "1" }
}Idempotent — revoking an already-revoked activation still returns 200. An activation that belongs to another tenant is reported as not found (ACTIVATION.INVALID), never revealed or revoked.
Error Responses
| Code | HTTP | Description |
|---|---|---|
ACTIVATION.INVALID | 400 | Activation not found (or not owned by your tenant) |
AUTH.TOKEN.REQUIRED | 401 | Missing / invalid Bearer token |
Activation States
| Status | Description |
|---|---|
active | Currently active, counts against activations.max |
suspended | Temporarily suspended |
revoked | Deactivated — deactivated_at set; no longer counts against the limit |