Server SDK API
The server SDK is created with createGuapocadoClient().
import { createGuapocadoClient } from "@guapocado/sdk";
const guap = createGuapocadoClient({ apiKey: process.env.GUAPOCADO_API_KEY!, customerId: "org_123",});Options
Section titled “Options”type GuapocadoClientOptions = { apiKey: string; customerId?: string; apiUrl?: string; adapter?: GuapAdapter;};Most apps should not set apiUrl. The default hosted API is:
https://api.guapocado.devEntitlements
Section titled “Entitlements”await guap.has("advanced-analytics");Returns boolean.
await guap.limit("seats");Returns:
type LimitBalance = { limit: number; included: number; purchased: number; expansionAllowed: boolean; autoExpansionEnabled: boolean;};await guap.usage.balance("api-calls");await guap.usage.consume("api-calls", 1);await guap.usage.refund("api-calls", 1, { idempotencyKey: refundRequestId });await guap.usage.configure("api-calls", { overageEnabled: true,});consume() accepts an optional idempotency key so a retried call (timeout, queue
redelivery) is applied at most once:
await guap.usage.consume("api-calls", 1, { idempotencyKey: requestId });refund() also accepts an optional idempotency key. It reverses the exact
allocation originally consumed, including the specific purchase-credit lots.
balance(), consume(), and refund() return:
type UsageBalance = { balance: number; included: number; consumed: number; overage: number; overageAllowed: boolean; overageEnabled: boolean; resets: string | null;};Limit Settings
Section titled “Limit Settings”await guap.limits.configure("seats", { purchased: 3, autoExpansionEnabled: false,});Returns LimitBalance.
Customers
Section titled “Customers”await guap.customers.create({ id: "org_123", name: "Acme Inc.", email: "owner@example.com",});Returns the customer record.
Context
Section titled “Context”await guap.context({ features: ["advanced-analytics"], usage: ["api-calls"], limits: ["seats"], includePlans: true, includeSubscription: true,});Use context when a route needs several billing answers at once.
await guap.plans.list();Returns products pushed from config.
Purchases
Section titled “Purchases”await guap.purchases.list();await guap.purchases.refund("pur_123", { mode: "prorated", idempotencyKey: "refund-pur-123",});Prorated purchase refunds are supported for a single metered-credit grant. Full refunds revoke all remaining grants from the purchase.
Subscriptions
Section titled “Subscriptions”await guap.subscription.current();await guap.subscription.change("pro");await guap.subscription.refund("sub_123", { mode: "prorated", idempotencyKey: "refund-sub-123",});Use checkout for new subscriptions. Use change() when a customer already has
a subscription. A subscription refund cancels immediately and uses the unused
fraction of the actual paid invoice period.
Checkout
Section titled “Checkout”await guap.checkout.create({ productKey: "pro", successUrl: "https://app.example.com/billing/success", cancelUrl: "https://app.example.com/billing",});Returns:
type CheckoutResponse = { url: string;};Webhooks
Section titled “Webhooks”await guap.webhooks.register({ url: "https://app.example.com/api/guap-webhook", events: "*", integration: "custom", registrationKey: "custom:primary",});Returns the registered receiver and signing secret.
Local Read Model (Store-Backed)
Section titled “Local Read Model (Store-Backed)”import { createGuapocadoClientWithLocal } from "@guapocado/sdk";
const guap = createGuapocadoClientWithLocal({ apiKey: process.env.GUAPOCADO_API_KEY!, store: myGuapStore, // defaults to createMemoryGuapStore() maxAgeMs: 60_000, // optional; unset means no expiry webhook: { publicUrl: "https://app.example.com/webhooks/guap" }, hooks: { onCancel, onPurchase },});
export default { fetch: (request: Request) => guap.handler()(request) };createGuapocadoClientWithLocal combines createGuapLocal with
createGuapocadoClient, attaching .handler to the returned client.
createGuapLocal alone returns the pieces separately:
type GuapLocal = { adapter: GuapAdapter; // pass to createGuapocadoClient({ adapter }) handler: (hooks?: GuapWebhookHooks) => (request: Request) => Promise<Response>; project: (event: GuapDomainEventEnvelope) => Promise<void>; // test/queue seam register: () => Promise<{ id: string; status: string; url: string }>;};webhook.publicUrl is required for auto-registration (see
Local Read Model).
hooks accepts onEvent, the raw per-type hooks
(onCustomerUpdated, onSubscriptionUpdated, onPurchaseCompleted,
onPurchaseUpdated, onEntitlementsUpdated, onInvoiceUpdated), the
semantic transition hooks (onSubscribe, onCancel, onPlanChange), and
onPurchase. See
Webhook hooks for the two-tier
delivery contract and idempotency requirement.
export function verifyGuapocadoSignature(input: { payload: string; secret: string; signature: string | null | undefined; toleranceSeconds?: number; // default 300}): Promise<boolean>;Verifies a guapocado-signature: t=...,v1=... header against the raw request
body. createGuapLocal’s handler uses this internally; call it directly if
you write a receiver by hand instead.
testGuapStoreContract (from @guapocado/sdk/testing) validates a custom
GuapStore implementation against the same contract suite the built-in
in-memory store passes.
Enterprise deals
Section titled “Enterprise deals”Per-customer custom pricing and limits. Uses the same entitlement keys as your catalog, with negotiated values, plus an optional custom price.
await guap.contracts.set( { priceAmount: 200000, // cents; e.g. $2,000 priceInterval: "month", entitlements: { seats: { included: 500 }, "api-calls": { included: 50_000_000 }, "advanced-analytics": true, }, committedVolume: 50_000_000, notes: "Annual enterprise agreement", }, { customerId: "org_123" },);
const deal = await guap.contracts.get({ customerId: "org_123" });await guap.contracts.delete({ customerId: "org_123" }); // reverts to catalog planSetting a deal applies the negotiated entitlement values immediately; checkout then bills that customer at their custom price. See Enterprise deals for the full model.
Audit log
Section titled “Audit log”Every mutating action is recorded with the token that performed it.
const { logs, nextCursor } = await guap.audit.list({ action: "usage.consume", resourceType: "meter", limit: 50,});Per-call Customer ID
Section titled “Per-call Customer ID”Every customer-scoped method accepts a customer override:
await guap.has("advanced-analytics", { customerId: "org_456",});Use this for admin tools and background jobs.