Base URL
https://gramspec.com/gramapi
Authentication
Every request must carry an X-Api-Key header with a
per-user API key. Keys are issued from
your profile and begin with the
prefix gramspec_. A key identifies a single GramSpec
user and inherits that user's permissions; only
Enterprise and Admin accounts
can use the API. If the plan behind a key lapses, the key stops
working immediately.
X-Api-Key: gramspec_your_api_key_here
Missing or invalid keys get 401 Unauthorized. A
valid key on a non-Enterprise account gets
403 Forbidden. Keep keys out of client-side
code — treat them like a password.
Rate limits
Requests are throttled per user. The prompt-and-export
endpoints (SystemPrompt, AnalystKit,
Projects, Graph,
BuildPrompt, Rules) allow up to
120 requests per minute;
Query, which spends AI budget, allows
30 per minute. Over the limit you get
429 Too Many Requests with body
{ "error": "rate_limited" } — wait a moment
and retry. This is separate from the Query-only
AI-budget 429 (budget_cooldown, see
Error responses).
Endpoints
GET /gramapi/SystemPrompt
The primary endpoint. Returns the complete LLM system message — GRAM rules, SQL dialect profile, and your project's knowledge graph, stitched into one string. Cache it, pair it with the user's question, and send it to whatever model you like. GramSpec does not run the LLM and does not see your data.
Parameters
| Field | Required | Notes |
|---|---|---|
projectName | Yes (or projectId) | Exact project title as shown in Grammar. Case-insensitive; URL-encode spaces. |
projectId | Yes (or projectName) | Stable GUID from /gramapi/Projects; survives renames. |
databaseType | Yes | sqlserver, snowflake, postgresql, mysql, mariadb, databricks. Pass the dialect your app executes SQL against. |
promptMode | No | chat (default): markdown fences, multi-query, chart configs. singleshot: raw SQL only. |
Request
curl "https://gramspec.com/gramapi/SystemPrompt?projectName=YourProjectName&databaseType=snowflake" \
-H "X-Api-Key: gramspec_your_api_key_here"
Response 200
{
"systemPrompt": "<complete string to send as the LLM system role>",
"projectName": "YourProjectName",
"projectId": "6f1e7a5c-4b12-4d9e-9a31-6c0f88b2a4d2",
"databaseType": "snowflake",
"promptMode": "chat",
"graphHash": "sha256:7a8b..."
}
Send systemPrompt verbatim as the system role. Do
not append, prepend, or re-wrap it — the graph and rules
are already inside.
Caching
The response carries an ETag header equal to
graphHash. Send it back on later calls:
curl "https://gramspec.com/gramapi/SystemPrompt?projectName=YourProjectName&databaseType=snowflake" \
-H "X-Api-Key: gramspec_your_api_key_here" \
-H 'If-None-Match: "sha256:7a8b..."'
Unchanged → 304 Not Modified, no body; keep
your cache. The hash covers the fully assembled prompt, so any
graph edit, dialect update, or rule change invalidates it
automatically.
GET /gramapi/AnalystKit
The agentic path. Everything needed to stand up
your own Analyst-style tool loop against your own data plane:
the assembled analyst system prompt, the full graph, a compact
name index, and the JSON Schemas for the seven analyst tools
(run_query, search_graph,
describe_entity, ask_user,
record_finding, record_ledger_entry,
end_turn). You run the loop; there is no server
orchestration on this endpoint.
Parameters
| Field | Required | Notes |
|---|---|---|
projectName / projectId | Yes (one) | Same resolution rules as SystemPrompt. |
databaseType | Yes | Same dialect list as SystemPrompt. |
connectionName | No | Display name echoed into the prompt's "Connected data source" line. |
syncedSqlSchema | No | Physical schema qualifier, when your copy of the data lives under one. |
Response 200
{
"systemPrompt": "<assembled analyst system prompt>",
"graph": { "entities": [...], "factTypes": [...] },
"graphJson": "{\"entities\":[...]}",
"compactIndex": "<name-only graph index>",
"entityDossiers": {
"sales.SalesOrder": "<pre-rendered markdown dossier>",
"catalog.Product": "<...>"
},
"tools": [
{
"name": "run_query",
"description": "...",
"inputSchema": { "type": "object", "properties": { ... } },
"inputSchemaJson": "{...}"
}
],
"databaseType": "sqlserver",
"projectId": "6f1e7a5c-...",
"projectName": "YourProjectName",
"promptHash": "sha256:9c2d..."
}
Register the seven tools with your LLM exactly as returned
— the system prompt references them by name, and their
order is stable for prompt caching. Implement the handlers
locally: run_query executes read-only SQL against
your database, describe_entity returns
entityDossiers[name] (a pre-rendered dossier per
table — key, columns, aliases, enums, sample values,
derived formulas, relationships — from the same renderer
GramSpec's own apps use), search_graph searches
the returned graph across names, aliases, readings, and
sample values, and end_turn terminates the loop.
promptHash covers the prompt and the dossiers and
works with If-None-Match for 304
caching, same as SystemPrompt.
GET /gramapi/Projects
Lists the Grammar projects owned by the authenticated user. Use
it to render a project picker, or to cache the stable
projectId.
curl https://gramspec.com/gramapi/Projects \
-H "X-Api-Key: gramspec_your_api_key_here"
[
{
"projectId": "6f1e7a5c-4b12-4d9e-9a31-6c0f88b2a4d2",
"title": "<project title>",
"modifiedUtc": "2026-08-01T14:22:03Z"
}
]
GET /gramapi/Graph
Exports a project's GRAM knowledge graph as JSON, without
building a prompt. Useful when your app renders the graph in its
own explorer — the graph is already inside
systemPrompt, so the LLM call doesn't need this.
Parameters
| Field | Required | Notes |
|---|---|---|
projectName / projectId | Yes (one) | Same resolution rules as SystemPrompt. |
download | No | 1 or true returns the raw graph JSON as an attachment named <title>.gramspec-graph.json. |
Inline (default)
curl "https://gramspec.com/gramapi/Graph?projectName=YourProjectName" \
-H "X-Api-Key: gramspec_your_api_key_here"
{
"projectId": "6f1e7a5c-4b12-4d9e-9a31-6c0f88b2a4d2",
"title": "<project title>",
"graph": { "entities": [...], "factTypes": [...] },
"graphJson": "{\"entities\":[...],\"factTypes\":[...]}"
}
graph is the parsed object; graphJson
is the raw string, byte-identical to what
SystemPrompt embeds. Prefer graphJson
when you round-trip the graph back to the API.
File download
curl "https://gramspec.com/gramapi/Graph?projectName=YourProjectName&download=1" \
-H "X-Api-Key: gramspec_your_api_key_here" \
-OJ
POST /gramapi/BuildPrompt
Same assembly as SystemPrompt, returned as
structured pieces: the full prompt plus the
rules template, the dialect block, and
the graph as separate fields. Accepts a raw
graphJson string as an alternative to a project
reference — useful for inspecting how a graph you hold
locally would be framed.
Parameters (JSON body)
| Field | Required | Values |
|---|---|---|
graphJson | One of these three | Raw GRAM knowledge-graph JSON string. |
projectName | Exact project title as shown in Grammar. | |
projectId | GUID from /gramapi/Projects. | |
databaseType | Yes | Same dialect list as SystemPrompt. |
promptMode | No | chat (default) or singleshot. |
Response 200
{
"prompt": "<assembled GRAM system prompt>",
"graphJson": "{\"entities\":[...]}",
"graph": { "entities": [...], "factTypes": [...] },
"rules": "<rules template, graph slot empty>",
"dialect": "<dialect profile>",
"databaseType": "sqlserver",
"promptMode": "chat"
}
GET /gramapi/Rules
The GRAM rules template and dialect profile with no graph
embedded. For inspection — use SystemPrompt
for production assembly, which handles the substitution
correctly.
curl "https://gramspec.com/gramapi/Rules?databaseType=snowflake" \
-H "X-Api-Key: gramspec_your_api_key_here"
{
"dialect": "<dialect profile>",
"rules": "<GRAM rules template>"
}
POST /gramapi/Query
The managed path: runs a natural-language prompt through
GramSpec's own LLM pipeline against a saved dataset and returns
the parsed result. This is the one endpoint that spends your
GramSpec AI allowance — if you run your own LLM, use
SystemPrompt instead and keep model control local.
Parameters (JSON body)
| Field | Required | Notes |
|---|---|---|
prompt | Yes | Natural-language question. |
chatConfigId | Yes | GUID of a saved dataset you own. |
provider | No | gemini (default), chatgpt, claude, grok. |
promptMode | No | chat (default) or singleshot. |
Request
curl -X POST https://gramspec.com/gramapi/Query \
-H "Content-Type: application/json" \
-H "X-Api-Key: gramspec_your_api_key_here" \
-d '{
"prompt": "Top 10 customers by revenue last quarter",
"chatConfigId": "b1d2e3f4-5678-4abc-9def-1234567890ab"
}'
Response 200
{
"content": "Here are the top 10 customers...",
"sqlBlocks": [ "SELECT TOP 10 ..." ],
"sharePointBlocks": [],
"chartConfig": {
"type": "bar",
"xColumn": "CustomerName",
"yColumn": "Revenue",
"title": "Top customers by revenue"
},
"raw": "<full model output>",
"provider": "gemini"
}
sqlBlocks is an array of SQL strings — a
question can legitimately produce more than one query, so loop
the array rather than taking the first element.
chartConfig is present only when the model proposed
a chart; its optional seriesColumn adds multi-series
grouping. If the model call itself fails, the response is still
200 with an error field set and empty
content — transport worked, the model call didn't.
Supported databases
databaseType accepts the dialects the GramSpec
prompt engine ships rules for:
sqlserver— Microsoft SQL Server (T-SQL)snowflake— Snowflakepostgresql— PostgreSQLmysql— MySQLmariadb— MariaDBdatabricks— Databricks SQL
Anything else falls back to a generic SQL profile. SharePoint
graphs are not supported by this API —
databaseType: "sharepoint" is rejected with
400 on every endpoint, because synced SharePoint
data lives on GramSpec's private storage that remote callers
cannot execute against.
End-to-end example
Python
import requests
API_KEY = "gramspec_your_api_key_here"
BASE_URL = "https://gramspec.com/gramapi"
HEADERS = {"X-Api-Key": API_KEY}
# Fetch (or revalidate) the system prompt for a project
resp = requests.get(
f"{BASE_URL}/SystemPrompt",
headers=HEADERS,
params={"projectName": "YourProjectName", "databaseType": "sqlserver"},
)
resp.raise_for_status()
body = resp.json()
system_prompt = body["systemPrompt"]
graph_hash = body["graphHash"] # send back via If-None-Match next time
# Hand system_prompt to your LLM of choice as the system role,
# with the user's question as the user message.
C# / .NET
using System.Net.Http;
using System.Net.Http.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Api-Key", "gramspec_your_api_key_here");
var body = await client.GetFromJsonAsync<JsonElement>(
"https://gramspec.com/gramapi/SystemPrompt" +
"?projectName=YourProjectName&databaseType=sqlserver");
string systemPrompt = body.GetProperty("systemPrompt").GetString();
string graphHash = body.GetProperty("graphHash").GetString();
Error responses
| Status | Meaning |
|---|---|
400 | Missing or invalid parameters; unsupported databaseType; or a typed condition — connection_password_expired (the dataset owner must re-enter their database password) or graph_member_unresolved (a composed dataset references a graph that no longer resolves). |
401 | Missing, invalid, revoked, or expired X-Api-Key. |
403 | Valid key without an active Enterprise plan — or a dataset you don't own. |
404 | Project or dataset not found for this user. |
429 | Two cases, both JSON: rate_limited — per-user request rate exceeded (any endpoint; see Rate limits); or budget_cooldown — the account's AI allowance is used for now, body includes resetsAtUtc (Query only). Distinguish them by the error field. |
500 | Server error while loading or exporting the project. |
503 | Authentication service temporarily unavailable; retry. |
Error responses are JSON of the form
{ "error": "message" }. One deliberate exception:
an LLM-level failure on Query returns
200 with the error field set on the
parsed response, so your parser handles one shape for both
outcomes.
Getting an API key
- Make sure your GramSpec account is on the Enterprise plan. See Pricing.
- Open your profile and scroll to the API keys section.
- Generate a new key, copy it immediately (the full value is shown only once), and store it in your secret manager. Keys are perpetual by default; set an optional expiry in days at creation if your security policy wants rotating credentials.
- Send it as
X-Api-Keyon every request.
If you suspect a key has leaked, revoke it from the same profile section and issue a new one — revoked keys stop working immediately.
See also
- GRAM Specification v1.1 — the formal standard the API's rules are built on.
- Features — what the GramSpec platform does around this API.
- About — why GRAM exists.