Stripe Integration

How billing works when Tanso syncs with Stripe — Stripe handles payment collection and invoicing, Tanso manages entitlements and credits.

In Stripe Integration mode, Stripe is the payment engine and Tanso is the entitlement and metering engine. Tanso syncs your plans and customers to Stripe, and Stripe handles invoicing and payment collection. Tanso listens for webhooks to keep everything in sync.


Setup

  1. Register your Stripe API key in the Tanso dashboard or via MCP (registerStripeApiKey)
  2. Set up the integration — Tanso creates a webhook endpoint in Stripe and switches your account to Stripe Integration mode
  3. Optionally import existing data — If you already have products, customers, and subscriptions in Stripe, Tanso can import them automatically

How it works

1. Create a customer

Same API call as Tanso mode. Tanso automatically creates a matching customer in Stripe, linked by your customerReferenceId.

await fetch(`${TANSO_API}/customers`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    customerReferenceId: 'user_456',
    email: '[email protected]',
    firstName: 'Jane',
    lastName: 'Smith',
  })
})
// Customer created in Tanso AND synced to Stripe.

2. Subscribe the customer to a plan

// List plans to get the plan ID
const plans = await fetch(`${TANSO_API}/plans`, { headers })
  .then(r => r.json())

const proPlan = plans.data.find(p => p.plan.key === 'pro_monthly')

// Subscribe the customer
const result = await fetch(`${TANSO_API}/subscriptions`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    customerReferenceId: 'user_456',
    planId: proPlan.plan.id,
  })
}).then(r => r.json())

What happens next depends on billing timing:

  • In-advance plans — The response includes a checkoutUrl. Redirect your customer to pay. No subscription or invoice is created yet — Tanso waits for Stripe to confirm payment.
  • In-arrears plans — The subscription activates immediately. Stripe invoices at the end of the period.

3. Redirect to pay (in-advance plans)

For paid in-advance plans, the subscribe response includes a Stripe Checkout URL. Redirect your customer there to collect payment:

if (result.data.checkoutUrl) {
  // Redirect customer to Stripe Checkout
  res.redirect(result.data.checkoutUrl)
  // e.g. https://checkout.stripe.com/pay/cs_test_a1b2c3...
}

When payment completes, Stripe sends a webhook to Tanso. Tanso automatically:

  • Creates the subscription
  • Creates and marks the invoice as paid
  • Grants entitlements and credits

No additional API calls needed on your end. Free plans ($0) skip checkout and activate immediately.

4. Check entitlements before serving requests

Same as Tanso mode — same endpoint, same response:

app.post('/api/chat', async (req, res) => {
  // Check entitlement
  const entitlement = await fetch(
    `${TANSO_API}/entitlements/${req.userId}/ai_chat`,
    { headers }
  ).then(r => r.json())

  if (!entitlement.data.isAllowed) {
    return res.status(403).json({
      error: 'Usage limit reached',
      usage: entitlement.data.usage
    })
  }

  const result = await openai.chat.completions.create(req.body)

  // Report usage — Tanso records the event AND forwards usage
  // to Stripe Meters for billing. Credits are deducted first;
  // only overage is sent to Stripe.
  await fetch(`${TANSO_API}/events`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      eventIdempotencyKey: crypto.randomUUID(),
      eventName: 'chat_completion',
      customerReferenceId: req.userId,
      featureKey: 'ai_chat',
      costInput: {
        model: 'gpt-4o',
        modelProvider: 'openai',
        inputTokens: result.usage.prompt_tokens,
        outputTokens: result.usage.completion_tokens,
      },
      usageUnits: result.usage.total_tokens,
    })
  })

  res.json(result)
})

5. Pre-flight check with usage simulation

Same as Tanso mode:

const evaluation = await fetch(`${TANSO_API}/entitlements`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    customerReferenceId: 'user_456',
    featureKey: 'ai_chat',
    track: {
      eventName: 'chat_completion',
      usageUnits: 5000
    }
  })
}).then(r => r.json())

if (evaluation.data.simulation.wouldExceedLimit) {
  return res.status(403).json({ error: 'Would exceed usage limit' })
}

