Non-expiring prepaid credits should be represented as durable grant and transaction records with an explicit non_expiring policy—not only as a mutable balance or an arbitrary future expiration date. Account inactivity should create no debit, expiration, forfeiture, or reset event. The available balance should remain reconstructable from preserved issuance, consumption, refund, reversal, and adjustment entries.
Short Answer: Use Durable Events and an Explicit Non-Expiring State
A robust design begins with an explicit distinction between credit validity and the passage of time. If the governing terms say that a grant does not expire, represent that policy directly:
``yaml grant_id: grant_123 expiry_policy: non_expiring expires_at: null ``
The expiry_policy field supplies the meaning; expires_at: null is only its timestamp representation. A null date without an explicit policy can be ambiguous because it might also mean that expiration has not yet been assigned, is unknown, or is not applicable for another reason.
Avoid substituting a date decades in the future for a true non-expiring state. Far-future dates can produce incorrect expiration jobs, date-range errors, confusing reports, and accidental policy changes during migrations. They also obscure the business meaning of the grant.
The ledger should preserve every value-changing event. A current balance can be cached or materialized for fast reads, but it should be derived from—or regularly reconciled against—the durable event history. This makes it possible to reconstruct the balance after years without activity, even if operational systems, database versions, or reporting layers change.
A practical design therefore has three related layers:
- Grant records define where credits came from and whether they expire.
- Ledger events record each issuance, consumption, refund, reversal, or adjustment.
- Balance projections provide efficient current-state views without replacing the durable history.
Model Credit Grants, Ledger Events, and Available Balances Separately
Treat a credit grant as a distinct business object rather than only increasing an account-level balance. The grant can identify the source, credit category, original quantity, contractual policy, and any restrictions. Ledger events then record what happens to that grant over time.
Useful fields include:
| Field | Purpose |
|---|---|
grant_id | Stable identifier for the source grant |
account_id | Account or wallet that owns the credits |
event_id | Unique identifier for the ledger event |
event_type | Issuance, consumption, adjustment, reversal, or refund |
effective_at | When the underlying business event took effect |
recorded_at | When the ledger accepted the event |
units | Quantity of service credits affected |
unit_type | Denomination, such as inference credits or another defined service unit |
amount and currency | Monetary information, where applicable and supported by documented rules |
source_reference | Order, invoice, usage record, case, or contract reference |
idempotency_key | Key used to identify retried posting requests |
reversal_of | Link to an event being reversed or corrected |
expiry_policy | Explicit policy such as non_expiring or expires_at_date |
expires_at | Applicable expiration timestamp; null for an explicitly non-expiring grant |
Keep event types distinct. A refund is not simply another issuance, and a reversal is not a destructive deletion of the original event. Explicit event semantics make reporting, dispute investigation, and reconciliation more reliable.
The balance projection might contain the total available units and a version or sequence number. It should not be the only record of value. If that projection becomes inconsistent, the system should be able to rebuild it by processing valid ledger entries in a defined order.
Service-credit units should also remain separate from currency amounts. A credit may represent a service entitlement rather than cash, and its monetary treatment can depend on the agreement and reporting purpose. Where finance workflows require valuation or allocation, document the relevant conversion rule, currency, rounding method, and effective period instead of assuming that one credit always equals a fixed cash amount.
Treat Account Inactivity as a No-Op, Not a Balance Event
When credits are contractually non-expiring, inactivity should not itself produce a ledger transaction. Time can pass without changing the grant or its available balance.
A simplified event sequence could look like this:
``text 2026-01-15 ISSUANCE +10,000 units grant_123 2026-02-10 CONSUMPTION -750 units grant_123 2026–2031 NO EVENTS account inactive 2031-08-04 CONSUMPTION -250 units grant_123 ``
The balance before the 2031 consumption remains 9,250 units. The inactive interval does not contain a synthetic expiration, dormancy debit, forfeiture, or balance-reset entry.
Account lifecycle status should be modeled separately from credit validity. An account might be archived, suspended, locked pending identity verification, or moved to a lower-cost storage tier while its credit records remain intact. Operational access controls may affect when a customer can transact, but they should not silently rewrite ownership or availability rules.
This separation also makes reactivation safer. Rather than recreating a balance from an old report or support ticket, the system can restore access to the balance projection and verify it against the preserved ledger.
Contractual policy still matters. A technical non_expiring state should reflect the actual agreement governing the credits; it should not be used to override valid closure, refund, transfer, or regulatory requirements.
Define Deterministic Drawdown Rules Across Multiple Credit Grants
An account may hold credits from several purchases, promotions, refunds, or contract periods. Each consumption event should therefore identify which grant—or combination of grants—funded the usage.
The allocation policy must be deterministic. Given the same grant set and consumption event, the system should produce the same result during posting, reconciliation, replay, and migration. Possible policies include:
- drawing from the oldest grant first;
- prioritizing grants with the earliest valid expiration date;
- drawing from contract-specific or service-specific grants before general credits; or
- preserving restricted grants until eligible usage occurs.
No single ordering method is universally correct. The appropriate rule depends on contractual terms, customer expectations, refund policy, and operational requirements. Mixed expiring and non-expiring balances require especially clear rules. If expiring grants are prioritized, that behavior should be explicit rather than an accidental result of database ordering.
For example, if an account has 500 units expiring next quarter and 1,000 non-expiring units, a 600-unit consumption could be allocated as 500 units from the expiring grant and 100 from the non-expiring grant—if that is the documented policy. The ledger should retain both allocation links.
Explicit allocation supports several later operations:
- A refund can restore units to the same source grant under the applicable policy.
- A reversal can negate the original allocations rather than guessing where value came from.
- A dispute review can trace usage to a specific grant and contract.
- A migration can reproduce grant-level remaining balances, not merely the account total.
Concurrency also matters. When multiple usage events arrive together, posting should prevent them from spending the same remaining units. Transactional controls, sequence numbers, reservations, or another consistent concurrency mechanism can be used, depending on the system architecture.
Preserve Auditability Through Corrections, Reconciliation, and Long-Term Controls
Historical events should generally be preserved rather than overwritten. If a posting is wrong, record a linked compensating entry and, where appropriate, a corrected replacement. This retains both the original action and the reason the balance changed later.
For example, an erroneous 300-unit consumption could be handled with a 300-unit reversal linked through reversal_of, followed by a correctly allocated consumption event. Deleting the original transaction would make it harder to explain prior statements, investigate the error, or reconcile downstream systems.
Several operational controls help maintain a reconstructable ledger over long periods:
- Idempotent posting: Require a stable idempotency key for issuance, usage, refunds, and other externally initiated events. Retried requests should return the existing result rather than post the same event again.
- Balance reconciliation: Regularly compare the materialized balance with the balance reconstructed from durable events. Investigate discrepancies instead of silently replacing history.
- Access separation: Restrict who can issue credits, post administrative adjustments, reverse usage, or alter grant policy. Record the actor and reason for sensitive actions.
- Retention and backup: Align retention, backup, restoration, and archival practices with contractual commitments and applicable requirements. A non-expiring database flag does not help if the underlying records are discarded.
- Migration verification: Preserve identifiers, event ordering, grant allocations, and explicit expiration policies when moving data between systems.
- Audit logging: Record administrative actions and policy changes separately from financial or service-credit events so investigators can distinguish value movement from system configuration.
Both effective_at and recorded_at can be important. A delayed event may be recorded today but represent usage from an earlier period. The ledger should define which timestamp controls allocation, statements, reporting periods, and replay order. Tie-breaking rules are necessary when timestamps are equal or when events arrive out of sequence.
Long-term restoration should also be tested. A backup that exists but cannot reconstruct grant-level balances, allocation links, or non-expiring semantics may not preserve the intended business state.
Plan for Closure, Transfers, Refunds, Disputes, and System Changes
Ordinary issuance and consumption are only part of the lifecycle. Define explicit behavior for less frequent events before they occur.
Account closure: Closing an account should not automatically mean silently deleting its credits. The contract and applicable rules should determine whether credits remain recoverable, transfer, are refunded, or receive another documented treatment. The ledger should record the resulting event and its authority.
Contract or account transfer: Preserve the original grant and transaction references. A transfer can be represented as linked debit and credit events or another traceable mechanism, with authorization, source, destination, and effective time recorded.
Refunds: Specify whether a refund restores service-credit units, returns currency, or does both under separate rules. If units are restored, define whether they return to the original grant and retain its expiration policy.
Disputed usage: Avoid deleting the disputed transaction. A hold, provisional credit, reversal, or final adjustment can be represented through distinct events that show how the dispute progressed.
Denomination changes: If credit units change meaning, preserve the original denomination and record the conversion rule, rounding treatment, and effective date. Do not rewrite historical quantities as though the new denomination had always applied.
System migrations: Reconcile record counts and balances before and after migration. Preserve stable identifiers where possible, or maintain durable mapping records where identifiers must change. Test specifically that non_expiring grants do not acquire arbitrary dates through schema defaults, serialization behavior, or destination-system validation.
Credit categories should not be treated as interchangeable without analysis. Prepaid service credits, promotional credits, cash deposits, gift cards, and other stored-value arrangements can have different contractual, economic, accounting, and legal characteristics. Store a clear credit type and apply category-specific policies where needed.
Separate Ledger Validity From Accounting and Legal Treatment
A ledger can preserve the technical availability and transaction history of credits without deciding their accounting or legal classification. These are related but separate questions.
A non-expiring state means the application does not expire the grant merely because time has passed. It does not automatically determine whether the amount is a contract liability, another type of obligation, stored value, taxable consideration, unclaimed property, or subject to consumer-protection rules.
Likewise, a long period of inactivity does not by itself establish that an obligation can be derecognized or that a balance may be removed. Any such conclusion can depend on factors including:
- the type of credit and what the holder is entitled to receive;
- the wording of the contract and published policies;
- customer and issuer locations;
- refundability and transferability;
- the issuer’s continuing performance obligations; and
- applicable accounting, tax, stored-value, consumer-protection, and unclaimed-property requirements.
Finance, legal, tax, product, and engineering teams should align the ledger state with the governing terms while keeping each discipline’s conclusions distinct. Qualified advisers should review the relevant contracts, jurisdictions, and authoritative guidance. The ledger should then preserve the data needed to apply those conclusions without treating the technical schema as the conclusion itself.
In implementation terms, the core principle is straightforward: represent non-expiration explicitly, preserve value-changing events durably, make inactivity a no-op, and ensure that balances remain reconstructable. This creates a stable technical foundation for long-lived credits while leaving contract-specific accounting and legal determinations to the appropriate review.
Next Step
This guide addresses general prepaid-credit ledger architecture and does not describe a Token Forge Cloud wallet, billing, accounting, or stored-value feature.
For enterprise AI workloads, Token Forge Cloud Managed Model APIs provides an API-first path for evaluating model demand, while Token Forge Cloud Private LLM Inference supports private deployment and serving-layer optimization through capabilities such as caching, routing, batching, quantization, and GPU scheduling.
Contact Token Forge Cloud to discuss API access, private deployment, and LLM inference cost control.