Guides
License Lifecycle
Every license follows a state machine with defined transitions. Understanding the lifecycle helps you handle each status correctly.
State Diagram
License state machine
┌──────────┐ suspend ┌───────────┐
│ active │──────────────→│ suspended │
│ │←──────────────│ │
└──────────┘ reinstate └───────────┘
│ │
│ revoke │ revoke
▼ ▼
┌──────────┐ ┌───────────┐
│ revoked │ │ revoked │
│ (terminal)│ │ (terminal) │
└──────────┘ └───────────┘
┌──────────┐ reinstate ┌───────────┐
│ expired │──────────────→│ active │
└──────────┘ └───────────┘
┌──────────┐
│ banned │ (terminal — no transitions out)
└──────────┘License States
- active — License is valid and operational
- suspended — Temporarily disabled (e.g., payment issue); can be reinstated
- expired — Past expiration date; can be reinstated to extend
- revoked — Permanently disabled; terminal state, no transitions out
- banned — Permanently banned for abuse; terminal state, no transitions out
State Transitions
| From | To | Action | Reversible |
|---|---|---|---|
| active | suspended | suspend | Yes |
| active | revoked | revoke | No |
| suspended | active | reinstate | Yes |
| suspended | revoked | revoke | No |
| expired | active | reinstate | Yes |
| revoked | (terminal) | none | No |
| banned | (terminal) | none | No |
Terminal states
revoked and banned are terminal. Once a license enters either state, no further transitions are possible. Invalid transitions return a
409 Conflict error.Suspending a License
Suspend a license temporarily. Common reasons: payment failure, policy violation, or manual hold. Suspended licenses return SUSPENDED on validation.
suspend.py
from licentric import Licentric
client = Licentric(api_key="lk_live_your_key_here")
# Suspend a license (e.g., payment issue, policy violation)
client.licenses.suspend(
license_id="lic_abc123",
reason="Payment failed — invoice overdue"
)
# The license key now returns SUSPENDED on validationReinstating a License
Reinstate a suspended or expired license to make it active again.
reinstate.py
# Reinstate a suspended or expired license
client.licenses.reinstate(
license_id="lic_abc123"
)
# The license is now active againRevoking a License
Permanently revoke a license. This is irreversible and should be used for refunds, abuse, or permanent cancellations.
revoke.py
# Permanently revoke a license (terminal — cannot be undone)
client.licenses.revoke(
license_id="lic_abc123",
reason="Refund processed"
)
# The license key now returns REVOKED on validation
# No further state transitions are possibleExpiration Strategies
Configure how your policy handles license expiration.
| Strategy | Behavior | Use Case | Validation Code |
|---|---|---|---|
| RESTRICT_ACCESS | Block access immediately when the license expires | Subscriptions, time-limited licenses | EXPIRED |
| ALLOW_ACCESS | Allow continued access but flag the license as expired | Grace periods, soft enforcement | VALID (with warning metadata) |
| REVOKE | Permanently revoke the license on expiration | Strict enforcement, one-time trial licenses | REVOKED |
Handle Every Status
Your application should handle every possible validation status gracefully.
status_handler.py
def handle_validation_result(result):
"""Handle each possible license status."""
match result.code:
case "VALID":
grant_access()
case "EXPIRED":
show_renewal_prompt()
deny_access()
case "SUSPENDED":
show_message("License suspended. Contact support.")
deny_access()
case "REVOKED":
show_message("License has been revoked.")
deny_access()
case "BANNED":
show_message("License has been banned.")
deny_access()
case _:
deny_access()