KDPika Licensing Sign inStart free
API v1
Show all languages
Browse documentation

Choose a page in the navigation drawer.

KDPika Licensing · API v1 Intermediate

Deactivate an installation

Release this installation device seat.

On this page
Updated 2026-10-17 UTCDownload Markdown

Release this installation device seat.

What you will learn

  • Send this exact operation with its required credentials and fields.
  • Interpret success, refusal, side effects and retry risks.

Prerequisites

Method and path

POST /api/v1/licenses/deactivate

When to use it

Release this installation's active device seat when the user signs out or transfers the license to another device. Only the installation activation token is required.

Authentication and environment

Use Authorization: Bearer YOUR_ACTIVATION_TOKEN. The token fixes the installation/product/environment; X-Environment cannot override it.

Request headers

HeaderRequiredDescriptionExample
AcceptrecommendedJSON responsesapplication/json
Content-Typefor JSON bodyUse the documented JSON objectapplication/json
AuthorizationyesInstallation tokenBearer YOUR_ACTIVATION_TOKEN

Path and query parameters

No path parameters are accepted.

No pagination, filtering, sorting or list query parameters are implemented. Use JSON rather than relying on alternate form/query parsing.

Request body

No body fields are consumed. Omit the body or send an empty object.

Full request JSON

jsonjson
{}

The schemas describe supported recommended input types. Current PHP parsing trims/casts strings and may ignore unknown fields; it is not strict JSON-schema validation. Invalid optional descriptive fields can become empty/null. Conventions describes malformed JSON and alternate parsing.

Success response

HTTP 200. The following is a real isolated Sandbox capture; secret values are replaced with explicit placeholders.

jsonjson
{
  "success": true,
  "deactivated": true,
  "request_id": "req_29039d899dd3655d7ada1c89"
}

Response fields

FieldTypeRequiredConstraintsDescriptionExample
successbooleanyesconst=trueThe operation succeeded.true
deactivatedbooleanyesconst=trueDevice seat released; cumulative count is unchanged.true
request_idstringyespattern="^req_[a-f0-9]{24}$"Request correlation ID. Replay bodies can retain an earlier ID."req_29039d899dd3655d7ada1c89"

Response headers

X-Request-ID identifies the current request. No limiter headers are returned by this endpoint.

Errors omit those rate headers and Retry-After. See the complete rate-limit reference.

Error responses

CodeHTTPCauseFixRetryable?
INVALID_TOKEN401Missing/non-act_/unknown/revoked/deactivated activation tokenReactivate eligible installationNo blind retry; apply the correction
INTERNAL_ERROR500Uncaught exception at global boundarySafe retry only for idempotent operation; preserve request_idOnly safe reads after backoff; reconcile mutations

An unregistered path or wrong method is handled by the global router as NOT_FOUND (HTTP 404), not405. Every licensing error has success=false, error.code, error.message and request_id. Errors keeps SDK-local and operational namespaces separate.

Side effects

Marks the bound device DEACTIVATED and its active tokens DEACTIVATED, releasing the concurrent seat. Does not decrease activation_count. Audit/webhook license.deactivated are emitted; no email is sent directly. Other installations remain active. It does not require an otherwise usable license, but the supplied token must still be active.

Authenticated requests can consume the organization monthly API usage counter once tenant context is established, including some failures. This usage counter is currently warning-only, not a monthly API rejection gate. Developer-key authentication can update last_used_at before a later failure. No request body or Authorization value is saved by the API metadata logger.

Idempotency and concurrency

Idempotency-Key is ignored. The first accepted call returns 200; the same token subsequently returns 401 INVALID_TOKEN, not a successful replay. A lost response therefore requires inspecting the application's saved state and, if necessary, developer support. Do not treat every unknown token as proof that this particular deactivation succeeded.

Rate limits

No dedicated deactivation endpoint limiter is currently implemented. Do not invent an unlimited-service promise; use reasonable client throttling and avoid loops.

Fixed windows begin with the first hit after expiry. Attempted calls consume every bucket they reach, even if later business validation fails.

Runnable examples

These are complete native HTTP transport programs, not full SDK clients or entitlement verifiers. JSON request bodies and credentials come from KDP_* environment variables. They print raw responses to a private terminal; do not send their stdout to application/CI logs. Use the P5 verification guides before granting access.

Ruby

Save every file shown below. Install the exact runtime/dependencies from the complete example archive README. Set the endpoint request JSON in KDP_BODY_JSON and the documented KDP_* credential variables in your private process environment.

Run ruby request.rb deactivate. Expected: full JSON, exit 0 for success, exit 1 for an API rejection; exit 2 for setup/transport failure. The cURL sample checks HTTP status; parse JSON before use. Never authorize a feature from transport output alone.

