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)
- Create one or more variants in
/portal/licenses. - Generate codes in bulk or upload predefined codes via CSV.
- Distribute codes to customers/users.
- Users redeem code after app connection.
- 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
409with replacement options. - Send
replacementVariantIdto 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:
5000rows per request. - Invalid rows and duplicates are skipped.
- Response includes
createdCountandskippedCount.
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 calculatedexpiresAt.
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
variantNamedoes not yet exist. revoke: trueexpires 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.