In this tutorial, you’ll build NeuralAPI — a tiered AI platform where each subscription plan comes with a monthly token credit allowance, customers can buy top-up packs when they run low, and your backend automatically deducts credits as requests are processed by OpenAI.Documentation Index
Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
Use this file to discover all available pages before exploring further.
- Create a custom credit entitlement (tokens) and a meter that auto-deducts from it
- Attach credits to subscription plans (with and without overage) and a one-time top-up product
- Wire a real OpenAI completion endpoint that bills tokens through Dodo Payments
- Query a customer’s live credit balance via the SDK
- Verify webhook signatures and route Dodo Payments credit events
What We’re Building
Here’s the pricing model for NeuralAPI:| Product | Price | Tokens | Overage |
|---|---|---|---|
| Starter Plan | $29/month | 10,000,000 tokens/cycle | Blocked at zero |
| Pro Plan | $99/month | 40,000,000 tokens/cycle | $0.005 per 1K tokens |
| Token Top-Up Pack | $19 one-time | +5,000,000 tokens | — |
- A Dodo Payments account (test mode is fine)
- An OpenAI API key
- Node.js 18+
- Basic familiarity with TypeScript/Node.js
Step 1: Create Your Token Credit Entitlement
First, create the credit entitlement that both subscription plans and the top-up pack will share. Think of this as defining the “token” unit your platform uses.
Navigate to Credits
- Log into your Dodo Payments dashboard
- Click Products in the left sidebar
- Select the Credits tab
- Click Create Credit
Configure the credit unit
API TokensCredit Type: Select Custom UnitUnit Name: tokenPrecision: 0 (tokens are always whole numbers)Credit Expiry: 30 days (credits reset each billing cycle)Skip overage at the credit level
Step 2: Create a Meter for Token Usage
A meter aggregates incoming usage events and converts them into credit deductions. You need this before creating the plan products, since you’ll attach it during product creation in Step 3.Configure the meter
Token Usage MeterEvent Name: api.tokens_used (this must match exactly what your app sends)Aggregation Type: Sum — we sum the token count from each eventOver Property: tokens — the metadata key on each event whose value will be summedMeasurement Unit: tokensSave the meter and copy its ID — you’ll reference it when attaching to products.Step 3: Create the Plan Products
Both plans need to be Usage Based Billing products, not plain Subscriptions — meters can only attach to UBB products, and you need the meter to auto-deduct credits as customers call your API. UBB products still support a recurring base fee (the$29 / $99); usage on top of that gets billed in credits.

Starter Plan ($29/month — 10M tokens, no overage)
Create the Starter UBB product
- Go to Products → Create Product
- Select Usage Based Billing as the pricing type
- Fill in:
NeuralAPI StarterDescription: 10 million API tokens per month. Perfect for individual developers and small projects.Fixed Price: 29.00 (the recurring base fee — billed monthly even before any usage)Billing Cycle: MonthlyCurrency: USDAttach the meter
Token Usage Meter. Then on the meter:- Toggle Bill usage in Credits on
- Credit Entitlement: select
API Tokens - Meter units per credit:
1— each token in the event maps to 1 credit deducted - Free Threshold:
0— the credit allocation itself is the customer’s “free tier”; we don’t need an extra free band

