TWELVETAKE VAULT

API Reference

Public API reference for TwelveTake Vault. License validation, activation, management, product listing, and software update endpoints.

Overview

TwelveTake Vault is a license key management system for software products. It supports multi-tenant deployment with customizable key formats, machine activation tracking, abuse detection, and a built-in software update system with signed releases.

Base URLs

EnvironmentURL
Productionhttps://vault.twelvetake.com
Local developmenthttp://localhost:3002

Interactive API docs are also available at /api/docs in every installation via Swagger UI.

API Versioning

All public endpoints use the /api/v1/ prefix.

Authentication

The API uses three authentication methods depending on the endpoint type.

API Key (Public Endpoints)

For license validation, management, and product listing. Pass the key in the X-API-Key header.

X-API-Key: your-api-key-here

Create keys in the admin dashboard under Settings > API Keys. Keys are scoped:

ScopeAccess
VALIDATE_ONLYActivate, validate, deactivate, heartbeat, check
CREATE_LICENSEEverything above + create, revoke, renew licenses
READ_ONLYEverything above + list products, lookup by order

License Key (Update Endpoints)

Software update endpoints authenticate with the license key itself via the X-License-Key header. The license must be ACTIVE and belong to the target product.

X-License-Key: TT-ABCD-EFGH-IJKL-MNOP

Errors & Response Format

All endpoints return JSON. Successful responses include "success": true. Errors include a structured error object:

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid license key"
  }
}

Standard HTTP status codes are used: 200 success, 201 created, 207 partial success (bulk), 400 validation error, 401 unauthorized, 403 forbidden, 404 not found, 429 rate limited, 503 service degraded.

Pagination

List endpoints accept page (default 1) and limit (default 50, max 500) query parameters. Paginated responses include:

{
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 142,
    "totalPages": 3
  }
}

Schemas

Enums

NameValues
LicenseStatusACTIVE, EXPIRED, SUSPENDED, REVOKED
LicenseTypePERPETUAL, SUBSCRIPTION, TRIAL, BETA
LicenseTierPERSONAL, PROFESSIONAL, BUSINESS, ENTERPRISE
ProductTypeDESKTOP, WEB, MOBILE, PLUGIN, API
ProductStatusACTIVE, DEPRECATED, DISCONTINUED
ApiKeyScopeVALIDATE_ONLY, CREATE_LICENSE, READ_ONLY

LicensePublic

Returned by public validation endpoints.

FieldTypeDescription
keystringLicense key (e.g., TT-ABCD-EFGH-IJKL-MNOP)
productstringProduct name
tierLicenseTierLicense tier
typeLicenseTypeLicense type
validUntildate-time | nullExpiration (null for perpetual)
activationsUsedintegerCurrent activation count
maxActivationsintegerMaximum allowed activations

LicenseCreated

Returned by create, revoke, and renew endpoints.

FieldTypeDescription
idstringLicense ID
keystringLicense key
productstringProduct ID
typeLicenseTypeLicense type
tierLicenseTierLicense tier
statusLicenseStatusCurrent status
maxActivationsintegerMaximum activations
validUntildate-time | nullExpiration
createdAtdate-timeCreation timestamp

Activation

FieldType
machineIdstring
machineNamestring
activatedAtdate-time

ReleaseInfo

FieldTypeDescription
versionstringSemver version
channelstringstable, beta, alpha, rc, nightly
changelogstringRelease notes
bundleFilenamestringDownload filename
bundleSizeintegerFile size in bytes
bundleSha256stringSHA-256 hash
signaturestringEd25519 signature
isCriticalbooleanCritical update flag
requiresMigrationbooleanMigration needed
publishedAtdate-time | nullPublish timestamp

Health

GET /api/health

Returns service status and database connectivity. No authentication required.

Response 200:

{ "status": "ok", "version": "1.0.0", "timestamp": "2026-03-13T..." }

Response 503: Service degraded (database unreachable).

License Validation

Public API for activating, validating, and deactivating license keys. All endpoints require X-API-Key with at least VALIDATE_ONLY scope.

POST /api/v1/license/activate

Activate a license on a machine. Idempotent — if the machine is already activated, returns the existing activation.

Request body:

FieldTypeRequiredDescription
licenseKeystring (10-100)YesThe license key
machineIdstring (8-255)YesUnique hardware fingerprint
machineNamestring (max 255)NoHuman-readable name
osNamestring (max 100)NoOperating system
osVersionstring (max 100)NoOS version
appVersionstring (max 50)NoApplication version

