BotForge

Resources

Examples

Real code against the real 11-endpoint v1 API — see the full endpoint list on the API Reference page.

REST / cURL

List paid orders

curl "https://bot-forge-coral.vercel.app/api/v1/orders?status=paid&limit=25" \
  -H "Authorization: Bearer bf_live_xxx"

Create a product

curl -X POST https://bot-forge-coral.vercel.app/api/v1/products \
  -H "Authorization: Bearer bf_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"name":"Blue Hoodie","price_cents":4999,"currency":"usd"}'

TypeScript client

A minimal typed wrapper — expand it with the schemas from /api/v1/openapi.json.

botforge-client.ts

const BASE = "https://bot-forge-coral.vercel.app/api/v1";

async function bf<T>(path: string, init?: RequestInit): Promise<T> {
  const res = await fetch(`${BASE}${path}`, {
    ...init,
    headers: { Authorization: `Bearer ${process.env.BOTFORGE_API_KEY}`, ...init?.headers },
  });
  if (!res.ok) throw new Error(`BotForge API error ${res.status}: ${await res.text()}`);
  return res.json();
}

interface Order { id: string; number: number; status: string; total_cents: number; currency: string }
export const listOrders = (status?: string) =>
  bf<{ data: Order[]; pagination: { total: number; limit: number; offset: number } }>(
    `/orders${status ? `?status=${status}` : ""}`,
  );

Webhook handler (Next.js route)

app/api/botforge-webhook/route.ts

import crypto from "crypto";

export async function POST(req: Request) {
  const rawBody = await req.text();
  const signature = req.headers.get("x-botforge-signature") ?? "";
  const expected = "sha256=" + crypto.createHmac("sha256", process.env.BOTFORGE_WEBHOOK_SECRET!)
    .update(rawBody).digest("hex");

  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
    return new Response("Invalid signature", { status: 401 });
  }

  const { event, data } = JSON.parse(rawBody);
  if (event === "order.paid") {
    // fulfil the order
  }
  return new Response("ok", { status: 200 });
}

Full event list and retry schedule on the Webhooks page.

Error handling

Retry on 429 with backoff

async function bfWithRetry<T>(path: string, attempt = 1): Promise<T> {
  try {
    return await bf<T>(path);
  } catch (err) {
    if (String(err).includes("429") && attempt <= 3) {
      await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
      return bfWithRetry<T>(path, attempt + 1);
    }
    throw err;
  }
}

Full error code table on API Reference.