Quickstart
Create an index, mint a key, upload documents and run your first search — end to end with curl.
Start in the console
After confirming your email, choose Search on a website or Search through the API. Name your search; your first workspace is created with it. The wizard has three steps: Data → Check → Connect. Website users can preview and map file fields or connect a CMS/feed. API users get an index-scoped server key and requests filled with their index parameters. Run a successful preview before connecting. Installation code or a created key does not complete setup: send a search from your site/application, then finish. You can leave and resume; advanced schema and ranking tools remain available separately.
This walkthrough assumes a console account with an organization and access to the AACSearch API.
1. Create an index
Index creation is a console action: Search → Indexes → New index. Give it a name, an optional slug (generated from the name when omitted, and suffixed -2, -3 on collision) and, if you need more than the built-in fields, a schema.
A minimal marketing-site index needs no extra fields at all. A product index usually declares the things you filter on:
{
"name": "Documentation",
"slug": "documentation",
"fields": [
{ "name": "category", "type": "string", "facet": true },
{ "name": "published_at", "type": "int64", "sort": true },
{ "name": "views", "type": "int32", "optional": true }
]
}The console validates this schema and creates a managed index. Use its logical slug in API requests:
{
"id": "idx_01HZX8",
"slug": "documentation",
"name": "Documentation"
}Field names must match ^[a-zA-Z_][a-zA-Z0-9_]{0,63}$ and must not shadow the reserved ones (id, external_id, title, content, url, source_type, organization_id, tags, indexed_at, metadata).
2. Create an API key
Search → API keys → New key. Choose the scopes to grant. The default set — search:read, documents:read, documents:write — is what an ingest job needs. Add settings:write for reindexing and scoped keys, analytics:write for click tracking.
The response contains the key exactly once:
{
"id": "key_01HZX9",
"name": "Ingest",
"prefix": "aac_live_9f3c2a1b…",
"scopes": ["search:read", "documents:read", "documents:write"],
"createdAt": "2026-10-23T09:12:44.000Z",
"key": "aac_live_9f3c2a1bD4eF6gH8iJ0kL2mN4oP6qR8s"
}Production organizations get aac_live_…; outside production the generated key is aac_test_…. Only the SHA-256 hash is stored — if you lose the key, revoke it and create another.
Export it once for the commands below:
export AAC_KEY="aac_live_9f3c2a1bD4eF6gH8iJ0kL2mN4oP6qR8s"
export AAC_API="https://search.example.com/api/v1"3. Upload documents
external_id and content are required; everything else is optional. Your own schema fields are passed through as top-level keys.
curl -sS -X POST "$AAC_API/indexes/documentation/documents" \
-H "Authorization: Bearer $AAC_KEY" \
-H "Content-Type: application/json" \
-d '{
"documents": [
{
"external_id": "pricing",
"title": "Pricing",
"content": "Free includes 10,000 searches per month. Pro is 29 USD per month with 500,000 searches.",
"url": "https://example.com/pricing",
"tags": ["billing"]
},
{
"external_id": "limits",
"title": "Rate limits",
"content": "Each API key allows 600 requests per minute in a sliding window.",
"url": "https://example.com/limits",
"tags": ["api"]
}
],
"action": "upsert"
}'{
"index": "documentation",
"indexed": 2,
"failed": [],
"usage": {
"plan": "pro",
"planName": "Pro",
"period": "2026-10",
"resetsAt": "2026-11-01T00:00:00.000Z",
"searches": { "used": 0, "limit": 500000 },
"documents": { "used": 2, "limit": 50000 },
"aiTokens": { "used": 0, "limit": 100000 },
"indexes": { "used": 1, "limit": 10 },
"apiKeys": { "used": 1, "limit": 10 },
"connectors": { "used": 0, "limit": 10 },
"wallet": { "balanceCents": 0, "currency": "USD" }
},
"request_id": "req_5b1d9c0a7e2f4a6b8c0d1e2f"
}A batch is not all-or-nothing: rejected documents appear in failed as { "external_id", "error" } while the rest are indexed. Up to 500 documents per request.
4. Run your first search
curl -sS -G "$AAC_API/indexes/documentation/search" \
-H "Authorization: Bearer $AAC_KEY" \
--data-urlencode "q=pricing" \
--data-urlencode "query_by=title,content" \
--data-urlencode "per_page=5"{
"index": "documentation",
"query": "pricing",
"language": "en",
"found": 1,
"out_of": 2,
"page": 1,
"per_page": 5,
"took_ms": 12,
"engine_ms": 3,
"hits": [
{
"id": "pricing",
"score": 1754,
"document": {
"id": "pricing",
"external_id": "pricing",
"title": "Pricing",
"content": "Free includes 10,000 searches per month. Pro is 29 USD per month with 500,000 searches.",
"url": "https://example.com/pricing",
"source_type": "api",
"organization_id": "org_01h9",
"tags": ["billing"],
"indexed_at": 1761214364
},
"highlights": [
{ "field": "title", "snippet": "<mark>Pricing</mark>", "matchedTokens": ["pricing"] }
]
}
],
"facets": [],
"request_id": "req_9a7c3d1e5f0b2a4c6d8e0f1a"
}Response headers carry the numbers you need for back-off and dashboards:
x-aac-quota-limit: 500000
x-aac-quota-remaining: 499999
x-aac-index: documentation
x-aac-profile: default
x-aac-charged-cents: 0
x-ratelimit-limit: 600
x-ratelimit-remaining: 599
x-ratelimit-reset: 1761214424
x-request-id: req_9a7c3d1e5f0b2a4c6d8e0f1aA search without matches still succeeds with found: 0; it is logged as a zero-result query and shows up in /analytics/alerts.
5. Add autocomplete
curl -sS -G "$AAC_API/indexes/documentation/suggest" \
-H "Authorization: Bearer $AAC_KEY" \
--data-urlencode "q=pri" \
--data-urlencode "limit=5"{
"index": "documentation",
"query": "pri",
"suggestions": [
{
"text": "Pricing",
"source": "document",
"documentId": "pricing",
"url": "https://example.com/pricing",
"score": 3,
"highlight": "<mark>Pri</mark>cing"
}
],
"did_you_mean": null,
"sources": { "documents": 1, "queries": 0 },
"cache": "miss",
"request_id": "req_1c2d3e4f5a6b7c8d9e0f1a2b"
}Suggest calls are rate-limited but never metered — an autocomplete that bills per keystroke would be unusable.
Where to go next
- Search endpoint — every parameter and response field.
- Documents — partial updates, TTL, bulk delete, export.
- Embeddable widget — the same index in a
<script>tag. - Errors & limits — what the 4xx codes mean.