Developers

REST API reference.

Every endpoint, the role it needs and a request and response you can copy. Elasticsearch-compatible, with a documented subset of its query language.

Overview

Elasticsearch-style endpoints under /v1 at https://api.boltsearch.app, a separate host from the web console, which is where you sign in and manage projects. Requests send Authorization: ApiKey bsk_…; see authentication. Index names are your own: the project prefix is added and removed for you.

EndpointPurposeRoleMetered
PUT /v1/{index}Create an index with optional field mappingseditor—
GET /v1/{index}Index mappings and document countviewer—
DELETE /v1/{index}Delete an index and its documentseditor—
GET /v1/_cat/indicesList the project’s indexes with health, document count and sizeviewer—
GET /v1/{index}/_mappingField mappings of an indexviewer—
HEAD /v1/{index}Check that an index existsviewer—
PUT /v1/{index}/_doc/{id}Index a document; the same id replaces iteditor—
POST /v1/{index}/_docIndex a document under a generated ideditor—
PUT /v1/{index}/_create/{id}Index a document only if the id is neweditor—
POST /v1/{index}/_update/{id}Update fields of an existing documenteditor—
HEAD /v1/{index}/_doc/{id}Check that a document existsviewer—
GET /v1/{index}/_doc/{id}Get a document by idviewer—
DELETE /v1/{index}/_doc/{id}Delete a documenteditor—
POST /v1/_mgetGet many documents by idviewer—
POST /v1/{index}/_mgetGet many documents of one index by idviewer—
POST /v1/_bulkIndex and delete many documents (NDJSON)editor—
POST /v1/{index}/_delete_by_queryDelete every document that matches a queryeditor—
POST /v1/{index}/_searchQuery, sort, paginate and aggregateviewerYes
GET /v1/{index}/_searchSame as POST, with query-string parametersviewerYes
POST /v1/{index}/_countCount the documents that match a queryviewerYes
GET /v1/{index}/_countSame as POST, with query-string parametersviewerYes
POST /v1/_msearchRun several searches in one request (NDJSON)viewerYes, per contained search
POST /v1/{index}/_msearchRun several searches against one index (NDJSON)viewerYes, per contained search
POST /v1/_search/scrollFetch the next page of a scrollviewerYes
DELETE /v1/_search/scrollClear a scrollviewer—
GET /v1/{index}/_analytics/top_queriesMost frequent queriesviewer—
GET /v1/{index}/_analytics/zero_resultsQueries that found nothingviewer—
GET /v1/{index}/_analytics/low_ctrQueries people search for but rarely click throughviewer—
POST /v1/{index}/_trackRecord a click on a resulteditor—
GET /v1/_cluster/healthService status of the project’s indexesviewer—

Metered requests use credits: 10 attempts per credit. Sync endpoints are on the PostgreSQL sync page. Project, member, key and billing management needs a signed-in user and is done in the web console.

Indexes

Field types

TypeAliasesHow it is stored and searchedTypical use
text—Full-text search with BM25 scoring (tokenized).Titles, descriptions, article bodies
keywordstringExact match and aggregations; not tokenized. Set "fast": true to aggregate.Categories, tags, status codes
integerlong, i6464-bit signed integer.Counts, years, quantities
floatdouble, f6464-bit floating point.Prices, ratings
booleanboolTrue or false; range queries work on it too.Flags such as in_stock
datedatetimeRFC 3339 timestamp, for example 2026-01-15T10:30:00Z.Created and updated times

PUT /v1/{index}

Role editor

Creates an index. mappings.properties is optional; each field has a type and optional stored, indexed and fast flags (stored and indexed default to true, fast to false). Answers 409 if the index exists.

Request

curl -X PUT https://api.boltsearch.app/v1/movies \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "mappings": {
      "properties": {
        "title": { "type": "text" },
        "year": { "type": "integer" },
        "genre": { "type": "keyword", "fast": true }
      }
    }
  }'

