Documents API
The Documents API reads, creates, updates, and deletes documents in an index under /v1alpha1/indexes/{name}/documents.
Each endpoint also has a generated page stating every field it accepts and returns. See Documents.
Routing and commits
Section titled “Routing and commits”Each index is written by one node at a time. A node that receives a write request for an index it does not hold forwards the request to the active indexer node. If no target node is available to handle the forwarded request, the request returns status 409 with error indexer:unavailable.
Changes become searchable and replicate to remote storage after the index commits. The writer commits automatically based on indexed document volume or elapsed time. For commit configuration details, see Committing.
To commit changes immediately, send a request to the admin API:
POST /v1alpha1/admin/indexes/{name}/actions/commitFor more information, see the Admin API.
How a document is shaped
Section titled “How a document is shaped”A document specifies its own primary key. Indexing a document with an existing key replaces the document under that key. If an index definition does not declare a primary key, each request adds a new document.
The following table lists the supported field formats:
| Field type | Format | Example |
|---|---|---|
| Single value | Value literal | "name": "rågbröd" |
Declared multiple | Array of values | "tags": ["sylt", "bär"] |
| Locale-specific | Object keyed by locale tag | "name": { "sv": "sylt", "en": "jam" } |
| Geo point | Object with lat and lon fields | "origin": { "lat": 59.33, "lon": 18.07 } |
| Vector | Array of numbers | "embedding": [0.12, -0.4] |
| Object | JSON object of declared fields | "variants": { "size": "S" } |
| Timestamp | ISO 8601 string | "published": "2026-08-16T09:00:00Z" |
Document fields follow these rules:
- The schema definition determines how a JSON object is parsed (for example, as a locale map or a geo point).
- If you provide a value without a locale tag for a locale-specific field, the value is stored in the field’s default locale.
- Search hits return a locale-specific field in the single requested locale. For more information, see locale-specific fields in search results. Indexing that search hit replaces the field with only that single language variant.
- Object fields must be formatted as nested JSON objects. Specifying dotted paths such as
"dimensions.width"directly returns the errordocument:field_inside_object. - A field set to
nullis treated as omitted. If the schema marks the field asrequired, validation fails and reports the field as missing.
Indexing documents
Section titled “Indexing documents”POST /v1alpha1/indexes/{name}/documentsIndexes one or more documents into the specified index.
Query parameters
Section titled “Query parameters”The request supports the following query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
onError | string | fail | Behavior when the index refuses a document. Allowed values are fail (stops at the first refused document and fails the request) and skip (processes the batch and reports refused documents in failed). Other values return document:on_error_invalid. See Skipping refused entries. |
Request headers
Section titled “Request headers”The request supports the following headers:
| Header | Description |
|---|---|
Content-Type | Set to application/json or application/x-ndjson. |
Request body
Section titled “Request body”You can format the request body in two ways:
application/json: A JSON object with adocumentsarray containing document objects.application/x-ndjson: Newline-delimited JSON containing one document object per line without a wrapper.
The following example uses Content-Type: application/json:
{ "documents": [ { "id": "1", "name": "blåbärssylt", "tags": ["sylt", "bär"], "energy": 234 } ]}The following example uses Content-Type: application/x-ndjson:
{"id": "1", "name": "blåbärssylt"}{"id": "2", "name": "rågbröd"}Response
Section titled “Response”The endpoint returns status 200 OK with the count of indexed documents, any documents the index refused, and the state the batch lands in:
{ "indexed": 2, "failed": [], "freshness": "AQoIcHJvZHVjdHMSATIYBw" }The failed array is always present and contains entries only when the request is sent with ?onError=skip. The indexed count excludes documents in failed. For the entry structure, see Skipping refused entries.
freshness is a token naming the commit the batch lands in. Pass it in freshness.atLeast on a search request to read from a state that includes this batch. For more information, see Freshness.
Indexing one document
Section titled “Indexing one document”PUT /v1alpha1/indexes/{name}/documents/{key}Indexes the document in the request body under the primary key in the path, replacing whatever is indexed under that key.
One request carries one document. To load a dataset, send batches to POST /v1alpha1/indexes/{name}/documents, which accepts a newline-delimited body and costs one request for each batch instead of one for each document.
Path parameters
Section titled “Path parameters”The request requires the following path parameters:
| Parameter | Type | Description |
|---|---|---|
name | string | Name of the index. A generation is named as books@2. |
key | string | Primary key to index the document under. Parsed according to the key field type. |
The key arrives as text regardless of the declared key field type.
Permissions and routing
Section titled “Permissions and routing”Indexing a document requires the documents.write permission at the index scope. Anonymous requests are refused. The writer and admin roles include this permission; the reader role does not.
The operation runs on the index writer node. A write request received by another node is forwarded automatically.
Request body
Section titled “Request body”The body is one document object, formatted like an entry of the documents array of POST /v1alpha1/indexes/{name}/documents:
{ "name": { "sv": "blåbärssylt" }, "tags": ["sylt", "bär"], "energy": 234}Leave the primary key field out. The document is indexed under the key in the path. A body that includes the primary key field must give that same key, or the request returns document:key_conflicting. A repeated key can be written as text or as a number, because the engine takes the key from the path.
The content type is application/json. The endpoint has no newline-delimited form, because one request carries one document.
Desired state
Section titled “Desired state”Indexing is a statement of desired state. Repeating the request produces the same outcome, and the response is the same whether or not a document was indexed under the key before the request. A request that times out can be sent again without reading the index first.
The endpoint does not require a document to exist. Unlike PATCH on the same path, which describes changes to an existing document and returns 404 when nothing is indexed under the key, PUT indexes under the key either way.
Response
Section titled “Response”The endpoint returns status 204 No Content, whether or not a document existed under the key.
The X-Exofind-Freshness response header carries a token naming the commit the write lands in. Pass it as freshness.atLeast on a search request, or in the X-Exofind-Freshness header of a read request, to be answered only once the node holds the write.
Changes become searchable and replicate to remote storage after the index commits.
Index requirements
Section titled “Index requirements”The index definition must declare a primary key, because the path gives the key to index the document under.
An index defined with source: none accepts the document. Indexing needs no copy of what was indexed before.
Errors
Section titled “Errors”The endpoint returns the following errors:
| Condition | Error code | Status |
|---|---|---|
| The key cannot be read as the type of the primary key field | search:value_invalid | 400 |
| The index definition declares no primary key | index:no_primary_key | 400 |
| The body gives the primary key field a value other than the key in the path | document:key_conflicting | 400 |
| The request carries no document | request:body_required | 400 |
| No index of that name on this node, or the API key has no permission on it | index:not_found | 404 |
| No node is available to write the index | indexer:unavailable | 409 |
| The index is synchronizing | index:out_of_date | 409 |
| The node lost the writer role while the request ran | index:readonly | 409 |
| An active reindex job holds the target generation | reindex:target_busy | 409 |
| The request was forwarded to the writer and the writer did not answer | indexer:unreachable | 502 |
| The request raced the index being closed to free local resources | index:closed | 503 |
The endpoint also returns every code that a document in a batch is refused with, such as document:field_unknown, document:field_required, and document:number:value_invalid. The whole document is validated as one, so a refused document leaves the index unchanged.
Example
Section titled “Example”PUT /v1alpha1/indexes/foods/documents/1Content-Type: application/json
{ "name": "Blueberry jam", "energy": 234 }Changing some of the fields
Section titled “Changing some of the fields”You can change one document by its key in the URL path, or change several documents in a batch. Both forms describe the change the same way, and both require an index that declares a primary key. A change needs the document source unless it names only signal fields.
A change that names only the primary key and signal fields refreshes those fields in place. The engine replaces doc values without reading or rewriting the document. This is called a refresh, and it works on an index where source is none. A change that names any other field, adds a value, or reaches inside a field reads the document from its source, merges it, and indexes it again. Signal fields named in that change take the specified values, while unnamed signal fields keep their existing values.
Change documents in a batch
Section titled “Change documents in a batch”POST /v1alpha1/indexes/{name}/documents/actions/updateUpdates specific fields of existing documents in the index.
Query parameters
Section titled “Query parameters”The request supports the following query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
missing | string | fail | Behavior when a document key does not exist. Allowed values are fail (fails the request) and skip (skips missing documents and lists them in the response). |
onError | string | fail | Behavior when the index refuses a change. Allowed values are fail (stops at the first refused change and fails the request) and skip (processes the batch and reports refused changes in failed). When missing is skip, keys with no indexed document are reported under missing instead. Other values return document:on_error_invalid. See Skipping refused entries. |
Request headers
Section titled “Request headers”The request supports the following headers:
| Header | Description |
|---|---|
Content-Type | Set to application/json or application/x-ndjson. |
Request body
Section titled “Request body”The body contains change objects. Each object must include the primary key. Every other key is a path naming a place in the document, and the value is what that place becomes.
The following example uses Content-Type: application/json:
{ "documents": [ { "id": "1", "price": 34.50, "inStock": true }, { "id": "2", "price": 12.00, "discount": null } ]}You can also send updates using Content-Type: application/x-ndjson with one change object per line.
A path is a field name, and may carry a selector in brackets and a field inside the value the selector picks:
| Path | Names |
|---|---|
price | The field itself, with every value it holds. |
title[sv] | The sv variant of a locale-specific field. |
tags[] | A value added to the ones the field holds. |
variants[sku=V-2] | The object values whose sku field reads as V-2. |
variants[sku=V-2].price | The price field inside those values. |
variants[V-2] | The object value whose key reads as V-2. |
variants[V-2].price | The price field inside that value. |
dimensions.width | The width field inside a single object value. |
A backslash escapes the character after it, in a field name and inside brackets alike. For the path syntax, the selector forms, and the escaping rules, see Change paths.
Paths follow these rules:
- A BCP 47 tag resolves to the variant the field declares, so
title[nb-NO]changes a field that holdsno. - A key path on a field declaring no key is refused with
document:patch:key_unsupported. - Empty brackets need a field declared
multiple. - A field inside a list of objects requires a selector saying which value. Without one, the request returns
document:patch:selector_required.
Update behavior
Section titled “Update behavior”Path changes apply as follows:
| Change | Behavior |
|---|---|
| Path with a value | Replaces what the path names. |
Path set to null | Empties what the path names. On a selector naming object values, this removes those values. |
| Path not given | Leaves what it would name unchanged. |
Updates follow these rules:
- The path replaces exactly what it names, and leaves everything around it.
variantsreplaces every value of the field. Thefield=valueform replaces every value it matches, while a key path names at most one because keys are unique within a document.variants[sku=V-2].pricereplaces one field inside those values. - A value replaced in place keeps its position in the list. An added value goes last.
- Multiple updates to the same document in a single batch apply in the order provided.
- Every change to one document is applied and validated as a whole. If validation fails, the request is rejected and the document remains unchanged.
- The whole document is rewritten in the index either way, so a change to one sub-document costs what rewriting the document costs. For more information, see How sub-documents are stored.
- A change that names only signal fields refreshes doc values in place without rewriting the document. Setting a signal field to
nullclears the value. A refresh rewrites the doc values of the field once per touched segment at the next commit, so send refreshes in a few large batches rather than many small requests.
Constraints and errors
Section titled “Constraints and errors”- If the index definition sets
sourcetonone, or if a document was indexed when source was disabled, the endpoint returnsdocument:source_not_kept. A change that names only signal fields works whensourceisnone. For more information, see the Admin API. - If the index definition declares no primary key, the endpoint returns
index:no_primary_key. - If
missingis set tofail(default) and a document key is not found, the request fails withdocument:not_foundfor that entry. Ifmissingis set toskip, missing keys are skipped and returned as text strings undermissingin the response. - A selector that names no value the document holds returns
document:patch:no_match. A key nothing matches is not created.
The following error codes report a path the endpoint cannot use:
| Code | Meaning |
|---|---|
document:patch:path_invalid | The key cannot be read as a path. |
document:patch:add_reaches_inside | The path reaches inside a value that is being added. |
document:patch:field_unknown | The path reaches into a field the index does not have. |
document:patch:selector_unsupported | The path names one value of a field that holds neither locale variants nor objects. |
document:patch:match_not_an_object | The path matches on an inner field of a field whose values are not objects. |
document:locale_unknown | The field holds no variant for the named locale. |
document:patch:add_unsupported | The path adds a value to a field that holds a single value. |
document:patch:not_an_object | The path reaches inside a field whose values are not objects. |
document:patch:selector_required | The path reaches into a list of objects without saying which value. |
document:patch:key_unsupported | The path uses a key selector on a field that declares no key. |
document:patch:no_match | The selector names no value the document holds. |
The first two report a mistake in the path text alone. The rest report a path that disagrees with the index definition or with the stored document. For the rule behind the prefixes, see Errors.
Response
Section titled “Response”The endpoint returns status 200 OK with the count of updated documents, any missing keys, and any changes the index refused:
{ "updated": 2, "missing": [], "failed": [], "freshness": "AQoIcHJvZHVjdHMSATIYBw" }When called with ?missing=skip:
{ "updated": 1998, "missing": ["sku-9", "sku-40"], "failed": [], "freshness": "AQoIcHJvZHVjdHMSATIYBw" }freshness is a token naming the commit the changes land in. For more information, see Freshness.
Each key in missing is returned as text, regardless of the declared key field type. For example, a whole-number key 9 is returned as "9". This matches the format accepted by the {key} path parameter and the after query parameter. For more information, see Primary keys on the wire.
The failed array is always present and contains entries only when the request is sent with ?onError=skip. The updated count excludes changes in failed. For the entry structure, see Skipping refused entries.
Change one document by key
Section titled “Change one document by key”PATCH /v1alpha1/indexes/{name}/documents/{key}Changes named parts of the single document indexed under the specified key.
Path parameters
Section titled “Path parameters”The request requires the following path parameters:
| Parameter | Type | Description |
|---|---|---|
name | string | Name of the index. |
key | string | Primary key of the document to change. Parsed according to the key field type. |
Request body
Section titled “Request body”The body is a single change object, meaning what one entry of the batch means. The key comes from the URL path, so the body holds paths only:
{ "price": 34.50, "variants[sku=V-2].price": 29.0, "discount": null }Paths and update behavior are the same as in the batch. The body may repeat the primary key field as long as it gives the key the path already names; a different value returns document:key_conflicting.
Errors
Section titled “Errors”document:not_found: Nothing is indexed under the key. The endpoint returns status404and creates nothing, because a change describes what to change about a document rather than what should be there.document:key_conflicting: The body names the primary key field as another document than the path does.search:value_invalid: The key cannot be parsed as the defined key field type.- The path codes listed for the batch,
index:no_primary_keyanddocument:source_not_keptmean here what they mean in the batch. A key nothing is indexed under isdocument:not_foundhere too, returned with404because the URL names the document.
Response
Section titled “Response”The endpoint returns status 204 No Content. The batch action remains the only form that reports a count. The X-Exofind-Freshness response header carries a token naming the commit the change lands in. For more information, see Freshness.
PATCH /v1alpha1/indexes/foods/documents/1Reading one document
Section titled “Reading one document”GET /v1alpha1/indexes/{name}/documents/{key}Reads the single document indexed under the specified primary key, returning it as originally indexed.
Path parameters
Section titled “Path parameters”The request requires the following path parameters:
| Parameter | Type | Description |
|---|---|---|
name | string | Name of the index. A generation is named as books@2. |
key | string | Primary key of the document to read. Parsed according to the key field type. |
The key arrives as text regardless of the declared key field type. For example, a whole-number key field reads the text "2" as the number 2.
Permissions and routing
Section titled “Permissions and routing”Reading a document requires the documents.read permission at the index scope. Anonymous requests are refused. The writer and admin roles include this permission; the reader role does not.
Read requests are answered directly by the node that receives them, using data that the node has pulled from storage. The request is never forwarded to the indexer node.
Request headers
Section titled “Request headers”The request supports the following headers:
| Header | Description |
|---|---|
X-Exofind-Freshness | Optional. A freshness token returned by an earlier response. The document is read only once the node holds the state the token names. |
Response
Section titled “Response”The endpoint returns status 200 OK with the document under document and the state it was read from under freshness:
{ "document": { "id": "1", "name": { "sv": "blåbärssylt" }, "energy": 234 }, "freshness": "AQoIcHJvZHVjdHMSATIYBw"}The document value is formatted exactly as the indexing endpoint accepts it, so you can send it directly back to POST /v1alpha1/indexes/{name}/documents inside a documents array.
freshness is a token naming the state the document was read from. Pass it in the X-Exofind-Freshness header of a later request to answer that request from this state or a later state on any node.
The endpoint has no newline-delimited form. One document is returned as one JSON object.
Consistency and visibility
Section titled “Consistency and visibility”A read request is answered from a point-in-time snapshot and sees committed data only:
- A document indexed since the last commit is reported as missing with
document:not_found. - A document removed since the last commit is still returned.
To read back a write as soon as it lands, pass the freshness token returned by the write in the X-Exofind-Freshness header.
Errors
Section titled “Errors”The endpoint returns the following errors:
| Condition | Error code | Status |
|---|---|---|
| Nothing is indexed under the key, as of the last commit | document:not_found | 404 |
| No index of that name on this node, or the API key has no permission on it | index:not_found | 404 |
| The key cannot be read as the type of the primary key field | search:value_invalid | 400 |
| The index definition declares no primary key | index:no_primary_key | 400 |
The index is defined with source: none and keeps no document copies | document:source_not_kept | 400 |
| The freshness token is not one the engine issued | search:freshness:invalid | 400 |
| The freshness token is of a format version this node does not read | search:freshness:version_unsupported | 400 |
| The freshness token is of another index than the one in the path | search:freshness:index_mismatch | 400 |
| The node did not reach the state the freshness token asks for | search:freshness:unavailable | 503 |
| The request raced the index being closed to free local resources | index:closed | 503 |
Example
Section titled “Example”GET /v1alpha1/indexes/foods/documents/1Authorization: Bearer <key>Reading documents
Section titled “Reading documents”GET /v1alpha1/indexes/{name}/documentsReads documents back out of an index in primary key order, returning them as originally indexed.
Permissions and routing
Section titled “Permissions and routing”Reading documents requires the documents.read permission at the index scope. Anonymous requests are refused. The writer and admin roles include this permission; the reader role does not.
Read requests are served directly by whichever node receives them, using data that the node has pulled from storage. Unlike write operations, read requests are never forwarded to the indexer node.
To read from a state at or after a change, pass the freshness token from the change in the X-Exofind-Freshness request header. The node pulls that state before reading, and returns search:freshness:unavailable with a Retry-After header if the state does not arrive within EXOFIND_SEARCH_FRESHNESS_WAIT. For more information, see Freshness.
Query parameters
Section titled “Query parameters”The request supports the following query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
after | string | None | Primary key to resume reading after. The specified key is omitted from the response. Formatted as text matching the key path parameter in DELETE /v1alpha1/indexes/{name}/documents/{key} (for example, numeric keys are written as numbers). If no document exists under this key, reading resumes from where the key would be positioned in the order. |
limit | integer | 100 | Maximum number of documents to return. Must be a whole number from 1 to 10000. |
Response formats
Section titled “Response formats”Set the Accept request header to select the response format. The default format is application/json, which also applies to Accept: */*.
JSON format (application/json)
Section titled “JSON format (application/json)”Returns a JSON object with the list of documents and a continuation key:
{ "documents": [ { "id": "1", "name": "blåbärssylt", "energy": 234.5 }, { "id": "2", "name": "rågbröd", "energy": 217.0 } ], "next": "2", "freshness": "AQoIcHJvZHVjdHMSATIYBw"}The response fields are:
documents: Documents in primary key order, formatted as originally indexed.next: Primary key to pass as theafterparameter on the next request. Present only when the response returns as many documents as requested bylimit. If a batch ends exactly on the last document of the index,nextis returned and the subsequent request returns an emptydocumentsarray without anextfield.freshness: A token naming the state the documents were read from. Pass it in theX-Exofind-Freshnessrequest header of the next request to read from the same state or a later state on any node. For more information, see Freshness.
Newline-delimited JSON (application/x-ndjson)
Section titled “Newline-delimited JSON (application/x-ndjson)”Returns newline-delimited JSON containing one document object per line with no outer wrapper:
{"id": "1", "name": "blåbärssylt", "energy": 234.5}{"id": "2", "name": "rågbröd", "energy": 217.0}The body contains only documents, matching byte-for-byte the format accepted by POST /v1alpha1/indexes/{name}/documents with Content-Type: application/x-ndjson. The X-Exofind-Freshness response header carries the token that the JSON format returns in freshness.
To determine if more documents are available, check the number of lines returned. If the response contains as many lines as requested by limit, resume the next request by passing the primary key of the last document in the after parameter. When the response returns fewer lines than limit, all documents have been read.
Ordering
Section titled “Ordering”Documents are returned in primary key order:
- Whole-number keys (
int32,int64) return in numeric order, with negative numbers first. - Text keys return in UTF-8 byte order (for example,
"100"precedes"50").
Document order depends solely on primary keys and does not reflect the order in which documents were indexed. Merges, removals, replacements, and pulls do not change the position of a document in the key sequence. Repeating the same request returns the same sequence.
Consistency and visibility
Section titled “Consistency and visibility”A single request reads from a point-in-time snapshot of the index and sees committed data only. Uncommitted writes are not visible.
Across multiple requests, index changes can occur between calls:
- Documents indexed under keys that the read has already passed are omitted from subsequent responses.
- Documents modified after being read are returned in the state they had when read.
- Documents deleted after being read remain included in earlier responses.
To retrieve a consistent full dataset from an index that is receiving writes, track concurrent modifications and replay them after reading completes.
Across nodes, pass the freshness token from each response in the X-Exofind-Freshness request header of the next request. Each batch is then read from the state of the first batch or a later state, regardless of which node answers the request.
Request limits and pagination
Section titled “Request limits and pagination”Every response is bounded. The limit parameter cannot exceed 10000 in either response format. Reading an entire index requires a sequence of requests, each passing the previous response’s final key in the after parameter. Bounding responses prevents reads from blocking index pulls.
Refusals and errors
Section titled “Refusals and errors”The endpoint rejects requests before generating the response body in the following conditions:
| Condition | Error code | Status |
|---|---|---|
| The index definition declares no primary key | index:no_primary_key | 400 |
The index is defined with source: none and does not store document copies | document:source_not_kept | 400 |
The limit parameter is not a whole number between 1 and 10000 | request:limit_out_of_range | 400 |
Removing documents
Section titled “Removing documents”You can remove a single document by its key in the URL path, or remove multiple documents in a batch by keys or search query.
Delete a document by key
Section titled “Delete a document by key”DELETE /v1alpha1/indexes/{name}/documents/{key}Deletes a single document matching the specified key.
Path parameters
Section titled “Path parameters”The request requires the following path parameters:
| Parameter | Type | Description |
|---|---|---|
name | string | Name of the index. |
key | string | Primary key of the document to remove. Parsed according to the key field type. |
Errors
Section titled “Errors”search:value_invalid: The key value cannot be parsed as the defined key field type.index:no_primary_key: The index definition declares no primary key.
Response
Section titled “Response”The endpoint returns status 204 No Content whether or not a document existed under the specified key. The X-Exofind-Freshness response header carries a token naming the commit the removal lands in. For more information, see Freshness.
DELETE /v1alpha1/indexes/foods/documents/1Delete documents by keys, query, or all
Section titled “Delete documents by keys, query, or all”POST /v1alpha1/indexes/{name}/documents/actions/deleteDeletes multiple documents matching a list of primary keys or a search query, or empties the index. The request body must name exactly one of keys, query, and all.
Request body
Section titled “Request body”The request body supports the following fields:
| Field | Type | Description |
|---|---|---|
keys | array of strings | List of primary keys to delete. An empty array deletes nothing. |
query | array of objects | Query clauses matching documents to delete. For clause syntax, see the Search API. The array requires at least one clause. |
all | boolean | Set to true to delete every document and empty the index. |
locale | string | Optional. Specifies the locale variant to match for locale-specific fields. Valid only when query is provided. |
The following example deletes documents by keys:
{ "keys": ["1", "2", "3"] }The following example deletes documents by query:
{ "query": [ { "field": "category", "match": { "value": "sylt" } } ], "locale": "sv"}The following example deletes every document in the index:
{ "all": true }Errors
Section titled “Errors”document:delete:target_required: The body names none ofkeys,query, andall.document:delete:target_conflicting: The body names more than one ofkeys,query, andall.document:delete:query_empty: The body names aquerywithout clauses. Sendallto empty the index.document:delete:locale_without_query: The body states alocalewithout aquery.
Execution behavior
Section titled “Execution behavior”- When deleting by
keys, all keys are validated before any documents are removed. If any key is invalid, no documents are removed. - When deleting by
query, the operation removes matching committed searchable documents and any uncommitted documents indexed since the last commit. - When deleting with
all, the operation removes every document the same way a query does, including documents indexed since the last commit.
Response
Section titled “Response”The endpoint returns status 200 OK with the count of deleted documents:
{ "deleted": 3, "freshness": "AQoIcHJvZHVjdHMSATIYBw" }For requests using keys, deleted is the number of keys provided in the request. For requests using query or all, deleted is the number of matching committed searchable documents. freshness is a token naming the commit the removal lands in. For more information, see Freshness.
Failures
Section titled “Failures”Documents in a batch are processed in the order sent. The first refused document halts processing and returns status 400 Bad Request. Documents processed before the failure remain in the index.
Locating a failed entry
Section titled “Locating a failed entry”Errors concerning a specific entry in a batch include locating values in the arguments map of each error object. All values in arguments are strings.
| Argument | Type | Description |
|---|---|---|
position | string | Index of the batch entry the error concerns, counted from zero. Matches the index in path (documents[n] for a JSON array body, [n] for newline-delimited JSON). |
processed | string | Number of entries accepted before the failure. For POST /v1alpha1/indexes/{name}/documents, this is the count of indexed documents. For POST /v1alpha1/indexes/{name}/documents/actions/update, this is the count of changed documents, excluding keys skipped by missing=skip. |
line | string | Line number where the entry starts in the request body, counted from one. Present only for application/x-ndjson. For document:malformed, this is the line where parsing stopped. |
position and line count different units. In a newline-delimited request body, an entry formatted across multiple lines or separated by blank lines results in a line count that differs from the position count.
Arguments are included based on the error type:
- Entry-level errors carry
position,processed, andline(forapplication/x-ndjson). These includedocument:not_an_object, errors where an entry breaks the index definition (such asdocument:field_unknownanddocument:field_required),document:not_found,document:malformed, andstorage:io_error. request:body_unreadablecarriespositionandprocessedonly.- Request-level errors (such as
request:body_required) carry none of these arguments.
Skipping refused entries
Section titled “Skipping refused entries”When a batch write request includes onError=skip, the endpoint processes the whole batch and returns status 200 OK. Refused entries are listed in failed:
{ "indexed": 2, "failed": [ { "position": 1, "line": 2, "errors": [ { "code": "document:field_unknown", "message": "Field `nonexistent` does not exist in index", "path": "[1].nonexistent", "arguments": { "position": "1", "processed": "1", "line": "2", "name": "nonexistent" } } ] } ]}Each entry of failed contains the following fields:
| Field | Type | Description |
|---|---|---|
position | integer | Index of the refused entry in the batch, counted from zero. |
line | integer | Line number where the entry starts, counted from one. Present only for application/x-ndjson. |
errors | array of objects | Error objects describing each validation failure for the entry, matching the format of top-level request errors. |
The onError parameter accepts fail (the default) and skip. Any other value returns document:on_error_invalid with status 400, with path set to onError.
When onError is set to skip, the endpoint skips and reports the following entry errors in failed:
- An entry that is not an object (
document:not_an_object). - An entry that breaks the index definition (such as
document:field_unknownordocument:field_required). - On the batch update endpoint, a key that does not exist in the index when
missingisfail.
The following errors are not skipped and halt request processing:
- Request body parsing failures (
document:malformed). - Index or node failures, including
storage:io_error,index:readonly, andindexer:unavailable.
Error response format
Section titled “Error response format”The error response contains the following fields:
| Field | Type | Description |
|---|---|---|
code | string | Top-level error classification code (for example, "validation"). |
message | string | Human-readable description of the error. |
errors | array of objects | Detailed list of error objects. Each object contains code, message, path (identifying the document and field location), and optional arguments. |
The following example shows an error response:
{ "code": "validation", "message": "Field `nonexistent` does not exist in index", "errors": [ { "code": "document:field_unknown", "message": "Field `nonexistent` does not exist in index", "path": "documents[1].nonexistent", "arguments": { "name": "nonexistent" } } ]}The path names the location in the body you sent. A body with a documents array names the array, as documents[1].nonexistent. A newline-delimited body has no wrapper, so the path starts at the document, as [1].nonexistent. Both count from zero.
HTTP status codes
Section titled “HTTP status codes”The API uses the following HTTP status codes:
| Status code | Condition |
|---|---|
200 | The documents were indexed, read, updated, or deleted successfully. |
204 | The document was changed or removed by key in the URL path. |
400 | A document or key was rejected by validation, the index definition lacks a primary key or stored source, the limit parameter was invalid, or the request body could not be parsed. |
404 | No index with the specified name exists on this node, or a PATCH named a key nothing is indexed under (document:not_found). |
409 | No node is available to forward the request to (indexer:unavailable), or the index is currently synchronizing. |
502 | The node holding the index writer did not respond to the forwarded request. |
503 | The index was closed to free resources; repeating the request reopens the index. |
Exofind is built by Level Four AB and is available under the Apache License 2.0.