Quickstart
From account to first search
Six steps with curl. If the concepts are new to you, read the Introduction first. Every call after the first two works the same from the cabinet or an MCP client.
Create an account
Register with your email and confirm it from the verification mail. Registration creates an organization, a project called Default and the Free plan for you. Open the project in the cabinet and copy its id from the URL: /app/p/<project id>/….
Create a secret key
In the cabinet, open API keys and create a secret key (zs_sk_…) with full access. The key is shown once, so copy it now. Creating keys needs a confirmed email and the admin role in the organization.
export PROJECT_ID=<project id>
export ZS_KEY=zs_sk_...
Create an index
POST/v1/projects/:projectId/indicesSecret key with full accesscurl -X POST https://api.zaproo-search.com/v1/projects/$PROJECT_ID/indices \
-H "Authorization: Bearer $ZS_KEY" -H "Content-Type: application/json" \
-d '{"name": "products", "language": "english"}'
The answer is the new index with its id. Leave out fields and the first upload maps every field it can recognise. language sets stemming and stop words; changing it later needs a reindex.
Upload documents
POST/v1/projects/:projectId/indices/:indexId/documentsSecret key with full accessThe body is a bare JSON array of up to 1000 documents, each with an id. Writes are asynchronous: the API answers 202 with a task id.
export INDEX_ID=<index id>
curl -X POST https://api.zaproo-search.com/v1/projects/$PROJECT_ID/indices/$INDEX_ID/documents \
-H "Authorization: Bearer $ZS_KEY" -H "Content-Type: application/json" \
-d '[
{"id": "tv-1", "title": "55 inch OLED TV", "brand": "Samsung", "price": 899, "inStock": true},
{"id": "tv-2", "title": "50 inch LED TV", "brand": "LG", "price": 449, "inStock": true}
]'
# 202 {"taskId": "..."}
Poll the task until its status is SUCCEEDED. PARTIAL means some documents failed; the task's errors say which and why.
/v1/projects/:projectId/tasks/:taskIdSecret keycurl https://api.zaproo-search.com/v1/projects/$PROJECT_ID/tasks/$TASK_ID -H "Authorization: Bearer $ZS_KEY"
Create a search profile
A search profile fixes which fields a query looks in, the facets and the sort orders. Your storefront only sends the query, filters, sort and page.
POST/v1/projects/:projectId/indices/:indexId/profilesSecret key with full accesscurl -X POST https://api.zaproo-search.com/v1/projects/$PROJECT_ID/indices/$INDEX_ID/profiles \
-H "Authorization: Bearer $ZS_KEY" -H "Content-Type: application/json" \
-d '{
"name": "Storefront",
"queryFields": {"title": 3, "brand": 1},
"facets": [{"type": "terms", "field": "brand"}],
"sortOptions": ["_relevance", "price:asc", "price:desc"]
}'
The answer carries the profile's profileKey, which goes into the public search URL and never changes.
Search
POST/v1/search/:profileKeyPublic key from an allowed origin, or a secret keycurl -X POST https://api.zaproo-search.com/v1/search/$PROFILE_KEY \
-H "Authorization: Bearer $ZS_KEY" -H "Content-Type: application/json" \
-d '{"q": "tv", "filters": {"brand": ["Samsung"]}, "page": 1}'
The answer holds items, total, facets with counts and correctedQuery when did-you-mean stepped in. For the storefront, call search from the shopper's browser with a public key (zs_pk_…) that lists your shop's domains, or from your shop's server with a secret key that has read access and is limited to the index. Integrate a storefront shows the search page, facets and autocomplete in full.
Or let your agent do it
Every step above is also an MCP tool. Connect Claude Code or another MCP client with your secret key (see MCP setup) and ask in plain words:
Create an index called products in English, upload the documents in ./catalog.json,
wait for the task to finish, then create a search profile that searches title and brand
with a brand facet, and search for "tv".
The agent calls create_index, index_documents, get_task, upsert_profile and search for you.
Languages
An index has one language for its analyzers. Pick it when you create the index:
| Language | language | Analysis |
|---|---|---|
| English (US) | english | Stemming and stop words |
| Bulgarian | bulgarian | Stemming and stop words |
| Croatian | croatian | Basic matching: no word-form reduction |
| Danish | danish | Stemming and stop words |
| Dutch | dutch | Stemming and stop words |
| Estonian | estonian | Stemming and stop words |
| Finnish | finnish | Stemming and stop words |
| French | french | Stemming and stop words |
| German | german | Stemming and stop words |
| Greek | greek | Stemming and stop words |
| Hungarian | hungarian | Stemming and stop words |
| Italian | italian | Stemming and stop words |
| Latvian | latvian | Stemming and stop words |
| Norwegian | norwegian | Stemming and stop words |
| Polish | polish | Stemming and stop words |
| Portuguese | portuguese | Stemming and stop words |
| Romanian | romanian | Stemming and stop words |
| Russian | russian | Stemming and stop words |
| Serbian | serbian | Stemming and stop words |
| Slovenian | slovenian | Basic matching: no word-form reduction |
| Spanish | spanish | Stemming and stop words |
| Swedish | swedish | Stemming and stop words |
| Language-neutral | standard | Basic matching: no word-form reduction |