Response

HTTP 200
{
  "acknowledged": true,
  "index": "movies"
}

GET /v1/{index}

Role viewer

Returns index information: the mappings and the number of documents.

Request

curl https://api.boltsearch.app/v1/movies \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY'

Response

HTTP 200
{
  "name": "movies",
  "mappings": {
    "properties": {
      "title": { "type": "text", … },
      "year": { "type": "long", … }
    }
  },
  "doc_count": 5
}

GET /v1/_cat/indices

Role viewer

Lists the project’s indexes in the Elasticsearch cat format: a text table by default, with a header row when you add ?v, or ?format=json for an array of objects whose values are strings. ?bytes=b gives sizes in bytes. The project prefix is never shown, and other projects’ indexes never appear. Read mappings with GET /v1/{index}/_mapping.

Request

curl https://api.boltsearch.app/v1/_cat/indices?format=json \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY'

Response

HTTP 200
[
  {
    "health": "green",
    "status": "open",
    "index": "movies",
    "uuid": "…",
    "pri": "1",
    "rep": "0",
    "docs.count": "5",
    "docs.deleted": "0",
    "store.size": "12kb",
    "pri.store.size": "12kb"
  }
]

DELETE /v1/{index}

Role editor

Removes the index and its documents from disk. It cannot be undone.

Request

curl -X DELETE https://api.boltsearch.app/v1/movies \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY'

Response

HTTP 200
{
  "acknowledged": true
}

Documents

PUT /v1/{index}/_doc/{id}

Role editor

Indexes a document under an id. An existing document with that id is replaced as a whole.

Request

curl -X PUT https://api.boltsearch.app/v1/movies/_doc/1 \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "The Matrix",
    "year": 1999,
    "genre": "sci-fi",
    "rating": 8.7
  }'

Response

HTTP 201
{
  "_index": "movies",
  "_id": "1",
  "result": "created",
  "_version": 1,
  "_shards": { "total": 1, "successful": 1, "failed": 0 }
}

GET /v1/{index}/_doc/{id}

Role viewer

Returns one document. A missing id answers 404 with "found": false.

Request

curl https://api.boltsearch.app/v1/movies/_doc/1 \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY'

Response

HTTP 200
{
  "_index": "movies",
  "_id": "1",
  "found": true,
  "_source": { "title": "The Matrix", … },
  "_version": 1
}

DELETE /v1/{index}/_doc/{id}

Role editor

Deletes one document.

Request

curl -X DELETE https://api.boltsearch.app/v1/movies/_doc/1 \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY'

Response

HTTP 200
{
  "_index": "movies",
  "_id": "1",
  "result": "deleted"
}

POST /v1/_bulk

Role editor

Takes NDJSON: an action line, then a document line for index actions, and an action line alone for delete. End every line, including the last, with a newline. Actions can name several indexes. The body is limited to 50 MB.

Request

curl -X POST https://api.boltsearch.app/v1/_bulk \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY' \
  -H 'Content-Type: application/x-ndjson' \
  --data-binary '{"index":{"_index":"movies","_id":"1"}}
{"title":"The Matrix","year":1999}
{"index":{"_index":"movies","_id":"2"}}
{"title":"Inception","year":2010}
{"delete":{"_index":"movies","_id":"3"}}'

Response

HTTP 200
{
  "took": 15,
  "errors": false,
  "items": [
    { "index": { "_index": "movies", "_id": "1", "result": "indexed", "status": 201 } },
    { "index": { "_index": "movies", "_id": "2", "result": "indexed", "status": 201 } },
    { "delete": { "_index": "movies", "_id": "3", "result": "deleted", "status": 200 } }
  ]
}

POST /v1/{index}/_delete_by_query

Role editor

Deletes every document that matches query. The body must contain a query.

Request

curl -X POST https://api.boltsearch.app/v1/movies/_delete_by_query \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "query": { "range": { "year": { "lt": 1950 } } }
  }'

