Guapocado

Config-first billing for product teams

Billing logic that starts in your repo.

Define plans, entitlements, usage meters, and pricing in code. Guapocado syncs that config to Stripe and gives your server typed access checks — no plan logic scattered across conditionals.

synced
export default defineBilling({
  entitlements: {
    reports:   { type: "feature" },
    api_calls: { type: "meter",
                 reset: "monthly" },
    seats:     { type: "limit" },
  },
  products: [{
    key: "pro",
    pricing: {
      mode: "recurring",
      amount: 4900,
      currency: "usd",
      frequency: "month",
    },
    entitlements: {
      reports:   true,
      api_calls: { included: 40000 },
      seats:     { included: 10 },
    },
  }],
});

Runtime checks

guap.has("reports")

→ true

guap.usage.balance("api_calls")

→ balance: 31,200

guap.limit("seats")

→ limit: 10

Same three calls. Every framework. No Stripe SDK in your product code.

Agent-native development

Give your coding agent the Guapocado playbook.

Install one open-source skill and your agent can inspect the stack, choose the right billing primitives, wire the matching SDK, and validate the result. It retrieves current docs and works test-first instead of guessing from stale examples.

Stack-aware

Routes Next.js, Hono, Better Auth, React, Supabase, and raw HTTP correctly.

Billing-aware

Models features, meters, limits, checkout, and customer identity deliberately.

Safety-aware

Keeps keys server-side, starts in test, and asks before remote or live changes.

Terminal

Open skill

$ Install for your coding agent

npx skills add https://github.com/guapocado/guapocado --skill guapocado

Then ask

> Use $guapocado to add organization billing with a Pro plan, seat limits, and monthly AI credits.

Inspect Implement Verify

How it works

Define once. Sync once. Check anywhere.

The config file is the single source of truth. Everything else — Stripe products, access checks, usage tracking — derives from it.

01

Define in code

Write your plans, entitlements, and pricing in billing.config.ts. Features, meters with resets, limits with expansion, overage pricing — all in one place.

02

Push to sync Stripe

guap push creates Stripe products, prices, and metered rates from your config. Diffs show what changes before anything is applied.

03

Check from your server

Gate features, consume usage, and read limits through a typed SDK or plain HTTP. No Stripe SDK in your product code. No plan logic in conditionals.

Primitives

Small surface, predictable behaviour.

Three entitlement types cover the full range of product access. One call per check. No inspection of Stripe objects from app code.

Features

Boolean access gates. Ask once, get true or false. No plan conditionals scattered across your codebase.

await guap.has("advanced_reports")

→ true

Meters

Track usage that resets on a period. Consume, refund, and check balance. Overage continues billing when you allow it.

await guap.usage.balance("api_calls")

→ { balance: 31200, included: 40000 }

Limits

Numeric allowances that don't decrement from usage. Seats, projects, workspaces. Customers can expand by purchasing more.

await guap.limit("seats")

→ { limit: 13, included: 10, purchased: 3 }

Customers

Map your users, teams, and workspaces to billing state. Your app keeps its own user model — Guapocado only tracks the billing shape.

await guap.customer.sync()

→ { id: "org_123", planKey: "pro" }

Billing that adapts

Overage and expansion are billed events, not settings.

When a customer goes over their limit or buys more seats, Guapocado handles the Stripe subscription item automatically. You define the price in config. Nothing else changes.

Meter overage

Usage keeps flowing when the plan allows it.

Meters have a hard cutoff by default. Add an overage block and customers can opt in. Each consume call past the included balance reports a Stripe usage record. Stripe invoices the difference at period end.

api_calls: {
  included: 40000,
  overage: {
    allowed: true,
    unit: 10000,
    amount: 500,
    currency: "usd",
  },
}
await guap.usage.configure("api_calls", {
  overageEnabled: true,
})

Limit expansion

Customers can buy more without a plan change.

Expansion adds a licensed Stripe subscription item at the right quantity. Set a unit price and customers can go from 10 seats to 13 without hitting checkout again. There is no free expansion — if no price is defined, the request is rejected.

seats: {
  included: 10,
  expansion: {
    allowed: true,
    unit: 1,
    amount: 1200,
    currency: "usd",
  },
}
await guap.limits.configure("seats", {
  purchased: 3,
})
// Stripe subscription item updated automatically

CLI workflow

Config changes go through a diff before they touch Stripe.

The same four commands work for sandbox and production. guap plan shows exactly what will change — including a warning when a pricing change would leave existing subscribers on the old rate.

Field-level diff against the remote config

Pricing changes flagged with subscriber impact note

Confirm prompt before any push touches production

Terminal

guap init

Create billing.config.ts with a starter billing model

guap login --sandbox

Authenticate with your sandbox environment

guap plan --sandbox

Preview every change before it touches Stripe

guap push --sandbox

Apply the config — products, prices, and entitlement rates

~ products.pro.pricing.amount 4900 → 5900

⚠ existing subscribers keep current price

? Apply 1 change to production? › Yes

Integrations

SDK when it helps. HTTP when it does not.

Start with the thin server SDK, wire a framework helper, or call the managed API directly from another language or microservice. Better Auth and React get dedicated client plugins.

Ship billing without hiding the rules.

Sandbox is free for development. Use production when real customers are involved. Both environments live in the same config-first workflow.