AL License System setup guide
AL License System is the self-hosted, D1-backed license server behind the rest of the catalog. It issues keys, validates them over HTTP, binds activations to a server fingerprint, and enforces a per-key activation limit. This guide covers the D1 schema, all four endpoints, fingerprint binding, and an integration snippet.
Overview
A self-hosted license server
Every paid SKU issues a row in the licenses table, and any product, ours or yours, checks in against POST /api/license/validate. It runs on Cloudflare Pages Functions against a D1 database, so there is no server process to keep alive.
Keys carry a signed integrity check, so a forged key is rejected before any database lookup happens. Real status (active, revoked, expired) always lives in D1, the source of truth the offline check cannot fake.
Data model
D1 schema
Four tables in the license database. Price and activation limits stay server-side throughout, so a client can never set its own price or activation count.
- products the sellable SKU catalog: sku (primary key), name, price_cents, currency, kind (paid, free or subscription), max_activations, download_key, active, created_at.
- licenses one row per issued key: key (primary key, APLU-XXXX-XXXX-XXXX-XXXX), sku, product_name, email, status (active, revoked or expired), tier (standard, open-source or free), max_activations, stripe_session, stripe_payment, amount_cents, issued_by (webhook, free, admin or manual), expires_at, created_at, updated_at.
- activations the ledger validate enforces against: id, key, fingerprint (hashed), label, ip, first_seen, last_seen, unique on (key, fingerprint).
- validations an append-only audit log: id, key, sku, result (valid, invalid, revoked, over-limit or unknown), fingerprint, ip, at.
Endpoints
Validate a key
POST /api/license/validate takes a key, an optional product SKU to scope the check, and an optional fingerprint. It checks the key's signed integrity offline first, so a forged key never reaches the database, then looks it up by status and expiry.
POST /api/license/validate { "key": "APLU-7K2M-9QXR-4WTB-H3PZ", "product": "al-store", "fingerprint": "my-server-ip-or-cfx" } # valid { "valid": true, "status": "active", "activations_used": 1, "max_activations": 3 } # over { "valid": false, "status": "over-limit" } # revoked { "valid": false, "status": "revoked" }
Other statuses the same call can return: unknown (key not found), wrong-product (key belongs to a different SKU), expired, and unverifiable if the datastore is unreachable.
Fingerprint binding
How activations are enforced
Send a fingerprint (a server IP, cfx code or domain) and validate binds it on first use. The fingerprint is hashed before it is stored or compared; the activations table never holds it in plain text. A repeat call from the same fingerprint just refreshes its last-seen timestamp and calling IP.
A new fingerprint counts against the license's max_activations. Once that many fingerprints are bound, the next new one gets over-limit back, with the current activations_used and max_activations in the response, until you free a slot.
Endpoints
Activate, deactivate, lookup
POST /api/license/activate is a thin wrapper over validate that requires a fingerprint in the body (400 if missing), for an explicit activation step separate from the product's own boot-time validate calls.
POST /api/license/deactivate frees one activation slot so a key can move to a new server:
POST /api/license/deactivate { "key": "...", "fingerprint": "old-server-fingerprint" } # { "ok": true, "removed": 1, "activations_used": 0 }
POST /api/license/lookup is self-serve key recovery by email. It never returns keys in the response, so the API cannot be used to check whether an address has purchased; matching keys are emailed to the address on file instead, and every request gets the same generic reply.
Integrate it
Call it from anything
Validation is one HTTP POST, so any language that can make a request can check a key. Call it on every boot; the first call from a new fingerprint is what binds the activation.
# validate from any product, any language curl -X POST https://appleluis.ltd/api/license/validate \ -H "content-type: application/json" \ -d '{"key":"APLU-7K2M-9QXR-4WTB-H3PZ","product":"al-store","fingerprint":"srv-01"}' # {"valid":true,"status":"active","activations_used":1,"max_activations":3}