Skip to main content

Authorization State

What Authorization State Is

Authorization state determines whether a subject is currently permitted to access a resource.

This document defines the states an authorization can occupy and the rules governing transitions between them.

Why It Matters

Different instruments (subscriptions, credits) have different state machines, but they share common concepts:

  • active vs inactive
  • why authorization lapses
  • how it recovers

This document provides the common vocabulary for reasoning about authorization across all instrument types.

State Definitions

Active

The subject is currently authorized.

For subscriptions: payment has occurred and the access window has not expired.

For credits: credits have been allocated and not fully consumed.

isActive() returns true.

Inactive

The subject is not currently authorized.

This is the absence of active authorization. It may be temporary (awaiting payment) or permanent (canceled).

isActive() returns false.

Paused

The user has explicitly suspended their authorization.

The subscription or envelope exists and may have remaining value, but the user has chosen to halt execution. No payments process while paused.

Resuming returns to the previous state (minus any time elapsed).

Expired

The authorization's time bounds have been exceeded.

For subscriptions: lastPaidAt + interval + gracePeriod < now

For credits: the Permit2 allowance expiration has passed

Expiration is automatic. No transaction is required.

Exhausted

The authorization's usage bounds have been exceeded.

For subscriptions: remainingExecutions == 0

For credits: creditsConsumed == batchAmount

Exhaustion requires explicit action to reach.

Settled (Credits Only)

A credit batch has been fully consumed and is awaiting the next payment.

isSettled == true means the envelope is ready for a keeper to trigger the next batch purchase.

Subscription State Transitions

Trigger: Time

Subscriptions are time-driven. The key question:

Has enough time passed since the last payment that access should continue?

Access window = lastPaidAt + interval + gracePeriod

If now <= accessWindow, the subscription is active.

Key Transitions

FromToTrigger
Awaiting PaymentActiveFirst payment executes
ActiveDuenow >= nextChargeAt
DueActivePayment executes
ActivePausedUser pauses
PausedActiveUser resumes
ActiveExpiredAccess window passes
ActiveExhaustedNo remaining executions

What isActive() Checks

  1. Subscription exists
  2. lastPaidAt > 0 (at least one payment made)
  3. now <= lastPaidAt + interval + gracePeriod

If all three are true, the subscription is active.

Credit State Transitions

Trigger: Usage

Credits are usage-driven. The key question:

Has the agent consumed all allocated credits in this batch?

If creditsConsumed < batchAmount, credits remain. The agent is active.

If creditsConsumed == batchAmount, the batch is exhausted.

Key Transitions

FromToTrigger
SettledActivePayment executes
ActiveActiveCheckpoint submitted
ActiveExhaustedFull batch consumed
ExhaustedSettledSettlement voucher submitted
ActivePausedUser pauses
PausedActiveUser resumes

What isActive() Checks

  1. Envelope exists
  2. isSettled == false (has funded credits)
  3. Not paused
  4. Subject matches subscriber or agent

If all are true, the agent is active.

Subscriptions vs Credits

AspectSubscriptionsCredits
TriggerTimeUsage
Active meansWithin paid access windowHas unconsumed credits
Inactive meansAccess window expiredBatch exhausted or unfunded
Payment timingPredictable intervalsWhen batch depletes
User actionMostly passiveAgent consumes actively
Grace periodTime-based bufferNone

Execution Failures and State

Failed executions do not change authorization state.

If a keeper attempts execution and it fails:

  • Idempotency is not consumed (can retry)
  • Module state is unchanged
  • Authorization remains as it was

The only state changes occur on successful execution:

  • lastPaidAt updates (subscriptions)
  • sequence advances (credits)
  • remainingExecutions or remainingBatches decrements

Failures are logged but do not corrupt state.

Deriving Access From Chain State

Access is always computable from on-chain state alone.

For subscriptions:

active = (lastPaidAt > 0) && (now <= lastPaidAt + interval + gracePeriod)

For credits:

active = (isSettled == false) && (paused == false)

No off-chain state is required. The indexer may cache these computations, but any party can verify by querying the chain directly.

This is the core trust property: authorization is derived from immutable on-chain facts, not from a database that could be modified.

Relationship to RAI

Authorization state is the core primitive of Recurring Authorization Infrastructure.

The entire system exists to answer one question reliably:

Is this subject authorized to access this resource right now?

State transitions are the mechanics. Authorization is the product.

Non-Goals

The following are out of scope:

  • Subscription upgrades: Changing plans requires cancel and resubscribe.

  • Partial access: Authorization is binary. Tiered access is an application concern.

  • Historical queries: "Was this user active on date X?" requires event replay.

  • Cross-instrument authorization: A subscription does not grant credits. Each instrument is independent.

  • Automatic reactivation: Expired authorizations do not self-heal. User action is required.