Response

HTTP 200
{
  "deleted": 12
}

Search

POST /v1/{index}/_count

Role viewerMetered

Counts the documents that match a query; with no body it counts them all.

Request

curl -X POST https://api.boltsearch.app/v1/movies/_count \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "query": { "term": { "genre": "sci-fi" } }
  }'

Response

HTTP 200
{
  "count": 42
}

POST /v1/_search/scroll

Role viewerMetered

Fetches the next page for a scroll_id. Each page request is one metered attempt. Scroll ids carry their own signed state; a changed id is refused. DELETE /v1/_search/scroll with the same body clears it, and is not metered.

Request

curl -X POST https://api.boltsearch.app/v1/_search/scroll \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "scroll_id": "<scroll_id from the previous page>",
    "scroll": "1m"
  }'

Response

HTTP 200
{ "hits": { … }, "scroll_id": "…" }

Query language and aggregations

ClauseExampleWorks onNotes
match_all{ "match_all": {} }Any indexEvery document.
match{ "match": { "title": "dark knight" } }textAnalyzes the text and scores with BM25. The extended form takes "operator": "and"; the default is OR.
term{ "term": { "genre": "sci-fi" } }keyword, integer, float, booleanExact, unanalyzed value. Also written { "value": … }.
bool{ "bool": { "must": […], "should": […], "must_not": […] } }Other queriesmust is AND, should is OR, must_not is NOT.
range{ "range": { "year": { "gte": 2000, "lt": 2020 } } }integer, float, booleangte, gt, lte and lt.
terms (agg)"aggs": { "genres": { "terms": { "field": "genre", "size": 10 } } }keyword with "fast": trueBuckets by field value.
metrics (agg)"aggs": { "avg_rating": { "avg": { "field": "rating" } } }numeric fieldsavg, sum, min, max, value_count and stats.
range (agg)"ranges": [ { "to": 2000 }, { "from": 2000, "to": 2010 }, { "from": 2010 } ]numeric fieldsBuckets between from and to.

Examples

Both words required

{
  "query": {
    "match": {
      "title": { "query": "dark knight", "operator": "and" }
    }
  }
}

Combine clauses

{
  "query": {
    "bool": {
      "must": [{ "match": { "title": "matrix" } }],
      "should": [{ "term": { "genre": "sci-fi" } }],
      "must_not": [{ "range": { "year": { "lt": 1990 } } }]
    }
  }
}

Aggregations only

{
  "size": 0,
  "aggs": {
    "genres": { "terms": { "field": "genre", "size": 10 } },
    "avg_rating": { "avg": { "field": "rating" } },
    "decades": {
      "range": {
        "field": "year",
        "ranges": [{ "to": 2000 }, { "from": 2000, "to": 2010 }, { "from": 2010 }]
      }
    }
  }
}

Results appear under aggregations, using the names you gave. Aggregated fields need "fast": true, and text fields cannot be aggregated. Other Elasticsearch query types are not part of the supported set.

Analytics

GET /v1/{index}/_analytics/top_queries

Role viewer

Also /zero_results and /low_ctr. Query parameters: from and to (timestamps; the default range is the last 7 days), size (default 20, up to 1,000) and, for low_ctr, min_searches.

Request

curl https://api.boltsearch.app/v1/movies/_analytics/top_queries?size=5 \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY'

Response

HTTP 200
{
  "queries": [
    { "query": "matrix", "count": 42, "avg_latency_ms": 3.1, "avg_results": 3 }
  ]
}

POST /v1/{index}/_track

Role editor

Records that a person clicked a result. query and document_id are required; position is the rank of the result.

Request

curl -X POST https://api.boltsearch.app/v1/movies/_track \
  -H 'Authorization: ApiKey bsk_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "query": "matrix",
    "document_id": "1",
    "position": 0
  }'

Response

HTTP 200
{ "result": "created" }

Make an API key and try these requests.

Get startedSee pricing