Developer Platform
Build a complete headless SaaS
Use every promoted first-class module from your own React, mobile, desktop, or legacy interface without exposing an API credential to the browser.
A headless SaaS keeps your own interface while BuildWithHQ supplies the governed application backend. Developer Kit 1.20.65 exposes all 274 promoted first-class module operations plus tenant account, user, role/location assignment, delegated-token, revocation, and DeepSeek Harness contracts. You can build the complete catalog without calling an internal tenant URL or connecting React to SQL.
The production shape
Browser / mobile / desktop UI
| your session + CSRF
v
Your trusted server or narrow BFF
| app-bound BuildWithHQ credential
v
https://api.buildwithhq.com/v1/apps/{saasAppId}/...
| server-derived app + user + DataRole + location scope
v
Only the authorized, paginated result returns to your UI
The app credential is bound to one SaaS app. Your trusted server uses it to manage that app's tenant accounts and users, then exchanges its own user identity for a short-lived delegated token. Every module request executes the same secured service contract as the native application. The URL chooses a target; it never proves authority.
The kit-root TENANT-PROVISIONING-AND-AUTHENTICATION.md guide maps both supported provisioning paths. Signed-in SaaS builders can administer organizations in the Builder Console, while external servers use the published bwk_live_ tenant-account and tenant-user operations. Builder product routes intentionally are not app-credential routes. Their separate openapi/platform-owner.json contract and BuildWithHQPlatformClient use the current verified Builder session.
Connect a marketing-site signup
Your public pricing or signup page posts to your own authenticated, rate-limited backend-for-frontend. That server verifies the email and identity-provider subject, then calls createTenantAccount with its protected live-app credential. Never place a bwk_live_ credential in browser JavaScript, a public form, or a mobile bundle, and never send a raw password to BuildWithHQ.
The one idempotent call creates the top-level customer organization, first owner, protected owner role, up to five initial DataRoles, and up to five initial Locations. The returned key-to-ID maps can seed later user assignments. Because this is the same routed AppAccount contract used by the consoles, the new customer appears immediately under the app's Organizations directory and the owner sees the in-SaaS Account administration area. Additional roles and locations can be added later through normal administration.
Follow the complete customer-organization website signup guide.
Act as the real end user
- Create or resolve an AppAccount with your stable external organization ID.
- Create a passwordless TenantUser and assign only DataRoles and Locations from that account.
- Exchange the user's external subject for a 2–15 minute
bwu_live_token from your trusted server. - Give only that short-lived token to that user's browser or mobile client. It cannot manage identities or mint tokens.
- Revoke it explicitly or deactivate the user. Deactivation revokes every active delegated token for that app/account/user.
const account = await api.createTenantAccount({
providerKey: "your-auth", externalAccountId: organization.id,
accountName: organization.name, primaryEmail: organization.billingEmail,
ownerExternalSubject: currentUser.id, ownerEmail: currentUser.email,
ownerDisplayName: currentUser.name,
dataRoles: [{
key: "member", name: "Member", canRead: true,
canReadRecords: true, permissionKeys: ["records.read"],
}],
locations: [{
key: "head-office", name: "Head office",
timeZone: "America/Los_Angeles",
}],
});
const delegated = await api.exchangeDelegatedUserToken({
providerKey: "your-auth", externalAccountId: organization.id,
externalSubject: currentUser.id,
scopes: ["modules.contacts.read", "modules.work-orders.read"],
lifetimeMinutes: 10,
});
Zero UserLocationXref rows is the explicit all-locations contract. Send locationScopeMode: "all" deliberately; for "selected", send at least one reviewed location ID. An omitted or empty update never silently expands access.
Management scopes are tenant-accounts.read/write, tenant-users.read/write, and tenant-users.tokens.issue. Identity mutations and token issuance are written to the SaaS immutable Logs database with API-client and represented-user context.
Embed the published page body or the complete page
Create a delegated token with runtime.pages.read. BuildWithHQRuntimeClient.getPageBody(pageKey) returns the registered components and page body without BuildWithHQ menus or shell, so the existing product keeps its own navigation. Page design tokens are omitted by default and can be explicitly included. getPageBootstrap(pageKey) returns the complete shell, menus, components, and page when the host wants the full BuildWithHQ experience.
The kit carries one compiled local-only packages/page-runtime library. React and Puck install it through locked file: dependencies, so npm ci downloads their declared third-party dependencies without publishing BuildWithHQ code or requiring an npm organization. The library parses presentation data; the VB Developer API remains the secured HTTP data and authorization boundary.
For blocks with registered data sources, add runtime.bindings.read and call resolveBindings with at most 24 unique keys. All three calls require the short-lived bwu_live_ credential and reuse the hosted runtime's user entitlement, DataRole, Location, record filtering, tenant routing, stored procedures, and audit.
Copy the server-side TypeScript start
import { BuildWithHQModuleClient } from "./sdk/BuildWithHQConnector.js";
const api = new BuildWithHQModuleClient({
saasAppId: process.env.BWHQ_SAAS_APP_ID!,
credential: process.env.BWHQ_API_CREDENTIAL!,
});
export async function contactsPage(search = "") {
return api.contactsList({ search, pageNumber: 1, pageSize: 50 });
}
export async function workOrdersPage() {
return api.workOrdersList({ pageNumber: 1, pageSize: 50 });
}
Run this code on a trusted server only. Never put BWHQ_API_CREDENTIAL in VITE_*, NEXT_PUBLIC_*, page JSON, browser storage, a mobile bundle, logs, prompts, or source control.
What the 1.20.65 kit gives you
- All 369 public operations in semantically identical generated JSON and YAML OpenAPI files.
- All 274 first-class module operations as typed methods in
sdk/modules.generated.ts, exported byBuildWithHQConnector.ts. - Exact required scopes on every operation in
catalog/operations.json, with module rate classes and aliases in the sanitizedcatalog/module-surface.json. - Complete request and response DTOs, including lists, detail reads, writes, files, searches, ticketing, approvals, and module-specific state changes.
- React presentation sources for professional dashboards and native Builder pages, while leaving authentication and mutations on the trusted side of the boundary.
- Machine-readable coverage whose two SDK manifests must equal OpenAPI exactly before the ZIP builds.
Builder names and API names are explicitly joined
catalog/capabilities.json records each Builder feature slug beside its Developer API module key, public base path, and scopes. For example, the Builder feature record-relations uses the record-graph API module, knowledge-core uses knowledge-articles, and dynamic-records is served below /modules/dynamic. The React gallery displays both identities so developers do not infer route names from marketing labels.
Native Builder and headless are two views of the same system
Builders save registered React blocks and pages in BuildWithHQ; those blocks use a signed-in tenant session. Headless developers use the generated server SDK and paint the returned data in their own React or other client. Both paths reach the same module services and secured database contracts. A developer can prototype a presentation from the kit, then either publish it as a Builder component or host it in a headless interface—the identity mechanism changes, but the business contracts and server-side data scope do not.
Go-live checks
- Issue a least-privilege credential with only the module read/write scopes the server needs.
- Keep list/search calls bounded and preserve server pagination; never download a tenant graph to render one row.
- Handle 401, 403, 404, 409, 429, and 5xx distinctly and retain the correlation ID.
- Test a valid record, a foreign-tenant record, and a random nonexistent ID. Foreign and nonexistent responses must remain indistinguishable.
- Exercise optimistic concurrency, file scanning, retry/idempotency, empty states, mobile layout, keyboard access, and service recovery.
- Generate clients from the checked-in OpenAPI version and pin the Developer Kit SHA-256 for the release.
A missing credential scope returns HTTP 403 with code credential_scope_required, safe message The authenticated credential does not grant this operation., and a correlation ID. Checklist item updates and normal Contact updates declare HTTP 409 because they carry concurrency state. The Contacts favorite command is an idempotent boolean write without an expected revision, so its contract deliberately does not advertise 409.
The repository implementation and local battle environment expose and test this contract. Availability at api.buildwithhq.com still depends on deploying that gateway build, database grants, TLS, routing, and credentials to the production environment.
Capability review: 2026-09-14. See current features and setup requirements, the generated API Map and first-class module inventory.