Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.waffo.ai/llms.txt

Use this file to discover all available pages before exploring further.

SDKs & Libraries

Waffo Pancake provides official SDKs for TypeScript and Next.js, plus direct API access.

Choose Your Integration Level

Next.js SDK

Fastest — Drop-in components, hooks, and server actions. Handles checkout UI, webhook routing, and buyer self-service out of the box.npm install @waffo/pancake-nextjs

TypeScript SDK

Flexible — Full API coverage with automatic signing, typed responses, and webhook verification. Use with any Node.js framework.npm install @waffo/pancake-ts

Direct API

Full control — REST endpoints for writes, GraphQL for reads. Implement signing and verification yourself. Any language.
Next.js projects: Start with @waffo/pancake-nextjs — it wraps @waffo/pancake-ts and adds React components and server actions. You can always drop down to the TypeScript SDK or raw API calls for advanced use cases.

TypeScript SDK

@waffo/pancake-ts

Official TypeScript SDK on npm

Installation

npm install @waffo/pancake-ts

Features

  • Zero runtime dependencies, ESM + CJS, Node >= 20
  • Automatic request signing with deterministic idempotency keys
  • Full TypeScript type definitions (15 enums, 40+ interfaces)
  • Webhook verification with embedded public keys (test/prod)

Quick Start

import { WaffoPancake } from "@waffo/pancake-ts";

const client = new WaffoPancake({
  merchantId: process.env.WAFFO_MERCHANT_ID!,
  privateKey: process.env.WAFFO_PRIVATE_KEY!,
});

// Create a store
const { store } = await client.stores.create({ name: "My Store" });

// Create a one-time product
const { product } = await client.onetimeProducts.create({
  storeId: store.id,
  name: "E-Book: TypeScript Handbook",
  prices: {
    USD: { amount: "29.00", taxIncluded: false, taxCategory: "digital_goods" },
  },
});

// Create a checkout session
const session = await client.checkout.createSession({
  productId: product.id,
  currency: "USD",
});
// => redirect consumer to session.checkoutUrl

Configuration

ParameterTypeRequiredDescription
merchantIdstringYesYour Merchant ID
privateKeystringYesRSA private key (PEM, base64, or raw — auto-normalized)
baseUrlstringNoAPI base URL (default: production)
fetchtypeof fetchNoCustom fetch implementation

Available Resources

NamespaceMethodsDescription
client.storescreate() update() delete()Store management
client.onetimeProductscreate() update() publish() updateStatus()One-time product CRUD
client.subscriptionProductscreate() update() publish() updateStatus()Subscription product CRUD
client.subscriptionProductGroupscreate() update() delete() publish()Product groups for shared trial
client.orderscancelSubscription()Order management
client.checkoutcreateSession()Create checkout sessions
client.graphqlquery<T>()Typed GraphQL queries
client.authissueSessionToken()Issue buyer session token for checkout
client.webhooksverify()Webhook signature verification

Checkout Modes

The SDK supports two checkout modes based on whether you know the buyer’s identity:
ModeMethodBuyer IdentityFormUse Case
Authenticatedcheckout.authenticated.create()Merchant providesPre-filledSites with user accounts
Anonymouscheckout.anonymous.create()Not providedEmptyTemplate stores, shared links
Always use authenticated checkout when you know the buyer. Authenticated checkout binds orders to the buyerIdentity you provide — a stable, merchant-controlled identifier. Without it:
  • Trial abuse: buyers can claim unlimited free trials by changing their email
  • Order unlinking: different emails are treated as different users
  • No self-service: buyers cannot manage orders in Customer Portal
const result = await client.checkout.authenticated.create({
  productId: "PROD_xxx",
  currency: "USD",
  buyerIdentity: "userIdInYourSystem",
});
// Redirect: res.redirect(result.checkoutUrl) or window.location.href = result.checkoutUrl
buyerIdentity is for order attribution and trial tracking only — it is not rendered on the checkout page. To pre-fill the email field on the checkout form, pass buyerEmail explicitly.
With dynamic pricing and trial control:
const result = await client.checkout.authenticated.create({
  productId: "PROD_xxx",
  currency: "USD",
  buyerIdentity: "userIdInYourSystem",
  buyerEmail: "customer@example.com",
  priceSnapshot: { amount: "19.99", taxCategory: "digital_goods" },
  withTrial: true,
  billingDetail: { country: "US", isBusiness: false },
  successUrl: "https://example.com/thank-you",
});

Anonymous Checkout

const result = await client.checkout.anonymous.create({
  productId: "PROD_xxx",
  currency: "USD",
});
// Also supports priceSnapshot and withTrial

Webhook Verification

import { verifyWebhook, WebhookEventType } from "@waffo/pancake-ts";

