Private Preview - features may change without notice
GramSpec
Free Allowance →
Developer Reference

GRAM API

A small, JSON-over-HTTP surface for remote apps. You bring the LLM and the database; the API hands you a graph-grounded contract to build on: the exact system prompt the GramSpec pipeline uses, or a complete kit for running your own analyst agent loop.

Enterprise plan required. The GRAM API is part of the Enterprise tier. Generate an API key from your profile once your plan is active. See Pricing for tier details.

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

FieldRequiredNotes
projectNameYes (or projectId)Exact project title as shown in Grammar. Case-insensitive; URL-encode spaces.
projectIdYes (or projectName)Stable GUID from /gramapi/Projects; survives renames.
databaseTypeYessqlserver, snowflake, postgresql, mysql, mariadb, databricks. Pass the dialect your app executes SQL against.
promptModeNochat (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

FieldRequiredNotes
projectName / projectIdYes (one)Same resolution rules as SystemPrompt.
databaseTypeYesSame dialect list as SystemPrompt.
connectionNameNoDisplay name echoed into the prompt's "Connected data source" line.
syncedSqlSchemaNoPhysical 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

FieldRequiredNotes
projectName / projectIdYes (one)Same resolution rules as SystemPrompt.
downloadNo1 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)

FieldRequiredValues
graphJsonOne of these threeRaw GRAM knowledge-graph JSON string.
projectNameExact project title as shown in Grammar.
projectIdGUID from /gramapi/Projects.
databaseTypeYesSame dialect list as SystemPrompt.
promptModeNochat (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)

FieldRequiredNotes
promptYesNatural-language question.
chatConfigIdYesGUID of a saved dataset you own.
providerNogemini (default), chatgpt, claude, grok.
promptModeNochat (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 — Snowflake
  • postgresql — PostgreSQL
  • mysql — MySQL
  • mariadb — MariaDB
  • databricks — 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

StatusMeaning
400Missing 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).
401Missing, invalid, revoked, or expired X-Api-Key.
403Valid key without an active Enterprise plan — or a dataset you don't own.
404Project or dataset not found for this user.
429Two 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.
500Server error while loading or exporting the project.
503Authentication 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

  1. Make sure your GramSpec account is on the Enterprise plan. See Pricing.
  2. Open your profile and scroll to the API keys section.
  3. 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.
  4. Send it as X-Api-Key on 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