Quickstart
Get from nothing to your first live answers in under five minutes: mint an API key, ask your warehouse a plain-language question, pull a deterministic filtered slice, and fast-enrich a company — three real calls against your own data.
All consumer endpoints live under one base URL:
https://app.amdahl.co/api/platform/v1Every request sends your API key in the X-API-Key header. Everything below is plain HTTPS with JSON bodies, so the same flow works from a CLI, a backend service, or a long-running agent.
Prerequisites
- A workspace on Agent Platform v2 (the
agent_v2flag). If a call below returns403witherror.code: "feature_disabled", ask your Amdahl admin to enable it for the workspace — see Endpoints: prerequisites. curl, and optionallyjqfor readable output.
Step 1: Get an API key
Go to console.amdahl.co, open the workspace you want to operate against, and head to Settings -> Developer -> Create key. Scope the key to at least data:read, then copy the plaintext value the instant it is shown — the server stores only a hash and will never display it again; a lost key must be replaced, not recovered. Full details (OAuth, JWT, the scope matrix) are in authentication.md.
Export it so the rest of the examples stay short:
export AMDAHL_KEY="amdhl_your_key_here"
export AMDAHL_BASE="https://app.amdahl.co/api/platform/v1"Step 2: Ask your first question
POST /search is the fast lane: one blocking call that turns a plain-language ask into SQL over your interactions warehouse, runs it, and returns the rows and the SQL it ran. It needs only data:read.
curl -s -X POST "$AMDAHL_BASE/search" \
-H "X-API-Key: $AMDAHL_KEY" \
-H "Content-Type: application/json" \
-d '{ "query": "how many calls did we have in the last 30 days?" }' \
| jqExpected response shape (trimmed — the Search guide documents every field):
{
"success": true,
"query": "how many calls did we have in the last 30 days?",
"mode": "internal",
"internal": {
"status": "ok",
"sql": "SELECT COUNT(DISTINCT interaction_id) AS calls FROM interactions WHERE …",
"rows": [{ "calls": 214 }],
"row_count": 1
},
"message": "Found 1 result over your interactions.",
"coverage": { "latest_event_at": "2026-07-21T05:01:50Z", "days_behind": 1, "is_stale": false }
}Three things to notice: past parameter validation the fast lane always returns success: true (every failure mode is a typed field like internal.status, never a raw error); internal.sql is the receipt for what actually ran; and coverage tells you how current your warehouse data is. A 401 here means the key is missing or wrong; a 403 with feature_disabled means the workspace is not on Agent Platform v2 yet.
Step 3: Pull a deterministic slice
When you want predicates instead of prose — the same slice every run, no model interpreting your wording — use the routed endpoint POST /search/query with typed filters. The open pipeline over $50k, largest first:
curl -s -X POST "$AMDAHL_BASE/search/query" \
-H "X-API-Key: $AMDAHL_KEY" \
-H "Content-Type: application/json" \
-d '{
"surface": "deals",
"filters": [
{ "field": "deal_stage_status", "op": "eq", "value": "open" },
{ "field": "deal_amount", "op": "gte", "value": 50000 }
],
"order_by": { "field": "deal_amount", "dir": "desc" },
"limit": 10
}' | jq{
"success": true,
"mode_ran": "filter",
"results": [
{ "deal_id": "9214…", "deal_name": "Northwind expansion", "deal_amount": 180000, "deal_stage_status": "open" }
],
"compiled": { "sql": "SELECT … FROM deals WHERE `deal_stage_status` = 'open' AND `deal_amount` >= 50000 …" }
}Field names are never guessed: GET /search/fields lists every filterable field per surface with its type and operators, and a wrong one comes back as a typed invalid_argument naming the allowed set. The full filter DSL (plus the fuzzy and semantic lanes behind the same door) is in the Search endpoint guide.
Step 4: Enrich a company
POST /enrich/company returns intelligence on one account fast by default: a fresh cached brief instantly, or — on a cache miss — your own first-party conversation evidence now while the full web-fused brief rebuilds in the background:
curl -s -X POST "$AMDAHL_BASE/enrich/company" \
-H "X-API-Key: $AMDAHL_KEY" \
-H "Content-Type: application/json" \
-d '{ "domain": "stripe.com" }' | jqBranch on tier: cached carries the stored brief with its captured_at; first_party carries the evidence envelope (what this account said to you) with refresh_enqueued: true — re-call the same domain later and you land on the cache. The tier ladder, person and topic subjects, and the scope-degradation contract are in the Enrich guide.
What's next
You now have working auth and three live reads against your own data. Common next stops:
- Endpoints — the whole synchronous surface (Search, Enrich, Lookalike) and how the verbs chain into the expansion motion.
- Chat — hand a multi-step, server-side investigation to an agent and poll for the answer.
- Routines — schedule a Chat to run itself on a cadence.
- API reference — the operation catalog and OpenAPI spec.
If something breaks, start with pagination-errors.md to decode the error envelope, then check rate-limits.md if you are seeing rate_limited.