/payments-with-dodo

Dodo checkout, subscriptions and verified webhooks driving server-side entitlements.

Build·Checkout → Payment·MIT
$npx skills add tushaarmehtaa/tushar-skills --skill payments-with-dodo -g -a claude-code -y

Then type /payments-with-dodo in Claude Code, or describe the task and let it pick the skill.

What you get back contract tests · 10 Oct 2026

claude · tallyroom

Using /payments-with-dodo
  • Asked about accounts first
  • Return link never unlocks
  • 30 tests pass
Plus and Household start a real Dodo subscription. The server enforces the plan.
Claude Code 2.1.295·17m 06s·37 files changed
  • No auth and no persistence. The app has three pages and only Next/React as dependencies. The dashboard shows a hardcoded list of expenses. When the Dodo webhook says "subscription active", there's no account to attach it to and nowhere to save it.
  • The Choose Plus and Choose Household buttons on the pricing page now start a real Dodo subscription, and paying unlocks features that the server enforces. All 30 tests pass and next build is clean. I haven't been able to run a real payment end to end: the Dodo values in .env.local are marked as fake fixtures, and there's no local Postgres here.
  • Two copies of one event arriving at the same instant. That relies on Postgres row locking, and the in-memory test database can't simulate two connections. Worth checking once against real Postgres.
CaveatIt asked about auth and a database first and was told to go ahead with its suggestions.

Measured before → after

PlanGroupsCSV export
Free1no
Plusunlimitedno
Householdunlimitedyes

Input → output from the run

lib/checkout.js before
// TODO: move to env before launch
const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY || "sk_test_FAKE_FOR_FIXTURE";

export const PLANS = {
  plus: { price: "price_plus_monthly", label: "Plus" },
  household: { price: "price_household_monthly", label: "Household" },
};

export function checkoutUrl(plan) {
  const p = PLANS[plan];
  // Placeholder until the real Checkout session endpoint exists.
  return `/dashboard?plan=${p.price}&k=${STRIPE_SECRET_KEY.slice(0, 7)}`;
app/api/webhooks/dodo/route.js (new)
  let event;
  try {
    event = getDodo().webhooks.unwrap(body, { headers });
  } catch {
    return new Response("Invalid signature", { status: 401 });
  }

  try {
    const outcome = await handleWebhook(getDb(), headers["webhook-id"], event);
    return Response.json({ received: true, status: outcome.status });
  } catch (err) {
    // Not acknowledged, so Dodo retries. The inbox row keeps the event.
    console.error(`[billing] webhook ${headers["webhook-id"]} failed:`, err?.code ?? err?.name);
    return new Response("Temporary failure", { status: 503 });

When to use it

Use when

Use when adding Dodo billing or auditing its full lifecycle.

Skip it when

Skip it if you bill through another provider; it will not install Dodo beside one without a migration plan.

The thinking behind it

Billing breaks quietly. Wire checkout, webhooks, entitlements and refunds end to end, and people get exactly what they paid for, every time.

Output contract from the skill's Output section

Report product/entitlement mapping, SDK and environment detected, files/migrations changed, checkout/portal paths, webhook inbox and state transitions, payload minimization/access/retention decisions, server enforcement points, test evidence/event IDs, and exact dashboard/production steps still required.

How it checks its own work from the instructions

  • Duplicate and concurrent webhooks are tested in test mode
  • Invalid webhook signatures are tested
  • Renewal, cancellation, failed payment, and refund flows are tested
  • Stored subscriptions reconcile against the Dodo API

Requirements what it needs

Works in
Codex, Claude Code, Cursor
Needs
project files, terminal commands, network access

The instructions SKILL.md · 30 lines

Instructions & references

Back to overview ↑
On this page 4 sections
SKILL.md · MIT

Payments with Dodo

Implement the full billing lifecycle. Dodo is the source of billing events; the application’s server-side entitlement model is the authorization boundary.

Workflow

  1. Inspect framework/runtime, auth, database, existing provider/SDK and version, products, billing code, webhook storage, environment mapping, and deployment targets. Do not install Dodo beside another provider without explicit migration scope.
  2. Infer existing products and commercial policy. Ask only about unresolved one-time/subscription behavior, currency, trials, cancellation timing, refunds, tax, and capabilities unlocked.
  3. Model server-owned products, prices, and entitlements. The browser may submit a stable product key, never price, currency, credit amount, or entitlement.
  4. Keep test/live API keys, product IDs, webhook keys, and environment settings separate. Document names in .env.example without values.
  5. Read pricing and checkout for current official SDK checkout, product mapping, portal, and UI patterns. Read implementation guidance only when designing pricing or feature gates.
  6. Read webhooks before implementing event ingestion. Prefer official SDK verification, a durable webhook inbox with unique event ID, transactional state updates, explicit transient/permanent failure policy, and ordering by provider timestamps/version where available.
  7. Store provider customer/payment/subscription IDs and normalized status, billing-period boundaries, cancellation schedule, and last processed event data needed for reconciliation. Handle relevant payment, subscription, refund, dispute, dunning, and entitlement events.
  8. Protect paid features on the server using normalized entitlements. UI gates explain access but do not grant it.
  9. Build billing UI for checkout states, current entitlement, renewal/cancellation timing, failed-payment recovery, invoices/portal, and delayed webhook confirmation. Never treat a return URL or query parameter as proof of payment.

Verification

In Dodo test mode, test purchase, invalid product key, duplicate/concurrent webhook, invalid signature, transient database failure and retry, out-of-order update, renewal, scheduled cancellation, expiration, plan change, failed payment/on-hold/recovery, refund, dispute where relevant, replay, and unknown customer. Reconcile a stored subscription against the provider API. Run repository lint/type/test/build commands.

Output

Report product/entitlement mapping, SDK and environment detected, files/migrations changed, checkout/portal paths, webhook inbox and state transitions, payload minimization/access/retention decisions, server enforcement points, test evidence/event IDs, and exact dashboard/production steps still required.

View on GitHub ↗
Claude app, ChatGPT and ZIP download

local coding agent required

This skill requires project files, terminal commands, and network access. Uploading it to a chat app does not provide equivalent execution.

ChatGPT Skills

This workflow needs a local coding environment or capabilities that a chat-only Skills upload does not provide.

Package details
Package
payments-with-dodo/SKILL.md
Author
@tushaarmehtaa
Added
7 Aug 2026
Tags
dodo-paymentscheckoutsubscriptionswebhooksentitlementsbilling