request.rbruby
# Purpose: inspect one client-callable Sandbox operation, not grant feature access.
# Requires Ruby2.6+ standard library. Run: ruby request.rb public-key
# Expected: JSON; exit0 success/1 API rejection/2 setup or transport failure.
# Credentials/body: KDP_* variables. Private terminal only; output may contain secrets.
require 'json'
require 'net/http'
require 'uri'
require 'openssl'
STDOUT.set_encoding(Encoding::UTF_8)
OPERATIONS = JSON.parse(<<~'JSON')
{
  "public-key": {
    "method": "GET",
    "path": "/public-key",
    "auth": "public"
  },
  "activate": {
    "method": "POST",
    "path": "/licenses/activate",
    "auth": "publicApp"
  },
  "validate": {
    "method": "POST",
    "path": "/licenses/validate",
    "auth": "activation"
  },
  "deactivate": {
    "method": "POST",
    "path": "/licenses/deactivate",
    "auth": "activation"
  }
}
JSON
def required(name)
  value = ENV.fetch(name, '')
  raise 'configuration' if value.empty? || value.match?(/[\r\n]/)
  value
end
begin
  raise 'operation' unless ARGV.length == 1 && OPERATIONS.key?(ARGV[0])
  name = ARGV[0]; op = OPERATIONS.fetch(name)
  base = ENV.fetch('KDP_BASE_URL', 'https://licensing.kdpika.com/api/v1').sub(%r{/+$}, '')
  uri = URI.parse(base)
  local = uri.scheme == 'http' && ['127.0.0.1','localhost'].include?(uri.host) && ENV['KDP_ALLOW_LOOPBACK'] == '1'
  raise 'URL' unless uri.host && (uri.scheme == 'https' || local) && !uri.userinfo && !uri.query && !uri.fragment && uri.path == '/api/v1'
  target = URI.parse(base + op.fetch('path'))
  request = op.fetch('method') == 'GET' ? Net::HTTP::Get.new(target) : Net::HTTP::Post.new(target)
  request['Accept'] = 'application/json'; request['User-Agent'] = 'KDPikaDocsExample/1.0 Ruby'
  if op['auth'] == 'publicApp'
    request['X-App-ID'] = required('KDP_APP_ID'); request['X-Environment'] = 'SANDBOX'
  elsif op['auth'] == 'activation'
    request['Authorization'] = 'Bearer ' + required('KDP_ACTIVATION_TOKEN')
  end
  request['X-Installation-ID'] = required('KDP_INSTALLATION_ID') if name == 'validate'
  if op['method'] == 'POST'
    body = ENV.fetch('KDP_BODY_JSON', '{}'); raise 'JSON object' unless JSON.parse(body).is_a?(Hash)
    request['Content-Type'] = 'application/json'; request.body = body
  end
  http = Net::HTTP.new(target.host, target.port, nil)
  http.use_ssl = target.scheme == 'https'; http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  http.open_timeout = 5; http.read_timeout = 15
  response = http.request(request) # Net::HTTP does not follow redirects.
  result = JSON.parse(response.body)
  puts response.body
  unless response.code.to_i.between?(200,299) && result['success'] == true
    warn 'API rejection. Inspect error.code/request_id; reconcile mutations before retrying.'; exit 1
  end
rescue StandardError
  warn 'Request unavailable or configuration invalid. Check KDP_* settings/connectivity; do not blindly retry mutations.'; exit 2
end

Expected result

A correctly authenticated eligible request returns the documented HTTP status and schema. Check the actual success/error result and request IDs; a successful transport or unsigned management response does not grant a feature.

Common mistakes

  • Mixing Public App IDs, internal product IDs and product-plan IDs.
  • Assuming a mutation timeout means no work committed, or assuming Idempotency-Key protects every action.
  • Logging raw responses that contain a newly issued license key or activation token.

Security notes

Keep lmp_ credentials out of shipped desktop/browser code. Verify signed payload bytes and product/environment/installation/status/time/feature policy. The examples do not fix the documented idempotency, cache canonicalization or current-key-only rotation limitations.

Troubleshooting

SymptomCauseAction
INVALID_TOKEN (HTTP 401)Missing/non-act_/unknown/revoked/deactivated activation tokenReactivate eligible installation
INTERNAL_ERROR (HTTP 500)Uncaught exception at global boundarySafe retry only for idempotent operation; preserve request_id

Next steps

Read idempotency and signed responses before integrating a purchase-to-license workflow.

Was this page helpful?

Choose an answer

Do not include personal data, license keys or credentials. Retained for up to 30 days. This is not a support inbox.

Search documentation

Arrow keys to move, Enter to open, Escape to close. Search stays in your browser.

Cookie settings