Response 200: { success, message, license: LicensePublic, activation: Activation }

Response 400: Max activations reached, expired, suspended, or revoked.

POST /api/v1/license/validate

Check if a license is valid for a specific machine. Read-only — does not create or modify activations. Always returns 200; check the valid field.

Request body: licenseKey (required), machineId (required).

Response 200: { success, valid: boolean, status: LicenseStatus, message, license: LicensePublic, activation: Activation }

POST /api/v1/license/deactivate

Remove a license activation from a machine, freeing the activation slot.

Request body: licenseKey (required), machineId (required).

Response 200: { success, message }

POST /api/v1/license/heartbeat

Periodic check-in from an activated machine. Updates lastSeenAt and returns the next expected heartbeat time. Machines that stop sending heartbeats may be auto-deactivated based on the applicable policy.

Request body: key (required), machineId (required).

Response 200: { success, nextHeartbeatAt: date-time | null }

GET /api/v1/license/check/{key}

Quick status check. Returns only the license status. Does not require a machine ID.

Response 200: { success, status: LicenseStatus }

Response 404: License not found.

License Management

Public API for creating and managing licenses programmatically. Designed for server-to-server integrations (e.g., e-commerce checkout webhooks). Requires X-API-Key with CREATE_LICENSE scope or higher.

POST /api/v1/license/create

Create a new license. Supports idempotency via X-Idempotency-Key header — same key returns the existing license instead of creating a duplicate.

Request body:

FieldTypeRequiredDescription
productIdstring (max 30)YesProduct ID
customerEmailemail (max 255)YesCustomer email
customerNamestring (max 255)NoCustomer name
typeLicenseTypeNoDefaults to product default
tierLicenseTierNoLicense tier
maxActivationsinteger (1-1000)NoActivation limit
validUntildate-timeNoExpiration date
orderIdstring (max 255)NoExternal order reference
metadataobjectNoCustom key-value pairs (max 20 keys)

Response 201: { success, license: LicenseCreated }

Response 200: Idempotent return — { success, license: LicenseCreated, idempotent: true }

POST /api/v1/license/create-bulk

Create up to 20 licenses in one request. Returns 207 on partial failure. Idempotency key is appended with :index per item.

Request body: { licenses: [{ productId, customerEmail, ... }] } (array of 1-20 items, same fields as create).

Response 201: All created. Response 207: Partial failure (each result includes success/error).

GET /api/v1/license/by-order/{orderId}

Look up all licenses associated with an external order ID. Requires READ_ONLY scope or higher.

Response 200: { success, licenses: LicenseCreated[] }

POST /api/v1/license/revoke

Revoke a license permanently. Provide either licenseId or licenseKey.

Request body: licenseId or licenseKey (one required), reason (optional).

Response 200: { success, license: LicenseCreated }

POST /api/v1/license/renew

Extend a license expiration date. Cannot renew revoked licenses.

Request body: licenseId or licenseKey, validUntil (required, date-time).

Response 200: { success, license: LicenseCreated }

Products

GET /api/v1/products

List all active products. Requires CREATE_LICENSE, READ_ONLY, or FULL_ADMIN scope.

Response 200: { success, products: ProductPublic[] }

Software Updates

Built-in update system for distributing software releases with Ed25519 signed bundles. Clients authenticate with their license key via X-License-Key header.

GET /api/v1/updates/check

Check if an update is available for the licensed product.

Query parameters: current_version (required, semver), channel (optional: stable, beta, alpha, rc, nightly; default stable).

Response 200:

{
  "success": true,
  "update_available": true,
  "version": "1.3.0",
  "changelog": "...",
  "bundle_size": 52428800,
  "sha256": "...",
  "signature": "...",
  "is_critical": false,
  "requires_migration": false,
  "published_at": "2026-03-13T...",
  "release_id": "..."
}

Rate limit: 60 requests per 15 minutes.

GET /api/v1/updates/download

Download a release bundle. Returns binary data (application/octet-stream).

Query parameters: release_id (required), from_version (optional).

Response headers: X-Bundle-SHA256, X-Bundle-Signature.

Rate limit: 10 requests per hour.

GET /api/v1/updates/manifest

Get release metadata without downloading the bundle.

Query parameters: release_id (required).

Response 200: Version, filename, size, sha256, signature, channel, criticality, migration flag, publish date.

GET /api/v1/updates/public-key

Get the Ed25519 public key for verifying release signatures. No license key required.

Query parameters: product (required, product slug), tenant (optional).

Response 200: { public_key: "base64-encoded Ed25519 key" }