Licenses

Complete documentation for LoginSign license management: variants, code lifecycle, developer APIs, user redemption, and automated status-based licensing.

1. What licenses do in LoginSign

  • Map your commercial plans (for example Free, Pro, Team, Enterprise) to configurable license variants.
  • Allow users to redeem codes after they connect your app in LoginSign.
  • Enable backend-driven status sync that grants/revokes licenses by globalId.
  • Provide searchable, auditable code inventory with owner and state metadata.

2. Core model

Variant

A variant defines a plan type (name, optional description, default duration) for one application.

Code

A code belongs to one variant and can be redeemed once per redemption lifecycle.

Datastore (PostgreSQL / Prisma)

Internally each code row belongs to exactly one variant. After redemption, LoginSign persists which AppConnection holds the entitlement via the foreign key linkedConnectionId. Developer APIs return a derived owner object instead of exposing the raw key. If you maintain database dumps or external reporting, run prisma migrate deploy so historical renames stay aligned with prisma/migrations/.

State

UNUSED   Code exists but was not redeemed yet
ACTIVE   Code is linked to an app connection
EXPIRED  Code reached expiry (non-lifetime) or was expired by flow logic

Duration

MONTH | YEAR | LIFETIME

3. Developer Portal workflow (recommended)

  1. Create one or more variants in /portal/licenses.
  2. Generate codes in bulk or upload predefined codes via CSV.
  3. Distribute codes to customers/users.
  4. Users redeem code after app connection.
  5. Monitor code states and owners in the license table.

4. Variant APIs (owner session)

GET    /api/developer/applications/:appId/licenses/variants
POST   /api/developer/applications/:appId/licenses/variants
PATCH  /api/developer/applications/:appId/licenses/variants/:variantId
DELETE /api/developer/applications/:appId/licenses/variants/:variantId

Create variant example

{
  "name": "Premium",
  "description": "Annual premium access",
  "defaultDuration": "YEAR",
  "active": true
}

Delete with replacement behavior

  • If no codes are linked: delete returns 204.
  • If linked codes exist and no replacement is sent: returns 409 with replacement options.
  • Send replacementVariantId to migrate linked codes and delete safely.

5. Code APIs (owner session)

POST   /api/developer/applications/:appId/licenses/codes/generate
POST   /api/developer/applications/:appId/licenses/codes/upload
GET    /api/developer/applications/:appId/licenses/codes?state=all|used|unused&q=...
DELETE /api/developer/applications/:appId/licenses/codes/:codeId

Generate codes example

{
  "quantity": 500,
  "variantId": "var_123",
  "duration": "MONTH"
}

Quantity is clamped server-side to 1..50000.

Upload codes example

{
  "variantId": "var_123",
  "duration": "YEAR",
  "codes": [
    "ABC1-DEF2-GHI3",
    { "code": "JKL4-MNO5-PQR6", "variantId": "var_999", "duration": "LIFETIME" }
  ]
}
  • Max upload size: 5000 rows per request.
  • Invalid rows and duplicates are skipped.
  • Response includes createdCount and skippedCount.

6. User redemption APIs (user session)

GET  /api/user/licenses/subscriptions
POST /api/user/licenses/redeem

Redeem request

{
  "code": "ABC1-DEF2-GHI3"
}

Redemption rules

  • Code must exist and not be expired.
  • Code already redeemed by another user returns conflict.
  • User must already have an active app connection for that application.
  • Activation persists linkedConnectionId, activatedAt, and calculated expiresAt.

Typical errors

  • 404: invalid code.
  • 400: expired code or missing connection.
  • 409: already used or race condition during concurrent redeem.

7. Status sync integration with licenses

Your backend can grant/revoke license-backed status directly:

PATCH /api/applications/:appId/users/:globalId/status
  • Uses Basic Auth (client_id:client_secret).
  • Can auto-create variant if variantName does not yet exist.
  • revoke: true expires active redeemed licenses for that user.

Detailed payloads are documented in Status.

8. Filtering, search, and reporting

  • Filter codes via state=all|used|unused.
  • Search by code, owner display name, owner email, alias email, and globalId.
  • Listing response includes summary counters: total, used, unused.

9. Operational best practices

  • Create clear variant naming conventions before large code generation.
  • Use CSV exports regularly for backup/audit trails.
  • When deleting variants, always verify replacement mapping first.
  • Treat generated and uploaded codes as secrets until redeemed.
  • Monitor spikes in redeem failures to detect integration issues.

10. Related docs