Introduction
Quickstart
From a fresh signup to a signed webhook delivery in five steps.
1. Create your organisation
Sign up at zengbook.com/signup and complete the onboarding wizard. You'll choose an org slug that becomes part of every in-app URL (for example, zengbook.com/acme-builders).
2. Upgrade to Growth or higher
The REST API and outbound webhooks are gated to the Growth, Business, and Enterprise plans. Upgrade under Settings → Billing.
402 INSUFFICIENT_PLAN.3. Generate an API key
Open Settings → API keys, give the key a label (such as data warehouse import), and click Create key. The full secret is shown once — copy it now. Stored keys are SHA-256 hashed and cannot be recovered.
Keys are prefixed zb_live_ followed by 22 base-62 characters, e.g. zb_live_4xK2pQ7nR9sT1vW3yZ5aBd.
4. Make your first request
Pass the key in the Authorization header. The simplest sanity check is GET /v1/me — it returns your organisation profile.
curl https://www.zengbook.com/api/v1/me \
-H "Authorization: Bearer zb_live_4xK2pQ7nR9sT1vW3yZ5aBd"You should get back:
{
"org": {
"id": "org_01HX...",
"name": "Acme Builders Pte Ltd",
"slug": "acme-builders",
"currency": "SGD",
"gstRate": 0.09,
"planTier": "growth"
}
}Every successful response also returns an X-Request-Id header and X-RateLimit-* headers. See rate limits for details.
5. Register a webhook endpoint
To receive Zeng Book events on your own server, open Settings → Webhooks, paste an HTTPS URL, select the events you care about (for example invoice.paid), and save. Zeng Book POSTs a JSON envelope and signs it with HMAC-SHA256.
A minimal verifier in Node:
import crypto from "node:crypto"
export function verify(rawBody: string, header: string, secret: string) {
const parts = Object.fromEntries(
header.split(",").map((p) => p.split("=") as [string, string])
)
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex")
return crypto.timingSafeEqual(
Buffer.from(expected, "hex"),
Buffer.from(parts.v1, "hex"),
)
}