Skip to main content
TLDR:
  • 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::MAX approval, 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 solders and 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 — repo solana-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. The Approve 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: “Spend permissions” on Solana is not a separate mechanism — it is the approve-delegate primitive described from a payments angle. The Subscriptions program is the thing that removes the one-delegate ceiling.

How it works

For each (user, mint) pair, the program derives a Subscription Authority (SA) PDA:
On initialization, the program calls SPL 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:
So the SPL allowance is a blunt “yes, everything” switch, and the program is the policy engine in front of it. You can create as many delegation PDAs as you like against the one SA — each with its own cap, cadence, expiry, and authorized puller. That is how a single token account supports unlimited concurrent subscriptions and allowances while staying exactly as safe as a normal approve-delegate (the SA can never move funds without an active delegation that permits it).
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: Fixed and recurring delegations are pull arrangements the user sets up for a specific delegatee — ideal for allowances and payroll. Subscription plans flip the direction: a merchant publishes immutable terms once, and any number of users subscribe to the same plan, each getting their own subscription PDA. The merchant (or a whitelisted puller) collects each cycle. Subscription plan terms (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.
The program’s README and the official docs state that seven extensions are rejected at SA initialization: ConfidentialTransfer, NonTransferable, PermanentDelegate, TransferHook, TransferFee, MintCloseAuthority, and Pausable. That is the design intent, and it’s the right mental model for what mints are safe.The shipped code is narrower: the runtime check (validate_mint_extensions) currently rejects only a mint with a configured TransferHook (an inert, permanently-unconfigured hook is allowed). The ConfidentialTransfer error code is even marked “reserved for backwards compatibility.” So don’t rely on the program to bounce a fee-bearing or permanent-delegate mint for you — treat the seven-item list as the set of mints you should not use, and pick your mint deliberately.
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.
We’ll use a plain SPL mint for the walkthrough.

Prerequisites

  • Python 3.10+
  • pip install solana solders (the solana package ships the spl.token helpers 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.
To get a devnet endpoint: in the Chainstack console, deploy a Solana devnet node and copy its HTTPS endpoint. We’ll refer to it as 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.
1

Constants and helpers

The program IDs, PDA derivation, ATA derivation, and a small instruction-data encoder.
2

Instruction builders

Each builder returns a solders.Instruction. The account order and discriminators come straight from the program’s instruction handlers.
The two read helpers decode the raw account bytes. Both accounts are #[repr(C, packed)], so the offsets are exact:
3

Fund the wallets

We need two wallets — a merchant and a subscriber — and some devnet SOL for fees and rent. Managed devnet nodes have requestAirdrop disabled, so we fund the merchant from the Chainstack faucet and then send the subscriber a little SOL from the merchant.
Paste the merchant address into the Chainstack Solana faucet to receive 1 devnet SOL, then run the rest:
4

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.
5

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.
6

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.
7

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.
8

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.
That’s the full lifecycle: one SA approval, one published plan, any number of subscribers, and a pull each cycle — all onchain, no billing backend.

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.

Conclusion

Subscriptions & Allowances turns recurring revenue from custom infrastructure into a shared, audited onchain primitive. The whole design rests on one idea — route every arrangement through a single Subscription Authority delegate and enforce the real limits in per-delegation PDAs — which is what lifts the one-delegate-per-account ceiling that blocked this for years. Because there’s no Python SDK, building the instructions by hand is also the best way to understand exactly what the program checks on every pull. Point the script at a Chainstack devnet node, run it top to bottom, and you have a working subscription in a few seconds.

About the author

Ake

Ake Director of Developer Experience @ Chainstack
Talk to me all things Web3
20 years in technology | 8+ years in Web3 full time years experience
Last modified on June 22, 2026