GraphQL Schema
The same data model that powers Seed Export can describe itself in GraphQL:
npx bd export-graphql-schema
That writes ./bd.data-model.graphql (change it with --out path) — SDL
generated from your org's custom collections:
- every object becomes a type, fields typed from their declarations;
- relations render as lists of the target type;
- SELECT fields become GraphQL enums where the values are valid enum names;
- a
Querytype is emitted with a list field and a by-id field for every object.
Add --include-standard and the platform's standard CRM types are emitted
beside your custom ones.
The @businessdash/sdk/graphql entrypoint exposes the generator
(dataModelToGraphqlSdl) and its supporting types for programmatic use.
Schema-first, deliberately
The SDL is a contract, and contracts are useful the moment they exist:
- feed it to GraphQL codegen and get typed clients in any language;
- commit it next to your code so schema changes show up in code review as a readable diff;
- give it to an AI agent alongside the seed snapshot — structure from one file, contents from the other.
The command renders a schema. To actually run queries against it, see Executable endpoint below — an enterprise add-on. Everyday reads and writes still go through the Package API and the SDK clients.
Scope
export-graphql-schema requires metadata:read_schema on a secret key —
schema only, so metadata:read_records is not needed.
Executable endpoint
Beyond generating the SDL, an org on the top (enterprise) plan can run GraphQL against its custom data model:
POST https://www.businessdash.us/api/package/v1/sites/{siteId}/graphql
Authorization: Bearer bd_…
Content-Type: application/json
{ "query": "{ projects(limit: 20) { nodes { id title tasks { id name } } nextCursor } }" }
The response is the standard GraphQL envelope — { "data": … }, or
{ "errors": [ … ] } for a bad query (a malformed query is a GraphQL error,
not an HTTP failure). Every relation is a list; each object exposes a
<plural>(limit, cursor) connection and a <singular>(id) field.
The @businessdash/sdk/graphql entrypoint ships a tiny client so you don't hand-roll
the fetch:
import { createGraphqlClient } from "@businessdash/sdk/graphql";
const gql = createGraphqlClient({
baseUrl: "https://www.businessdash.us/api/package/v1",
siteId: process.env.BD_SITE_ID!,
apiKey: process.env.BD_API_KEY!, // secret key with graphql:query
});
const { data, errors } = await gql.query(
`{ projects(limit: 20) { nodes { id title } } }`,
);
Access & limits
- Scope
graphql:query— a dedicated, secret-key-only scope (never publishable). Because only a secret key can reach it, a query reads the org's full model with no per-object visibility gate. - Plan — requires the
developer.graphql_apientitlement (top/enterprise plan). A non-entitled caller gets{ "available": false, "reason": "plan_required" }. Platform-developer keys bypass the plan gate. - Rate limit — each key has a per-minute ceiling set by BusinessDash as part
of your plan (a
429with a retry hint when exceeded). Platform-developer keys are unlimited. - Query depth is capped, and
limitis clamped per page, to keep a single query bounded.
Usage & billing
GraphQL usage is metered per month: the number of queries run and the number
of records they read, tracked separately from the REST custom-DB counters so
the surface can be priced on its own. Your GraphQL usage for the current month is
shown in Site Builder → Developer, beside the key that holds graphql:query.