Skip to content

Integration API Overview

The Integration API is a REST API for validating licenses, managing device activations, checking entitlements, and recording usage — authenticated with an X-API-Key header and rate-limited per key (see Rate Limits). It's the primary interface your application calls at runtime.

Base URL

https://api.validonx.com/api/v1/integration

Authentication

All requests require the X-API-Key header:

X-API-Key: vx_your_api_key_here

See API Key Authentication for details on obtaining and managing keys.

Endpoints

MethodPathDescription
POST/licenses/{licenseKey}/validateValidate a license key
POST/activationsCreate a device activation
POST/activations/{activationId}/validateValidate an existing activation
POST/entitlements/checkCheck feature entitlements
POST/licensing/resolveResolve a license to its current status, grace window, and allowed features in one call
POST/usage/recordRecord usage metrics

Partner-scoped endpoints (require a partner API key, not a standard tenant key — ADR-033): POST /billing/portal-session (billing-portal:mint scope, mints a Stripe Customer Portal session for a target tenant) and POST /checkout/create-session (checkout:create scope, hosted checkout for a target tenant).

Middleware Stack

Every request passes through:

  1. ResolveTenantFromApiKey — resolves tenant from API key
  2. EnforceRateLimit — enforces per-key rate limits (default: 1,000/hour)

Response Format

Success:

json
{
  "data": { ... },
  "meta": {
    "request_id": "uuid",
    "api_version": "1"
  }
}

Error:

json
{
  "error": {
    "code": "LICENSE.NOT_FOUND",
    "message": "License key not found.",
    "type": "license",
    "status": 404,
    "details": {}
  },
  "meta": {
    "request_id": "uuid",
    "api_version": "1"
  }
}

Rate Limits

1,000 requests per hour per API key. See Rate Limits.

Security Model

  • API keys are hashed with HMAC-SHA256 before storage
  • Raw keys are shown only once at creation
  • Each key is bound to one tenant
  • Suspended tenants are rejected with 403
  • All requests are rate-limited
  • last_used_at is updated on every request