REST API
Everything the console does goes through the same API that is open to you. There is no privileged API reserved for the interface.
One contract, and its golden rule
Section titled “One contract, and its golden rule”The API lives under /api/v1. The contract is described in OpenAPI and it is stable:
changes are additive.
A disabled feature answers 501 feature_disabled, never 404. This is not an implementation
detail, it is what makes an integration durable:
- your integration code tells “not available on this install” from “you got the URL wrong”;
- it does not break the day the feature is enabled.
The body of a 501 response names the disabled feature and indicates not to retry.
Authenticating
Section titled “Authenticating”Two headers, on every request:
Authorization: Bearer <token>X-Tenant: <your-tenant>X-Tenant is what selects the authentication realm, not the URL. The token comes from your
installation’s OpenID Connect issuer:
curl -s -X POST "https://identity.example.com/realms/$TENANT/protocol/openid-connect/token" \ -d grant_type=client_credentials \ -d "client_id=$APP_ID" -d "client_secret=$APP_SECRET"For a script or an integration, use an application’s credentials, not your own (see roles and permissions).
The media type, to the letter
Section titled “The media type, to the letter”Each resource has its own: application/vnd.graal.systems.v1.<type>+json, where <type> is the
exact resource name in the contract.
project · job · run · identity · assignment · library · blobmetadata · instance-typeEditing: JSON Patch, never a full replacement
Section titled “Editing: JSON Patch, never a full replacement”Edits use JSON Patch (RFC 6902), with the media type
application/json-patch+json;charset=UTF-8:
curl -s -X PATCH "$GRAAL_API/jobs/$JOB" \ -H "Authorization: Bearer $TOKEN" -H "X-Tenant: $TENANT" \ -H 'Content-Type: application/json-patch+json;charset=UTF-8' \ -d '[{"op":"replace","path":"/schedule","value":"0 6 * * *"}]'A full PUT would overwrite fields someone else changed between your read and your write. That is
why there is none.
Pagination
Section titled “Pagination”Lists are paginated by page and size, and the response carries the total:
curl -s "$GRAAL_API/projects?page=0&size=50" \ -H "Authorization: Bearer $TOKEN" -H "X-Tenant: $TENANT"Logs are the exception: they are paginated by cursor, because you follow them while they
are being written. The response carries an X-Cursor header to send back on the next call to get
the continuation — and only the continuation.
The shape of an error
Section titled “The shape of an error”{ "code": "JOB_NOT_FOUND", "message": "…", "errors": [] }code is stable and testable; message is for humans and may change. errors carries the
field-by-field detail of a validation error.
A few codes you meet early:
| Code | What it means |
|---|---|
feature_disabled (501) |
Feature disabled on this installation. Do not retry |
TENANT_CONFIGURATION_ERROR |
The tenant lacks required configuration (often: the storage’s internal address) |
MISSING_OWNER |
The created resource needs an explicit owner |
JOB_NOT_FOUND |
The identifier does not exist in this tenant |
The main resource families
Section titled “The main resource families”- Identity — tenants, users, groups, roles, assignments, identity providers, applications (tokens), audit.
- Workloads — projects, jobs, runs, logs, workflows, secrets, libraries, runtimes, instance types, quotas, editor graphs.
- Data — buckets, catalog (layers, databases, tables, fields), warehouses.
- ML — experiments, models.
- Operations — usage and costs, notifications, tickets, search.
The MLflow facade
Section titled “The MLflow facade”A facade compatible with the MLflow client for experiment tracking is served under /mlflow,
on the same host as the console and the API. It implements the subset of MLflow’s REST API 2.0
devoted to experiment tracking and the registry: see the machine learning page.
API tokens and agent tokens
Section titled “API tokens and agent tokens”A token carries the rights of a service account, subject to the same per-project access control as a user, and is revoked the same way. It is the technical support of the MCP server: each agent acts under a service account with limited rights.
The OpenAPI contract
Section titled “The OpenAPI contract”The full contract is an OpenAPI file: clients are generated from it, the console’s included.
In the console, the “Copy as…” menu gives the equivalent call as curl or as an MCP tool call.