6. Check credit balance

Same as Tanso mode:

const pools = await fetch(
  `${TANSO_API}/credits/user_456/pools`,
  { headers }
).then(r => r.json())

pools.data.forEach(pool => {
  console.log(`${pool.denomination}: ${pool.balance} remaining`)
})

Renewals

Stripe handles billing cycles automatically. When Stripe generates and collects payment for the next period, Tanso receives a webhook and:

  • Updates the subscription's billing period
  • Grants credits for the new period (applying rollover policies)
  • Refreshes entitlements

No code needed on your end — renewals are fully automated.


Upgrades and downgrades

Upgrade — Same API call. Tanso updates the Stripe subscription and Stripe calculates proration automatically, generating an adjustment invoice.

const customer = await fetch(
  `${TANSO_API}/customers/user_456`,
  { headers }
).then(r => r.json())

const subscriptionId = customer.data.subscriptions[0].id
const enterprisePlan = plans.data.find(p => p.plan.key === 'enterprise_monthly')

await fetch(`${TANSO_API}/subscriptions/${subscriptionId}/plan-change`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    changeToPlanId: enterprisePlan.plan.id,
    changeType: 'UPGRADE'
  })
})
// Stripe handles proration and charges the difference automatically.
// No manual payment step needed.

Downgrade — Scheduled for end of period. When applied, Tanso syncs the plan change to Stripe.

const starterPlan = plans.data.find(p => p.plan.key === 'starter_monthly')

await fetch(`${TANSO_API}/subscriptions/${subscriptionId}/plan-change`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    changeToPlanId: starterPlan.plan.id,
    changeType: 'DOWNGRADE'
  })
})
// Scheduled for end of current billing period.

Cancellation

End of period — Tanso sets cancelAtPeriodEnd on the Stripe subscription. Stripe stops billing when the period ends.

await fetch(
  `${TANSO_API}/subscriptions/cancellation/${subscriptionId}?cancelMode=END_OF_PERIOD`,
  { method: 'POST', headers }
)

Immediate — Tanso cancels the Stripe subscription, revokes entitlements, and claws back plan-included credits.

await fetch(
  `${TANSO_API}/subscriptions/cancellation/${subscriptionId}?cancelMode=IMMEDIATE`,
  { method: 'POST', headers }
)

Undo a scheduled cancellation:

await fetch(
  `${TANSO_API}/subscriptions/cancellation/${subscriptionId}/scheduled`,
  { method: 'DELETE', headers }
)

How usage-based billing works with Stripe

When you ingest events via POST /api/v1/client/events, Tanso:

  1. Records the event for analytics and entitlement tracking
  2. Deducts from credit pools if the customer has credits for this feature
  3. Forwards the overage (usage not covered by credits) to Stripe Meters
  4. Stripe calculates tiered charges and adds them to the next invoice automatically

You don't need to interact with Stripe's metering API directly — Tanso handles the forwarding.


Stripe webhooks

Tanso listens for these Stripe events to stay in sync:

WebhookWhat Tanso does
invoice.createdMirrors the invoice into Tanso
invoice.paidMarks invoice paid, activates subscription, grants entitlements and credits
invoice.payment_failedMarks invoice as PAST_DUE
customer.subscription.updatedSyncs plan changes back to Tanso
customer.subscription.deletedDeactivates the subscription in Tanso

The webhook endpoint is created automatically during setup — no manual configuration needed.


Key differences from Tanso mode

AspectTanso ModeStripe Integration
Payment collectionYou handle it, then call mark-paidStripe collects automatically
Invoice generationTanso creates invoicesStripe auto-generates invoices
Billing cycle renewalTanso scheduled jobStripe triggers via webhook
Usage-based billingTanso calculates at invoice timeStripe Meters calculate in real time
Proration on upgradeTanso creates adjustment invoiceStripe calculates automatically
Subscriptions per customerMultiple allowedOne active subscription per customer
Setup requiredNoneStripe API key + webhook registration

Entitlements, credits, events, and analytics work identically in both modes.