> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.talqora.com/build-retrieval/write-vectors/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.talqora.com/_mcp/server. # Write vectors > Upsert application-owned embeddings, metadata, and optional lexical text with idempotent batches. Use the Vector API write path when your application already owns extraction and embedding generation. A write creates or replaces a record in one index. Each record can contain a stable ID, a dense vector, filterable metadata, and optional `sparse_text` for lexical and hybrid retrieval. This is separate from [Serverless Processing](/build-retrieval/file-processing), where Talqora accepts a source file and generates chunks and embeddings asynchronously. Both paths produce searchable records in the same index. ## Write contract * A request accepts at most **500 vectors**. * Every `values` array must exactly match the index dimensions. * Values must be finite, float32-compatible numbers with a non-zero norm. All-zero vectors return `422`; they are never forwarded to storage. * IDs must be unique within one batch. A duplicate ID in one payload returns `422` with the failing `vectors[n].id` field. * Every write requires an `Idempotency-Key` header. * A key has `write` capability and must be scoped to the target index, or be allowed for all workspace indexes. * Reusing an existing record ID replaces its active dense, sparse, and metadata representation. Use stable IDs from your source system. For example, use `product:sku-42`, `ticket:INC-1842:summary`, or `policy:v3:page-12:chunk-2`. Avoid random IDs for records that will be updated; stable IDs make replacement and deletion precise. ## Upsert a batch ```bash curl --fail-with-body https://api.talqora.com/v1/indexes/$INDEX_ID/vectors \ -X POST \ -H "Authorization: Bearer $TALQORA_API_KEY" \ -H "Idempotency-Key: catalog-import-2026-08-11-001" \ -H "Content-Type: application/json" \ -d '{ "vectors": [ { "id": "product:shoe-42", "values": [0.12, 0.18, 0.44], "metadata": { "tenant_id": "acme", "category": "running", "price": 90, "in_stock": true, "locale": "en-US" }, "sparse_text": "lightweight red running shoe for trail training" } ] }' ``` In production, build the `values` array from the exact model used for this index. The three values above are only a compact example; a 1536-dimensional index requires 1,536 values per record. ## Dense, sparse, and metadata fields `values` is the dense representation used for semantic retrieval. It should be generated from the content you want to match, not from an ID or a few keywords. `sparse_text` is optional but recommended when users search names, policy codes, SKUs, error messages, dates, or product language. It is indexed for BM25 search and combines with dense candidates during hybrid retrieval. Omit it only for a genuinely dense-only workload. `metadata` carries structured facts for filters and for display after retrieval. Use booleans, numbers, strings, arrays, and stable source identifiers. Do not put source bodies, credentials, or unbounded arbitrary payloads in metadata. ## Idempotency and retries An `Idempotency-Key` makes a network retry safe. Use a unique deterministic key for one logical batch, persist it alongside the source checkpoint, and resend the exact same request if the client cannot confirm the response. * Same key, same body: Talqora returns the original outcome without a second write or second usage increment. * Same key, different body: Talqora rejects the request to prevent accidental data corruption. * New key: Talqora treats the payload as a new operation. If IDs already exist, it is an intentional upsert. Do not generate a new idempotency key immediately after a timeout. Retry the original request first. This is particularly important for worker queues and client libraries that may receive an ambiguous connection failure after the server has completed the durable write. ## Input failures are actionable Malformed JSON, a missing required field, invalid dimensions, duplicate IDs, and unsupported field types all return `422` with the same error envelope. Fix the reported `field`; do not retry it unchanged. Missing `Content-Type: application/json` returns `415`. Vector-store, sparse-store, and provider failures are distinct retryable `5xx` responses and include `request_id`. ## Upserts and usage Writing an existing ID replaces the live record. `documents` measures current live cardinality, while `rows_written` measures accepted write activity. Therefore an index with 10,000 current documents may have a much larger `rows_written` value after catalog refreshes. `data_written` reflects accepted write payload activity. Dense storage, sparse storage, and query transfer are tracked separately in the index and organization usage views. Read [Usage and limits](/operate-at-scale/usage-and-limits) before choosing an import batch size or refresh cadence. ## Batch design Batch up to 500 records to reduce request overhead, but keep batches small enough that your producer can retry one logical checkpoint. A common pattern is to checkpoint source offsets every 100–500 records, use one idempotency key per checkpoint, and only advance the source cursor after Talqora confirms the batch. For a very large backfill, run bounded concurrent batches rather than an unbounded fan-out. Respect `429` responses and the `RateLimit-*` headers. On a retryable transport or capacity error, use exponential backoff with jitter. Do not retry malformed vectors, invalid filters, or a mismatched dimension without correcting the payload. ## Updating and deleting To change content, write the same ID with a new vector, metadata, and `sparse_text`. To remove records, use `DELETE /v1/indexes/{index_id}/vectors` with an idempotency key. Deletion makes the record unavailable to dense, sparse, and hybrid retrieval before background sparse compaction completes. Use [File processing](/build-retrieval/file-processing) replacement and deletion endpoints for sources created through Processing. That path knows every chunk generated from the file and removes the complete source lifecycle safely. ## Validate before shipping 1. Confirm the index dimensions match the embedding model output. 2. Write a small fixture batch with realistic metadata and `sparse_text`. 3. Query dense, sparse, and hybrid modes with your production filters. 4. Test an upsert of the same ID and verify only the new representation is returned. 5. Test a delete and confirm no stale sparse candidate is exposed. 6. Record p50/p95 latency, error rate, transfer, and relevance before scaling the importer. > Upsert application-owned embeddings, metadata, and optional lexical text with idempotent batches.