API
Subscriptions
Plans and subscribers around TabSubscriptionRouter. All endpoints are session-authed via the dashboard (cookie); the public subscribe link bypasses auth for the read path only.
List my plans
GET /api/subscriptions/plans
Cookie: tab-session=…
→ 200 OK
{
"plans": [
{
"id": "plan_xxx",
"planKey": "0x…",
"name": "Silver tier",
"amount": "9.99",
"currency": "USDC",
"chain": "base",
"period": 2592000,
"status": "active"
}
]
}Look up a plan by key (public)
GET /api/subscriptions/plans?planKey=0x…
→ 200 OK
{ "plans": [ { /* …same shape… */ } ] }Create a plan
Stages an off-chain record and returns onChainArgs for the creator's browser to call createPlan on-chain.
POST /api/subscriptions/plans
{
"name": "Silver tier",
"description": "Discord access, early features.",
"amount": "9.99",
"chain": "base-sepolia",
"period": 2592000
}
→ 201 Created
{
"plan": { "id": "plan_xxx", "status": "pending_create", … },
"onChainArgs": {
"router": "0x…",
"planId": "plan_xxx",
"amount": "9990000",
"period": 2592000
}
}Confirm plan creation
POST /api/subscriptions/plans/{plan_id}
{
"action": "confirm_create",
"txHash": "0x…",
"planKey": "0x…"
}Deactivate / reactivate a plan
POST /api/subscriptions/plans/{plan_id}
{ "action": "deactivate" } // or "reactivate"Send the on-chain deactivatePlan / reactivatePlan call first, then notify the server with this endpoint.
Subscriber: list my subscriptions
GET /api/subscriptions/subs
→ 200 OK
{
"subscriptions": [
{
"id": "sub_xxx",
"planKey": "0x…",
"subscriberHandle": "alice",
"creatorHandle": "designstudio",
"status": "active",
"startedAt": 1759999999000,
"lastChargedAt": 1759999999000,
"chargesPaid": 3
}
]
}Creator: list subscribers for one of my plans
GET /api/subscriptions/subs?planId=plan_xxx
→ 200 OK
{ "subscriptions": [ … ] }Subscribe (record off-chain mirror)
Call after the subscriber's wallet has run subscribe(planKey) on-chain. The first-period charge happens as part of the on-chain call.
POST /api/subscriptions/subs
{
"planKey": "0x…",
"txHash": "0x…"
}Cancel a subscription
POST /api/subscriptions/subs/{sub_id}
{ "action": "cancel" }Subscriber or creator can call. Run the on-chain cancel first; the server marks the rowcancelled for the dashboard.
Cron: charge due subscriptions
POST /api/cron/charge
Authorization: Bearer $ADMIN_SECRET
Content-Type: application/json
{ "chain": "base" }
→ 200 OK
{
"chain": "base",
"scanned": 14,
"charged": 9,
"skippedEarly": 5,
"skippedFailed": 0,
"errors": []
}Schedule this once an hour. The contract enforces the per-sub period so frequent runs are safe.
Webhooks
Subscribe to these event types from /dashboard/webhooks:
subscription.plan_createdsubscription.startedsubscription.chargedsubscription.cancelledsubscription.halted