REST API reference
KeystoneIQ exposes a versioned REST API (/api/v1/*) for automation: Zapier, Make, custom scripts, and internal tools. Use it to read briefs, enqueue deal brief jobs, and add intelligence to your workspace.
Who can use it
| Requirement | Details |
|---|---|
| Plan | Growth or Pro for /api/v1/*. Starter workspaces can create the same API key, but it only unlocks the Context Layer (MCP) on Starter; /api/v1/* returns 402 until the workspace is on Growth or Pro. |
| Keys | Create and revoke keys in the app: Settings → Connections → API & MCP (workspace owners only). |
| Scope | Every request is scoped to the workspace tied to the API key. There is no cross-workspace access. |
If the workspace is on Free or Starter, /api/v1/* routes return 402 with upgrade_required: true. Looking for AI-assistant access instead? See the Context Layer (MCP) reference.
Base URL
All endpoints are served from:
https://keystoneiq.ai
Example full paths:
GET https://keystoneiq.ai/api/v1/briefs
POST https://keystoneiq.ai/api/v1/intelligence
Authentication
Send the API key on every request:
Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Best practices
- Treat keys like passwords: store in a secret manager, never commit to git, never embed in client-side browser code.
- Rotate if a key is exposed: revoke in Developer, create a new key, update Zapier/Make or your integration.
- Only owners can create or revoke keys; team members use the product via normal login, not this Bearer API.
Capabilities overview
| Capability | Method & path | Purpose |
|---|---|---|
| List briefs | GET /api/v1/briefs | Paginated list of brief metadata (id, type, timestamps). Optional filters. |
| Get brief | GET /api/v1/briefs/{id} | Full brief including content and content_json. |
| Trigger deal brief | POST /api/v1/jobs/trigger-deal-brief | Queue a deal brief job for a synced deal (by deal_id or HubSpot id). |
| Add intelligence | POST /api/v1/intelligence | Append structured intel (notes, recaps, evidence) linked to deals/competitors/products. |
Session-only features (browser cookie auth), such as some brief feedback endpoints, are not part of this Bearer API; they are for the web app.
GET /api/v1/briefs
List briefs for the workspace, newest first by created_at.
Query parameters
| Parameter | Description |
|---|---|
limit | Optional. Default 10, maximum 50. |
type | Optional. One of: weekly, deal_brief, deep_research, board_report, sales_playbook, product_intel_report, win_loss_report, meeting_brief, quick_brief. Any other value returns 400. |
product_id | Optional. UUID. Limits to a single product line. |
cursor | Optional. The next_cursor from the previous page. |
Example response
{
"briefs": [
{
"id": "uuid",
"created_at": "2026-09-28T12:00:00.000Z",
"updated_at": "2026-09-28T12:00:00.000Z",
"type": "weekly"
}
],
"next_cursor": "eyJjIjoi..."
}
next_cursor is null on the last page. Pass it back as cursor to read the next page.
Rate limit: 60 requests per workspace per hour (v1_briefs_list).
GET /api/v1/briefs/{id}
Fetch one brief by UUID. Returns 404 if the brief does not exist or belongs to another workspace.
Response fields include: id, created_at, updated_at, type, content, content_json.
Rate limit: 100 requests per workspace per hour (v1_briefs_get).
POST /api/v1/jobs/trigger-deal-brief
Queues a deal brief generation job for an existing deal.
Body (JSON). Provide one of:
| Field | Description |
|---|---|
deal_id | KeystoneIQ deal UUID (from CRM sync or manual deals). |
hubspot_deal_id | HubSpot deal ID string. The deal must already be synced into KeystoneIQ. |
Example
{ "deal_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }
{ "hubspot_deal_id": "123456789" }
Success response
{ "ok": true, "deal_id": "uuid" }
If a pending deal-brief job already exists for that deal, the API may return 200 with skipped: true and reason: "pending_deal_brief_exists" to avoid duplicate work.
Rate limit: 5 deal-brief triggers per workspace per hour (rolling window). On limit, response is 429 with Retry-After (e.g. 720 seconds).
POST /api/v1/intelligence
Adds an intelligence item (e.g. call notes, win/loss notes, competitor evidence) to the workspace.
Body (JSON)
| Field | Required | Description |
|---|---|---|
content | Yes | Text body (trimmed; large content is capped server-side). |
item_type | No | deal_note, win_note, loss_note, competitor_evidence, call_recap, or general (default). |
deal_id | No | UUID. Must be a deal in this workspace. |
competitor_id | No | UUID. Must be a competitor in this workspace. |
product_id | No | UUID. Must be a product in this workspace. |
Example
{
"content": "Discovery call: prospect evaluating us vs Acme on enterprise SSO.",
"item_type": "deal_note",
"deal_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Success response
{
"item": {
"id": "uuid",
"item_type": "deal_note",
"created_at": "2026-09-28T12:00:00.000Z"
}
}
Rate limit: 30 requests per workspace per hour (intelligence).
Outbound webhooks
Receive a POST from KeystoneIQ when events happen in your workspace. Create and manage endpoints from the Settings → Connections → API & MCP (owner only, Growth and Pro plans): set a destination URL, choose events, and copy the signing secret shown at creation (it starts with whsec_ and is shown once). Each endpoint can be turned off or deleted at any time. Send test event posts a signed ping event to that endpoint and tells you what it answered. If the workspace moves off Growth or Pro, deliveries stop; endpoints are kept and can be turned back on after upgrading.
Events
| Event | Fires when |
|---|---|
intel.created | A new intel signal is recorded (added in the app, uploaded, or sent to /api/v1/intelligence). |
brief.completed | A brief or report is saved: weekly, deal, meeting, deep research, product intel, board, win/loss or playbook. |
alert.triggered | An alert rule matches new activity. |
deal.updated | A tracked deal changes, in the app or from a CRM sync (HubSpot, Salesforce, Pipedrive, Zoho, Copper). |
competitor.added | A competitor is added to the workspace. |
* | Subscribe to all of the above. |
The test event, ping, is only sent by Send test event.
Delivery format
Each delivery is a POST with Content-Type: application/json and these headers:
| Header | Value |
|---|---|
X-KeystoneIQ-Event | The event type, e.g. brief.completed. |
X-KeystoneIQ-Signature | sha256=<hex HMAC> of the raw request body, keyed with your endpoint secret. |
Body shape:
{
"event": "brief.completed",
"workspace_id": "uuid",
"timestamp": "2026-07-21T12:00:00.000Z",
"data": { }
}
data carries the event-specific payload, for example brief_id and type for brief.completed, or deal_id, source and the changed fields for deal.updated. Payloads go to your own endpoint, so deal names are sent as stored (they are not masked).
Verifying signatures
Compute an HMAC-SHA256 of the raw request body with your endpoint secret and compare it (constant-time) to the value after sha256=:
const crypto = require("crypto");
function verifyKeystoneSignature(rawBody, signatureHeader, secret) {
const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const received = (signatureHeader || "").replace(/^sha256=/, "");
return (
received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received, "hex"), Buffer.from(expected, "hex"))
);
}
Reject any delivery whose signature does not verify.
Delivery behavior
- Requests time out after 5 seconds; respond with a
2xxquickly and process asynchronously. - Redirects are not followed: a
3xxanswer counts as not delivered. - Deliveries are not automatically retried, so treat webhooks as notifications and reconcile against the REST endpoints above if you need guaranteed consistency.
- Destination URLs must use
httpson port 443 and be publicly reachable. If any address the host resolves to is private or internal, the delivery is blocked.
Errors and HTTP status codes
| Status | Meaning |
|---|---|
| 200 | Success. |
| 400 | Bad request. Invalid JSON, missing required fields, invalid UUIDs. |
| 401 | Missing/invalid API key or wrong Authorization format. |
| 402 | API access requires Growth or Pro plan. Upgrade from Settings > Billing. |
| 404 | Resource not found (e.g. brief, deal, competitor not in workspace). |
| 429 | Rate limit exceeded. Back off and honor Retry-After when present. |
| 500 | Server error. Retry with backoff; contact support if persistent. |
Error bodies are JSON with an error string; rate limits may include retry_after (seconds).
Automation (Zapier & Make)
For step-by-step setup (triggers, actions, troubleshooting), see Zapier & Make setup. The same API key and endpoints power those integrations.
Audit
API usage is logged for security and compliance (successful and failed calls where applicable). Revoking a key immediately stops new requests using that key.