The public GraphQL schema definition is the
machine-readable type contract for POST /api/graphql. Use it to validate
operations, power editor completion, or generate types for queries your
integration owns. It is generated from the running schema and contains no
tenant data or credentials.
SDL describes GraphQL names and types. It does not describe every runtime rule that decides whether a query is authorized, affordable, or valid for a particular data model. Use it together with the GraphQL guide, not as a replacement for that guide.
Download the schema
Download the schema from the release-matched developer portal:
export HODOFLOW_DEVELOPER_URL=https://developer.hodoflow.com
curl -fsS "$HODOFLOW_DEVELOPER_URL/schema.graphql" -o hodoflow-schema.graphql
The first comment line identifies the contract version:
# Hodoflow GraphQL API — schema version YYYY-MM-DD
The next comment records that the file is generated from Hodoflow's running schema and must not be edited by hand.
The date is the GraphQL schema version. It is independent of JSON:API v1 and
of the x-api-version header returned by the HTTP API. There is no request
parameter that selects an older SDL: pin the file used by your integration and
review a newer schema before upgrading.
The endpoint serves SDL as text/plain, so it can be read directly in a
browser or fetched by build tooling without authentication. Fetching the
schema does not grant access to warehouse records.
Read the public type system
The schema currently has one root type:
schema {
query: RootQueryType
}
RootQueryType exposes two fields:
| Field | Purpose | Authentication |
|---|---|---|
health |
Lightweight liveness result | Public |
factQuery |
Read current or historical warehouse records for one data-model slug | Bearer token with api_read |
There is no mutation root and no subscription root. The application may expose
a GraphQL socket transport, but an SDL without a subscription root has no
subscription field to call. Check the schema rather than generating a
subscription client from the existence of a socket URL.
factQuery returns PageOfFact. Generate against the nullability written in
the SDL: the page itself and its results list are nullable, each returned
Fact is non-null, and count is optional. A Fact includes identifiers and
timestamps plus a Json data value whose properties come from the selected
data model.
Map the custom scalars deliberately:
| Scalar | Wire value | Suggested client representation |
|---|---|---|
DateTime |
ISO-8601 timestamp normalized to UTC | Your language's offset-aware timestamp type, or a validated string |
Json |
Arbitrary JSON value | A JSON value/object type rather than an unparsed GraphQL string |
The data object is intentionally not expanded into a static GraphQL object
type. Its keys and value shapes are defined by the data model in the workspace,
so validate or decode them with the model contract your integration expects.
Know what SDL cannot express here
Several factQuery arguments are currently String or Int in SDL even
though the resolver applies narrower rules. The SDL therefore cannot tell a
generic generator all of the following:
modeacceptslatestortimelineand defaults tolatest;timeAxisacceptsobserved_atorinserted_atand defaults toobserved_at;sortandsortDirectionaccept a defined set of values;limitdefaults to 50 and is capped at 250 before query-cost limits apply;offsetdefaults to 0;filtersis a JSON array encoded inside a GraphQL string, with field-type specific operators and a maximum of 20 entries;- omitted timeline bounds create a 90-day window, capped at 366 days; and
- complexity, nesting-depth, token, and per-credential rate limits apply before or during execution.
The exact values, paging rules, cost formula, and error examples are maintained
in GraphQL. Authentication is also outside GraphQL's type system:
send Authorization: Bearer $TOKEN for factQuery, and give that service
account api_read. A schema-aware client cannot infer those requirements from
the field signature.
Generate types from operations you own
Prefer document-based generation: keep each named query in source control and generate its variables and result type against the pinned SDL. This produces a smaller, more useful contract than generating a general-purpose client for the entire schema.
For example, a bounded operation can live in current-orders.graphql:
query CurrentOrders($slug: String!, $limit: Int!) {
factQuery(dataModelSlug: $slug, mode: "latest", limit: $limit) {
hasNextPage
results {
entityId
observedAt
data
}
}
}
Configure the generator's DateTime and Json mappings, then make the HTTP
request yourself or through a standard GraphQL client. Generated types do not
turn the result into a Hodoflow SDK, refresh access tokens, add the api_read
scope, choose safe query limits, or decode the model-specific data object for
you.
Keep variables separate from the query text. This is especially important for
filters, which is JSON nested inside a GraphQL string; passing it as a
variable avoids another layer of manual escaping.
Detect schema changes
Store the exact SDL used by a released integration. Before adopting a newer release, compare schemas with a GraphQL schema-diff tool or a plain text diff:
diff -u hodoflow-schema.graphql hodoflow-schema.next.graphql
Treat removed fields or arguments, tightened nullability, and changed scalar or field types as breaking. Additive fields remain safe only when your decoder ignores response keys it did not request—which ordinary GraphQL clients do, because a response follows the operation's selection set.
A changed date comment tells you the schema artifact changed; it does not by itself say whether the change affects your operations. Revalidate every stored query against the new SDL, regenerate types, and run the integration's own query-level checks before deployment.
For a complete request and operational behavior, continue to the GraphQL guide. For the other generated machine contract, see the OpenAPI contract.