appgram / docs
Dashboard

API REFERENCE

License Keys

Issue, revoke, and validate license keys.

v1.0
11 endpoints Authentication →

License Keys

List license keys for a project

Returns every license key for a project with its current activation count. Plaintext keys are never included — only metadata and the hashed key's last-four characters (when populated).

GET /api/v1/license-keys

Authorizations

Authorization string header required

Bearer token — an API key prefixed with app_. Create one in the dashboard under Settings → Developer → API Keys.

Query parameters

project_id string query required

Project ID

GET /api/v1/license-keys bash
curl --request GET \
  --url https://api.appgram.dev/api/v1/license-keys \
  --header 'Authorization: Bearer <token>'

License Keys

Mint a license key

Issue a new license key for a project. The response includes the plaintext key string ONCE — only its SHA-256 hash is persisted. Subsequent reads return metadata only, so the caller MUST capture data.key from this response. Optionally inline-upsert the end user by setting end_user{external_id, email, name, plan, attributes} instead of end_user_id — the EndUser is created or merged before the key is minted, and the key's end_user_id is set automatically. The license_key_minted webhook fires with metadata.end_user_email populated.

POST /api/v1/license-keys

Authorizations

Authorization string header required

Bearer token — an API key prefixed with app_. Create one in the dashboard under Settings → Developer → API Keys.

Body

application/json
end_user object
end_user_id string
expires_at string
max_devices integer
metadata object
plan string
project_id string required
POST /api/v1/license-keys bash
curl --request POST \
  --url https://api.appgram.dev/api/v1/license-keys \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
  "end_user": {
    "email": "string",
    "external_id": "string",
    "name": "string",
    "plan": "string"
  },
  "end_user_id": "string",
  "expires_at": "string",
  "max_devices": 0,
  "plan": "string",
  "project_id": "string"
}'

License Keys

Get the project's public verification key

Returns the Ed25519 public key the host app embeds to verify entitlement JWTs locally. Auto-creates the keypair on the first call. The private signing key is never returned by this or any other endpoint.

GET /api/v1/license-keys/public-key

Authorizations

Authorization string header required

Bearer token — an API key prefixed with app_. Create one in the dashboard under Settings → Developer → API Keys.

Query parameters

project_id string query required

Project ID

GET /api/v1/license-keys/public-key bash
curl --request GET \
  --url https://api.appgram.dev/api/v1/license-keys/public-key \
  --header 'Authorization: Bearer <token>'

License Keys

Rotate the project's signing keypair

Generate a fresh Ed25519 keypair for this project. Host apps embedding the old public key will fail JWT verification after their next refresh, so coordinate distributing the new public key BEFORE rotating. The new private key stays on the server.

POST /api/v1/license-keys/public-key/rotate

Authorizations

Authorization string header required

Bearer token — an API key prefixed with app_. Create one in the dashboard under Settings → Developer → API Keys.

Query parameters

project_id string query required

Project ID

POST /api/v1/license-keys/public-key/rotate bash
curl --request POST \
  --url https://api.appgram.dev/api/v1/license-keys/public-key/rotate \
  --header 'Authorization: Bearer <token>'

License Keys

Get a license key by ID

Returns one license key with its hydrated end user (when assigned) and the full list of device activations. Plaintext key is never returned.

GET /api/v1/license-keys/{id}

Authorizations

Authorization string header required

Bearer token — an API key prefixed with app_. Create one in the dashboard under Settings → Developer → API Keys.

Path parameters

id string path required

License key ID

GET /api/v1/license-keys/{id} bash
curl --request GET \
  --url https://api.appgram.dev/api/v1/license-keys/{id} \
  --header 'Authorization: Bearer <token>'

License Keys

Delete a license key

Permanently delete a license key and its activations. Prefer POST /revoke for normal lifecycle — delete is destructive and breaks audit trails.

DELETE /api/v1/license-keys/{id}

Authorizations

Authorization string header required

Bearer token — an API key prefixed with app_. Create one in the dashboard under Settings → Developer → API Keys.

Path parameters