api.tokens_used events actually deduct from the customer’s balance.Configure credit issuance for Starter
10000000Allow Overage: Disabled — Starter customers are blocked when tokens run outImport Default Credit Settings: Enabled — use the 30-day expiry from the credit entitlement
Pro Plan ($99/month — 40M tokens, overage enabled)
Create the Pro UBB product
NeuralAPI ProDescription: 40 million API tokens per month with overage. Built for production applications.Fixed Price: 99.00Billing Cycle: MonthlyCurrency: USDAttach the meter
Token Usage Meter, toggle Bill usage in Credits on, select API Tokens, Meter units per credit 1, Free Threshold 0.Configure credit issuance with overage
40000000Import Default Credit Settings: Disable — we need to customize overage settings per productAllow Overage: EnabledPrice Per Unit: 0.000005 USD per token (i.e., 5 per 1M tokens — above the plan’s effective per-token rate to discourage spillover)Overage Behavior: Bill overage at billing — overage is charged on the next invoice, then the balance resetsSave the product and copy the product ID.Step 4: Create the Token Top-Up Pack
The top-up pack is a one-time purchase that grants 5,000,000 tokens to an existing customer’s balance.
Create a one-time product
- Go to Products → Create Product
- Select Single Payment as the pricing type
- Fill in:
Token Top-Up PackDescription: Instantly add 5 million tokens to your NeuralAPI balance.Price: 19.00Currency: USDAttach the token credit
- In the Entitlements section, click Attach next to Credits
- Select
API Tokens - Set Credits issued:
5000000 - Disable Import Default Credit Settings — we want to override the default 30-day expiry
- Set Credit Expiry:
365 days - Save the product
Step 5: Build the Backend
Now let’s build the Express server that handles subscription checkout, top-up checkout, real OpenAI completions with token billing, balance queries, and credit webhook events.Set up environment variables
.env with your credentials and IDs from the previous steps:DODO_PAYMENTS_WEBHOOK_KEY in Step 7 after registering your webhook endpoint.Implement the server
src/server.ts:A note on how deductions actually happen
- Your handler calls OpenAI and gets back
usage.total_tokens(e.g., 1532). - You ingest a single usage event:
event_name: api.tokens_used,metadata: { tokens: 1532 }. - The
Token Usage Meteraggregates events by customer. - Because the meter is wired to the
API Tokenscredit with Bill usage in Credits, Dodo Payments deducts 1532 credits from the customer’s oldest non-expired grant (FIFO). - If overage is enabled and the customer goes below zero, the deficit is tracked and billed on the next invoice.
Step 6: Add a Demo Frontend
Createpublic/index.html to test all the flows in your browser. We persist the customer ID to localStorage so subscribe → generate → top-up all share the same identity, mimicking a logged-in app:
Step 7: Wire Up the Webhook
Webhooks let your server react to balance changes — you’ll use them to send “running low” emails before customers hit zero.Expose your local server
https://...ngrok-free.app URL.Register the webhook in Dodo Payments
- In the dashboard, go to Developers → Webhooks → Add Endpoint
- URL:
https://your-tunnel.ngrok-free.app/webhooks/dodo - Subscribe to (at minimum):
credit.addedcredit.deductedcredit.overage_charged
- Save and copy the Signing Secret
- Paste it into
.envasDODO_PAYMENTS_WEBHOOK_KEY, then restartnpm run dev
Step 8: Test the Full Flow
Subscribe a test customer
- Run
npm run dev - Open
http://localhost:3000 - Pick Pro Plan, enter a test email + name, click Get Checkout Link, complete checkout with test card details
- In the dashboard, go to Customers → most recent and copy the
cus_...ID - Paste it into the “Logged-in customer ID” field on the demo and click Save
Generate a real AI response
total_tokens, ingests a usage event, and returns the response.Troubleshooting
Credits not deducting after usage events
Credits not deducting after usage events
- The meter’s event name doesn’t match the
event_nameyou’re sending (api.tokens_usedis case-sensitive) - The meter isn’t linked to the
API Tokenscredit on the product — go to the product’s meter configuration and confirm Bill usage in Credits is on - The
metadata.tokenskey doesn’t match the meter’s “Over Property” field - The customer’s grant has expired (check the customer’s credit history)
- Products → Meters: open the meter and confirm it shows the linked credit name on the product attachment
- The Events tab on the meter — ingested events should appear there even before deduction
- Customers → [Customer] → Credits: ledger entries should appear within a minute or two
Balance always shows 0 or 'customer not found'
Balance always shows 0 or 'customer not found'
- The customer hasn’t completed checkout yet — credits are only issued after a successful payment
- You’re querying with the wrong
customer_id(use thecus_...ID from the dashboard, not your own DB ID) - The
CREDIT_ENTITLEMENT_IDin.envdoesn’t match the credit attached to the product
Overage not working for Pro plan customers
Overage not working for Pro plan customers
- Overage wasn’t enabled on the Pro product’s credit attachment (the credit-level setting is just a default)
- The customer is actually on Starter, not Pro
- Overage limit was set to 0
0.000005 (= $5 per million tokens; double-check the leading zeros — the field takes per-token price, not per-1K).`Webhook verification failed` in logs
`Webhook verification failed` in logs
- Body parsing order:
express.json()was applied to/webhooks/dodobeforeexpress.raw()— the SDK needs the raw bytes of the request, not parsed JSON - Wrong signing secret in
DODO_PAYMENTS_WEBHOOK_KEY - Reverse proxy is rewriting headers
app.use('/webhooks/dodo', express.raw(...)) line comes before app.use(express.json()) in server.ts.Need help?
Congratulations! You’ve Built Credit-Based Billing for NeuralAPI
Your platform now has a complete, production-ready credit billing system:Token Credit Entitlement
API Tokens credit with 30-day expiry, shared across all plans and the top-up packTiered Plans, One Credit
One-Time Top-Up Pack
Auto-Deduction via Meter
Live Balance API
Verified Webhook Pipeline
credit.added, credit.deducted, credit.overage_charged) routed through a signature-verified handler using the SDK’s Standard Webhooks helper- Auth on
/credits/:customerIdand/api/generate— currently anyone can hit these with any customer ID. Authenticate users and look up their customer ID server-side. - Stable
event_ids — the example usesDate.now() + random. In production, use your request ID so retries are idempotent (Dodo Payments deduplicates byevent_id). - Persist the customer↔user mapping — store
customer_idin your DB after the first checkout so you don’t need a manual paste step. - Decide what happens when a subscription ends. Plan credits remain in the customer’s ledger until their natural expiry (30 days from issuance) and top-up credits stay valid for 365 days — but the cookbook’s
/api/generateonly checks balance, not subscription status. So a cancelled customer can still consume their remaining tokens. That’s the consumer-friendly default. If you want stricter access control, either (a) listen to thesubscription.cancelledwebhook and gate/api/generateon subscription status, or (b) call Dodo’s ledger API to debit unused plan credits on cancel while leaving top-up credits intact. - Monitor the Usage Billing dashboard to catch metering anomalies early.