TLDR:Documentation Index
Fetch the complete documentation index at: https://docs.chainstack.com/llms.txt
Use this file to discover all available pages before exploring further.
- On June 2, 2026, the Solana Foundation shipped Subscriptions & Allowances — an audited, open-source reference program (program ID
De1egAFMkMWZSN5rYXRj9CAdheBamobVNubTsi9avR44) that makes recurring billing and delegated spending native to Solana, live on mainnet and devnet. - The trick it solves: an SPL token account can have only one delegate. The program routes every arrangement through a per-(user, mint) Subscription Authority PDA that holds the single
u64::MAXapproval, then gates each transfer through individual delegation PDAs — so one token account can power unlimited simultaneous subscriptions and allowances. - It exposes three models: fixed delegations (allowances), recurring delegations, and subscription plans.
- There is no Python SDK — the official TypeScript client is even Codama-generated — so we build the instructions by hand in Python with
soldersand run the full create-plan, subscribe, and collect lifecycle against a Chainstack Solana devnet node.
What shipped
On June 2, 2026, the Solana Foundation released Subscriptions & Allowances: a single shared program that any team can build on for recurring billing and delegated spending, instead of stitching together off-chain billing infrastructure. It is a Solana Foundation reference program — reposolana-program/subscriptions — written in Pinocchio (a lightweight no_std framework), with IDL and clients generated by Codama, audited by Cantina, and deployed under a Squads multisig upgrade authority. Design partners at launch include Helius (API-tier billing), Confirmo, Dynamic, Majority, Mesh, and Meow.
This guide explains the one idea that makes the whole thing work, disambiguates it from the two adjacent primitives people confuse it with, and then walks the full lifecycle in Python against a Chainstack node.
The one-delegate problem
Solana’s SPL Token program already lets you hand spending authority to someone else. TheApprove instruction records a delegate and an allowance on your token account: the delegate can move up to that many tokens out of your account without you signing each transfer. Revoke clears it. This is the primitive behind every “approve then pull” flow on Solana.
It has one hard limit, stated plainly in the program’s architecture notes:
Solana’s SPL Token delegate model allows only one delegate per token account.Approving a new delegate silently overwrites the previous one. So a single USDC account can authorize exactly one service at a time. Want to subscribe to two newsletters and give an AI agent a budget, all from the same balance? You can’t — the third approval wipes the first two. This constraint has been an open request since 2022 (solana-program-library issue #3858). The Subscriptions program fixes it with one level of indirection.
Not to be confused with
Before the mechanics, clear up three things that sound alike:| Primitive | What it is | Limit |
|---|---|---|
Approve delegate (spl-token) | The raw SPL Token instruction that sets one delegate + allowance on a token account | One delegate per account |
| Spend permissions | Solana’s product framing of that same approve-delegate primitive for builders | Same — one delegate per account |
| Subscriptions program | A program built on top of approve-delegate that multiplexes many policy-controlled delegations behind a single PDA delegate | Unlimited simultaneous arrangements |
How it works
For each(user, mint) pair, the program derives a Subscription Authority (SA) PDA:
Approve so the SA PDA becomes the user’s single delegate, with a u64::MAX allowance. From the token program’s point of view there is exactly one delegate — no conflict with the one-delegate rule.
The SA itself can’t move anything. It only transfers when a separate delegation PDA authorizes a specific amount to a specific party. Those delegation PDAs are where all the real limits live:
Each delegation PDA records the SA’s
init_id (the slot at which the SA was created). Every transfer checks it against the live SA. Closing and re-creating the SA in a later slot changes init_id, which invalidates old delegations — a coarse kill switch. To stop one specific delegation immediately, revoke that delegation PDA.The three models
One program, three delegation types:| Model | Who creates it | Cap behavior | Who can pull |
|---|---|---|---|
| Fixed delegation (allowance) | The token owner | One total amount, decremented per transfer; optional expiry | The delegatee only |
| Recurring delegation | The token owner | amount_per_period that resets each period; skipped periods don’t stack | The delegatee only |
| Subscription plan | The merchant | Plan-defined amount per period_hours, resets each period | Plan owner + up to 4 whitelisted pullers |
amount, period_hours, and an on-chain created_at fingerprint) are immutable and are snapshotted into each subscriber’s PDA at subscribe time. A merchant can’t change the price out from under existing subscribers — and can’t delete-and-recreate a plan at the same address with new terms, because the snapshot would no longer match (you’d get a PlanTermsMismatch).
Token-2022 and stablecoins
The program works with both SPL Token and Token-2022 mints, but Token-2022 extensions that would make delegated transfers unsafe are a problem. In practice:- USDC works — it’s a plain mint with no problematic extensions. (Solana’s announcement copy says the program works “including confidential transfers”; that contradicts both the README and the code, so don’t build on it.)
- PYUSD does not — PayPal’s Solana mint carries Token-2022 extensions (permanent delegate / transfer fee) that the design rules out for delegated pulls.
Prerequisites
- Python 3.10+
pip install solana solders(thesolanapackage ships thespl.tokenhelpers we use for mint setup)- A Chainstack Solana devnet node endpoint
- Some devnet SOL from the Chainstack faucet for fees and rent
Run Solana mainnet and devnet nodes on Chainstack
Start for free and get your app to production levels immediately. No credit card required. You can sign up with your GitHub, X, Google, or Microsoft account.CHAINSTACK_DEVNET below.
Build it in Python
There is no Python SDK for this program, and the official TypeScript client is Codama-generated (and gitignored in the repo) — so the cleanest path in Python is to build the instructions ourselves. The program makes this pleasant: every instruction is a single leading discriminator byte followed by a fixed, C-packed, little-endian payload — no Borsh length prefixes, no 8-byte Anchor hashes.Constants and helpers
The program IDs, PDA derivation, ATA derivation, and a small instruction-data encoder.
Instruction builders
Each builder returns a The two read helpers decode the raw account bytes. Both accounts are
solders.Instruction. The account order and discriminators come straight from the program’s instruction handlers.#[repr(C, packed)], so the offsets are exact:Fund the wallets
We need two wallets — a merchant and a subscriber — and some devnet SOL for fees and rent. Managed devnet nodes have Paste the merchant address into the Chainstack Solana faucet to receive 1 devnet SOL, then run the rest:
requestAirdrop disabled, so we fund the merchant from the Chainstack faucet and then send the subscriber a little SOL from the merchant.Create a mint and give the subscriber a balance
A fresh 6-decimal SPL mint, an ATA for each wallet, and 100 test tokens for the subscriber to be billed against. We use a plain SPL mint so there are no Token-2022 extensions to worry about.
Initialize the subscriber's Subscription Authority
This creates the SA PDA and approves it as the
u64::MAX delegate on the subscriber’s token account. The subscriber must sign — a sponsor can pay rent but cannot approve on someone else’s account.Merchant publishes a plan
A plan billing 1 token per day.
period_hours is the billing period, bounded to 1–8760 (up to one year); we pass 24.Subscriber subscribes
ix_subscribe reads the live plan terms and the SA init_id from chain and binds them into the instruction as consent fields. The program rejects the subscribe if the live plan disagrees.Merchant collects the first payment
The merchant pulls one period’s amount from the subscriber into the merchant’s token account. The program enforces that the caller is the plan owner (or a whitelisted puller), the receiver is allowed, and the per-period cap isn’t exceeded.A second collect inside the same 24-hour period fails with
AmountExceedsPeriodLimit — the cap resets only when the period rolls over. Skipped periods don’t accumulate.What’s next
This guide covered the user-facing lifecycle. Two follow-ups build on it:- Indexing subscription events with Yellowstone gRPC — the program emits create, cancel, and pull events as Anchor-compatible inner-instruction CPIs. Streaming them through a Chainstack Geyser endpoint gives you live revenue, churn, and failed-collection dashboards without polling.
- Capped onchain budgets for AI agents — the fixed-delegation model is the natural way to hand an autonomous agent a spending allowance, and it pairs with x402 for per-call agentic commerce.
