Skip to main content

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

FromToActionReversible
activesuspendedsuspendYes
activerevokedrevokeNo
suspendedactivereinstateYes
suspendedrevokedrevokeNo
expiredactivereinstateYes
revoked(terminal)noneNo
banned(terminal)noneNo
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 validation

Reinstating 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 again

Revoking 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 possible

Expiration Strategies

Configure how your policy handles license expiration.

StrategyBehaviorUse CaseValidation Code
RESTRICT_ACCESSBlock access immediately when the license expiresSubscriptions, time-limited licensesEXPIRED
ALLOW_ACCESSAllow continued access but flag the license as expiredGrace periods, soft enforcementVALID (with warning metadata)
REVOKEPermanently revoke the license on expirationStrict enforcement, one-time trial licensesREVOKED

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()