// Express (use raw body — parsed JSON breaks signature verification)
app.post("/webhooks", express.raw({ type: "application/json" }), (req, res) => {
  try {
    const event = verifyWebhook(
      req.body.toString("utf-8"),
      req.headers["x-waffo-signature"] as string,
    );
    res.status(200).send("OK");

    switch (event.eventType) {
      case WebhookEventType.OrderCompleted:
        // handle order completion
        break;
      case WebhookEventType.SubscriptionActivated:
        // handle subscription activation
        break;
    }
  } catch {
    res.status(401).send("Invalid signature");
  }
});

// Next.js App Router
export async function POST(request: Request) {
  const body = await request.text();
  const sig = request.headers.get("x-waffo-signature");
  try {
    const event = verifyWebhook(body, sig);
    // handle event ...
    return new Response("OK");
  } catch {
    return new Response("Invalid signature", { status: 401 });
  }
}

Error Handling

import { WaffoPancakeError } from "@waffo/pancake-ts";

try {
  await client.stores.create({ name: "" });
} catch (err) {
  if (err instanceof WaffoPancakeError) {
    console.log(err.status);  // 400
    console.log(err.errors);  // [{ message: "...", layer: "store" }, ...]
  }
}

Next.js SDK

@waffo/pancake-nextjs

Official Next.js SDK — components, hooks, and server actions

Installation

npm install @waffo/pancake-nextjs
Requires @waffo/pancake-ts as a peer dependency. Works with Next.js 14+ App Router.

Client Exports

ExportTypeDescription
CheckoutButtonComponentThree-mode checkout button (link / anonymous / authenticated)
WaffoPancakeProviderComponentBuyer self-service context with automatic token lifecycle
useCheckout()HookProgrammatic checkout control
useBuyer()HookBuyer self-service actions (cancel, refund, reactivate, query)
useBuyerOrders()HookFetch buyer’s orders
useBuyerPayments()HookFetch buyer’s payment records
useBuyerRefundTickets()HookFetch buyer’s refund tickets
useMerchantOrders()HookMerchant dashboard orders
useMerchantSales()HookMerchant sales overview
useMerchantSubscriptions()HookMerchant subscription overview
WebhookRoute HandlerAuto-verify signatures and dispatch events

Server Exports (@waffo/pancake-nextjs/server)

ExportDescription
createCheckoutAction(config)Server Action: create checkout sessions
createBuyerTokenAction(config)Server Action: issue buyer session tokens
createBuyerSessionAction(config)Server Action: buyer self-service operations
createMerchantQueryAction(config)Server Action: merchant GraphQL queries

Quick Example

// app/lib/actions.ts
"use server";
import { createCheckoutAction, createBuyerTokenAction } from "@waffo/pancake-nextjs/server";

const config = {
  merchantId: process.env.WAFFO_MERCHANT_ID!,
  privateKey: process.env.WAFFO_PRIVATE_KEY!,
};

export const checkoutAction = createCheckoutAction(config);
export const issueBuyerToken = createBuyerTokenAction(config);
// app/components/BuyButton.tsx
"use client";
import { CheckoutButton } from "@waffo/pancake-nextjs";
import { checkoutAction } from "@/app/lib/actions";

export function BuyButton({ productId }: { productId: string }) {
  return (
    <CheckoutButton
      type="authenticated"
      action={checkoutAction}
      productId={productId}
      currency="USD"
      buyerIdentity={user.email}
    >
      Subscribe Now
    </CheckoutButton>
  );
}

Webhook Route Handler

// app/api/webhooks/waffo/route.ts
import { Webhook } from "@waffo/pancake-nextjs";

export const POST = Webhook({
  onOrderCompleted: async (event) => {
    // Deliver digital goods
  },
  onSubscriptionActivated: async (event) => {
    // Provision access
  },
  onSubscriptionCanceled: async (event) => {
    // Revoke access
  },
});

Next.js Guide

Full step-by-step Next.js integration guide.

Direct API Access

You can also use the REST and GraphQL API directly. API Key authentication is handled automatically by the SDK — no manual header setup is needed.
// Create a product
const { product } = await client.onetimeProducts.create({
  storeId: "your-store-uuid",
  name: "My Product",
  prices: {
    USD: { amount: "29.00", taxIncluded: false, taxCategory: "saas" },
  },
});

// Query data via GraphQL
const data = await client.graphql.query<{ stores: Array<{ id: string; name: string; status: string }> }>(
  `{ stores { id name status } }`
);

SDK Roadmap

LanguageStatus
Node.js / TypeScriptAvailable — @waffo/pancake-ts
Next.jsAvailable — @waffo/pancake-nextjs
PythonPlanned
GoPlanned
PHPPlanned

Framework Guides

Next.js

Build with Next.js and Server Actions.

Checkout Sessions

Create checkout flows programmatically.

Subscriptions

Implement recurring billing.

Webhooks

Receive real-time event notifications.

API Reference

For complete endpoint documentation:

API Reference

Full REST and GraphQL API documentation.