ZapAPI Docs
Get StartedConceptsAI GatewayGuidesPayment GatewaySDKAPI ReferenceResources
Guides

Project Subscriptions

Recurring billing for your project — plans, hosted checkout, subscriber portal, dunning, and renewals that settle to your settlement wallet.

Project subscriptions bring Stripe-Billing-style recurring revenue to your project: you create plans (price + interval), share a hosted checkout link, and ZapAPI handles renewals, trials, failed-payment dunning and the subscriber portal. Renewal payments settle to the project's settlement wallet — including your own external wallet via NWC.

Lightning has no pull payments

Cards can be charged silently; Lightning cannot. Renewals work three ways: manual (the subscriber gets an invoice email each cycle), balance (auto-deducted from the subscriber's ZapAPI wallet), or NWC (the subscriber's own wallet auto-pays via a Nostr Wallet Connect budget they approve). The subscriber chooses — you never hold their keys.

1. Create a plan

From Dashboard → your project → Plans, or via the API:

Create a plan
curl -X POST https://api.zapapi.com/api/v1/plans \
  -H "Authorization: Bearer zap_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Pro",
    "amountSats": 21000,
    "interval": "month",
    "trialDays": 7,
    "perks": ["Priority support", "Early access"]
  }'

With the SDK (projectId is optional for project-scoped keys):

const plan = await zap.plans.create({
  name: 'Pro',
  amountSats: 21000,
  interval: 'month',   // 'week' | 'month' | 'year'
  trialDays: 7,        // 0–90 days free before the first charge
  maxSubscribers: 100, // optional scarcity cap
});

Every plan gets a hosted checkout page:

https://zapapi.app/subscribe/<plan.id>

The subscriber enters an email or nostr npub, pays the first invoice, and is in. No account needed. Trials activate immediately and charge at trial end; non-trial plans stay pending (no access) until the first payment settles.

3. The subscriber portal

Subscribers receive a magic-link portal (30-day token, refreshed with every renewal receipt) where they can:

  • View their plan, period and payment history
  • Pause / resume renewals
  • Enable NWC auto-pay (their wallet pays renewals automatically)
  • Cancel

4. The lifecycle (and dunning)

subscribe → pending → (first payment) → active → renewals…
                 ↘ trialDays > 0 → trialing → (trial ends, paid) → active

renewal fails → 3-day grace (still active)
grace expires → past_due + warning email  (subscription.past_due webhook)
7 more days unpaid → canceled             (subscription.canceled webhook)

Renewals run hourly with bounded parallelism. A paid renewal extends the period exactly once (compare-and-swap settlement — duplicate webhook deliveries can never double-extend).

5. Track revenue and subscribers

From Dashboard → your project → Subscriptions (list, filters, cancel) or the API:

const { subscriptions, total } = await zap.subscriptions.list({
  status: 'active',
});
const { activeSubscribers, mrrSats, arrSats } =
  await zap.subscriptions.revenue();
await zap.subscriptions.cancel(subscriptionId);

Webhook events for your endpoint: subscription.created, subscription.activated, subscription.renewed, subscription.past_due, subscription.canceled.

6. Where the money goes

Renewal invoices are minted on the project's settlement wallet (Project → Settlement Wallet): your default ZapAPI wallet, a dedicated project wallet, an account wallet, or your own external wallet via NWC — fully non-custodial when NWC is linked on both sides (your NWC wallet receives; the subscriber's NWC wallet pays).

API reference

EndpointScope
POST /v1/plansplans:write
GET /v1/plans?projectId=plans:read
GET/PATCH/DELETE /v1/plans/:idplans:read / plans:write
GET /v1/plans/:id/subscriptionssubscriptions:read
GET /v1/subscriptions?projectId=&status=subscriptions:read
GET /v1/subscriptions/revenue?projectId=subscriptions:read
POST /v1/subscriptions/:id/cancelsubscriptions:write

Public (rate-limited, no auth): GET /v1/subscribe/plans/:id, POST /v1/subscribe/plans/:id/subscribe, portal endpoints under /v1/subscribe/portal/:token/*.

On this page