id string path required

License key ID

DELETE /api/v1/license-keys/{id} bash
curl --request DELETE \
  --url https://api.appgram.dev/api/v1/license-keys/{id} \
  --header 'Authorization: Bearer <token>'
Response · 200 json
{
  "error": {
    "code": "string",
    "message": "string"
  },
  "page": 0,
  "per_page": 0,
  "success": true,
  "total": 0,
  "total_pages": 0
}

License Keys

Update a license key

Partial update — only safe-to-change fields (end_user_id, plan, max_devices, expires_at, metadata) are accepted. Project, plaintext key, and status cannot be changed here; use the dedicated /revoke endpoint to retire a key.

PATCH /api/v1/license-keys/{id}

Authorizations

Authorization string header required

Bearer token — an API key prefixed with app_. Create one in the dashboard under Settings → Developer → API Keys.

Path parameters

id string path required

License key ID

Body

application/json
end_user_id string
expires_at string
max_devices integer
metadata object
plan string
PATCH /api/v1/license-keys/{id} bash
curl --request PATCH \
  --url https://api.appgram.dev/api/v1/license-keys/{id} \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
  "end_user_id": "string",
  "expires_at": "string",
  "max_devices": 0,
  "plan": "string"
}'

License Keys

Revoke a license key

Mark a license key as revoked. Active host apps keep working until their currently-issued entitlement JWT expires (default 7 days); the next /portal/license-keys/refresh call will then fail.

POST /api/v1/license-keys/{id}/revoke

Authorizations

Authorization string header required

Bearer token — an API key prefixed with app_. Create one in the dashboard under Settings → Developer → API Keys.

Path parameters

id string path required

License key ID

POST /api/v1/license-keys/{id}/revoke bash
curl --request POST \
  --url https://api.appgram.dev/api/v1/license-keys/{id}/revoke \
  --header 'Authorization: Bearer <token>'

Portal - License Keys

Activate a license key on a device

Public endpoint called by the customer's host app to bind a device fingerprint to one of the key's seats. Returns a signed entitlement JWT — store it locally and verify it on every launch with the embedded public key (no network call required after activation).

POST /portal/license-keys/activate

Body

application/json
device_fingerprint string required
device_name string
key string required
platform string
project_id string required
POST /portal/license-keys/activate bash
curl --request POST \
  --url https://api.appgram.dev/portal/license-keys/activate \
  --header 'Content-Type: application/json' \
  --data '{
  "device_fingerprint": "string",
  "device_name": "string",
  "key": "string",
  "platform": "string",
  "project_id": "string"
}'

Portal - License Keys

Deactivate a device

Public endpoint called by the host app to release this device's seat against the license key. Idempotent — calling it for an already-deactivated device returns success. Use when the user uninstalls or wants to free a slot for a new machine.

POST /portal/license-keys/deactivate

Body

application/json
device_fingerprint string required
key string required
project_id string required
POST /portal/license-keys/deactivate bash
curl --request POST \
  --url https://api.appgram.dev/portal/license-keys/deactivate \
  --header 'Content-Type: application/json' \
  --data '{
  "device_fingerprint": "string",
  "key": "string",
  "project_id": "string"
}'
Response · 200 json
{
  "error": {
    "code": "string",
    "message": "string"
  },
  "page": 0,
  "per_page": 0,
  "success": true,
  "total": 0,
  "total_pages": 0
}

Portal - License Keys

Refresh an entitlement

Public endpoint called by the host app on a cadence (typically weekly, or when the JWT is near expiry) to re-issue the entitlement JWT. Server-side revocation takes effect on the next failed refresh — so a short refresh cadence is what makes /revoke bite quickly on customer devices.

POST /portal/license-keys/refresh

Body

application/json
device_fingerprint string required
key string required
project_id string required
POST /portal/license-keys/refresh bash
curl --request POST \
  --url https://api.appgram.dev/portal/license-keys/refresh \
  --header 'Content-Type: application/json' \
  --data '{
  "device_fingerprint": "string",
  "key": "string",
  "project_id": "string"
}'