Developers · HTTP API
The Agent API.
A read-only HTTP API for programmatic and agent access to your vault. Bearer-authed with a Personal Access Token, scoped to your account, part of Granite Paid.
Base URL & auth
All requests go to https://api.granite.co/v1 over HTTPS, with your token in the Authorization header:
Authorization: Bearer gra_live_…The API is served on its own host so your app session cookie never reaches it — it is bearer-only. Create a token under Settings → Developer → Access tokens. Free or canceled plans get 402.
Scopes
Each token carries one or more scopes (orthogonal to the plan gate):
| scope | grants |
|---|---|
documents:read | list / read / search documents, poll status |
vault:ask | vault Q&A (POST /ask) |
Endpoints
| method + path | scope | notes |
|---|---|---|
GET /v1/documents | documents:read | cursor-paginated list (metadata) |
GET /v1/documents/:id | documents:read | full doc; ?include=full_text adds the OCR body |
GET /v1/documents/:id/status | documents:read | ingest-status poll |
GET /v1/search?q=&mode= | documents:read | mode = hybrid (default) / keyword / semantic |
POST /v1/ask?q= | vault:ask | vault Q&A (answer + citations) |
Pagination
GET /v1/documents returns { documents, next_cursor, has_more }. Pass the opaque next_cursor back as ?cursor=… for the next page (a keyset on (created_at, id), stable across bulk-inserted ties). ?limit= defaults to 50, max 100.
Examples
TOKEN=gra_live_xxx
# list
curl -H "Authorization: Bearer $TOKEN" \
"https://api.granite.co/v1/documents?limit=20"
# next page
curl -H "Authorization: Bearer $TOKEN" \
"https://api.granite.co/v1/documents?cursor=<next_cursor>"
# full document incl. OCR text
curl -H "Authorization: Bearer $TOKEN" \
"https://api.granite.co/v1/documents/<id>?include=full_text"
# search
curl -H "Authorization: Bearer $TOKEN" \
"https://api.granite.co/v1/search?q=2024%20W-2"
# ask
curl -XPOST -H "Authorization: Bearer $TOKEN" \
"https://api.granite.co/v1/ask?q=When%20does%20my%20passport%20expire%3F"Rate limits
Per token (keyed on the owning account): 60 req/min, 500 reads/day, 200 ask/day (ask shares the in-app vault-Q&A budget). Responses advertise RateLimit-Policy; over a limit → 429 with Retry-After.
Errors
Errors are JSON { "error": "<code>" }:
| status | code | meaning |
|---|---|---|
| 401 | unauthenticated | missing / invalid / revoked / expired token |
| 402 | feature_locked | not on a paid plan |
| 403 | insufficient_scope | token lacks the required scope |
| 404 | not_found | no such document for this account |
| 422 | query_required / query_too_long / invalid_mode | bad input |
| 429 | rate_limited | throttled |
Security
Returned document text is run through an output sanitizer that neutralizes injected-instruction-shaped content — a defense against prompt injection via uploaded documents. It's a layer, not a guarantee; treat vault content as you would any data an agent ingests. Every call is written to your audit log and surfaced under Settings → Access tokens, so you can see exactly what each agent has done.
Prefer an MCP client? The MCP server wraps this API for Claude Desktop, Claude Code, and Cursor.