Drillr provides market data, SEC filings, and AI-generated analysis for informational purposes only. Third-party data is not guaranteed accurate. See Disclaimer.
Drillr External API — Developer Guide#
Access Drillr's AI-powered financial research and data feeds through MCP, REST API, or CLI.
Table of Contents#
- Authentication
- MCP Tools
- REST API
- CLI Tool
- Pricing
- Rate Limits
- Platform Setup Examples
- For AI Coding Agents
- Error Handling
Authentication#
Create and manage API keys yourself at the Developer Portal: https://drillr.ai/developer/keys. Keys follow the format drl_xxxxxxxx_xxx... (45 characters) and are shown exactly once at creation — store them in your secret manager immediately.
Two ways to pass the key (both permanently supported):
# Recommended
Authorization: Bearer drl_xxx
# Also supported
X-API-Key: drl_xxx
API key is the recommended way to connect. If you have an AI coding agent (Claude Code, Cursor, etc.), just say:
Please configure the Drillr MCP per https://drillr.ai/developer/docs and save the setup rules to memory.
Your agent will follow the For AI Coding Agents recipe below — one-shot config plus persistent rules so the next session keeps the API-key approach. Otherwise, paste the Claude Code config snippet into your client and replace the placeholder with the key you generated on the Developer Portal.
MCP Tools#
Connect to https://gateway.drillr.ai/mcp/data via MCP Streamable HTTP transport.
Nine data tools are exposed on this MCP server. Per-call pricing is listed in Pricing.
| Tool | Purpose |
|---|---|
run_sql | Read-only PostgreSQL SELECT over financial + alternative-data tables |
get_table_schema | Column metadata for a specific table (use before crafting run_sql) |
fiscal_utility | Convert calendar dates ↔ fiscal periods for a ticker |
list_tables | Browse altdata categories + their tables/columns |
signal_list | High-score news / market-event feed |
sec_report_list | List SEC filings (10-K / 10-Q / 8-K / S-4 / JP EDINET) by company + date |
sec_report_search | Vector + keyword search inside SEC filing narrative |
company_search | NL company / asset discovery — finds tickers matching a thematic prompt (e.g. "AI infra plays") |
ticker_resolve | Resolve a company name / brand / ticker substring to canonical ticker(s) with history |
Synchronous one-shot search is available as REST
POST /api/v1/search— see REST API.
Typical MCP flow#
1. list_tables({ categories: ["macro_indicators"] })
→ Discover available tables + their columns
2. get_table_schema({ table: "financial_statements" })
→ Column list before crafting a SQL query
3. run_sql({ sql: "SELECT ... FROM financial_statements WHERE ticker = 'AAPL' ..." })
→ Structured rows
4. sec_report_search({ ticker: "AAPL", query: "AI capex guidance" })
→ Relevant filing passages with citations
REST API#
Base URL: https://gateway.drillr.ai
All endpoints are rooted at /api/v1/ and require an API key.
| Method | Path | Purpose |
|---|---|---|
| POST | /api/v1/search | Synchronous research agent (NL question → answer) |
| POST | /api/v1/data/run_sql | REST mirror of MCP run_sql |
| GET | /api/v1/data/get_table_schema | REST mirror of MCP get_table_schema |
| GET | /api/v1/data/fiscal_utility | REST mirror of MCP fiscal_utility |
| GET | /api/v1/data/list_tables | REST mirror of MCP list_tables |
| GET | /api/v1/data/signal_list | REST mirror of MCP signal_list |
| GET | /api/v1/data/sec_report_list | REST mirror of MCP sec_report_list |
| POST | /api/v1/data/sec_report_search | REST mirror of MCP sec_report_search |
| POST | /api/v1/data/company_search | REST mirror of MCP company_search |
| POST | /api/v1/data/ticker_resolve | REST mirror of MCP ticker_resolve |
The /api/v1/data/* endpoints mirror the 9 MCP tools above 1:1 — same inputs, same outputs, same pricing. Use them when you'd rather call HTTP directly than wire up an MCP client.
POST /api/v1/search#
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| question | string | Yes | - | The question |
| context | string | No | - | Additional context |
| session_id | string | No | - | Continue a previous session |
| stream | boolean | No | true | SSE streaming or JSON response |
Streaming example:
curl -X POST https://gateway.drillr.ai/api/v1/search \
-H "Authorization: Bearer drl_xxx" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{"question": "What is NVDA PE ratio?"}'
SSE events:
| Event | Description |
|---|---|
status | Connection established, includes session_id |
tool_call | Agent is calling a data source (user-friendly label) |
text_delta | Incremental text content |
done | Complete or failed. Payload: { status, session_id, sources, duration_ms, _credits: { charged, method }, error? }. _credits.charged is 0 on status: 'failed' (failed calls aren't billed). |
Non-streaming JSON:
curl -X POST https://gateway.drillr.ai/api/v1/search \
-H "Authorization: Bearer drl_xxx" \
-H "Content-Type: application/json" \
-d '{"question": "AAPL market cap?", "stream": false}'
{
"data": {
"text": "Apple's market cap is approximately $3.4 trillion...",
"session_id": "uuid",
"sources": [{ "tool": "Looking up company info (AAPL)", "ticker": "AAPL" }],
"duration_ms": 12500,
},
"_credits": {
"charged": 4,
"method": "usage_based",
},
}
/api/v1/search uses the same envelope as /api/v1/data/* — see the Response envelope section under Pricing for the full schema (success + error). _credits.balance_after is not returned on this endpoint; check the Usage page for the latest balance.
For per-tool input/output shapes of the /api/v1/data/* endpoints, the description fields on each MCP tool are the source of truth — call once with sample inputs to inspect the response.
CLI Tool#
A first-party drillr CLI is coming soon — it'll wrap the same authentication, search, and data tools available through MCP and REST. Until then, please use the MCP or REST channels above.
Pricing#
Drillr Data API calls are billed in credits (cr). Each billable call deducts credits from your account balance. You can view per-call deductions on the Usage page.
Pricing modes#
Fixed — run_sql / sec_report_list / sec_report_search / signal_list charge a flat per-call rate (see the table below).
Usage-based — tools powered by an AI agent (the research agent, NL company discovery) are billed by actual work, so the per-call charge varies. Typical ranges are listed in the per-tool table below; responses surface the exact charge as _credits.charged and _credits.method: "usage_based".
Free — schema / navigation utilities are not billed.
Per-tool rates#
| Tool / Endpoint | Per call | Mode |
|---|---|---|
run_sql | 1 cr | Fixed |
sec_report_list | 1 cr | Fixed |
sec_report_search | 1 cr | Fixed |
signal_list | 2 cr | Fixed |
company_search | typical 3–5 cr | Usage-based |
POST /api/v1/search | typical 2–5 cr | Usage-based |
get_table_schema | 0 cr | Free |
fiscal_utility | 0 cr | Free |
list_tables | 0 cr | Free |
ticker_resolve | 0 cr | Free |
Notes#
- Same tool, same price across surfaces. A
run_sqlcall costs the same via MCP (/mcp/data) or REST (/api/v1/data/run_sql), and the same applies to every other data tool. - Failed calls are not billed. Errors before tool execution (auth, validation, permission 403) don't deduct credits. Errors during execution (upstream timeout, etc.) are also not billed.
- Balance + usage are surfaced on the Developer dashboard.
/api/v1/searchreturns402 Payment Requiredwhen your balance is too low. Keep your balance positive to avoid interrupted calls.
Response envelope#
All nine /api/v1/data/* endpoints use a uniform envelope so clients can write a single response parser and balance check across the surface.
Success (2xx):
{
"data": {
/* tool-specific payload — see each endpoint's schema in the OpenAPI spec */
},
"_credits": {
"charged": 5,
"method": "per_call", // per_call | usage_based | free
"balance_after": 1842, // remaining credit balance
},
}
_credits.charged— credits deducted for this call;0for free tools_credits.method— billing mode:per_call— fixed per-request chargeusage_based— variable charge, scales with the work donefree— no charge
_credits.balance_after— your credit balance after this call. Best-effort — may be omitted. For the authoritative balance, check the Usage page.
Error (4xx / 5xx):
{
"error": {
"code": "invalid_request", // stable machine-readable
"message": "Missing required query param: ticker", // human-readable, not stable
"retry_after_seconds": 30, // present on 429 only
"limit": 8, // present on 429 concurrency-limit only
},
}
Known error.code values: invalid_request, unauthenticated, forbidden, rate_limited. New codes may be added — treat unknown codes as opaque and fall back to error.message for the human detail.
Rate Limits#
| Limit | Value |
|---|---|
| Request rate | 30 / minute |
Rate limits apply per API key. 429 responses include retry_after_seconds. For balance-related failures see Pricing.
Platform Setup Examples#
Use the API key method below. It's the simplest path for every user. If you're not a developer, send the snippet to your agent (e.g. Claude Code) and follow its prompts; paste in the key you generated on the Developer Portal when asked.
Claude Code#
{
"mcpServers": {
"drillr": {
"type": "http",
"url": "https://gateway.drillr.ai/mcp/data",
"headers": { "Authorization": "Bearer ${DRILLR_API_KEY}" }
}
}
}
Hermes Agent#
mcp_servers:
drillr:
url: 'https://gateway.drillr.ai/mcp/data'
headers:
Authorization: 'Bearer drl_xxx'
timeout: 120
OpenClaw#
{
"mcp": {
"servers": {
"drillr": {
"url": "https://gateway.drillr.ai/mcp/data",
"headers": { "Authorization": "Bearer drl_xxx" }
}
}
}
}
Advanced: browser-based sign-in#
If you prefer not to manage an API key, MCP clients that support OAuth can sign in via Google in the browser instead — just omit the headers block from the snippets above and your client will prompt for sign-in on first connection.
For AI Coding Agents#
If you are an AI coding agent (Claude Code, Cursor, etc.) configuring Drillr for a user, follow these steps in order. The order matters: memory must be in place before the client restart so the rules survive into the next session.
1. Save the auth rules to your memory first#
Drillr's MCP server at gateway.drillr.ai/mcp/data accepts either an Authorization: Bearer <key> header or an OAuth flow — never both on the same connection. Once a user has chosen the API-key path, OAuth is not the right fix for any error. Record this so a future session (after the restart in step 3) does not relapse to OAuth on a transient failure.
If your runtime supports persistent memory (e.g. Claude Code's auto-memory under ~/.claude/projects/<project>/memory/), write two entries:
drillr-mcp-auth(type: reference) — "Drillr MCPhttps://gateway.drillr.ai/mcp/datauses static API key auth viaAuthorization: Bearer <key>. Do not attempt OAuth on this endpoint when a Bearer header is configured. Docs: https://drillr.ai/developer/docs. Key management: https://drillr.ai/developer/keys."drillr-mcp-troubleshooting(type: feedback) — "WhendrillrMCP calls fail, never suggest OAuth re-authorization. Diagnose in order: (1)claude mcp listshows the server connected, (2) inspect the client's MCP config to confirm theAuthorizationheader is present and non-empty, (3)curl -H 'Authorization: Bearer <key>' https://gateway.drillr.ai/api/v1/data/list_tablesreturns 200, (4) regenerate the key at https://drillr.ai/developer/keys if rejected."
If your runtime has no memory system, surface these rules to the user as setup notes they can paste back into a future session.
2. Configure the MCP server#
Ask the user for their API key (or have them generate one at https://drillr.ai/developer/keys), then run:
claude mcp add --scope user --transport http drillr \
https://gateway.drillr.ai/mcp/data \
--header "Authorization: Bearer <paste the user's key here>"
Substitute the literal key into the command. Do not store ${DRILLR_API_KEY} as a literal string in the header — it will not be interpolated at request time.
3. Ask the user to restart their client#
MCP servers only attach at client startup. Tell the user:
Please fully quit and reopen your MCP client (e.g. Claude Code). After restart, the
drillrserver's tools will be available.
4. After restart, verify#
In the new session, the memory entries from step 1 will keep you on the API-key path. Confirm the connection with a free smoke test:
list_tables({ categories: ["macro_indicators"] })
A successful response means the connection is healthy. A 401 means the key is wrong — regenerate at https://drillr.ai/developer/keys. Do not retry with OAuth.
Error Handling#
| HTTP Status | Meaning |
|---|---|
| 400 | Missing required parameter / malformed input |
| 401 | Invalid or missing credentials |
| 402 | Insufficient credits |
| 403 | API key doesn't have access to this endpoint |
| 404 | Resource not found or inaccessible |
| 429 | Rate limit exceeded (see retry_after_seconds) |
| 502 | Upstream data source unavailable |
Error-code strings in the response body:
| Code | Meaning |
|---|---|
unauthenticated | No credentials provided |
key_invalid | API key not recognized |
key_revoked | API key was revoked (see revoked_at) |
key_expired | API key has passed its expiry |
insufficient_credits | Balance can't cover this call |
invalid_query | Query parameter validation failed |
invalid_body | Request body validation failed |
invalid_id | Malformed UUID or similar |
not_found | Resource not found or inaccessible |
upstream_error | Database or data-source call failed |