FEATURES
Subscriptions
Recurring stablecoin charges. Publish a plan, share a link, the subscriber approves the router once — Tab's executor handles every charge after that. Useful for paid Discord communities, creator memberships, SaaS billing, and recurring tips.
How it works
- Creator publishes a plan. From
/dashboard/subscriptions, you set name, price, period (daily / weekly / monthly / quarterly / yearly) and chain. One tx publishes it onTabSubscriptionRouter. - Subscriber visits the share link. At
/subscribe/[planKey]they see the plan card and tap subscribe. Their wallet signs two txs: anapprove()for the lifetime allowance and onesubscribe()that charges the first period. - Tab cron charges each period.
POST /api/cron/chargewalks active subs and submits the contract'scharge(planKey, subscriber). The contract enforceslastChargedAt + period <= nowso double-charging is impossible. - Subscriber can cancel anytime. One on-chain tx flips the sub to inactive. Allowance revocation or zero balance also halts charges — Tab catches the revert and marks the sub
halted.
Trust model
- Funds never leave the subscriber's wallet until each charge fires. There's no escrow and no custody by Tab.
- The router can never increase the price. Plan
amountandperiodare immutable on-chain — to change pricing, the creator publishes a new plan and migrates subscribers. - Anyone can call
charge.The schedule, allowance check, and active-sub check live in the contract, so a malicious caller can't over-charge — only settle a legitimately-due period. - Protocol fee. Each charge takes a 1% fee (capped at 5% by the contract). Net goes to the creator.
Plan lifecycle
pending_create— staged off-chain, on-chain createPlan tx in flight.active— accepting new subscribers and charges.deactivated— no new subscribers; existing subscribers can still cancel but the cron won't advance their charges.
Subscription lifecycle
active— being charged each period.cancelled— subscriber or creator stopped it. No further charges; allowance left in place until the subscriber revokes manually.halted— last cron pass reverted (allowance or balance insufficient). The dashboard surfaces this so the creator can ping the subscriber to top up + resume.
Webhooks
Each lifecycle transition fires a webhook to any subscription registered for it:
subscription.plan_createdsubscription.startedsubscription.chargedsubscription.cancelledsubscription.halted
Contract reference
See TabSubscriptionRouter for the full surface and audit notes.