Skip to main content
Generated from contracts/http/v0/openapi.yaml by make generate. Do not edit this page: change the source and regenerate.
Quivr V2 public text foundation contract, version 0.0.0-draft. THE-543 and THE-547 evaluation contracts; endpoint implementations are separate work. Matching criterion is plugin-owned and deferred. One configured webhook destination, immutable Matches, independent at-least-once Delivery and reference-only notifications. OpenAPI is authoritative for transport shapes. THE-640 adds text search and asynchronous Corpus projection rebuild initiation.

Authentication

Every endpoint requires ApiKey unless it says otherwise.

Endpoints

Records

POST /v0/records

Operation ingestRecord. Requires content:write. Commit durable input, Receipt and dispatch intent before responding. Same key and canonical request returns same Receipt; changed request conflicts. A new source revision corrects the Record. All accepted/replayed submissions use 202, even when a replayed Receipt has resolved. Request body (required): application/json IngestCommand Responses

GET /v0/records

Operation listRecords. Requires content:read. Stable keyset traversal of one Corpus’s authorized canonical Records in Record ID order, including withdrawn Records. Each page is an independent read, not an atomic historical snapshot. Capture a start-now Change Cursor before scanning, then consume changes after it as invalidations by rereading current resources; see resynchronization procedure. The opaque page cursor is not a Change Cursor and binds the Corpus filter and authorization scope; a page cursor for another filter or scope is 409 cursor_scope_changed with resync_url. This route, relative to the API base, is the resync_url of change-feed and catalog cursor errors. Parameters Responses

POST /v0/records/batch

Operation ingestBatch. Requires content:write. Initial bound: 100 entries (413 batch_too_large), envelope 10 MiB (413 request_too_large). Validate envelope structure/size first, then each entry independently against IngestCommand, including wrong types or missing fields. Each raw entry is also held to the 1 MiB single-request bound (entry error entry_too_large), so the same entry bytes are never refused for size alone. HTTP 200 carries Receipt or Error per entry, with the same error codes as single submission. Same ingestion family/key as single submission. Reuse entry keys after unknown transport outcomes. Request body (required): application/json BatchRequest Responses

POST /v0/records/withdrawals

Operation withdrawRecord. Requires content:write. Durably commit withdrawal and Receipt before responding. Terminal identity fence, including before first materialization; no physical purge and no cascade. Uses a distinct withdrawal route family. Request body (required): application/json WithdrawalCommand Responses

GET /v0/records/{record_id}

Operation getRecord. Requires content:read. Authorized canonical currentness and withdrawal view. Parameters Responses

GET /v0/records/{record_id}/versions/{version_id}

Operation getVersion. Requires content:read. Authorized immutable source Manifest plus separate live availability and relation expansion. Available links supply current eligible target Record and Version IDs; unavailable links reveal no resolved target IDs or absence/access reason. Historical lookup grants no new rights. Parameters Responses

Ingestion receipts

GET /v0/ingestion-receipts/{receipt_id}

Operation getReceipt. Requires content:read. Return outcome and separately authorized linked availability/diagnostics. Omit unavailable linked content rather than bypassing rights through the Receipt. Linked Version/Record details require current content:read permission and target Corpus authorization. Parameters Responses

Uploads

POST /v0/uploads

Operation createUpload. Requires blobs:write. Create a transfer session with a single presigned PUT URL, required headers and expiry. Initial limits: 1 GiB Blob, configurable; oversized uploads are rejected before a session is issued. Request body (required): application/json UploadRequest Responses

POST /v0/uploads/{upload_id}/confirm

Operation confirmUpload. Requires blobs:write. Start or observe checksum/size verification; SDK polls until verified before referencing the Blob in ingestion. Confirmation is repeatable for this session. Parameters Responses

GET /v0/uploads/{upload_id}

Operation getUpload. Requires blobs:read. Observe upload verification independently of Ingestion Receipt. Parameters Responses

Blobs

GET /v0/blobs/{blob_id}

Operation getBlob. Requires blobs:read. Inspect verified Blob metadata within authorized Organization scope; ID possession does not grant access. Parameters Responses

Operations

GET /v0/operations/{operation_id}

Operation getOperation. Requires operations:read. Administrative progress only. This read schema does not specify every administrative command. Parameters Responses

POST /v0/operations/{operation_id}/cancel

Operation cancelOperation. Requires operations:write. Idempotent cancellation request; does not undo committed effects. Terminal operation returns its existing state. A racing completion may win. Cancellation becomes terminal only after work stops safely; no partial active projection cutover. Parameters Request body (required): application/json ActionRequest Responses

POST /v0/operations/{operation_id}/rerun

Operation rerunOperation. Requires operations:write. Only terminal Operations can be intentionally rerun; otherwise 409 operation_not_terminal. A request key replays the same new linked Operation. Revalidate current scope and command eligibility; completed effects remain subject to domain idempotency. Parameters Request body (required): application/json ActionRequest Responses

Corpora

POST /v0/corpora

Operation createCorpus. Requires corpora:write. Explicit Corpus creation. Same creation route-family key and canonical request replays the same Corpus. Requires corpora:write. Request body (required): application/json CorpusRequest Responses

GET /v0/corpora

Operation listCorpora. Requires corpora:read. Authorized Corpora only. Opaque page cursor bound to action/filter/scope; not a Change Cursor or a Record page cursor (either is 422 invalid_cursor). Parameters Responses

GET /v0/corpora/{corpus_id}

Operation getCorpus. Requires corpora:read. Read effective resolved configuration. Parameters Responses

PUT /v0/corpora/{corpus_id}/retrieval

Operation configureRetrieval. Requires corpora:write, operations:write. Resolve mapping and schedule a new immutable Projection Generation through a retrieval_configuration Operation (202 with Location). Existing active config remains in effect, and is what getCorpus returns, until validated cutover; the Operation reports the pending config’s progress and outcome but not its content. A newer accepted config supersedes older pending ones, and a generation pinned to an older config than the effective one fails with retrieval_configuration_superseded instead of reverting it. Same key and canonical request replay the Operation; a changed request is 409 idempotency_conflict. Does not require a separate per-Corpus physical collection. Parameters Request body (required): application/json ConfigUpdate Responses

GET /v0/corpora/{corpus_id}/vector-spaces

Operation listVectorSpaces. Requires corpora:read. The vector spaces the Corpus’s routed Projection Generation carries, the served one first, each with its owner (the engine, or the ingestion plugin that declares it), model, dimensions, metric, indexed and query modalities, its role in the generation (served answers search, evaluation is indexed and compared but never served) and its coverage, the current segments that hold a vector in it. A Corpus built before a space was enabled lists only the spaces it was built with; rebuild it (rebuildCorpusProjection) to add the others. Parameters Responses

POST /v0/corpora/{corpus_id}/rebuilds

Operation rebuildCorpusProjection. Requires projections:rebuild. Durably commit a projection_rebuild Operation and dispatch intent before returning. Rebuild the requested Corpus from canonical text and durable artifacts, then activate its validated logical generation. Same Organization + Corpus + rebuild route + idempotency key and canonical request returns the same Operation, including after terminal completion; changed request conflicts. HTTP does not wait for reconstruction. Retries/restarts keep identity and target generation. Preserve other Corpora when physical storage is shared. Normal ingestion/withdrawal guards still apply. Live evaluation schema migrations remain a separate mechanism. Activation follows acceptance order, so a rebuild accepted before one that already activated for the same Corpus and retrieval configuration fails with operation_superseded instead of replacing it. Parameters Request body (required): application/json ActionRequest Responses

Changes

GET /v0/changes

Operation pollChanges. Requires changes:read. Same durable journal as SSE. Without cursor, return empty items and current committed position as next_cursor (start now). With cursor, return authorized events after it, in commit order; duplicates possible. Cursor binds Organization, Corpus filter and authorization scope. Expiry is 410 cursor_expired with resync_url, never silent reset; changed scope/filter is 409 cursor_scope_changed with resync_url. resync_url is the API-relative Record catalog route for the Corpus (/v0/records?corpus_id=…). next_cursor advances over scanned events even when none are visible. Public events are invalidations; reread current state, do not replay historical content into a current mirror. Parameters Responses

GET /v0/changes/stream

Operation streamChanges. Requires changes:read. SSE over the same journal. Last-Event-ID takes precedence over query cursor on reconnect. id is an opaque Change Cursor; data.event_id is deduplication identity. Named change events carry ChangeEvent JSON. checkpoint events carry a cursor when no visible event is emitted, including initial start-now checkpoint. Resume cursor expires or scope changes: before headers use HTTP 410/409; after headers send stream_error with Error JSON then close, without advancing id. Use authenticated streaming fetch/http client. See contract for checkpoint framing and resync. Parameters Responses Example 200 response text/event-stream:

Saved queries

POST /v0/saved-queries

Operation createSavedQuery. Requires monitoring:write. Persist definition and first immutable version. Replay same key/request returns same IDs; conflict on changed request. Query creation alone evaluates nothing. Request body (required): application/json SavedQueryCreate Responses

GET /v0/saved-queries/{saved_query_id}

Operation getSavedQuery. Requires monitoring:read. Authorized current query view. Parameters Responses

GET /v0/saved-queries/{saved_query_id}/versions/{version_id}

Operation getSavedQueryVersion. Requires monitoring:read. Read any immutable Version of the Saved Query, current or earlier, such as the one a Subscription Version or Match pins. The key must grant the Corpora of the Saved Query’s current Version and of this Version. A deleted Saved Query’s Versions stay readable. Parameters Responses

POST /v0/saved-queries/{saved_query_id}/versions

Operation createSavedQueryVersion. Requires monitoring:write. Edit a Saved Query by committing a new immutable Version that becomes its current Version, with saved_query.updated in every Corpus of the previous and new scope. Subscriptions keep the Version they pin; a new Subscription Version moves one. The key must grant every Corpus of the current and new definitions. Replay of the same key and request returns the same Version; a changed request is 409 idempotency_conflict. A deleted Saved Query is 409 saved_query_deleted. Parameters Request body (required): application/json SavedQueryVersionCreate Responses

POST /v0/saved-queries/{saved_query_id}/delete

Operation deleteSavedQuery. Requires monitoring:write. Logically delete a Saved Query that no Subscription which is not deleted belongs to (409 saved_query_in_use otherwise), with saved_query.deleted per Corpus. It and its Versions stay readable with deleted true; it gets no new Version or Subscription. Repeat is idempotent and commits no event. Parameters Request body (required): application/json ActionRequest Responses

POST /v0/saved-queries/{saved_query_id}/rename

Operation renameSavedQuery. Requires monitoring:write. Change the display name of a Saved Query. The name belongs to the Saved Query, not to its immutable Versions, so no Version is created and no Subscription moves. A new name commits saved_query.renamed in every Corpus of the current Version; the same name commits nothing. Replay of the same key and request returns the Saved Query; a changed request is 409 idempotency_conflict. A deleted Saved Query is 409 saved_query_deleted. Parameters Request body (required): application/json RenameRequest Responses

Subscriptions

GET /v0/subscriptions

Operation listSubscriptions. Requires monitoring:read. Active (enabled, not deleted) Subscriptions of one Subscription Owner, or the global ones with owner=none, in stable Subscription ID order. Lists only Subscriptions the key sees, like every Subscription read. Stable keyset page cursor bound to the owner filter and key scope, not a Change Cursor. Quivr applies no per-owner rule; a layer above can use this listing to enforce its own. Parameters Responses

POST /v0/subscriptions

Operation createSubscription. Requires monitoring:write. Atomically create enabled Subscription/Version and activation boundary in commit-ordered journal. Evaluate future eligible transitions, not existing history. Replay same key/request returns same identity and does not reactivate a disabled Subscription. The evaluator must be installed (422 unsupported_evaluator); the pinned Saved Query Version expression and the evaluator configuration must satisfy the evaluator’s declared schemas (422 invalid_expression with field /saved_query_version_id, or invalid_subscription_configuration with field /evaluator/configuration/…; message names the first schema issue). Request body (required): application/json SubscriptionCreate Responses

GET /v0/subscriptions/{subscription_id}

Operation getSubscription. Requires monitoring:read. Read enabled state and pinned current configuration. Parameters Responses

GET /v0/subscriptions/{subscription_id}/versions/{version_id}

Operation getSubscriptionVersion. Requires monitoring:read. Read any immutable Version of the Subscription, current or earlier, such as the one a historical Match names. As for every read of a Subscription, its Matches and Deliveries, the key must grant every Corpus any of its Versions pinned. A deleted Subscription’s Versions stay readable. Parameters Responses

POST /v0/subscriptions/{subscription_id}/versions

Operation createSubscriptionVersion. Requires monitoring:write. Edit a Subscription by committing a new immutable Version that becomes current. It pins the current Version of the Subscription’s own Saved Query (422 unknown_saved_query otherwise), an evaluator and a destination. It takes effect from its commit, recorded as its activation position with subscription.updated in every Corpus of the previous and new scope. Each later change is judged by the new Version, each earlier one by the Version effective before it. Nothing is backfilled and Matches keep the Version that produced them. Enabled state is unchanged. The evaluator, expression and configuration are checked as on creation (422 unsupported_evaluator, invalid_expression or invalid_subscription_configuration). Replay of the same key and request returns the same Version; a changed request is 409 idempotency_conflict. A deleted Subscription is 409 subscription_deleted. Parameters Request body (required): application/json SubscriptionVersionCreate Responses

POST /v0/subscriptions/{subscription_id}/delete

Operation deleteSubscription. Requires monitoring:write. Logically delete a Subscription for good, with subscription.deleted per Corpus. It is also disabled, with every disable guarantee - no new evaluation commit and no new Delivery Attempt admission (reason subscription_deleted); an in-flight attempt may complete. As for a disabled Subscription, a match.withdrawn notice for one of its Matches is still committed with its pending Delivery, which is never attempted. The Subscription, its Versions, Matches and Deliveries stay readable with deleted true. Enable or edit is then 409 subscription_deleted. Repeat is idempotent and commits no event. Parameters Request body (required): application/json ActionRequest Responses

POST /v0/subscriptions/{subscription_id}/disable

Operation disableSubscription. Requires monitoring:write. Commit disable. Block new evaluation commits and new Delivery Attempt admissions, including queued retries and update notices. In-flight attempts may complete. A match.withdrawn notice for a Match of this Subscription is still committed with its pending Delivery, which makes no attempt until re-enable. Repeat is idempotent; history remains. Parameters Request body (required): application/json ActionRequest Responses

POST /v0/subscriptions/{subscription_id}/enable

Operation enableSubscription. Requires monitoring:write. Commit re-enable of a disabled Subscription on the same Subscription Version. Evaluation resumes from this commit; changes made while disabled are never evaluated. Pending Deliveries parked by the disable become eligible again under the usual admission checks and keep their delivery window, except a match.withdrawn notice committed while disabled, whose window starts at this re-enable. Enabling an enabled Subscription, or repeating the request, is idempotent and commits no event. A deleted Subscription is 409 subscription_deleted. Parameters Request body (required): application/json ActionRequest Responses

POST /v0/subscriptions/{subscription_id}/rename

Operation renameSubscription. Requires monitoring:write. Change the display name of a Subscription. The name belongs to the Subscription, not to its immutable Versions, so no Version is created, evaluation and enabled state are unchanged, and its Matches and Deliveries stay attached. A new name commits subscription.renamed in every Corpus of the current Version; the same name commits nothing. Replay of the same key and request returns the Subscription; a changed request is 409 idempotency_conflict. A deleted Subscription is 409 subscription_deleted. Parameters Request body (required): application/json RenameRequest Responses

Subscription previews

POST /v0/subscription-previews

Operation previewSubscription. Requires monitoring:write. Dry run of a proposed Subscription. Runs the evaluator on the most recently accepted current eligible Record Versions of the Saved Query’s Corpora, newest first, and returns what it would have matched. Nothing is written - no Saved Query, Subscription, Match, Delivery or event - and it is not idempotent. The Saved Query is an inline definition or an existing Saved Query Version; the pair is validated as at Subscription creation (422 unsupported_evaluator, invalid_expression, invalid_subscription_configuration). Each Record Version costs one evaluator call, sent with the synthetic Subscription reference preview. At most limit Record Versions (1 to 50, default 20) are judged, within a time budget of a few seconds; those still undecided when it runs out are left out and complete is false. An evaluator that cannot be reached or reports a transient failure fails the preview with 503 evaluator_unavailable, and one that refuses or breaks an evaluation with 502 evaluator_error. Quivr applies no rate or cost rule; a layer above can limit who previews and how often. Request body (required): application/json SubscriptionPreviewRequest Responses

Matches

GET /v0/matches

Operation listMatches. Requires monitoring:read. Authorized historical Matches for a Subscription. Stable keyset page cursor, not a Change Cursor. Absence of a Match does not distinguish an evaluator still working from a negative result. Parameters Responses

GET /v0/matches/{match_id}

Operation getMatch. Requires monitoring:read. Authorized historical positive result, explanation and provenance. Recheck current access to Subscription and content; disabled state alone does not erase history. Historical content retention remains separate from search eligibility. Parameters Responses

Deliveries

GET /v0/deliveries/{delivery_id}

Operation getDelivery. Requires monitoring:read. Read logical notification status and current admission view. Rights on the referenced Subscription/Corpus are still required for withdrawal-notice metadata. Parameters Responses

GET /v0/deliveries/{delivery_id}/attempts

Operation listDeliveryAttempts. Requires monitoring:read. Paginated append-only transport history, without secrets or receiver bodies. Parameters Responses

Connectors

POST /v0/connectors

Operation createConnector. Requires connectors:write. Create a Connector Instance bound to exactly one authorized Corpus and one Source Namespace. Kind-specific config and credential secret are validated against the kind’s JSON Schema (see listConnectorKinds); a failure is 422 invalid_config or invalid_credential with field pointing at the offending member. Replaying the same idempotency key and request returns the same instance (without re-enabling a disabled one); a different request under the same key is 409 idempotency_conflict. Another enabled instance on the same Corpus and Source Namespace is 409 source_namespace_in_use. The interval defaults per kind and is refused below the deployment floor (30 s by default) with 422 invalid_interval. Deposited credentials are write-only and never returned. A deployment without a credential key refuses any request carrying a credential with 503 credentials_unavailable (retryable false) before storing or digesting it; instances without a credential are unaffected. Commits connector.created in the change feed. Request body (required): application/json ConnectorCreate Responses

GET /v0/connectors

Operation listConnectors. Requires connectors:read. Connector Instances of authorized Corpora, optionally filtered to one Corpus, in stable identifier order. Opaque page cursor bound to filter and scope; not a Change Cursor or another list page cursor (422 invalid_cursor). Parameters Responses

GET /v0/connectors/{connector_id}

Operation getConnector. Requires connectors:read. Read configuration, credential metadata (never the secret) and the last evaluated Connector Health. Instances of other Organizations or unauthorized Corpora are 404. Parameters Responses

POST /v0/connectors/{connector_id}/disable

Operation disableConnector. Requires connectors:write. Commit disable. No new acquisition run is scheduled; an in-flight run cannot advance the Acquisition Checkpoint afterwards. Repeat is idempotent and disable is absorbing (no re-enable). Commits connector.disabled and connector.health_changed. Parameters Request body (required): application/json ActionRequest Responses

PUT /v0/connectors/{connector_id}/credential

Operation replaceConnectorCredential. Requires connectors:write. Deposit a new credential version to rotate the current one. The secret is encrypted at rest and never returned. Replaying the same key and request is idempotent; a different request under the same key is 409 idempotency_conflict. A disabled instance is 409 connector_disabled. Commits connector.credential_replaced, and connector.health_changed when the evaluated health changes. A deployment without a credential key refuses every rotation with 503 credentials_unavailable (retryable false) before storing or digesting it. Parameters Request body (required): application/json CredentialReplace Responses

PUT /v0/connectors/{connector_id}/schedule

Operation changeConnectorSchedule. Requires connectors:write. Set the polling interval of an enabled instance. Setting the current value commits nothing, so repeating the request is harmless. A shorter interval pulls the next scheduled run in; a longer one applies after the run already scheduled. A disabled instance is 409 connector_disabled; an interval below the deployment floor (30 s by default) or above 24 h is 422 invalid_interval with field /interval_seconds. Commits connector.schedule_changed only when the interval changes. Parameters Request body (required): application/json ScheduleChange Responses

POST /v0/connectors/{connector_id}/runs

Operation requestConnectorRun. Requires connectors:write. Ask for an acquisition run now instead of at the next scheduled time, for example to check again a source that failed. The next run is pulled in, never pushed out, so repeating the request changes nothing and a run already in flight answers it. Rate limits still hold — the run starts no sooner than the deployment interval floor (30 s by default) after the previous run ended, nor before the Retry-After the source asked for. The run then goes through the usual scheduler lease and records its outcome in health, committing connector.health_changed when the state changes; the request itself commits no event. run_at is when the run is due; the scheduler starts it within seconds after. A disabled instance is 409 connector_disabled. Parameters Request body (required): application/json ActionRequest Responses

Connector webhooks

GET /v0/connector-webhooks/{connector_id}

Operation relayConnectorChallenge. No authentication. Public webhook route of one Connector Instance whose kind declares the push mode; the address is its webhook_url. There is no API key; the connector plugin verifies the request (a signature, a challenge) with the Deposited Credential. A GET is typically a source’s verification challenge, relayed to the plugin like a delivery. Parameters Responses

POST /v0/connector-webhooks/{connector_id}

Operation relayConnectorDelivery. No authentication. Relay one delivery the source sends to the Connector Instance. The core passes the raw request (a body of at most 1 MiB, lowercase headers) to the connector plugin, which verifies it and returns the items it carries. Items converge with those of pull runs on the same Receipts. Deliveries update health.push. Parameters Responses

Connector kinds

GET /v0/connector-kinds

Operation listConnectorKinds. Requires connectors:read. Connector kinds enabled in this deployment, with the JSON Schemas that validate their config and credential secret, so clients can render configuration forms without knowing the kinds. credential_deposits tells whether this deployment accepts Deposited Credentials at all; when unavailable, any create carrying a credential and every rotation is 503 credentials_unavailable. Responses

Admin

GET /v0/admin/plugins

Operation listPluginRegistrations. Requires plugins:admin. Every plugin version this deployment has registered, oldest first, with its endpoint, manifest digest, the roles its manifest declares and its state. Quivr never starts a plugin; the operator runs it at its endpoint. On first start the registry is seeded, as active registrations, from the plugins pinned in the startup configuration. Deployment-wide and not paginated. Requires plugins:admin, an operator action that organization keys do not get. Responses

GET /v0/admin/plugins/plan

Operation getActivePipelinePlan. Requires plugins:admin. The active Pipeline Plan, an immutable mapping of every role of the deployment to the registration serving it. 404 not_found when no plan is active, because the startup configuration pins no plugin. Requires plugins:admin. Responses

POST /v0/search

Operation searchRecords. Requires content:read, search:query. Resolve the requested profile, compile mandatory Corpus/Organization prefilters and any requested filter, obtain candidates, then canonically hydrate and reauthorize every returned segment. Lexical-first records remain eligible without embeddings; semantic-only queries require vector coverage. Profile selection does not change access/currentness rules. When a retrieval plugin is pinned, it ranks. It asks the engine for candidates in up to three rounds and returns its ranking, which may hold only candidates the engine served in this search, each already authorized and hydrated. Request body (required): application/json SearchRequest Responses

GET /v0/search/profiles

Operation listSearchProfiles. Requires search:query. The search profiles this deployment answers, default first. Without a retrieval plugin only the built-in default exists; with one, its declared profiles and budgets. Responses

Webhooks

Requests the server sends to a receiver you run; they are not routes of this API.

monitoringNotification (POST)

Operation receiveMonitoringNotification. No authentication. Receiver endpoint, not a Quivr API route. Verify Standard Webhooks v1 HMAC-SHA256 over webhook-id + dot + webhook-timestamp + dot + raw body before parsing. Timestamp refreshed per attempt; body event_id equals webhook-id. See monitoring contract for retry defaults. Parameters Request body (required): application/json WebhookEvent Responses

Schemas

SourceIdentity

Defined in contracts/shared/v0/manifest.schema.json, which other contracts share.

Error

Diagnostic

A structured processing diagnostic. plugin, contribution and invocation_id name the external invocation a normalization diagnostic concerns. Codes of external normalization:
  • normalizer_failed: the normalizer answered a terminal error. The Version is quarantined.
  • normalizer_invalid_output: the output broke the Plugin Protocol or the Manifest rules (schema, malformed or duplicate Part, a Blob Part that is not the input Blob or has another checksum, an undeclared extension namespace, too many Parts, a response over the size bound). Nothing from it is published; the Version is quarantined.
  • normalizer_timeout: the invocations kept exceeding the timeout until the retry budget (the manifest’s retry.max_attempts, capped by the engine at 5) was spent. The Version is quarantined.
  • normalizer_retries_exhausted: the normalizer kept answering retryable errors until the retry budget was spent. The Version is quarantined.
  • input_unverified: the input Blob was no longer the verified accepted input. The Version is quarantined.
  • normalizer_unrouted: the media type’s route was removed after acceptance and the built-in text path cannot read it (a text/* Blob takes the built-in text path instead). The Version is quarantined.
  • normalization_superseded: a newer revision of the Record was accepted before this Version was normalized, so the normalizer was not invoked. The Version is quarantined and never current.
  • normalizer_conflict: a later invocation with the same idempotency key returned a different output. The first recorded output is kept and published; nothing is overwritten.
On an optional route every quarantining code above that comes from the normalizer is instead listed on a searchable Version published through the built-in text path. A plugin that is unavailable (connection failure, 5xx without an error envelope, discovery that does not match the pinned manifest) is retried with backoff and never produces a diagnostic here; the Receipt shows plugin_unavailable while it retries. Quarantined Versions keep their input reference and reason; reprocessing them is not available yet.

Extensions

Defined in contracts/shared/v0/manifest.schema.json, which other contracts share. Keys are plugin namespaces. Data is validated against the installed schema version; source data is not a computed Annotation. Type: map of object.

TextContent

Defined in contracts/shared/v0/manifest.schema.json, which other contracts share.

BlobContent

Defined in contracts/shared/v0/manifest.schema.json, which other contracts share.

Part

Defined in contracts/shared/v0/manifest.schema.json, which other contracts share.

RelationInput

Defined in contracts/shared/v0/manifest.schema.json, which other contracts share. Source-provided link to an independently identified Record in the same Organization. Optional source revision preserves provenance; ordinary expansion resolves the current eligible target. Missing targets do not block readiness. Every expansion reauthorizes the target. Precise Part-target syntax remains outside this initial draft.

ManifestContent

Defined in contracts/shared/v0/manifest.schema.json, which other contracts share. Unique Part keys, acyclic parent references within this Manifest, and verified same-Organization Blobs are checked before atomic publication. These semantic constraints need server validation in addition to JSON Schema.

Provenance

Defined in contracts/shared/v0/manifest.schema.json, which other contracts share.

NormalizationProvenance

Defined in contracts/shared/v0/manifest.schema.json, which other contracts share. Engine-owned record of the external normalizer invocation whose output a Record Version publishes. Present only on read; a submission that sets it is rejected. producer and producer_version keep naming the acquirer, and source_blob_ids keeps the input Blob.

IngestCommand

Initial request shape. Same source identity creates or corrects a Record. Same external revision with different canonical content conflicts. No revision means canonical Manifest digest identity; no source position means durable acceptance order. Single and batch entry replay share route_family=ingestion. A blob content accepts a verified text/* Blob, read at acceptance, or a Blob whose media type the installation routes to an external normalizer; that normalizer runs after acceptance and its output is the published Manifest, while the Version identity still derives from the submitted Blob. When the normalizer fails, the Version is quarantined with a Diagnostic on the Version read (or, on an optional text/* route, published through the built-in text path with provenance.normalization.fallback). Other media types are rejected with unverified_blob. provenance.normalization is engine-owned and rejected on input. Extension namespaces owned by the pinned plugin are written only by its normalizer output, published on the Version; a submission writing one, top-level or on a Part, is rejected with 422 extension_namespace_owned. Example structured_inline:
Example structured_manifest:
Example blob_input:

WithdrawalCommand

Availability

Receipt

Durable acceptance outcome, not workflow state. Availability is a separate authorized live read view; omitted before a linked version exists. Infrastructure retry never resolves a Receipt as failed. Further rules (conditional requirements or combinations) are in the full schema below. Example pending_receipt:
Example resolved_receipt:

BatchRequest

Envelope validation checks items array and batch/body limits only. Each raw entry is independently validated as IngestCommand; even a missing required field or wrong JSON type returns an entry error. SDK convenience builders may type valid entries as IngestCommand, but server envelope validation must not reject the entire batch for an invalid entry. Example mixed_batch_input:

BatchItem

Further rules (conditional requirements or combinations) are in the full schema below.

BatchResult

Example mixed_batch_result:

Record

Version

Example version_relations:
Example quarantined_version:
Example fallback_version:

UploadRequest

Upload

Upload URL and headers are transfer capabilities. Only verified uploads expose a usable Blob ID. Repeated confirmation of the same session observes the same verification, never a second upload. Further rules (conditional requirements or combinations) are in the full schema below. Example verified_upload:

Blob

Operation

Administrative execution only. Retries keep identity. Intentional terminal rerun has a new ID and previous_operation_id. Cancellation does not promise universal rollback; already-terminal state and racing completion may win. projection_rebuild and retrieval_configuration Operations require corpus_id; when succeeded they require result naming the activated logical generation. This result shape covers those two command kinds only. Further rules (conditional requirements or combinations) are in the full schema below. Example administrative_operation:
Example rebuild_queued:
Example rebuild_succeeded:

FieldMapping

v0 logical field mapping. name is a logical name matching ^[a-z][a-z0-9_]{0,63}$, never a search-engine field name. source_pointer is an RFC 6901 JSON Pointer into the canonical source view of a Version, rooted at /manifest, /provenance or /extensions/{namespace} with a declared namespace (built in, or owned by the startup-pinned plugin); other roots are rejected as invalid_mapping. Core validates role/type compatibility (search requires string or string_array). A search field named title replaces the projected title; other search fields add text once per Record Version. Filter roles are validated and preserved; no public filter API consumes them in v0.

RetrievalConfig

Pin a plugin-provided profile when resolving config. Explicit fields override default fields by logical name; unmapped source data remains preserved. getCorpus returns the effective resolved fields. The only built-in profile, example.editorial, is illustrative (paired with the example extension namespace), not a product default; an uninstalled profile is 422 unsupported_profile.

ConnectorKind

Connector kind, provided by the engine or by a pinned connector plugin; listConnectorKinds lists the kinds this deployment accepts. Built-in kinds are fixture (a deterministic test connector available only when the deployment enables it). First-party connector plugins provide rss (RSS 2.0, RSS 1.0, Atom and JSON Feed documents; config url, optional honor_ttl; optional credential username+password or token), x_list (an X list) and m365_mail (Microsoft 365 mailboxes). Another kind is refused with 422 unsupported_connector_kind. Type: string. Pattern ^[a-z][a-z0-9_]{0,31}$.

CredentialDeposit

CredentialReplace

ConnectorSchedule

ConnectorRunRequest

ScheduleChange

Example connector_schedule_change:

ConnectorKindDescription

PluginRegistration

PluginRegistrationList

Example plugin_registrations:

PipelinePlanRole

PipelinePlan

Example pipeline_plan:

ConnectorKindCatalog

Example connector_kinds:

ConnectorHealthPolicy

ConnectorCreate

Example connector_create:

CredentialMetadata

Metadata of the current Deposited Credential; the secret itself is never returned.

ConnectorError

ConnectorUsage

Per-UTC-day source read counters, present only for kinds that report reads.

ConnectorHealth

Last committed Connector Health, evaluated at each acquisition run, credential replacement and disable; evaluated_at shows its age. Precedence disabled, access_error, credential_expiring, silent, active. access_error means the source refused access (distinct from silent, which means no new item within the threshold), including a push channel refused access while polling carries the collection. Other failures appear only as last_error.

ConnectorPush

Push delivery health, present once a kind that declares the push mode reports its push channel.

ConnectorPushError

Connector

Example connector:
Example connector_x_list:

ConnectorPage

CorpusRequest

Corpus

VectorSpaceList

VectorSpace

CorpusPage

RecordPage

ConfigUpdate

ActionRequest

RenameRequest

New display name of a Saved Query or Subscription. Example rename:

ResourceReference

ChangeEvent

Every change to a Record catalog entry emits an event with resource.kind=record and resource.id=the affected Record ID. Additional resource-specific events do not replace this invalidation. Consumers reread current state; payload detail belongs to THE-547. Monitoring notice types mirror WebhookEvent and include monitoring references; event_id identifies that same committed notice. Delivery status changes emit delivery.updated events only to the feed, never recursive webhooks. Example monitoring_change:

ChangePage

ResolvedRelation

Separate live view, not a mutation of the source Manifest. Unavailable covers missing, unready, withdrawn and inaccessible without distinguishing existence or revealing resolved target IDs. Further rules (conditional requirements or combinations) are in the full schema below.

ProcessingSummary

Live read view, not a Receipt lifecycle or public workflow identifier. blocked means an outstanding contribution needs intervention; diagnostics describe why. idle means no work currently pending, not a promise of final enrichment. Phase is omitted when idle; required and optional progress do not override Version Availability.

SavedQueryDefinition

Immutable query definition. Expression semantics belong to the evaluator plugin; no core keyword or semantic threshold is implied. All Corpora belong to the authorized Organization.

SavedQueryCreate

Example saved_query_create:

SavedQueryVersionCreate

New immutable definition of an existing Saved Query. The name is unchanged (rename changes it). Example saved_query_version_create:

SavedQueryVersion

SavedQuery

Example saved_query:

EvaluatorConfig

Pins an installed evaluator by plugin id and version, and its configuration. Evaluators are the subscription Contributions of the plugins pinned at startup (Plugin Protocol v0); test deployments may also install the deterministic fixture quivr.fixture@1. The configuration must satisfy the evaluator’s declared configuration schema.

SubscriptionCreate

Create enabled from-now Subscription. An optional owner makes it the Subscription of one end user of the client application; without one it is global to the Organization. The owner is fixed for the Subscription’s life and part of the idempotent request. One deployment-configured destination per version; destination belongs to this Organization. URL and signing key are provisioned outside this API and not returned. No inline secret or dynamic destination registry in the tracer. Example subscription_create:
Example owned_subscription_create:

SubscriptionVersionCreate

New immutable configuration of an existing Subscription. The Saved Query and name are unchanged (rename changes the name); saved_query_version_id is the current Version of that Saved Query. Example subscription_version_create:

SubscriptionVersion

Immutable Subscription configuration. Every Version keeps the Subscription’s owner, absent for a global Subscription.

Subscription

Absent owner means a global, organization-wide Subscription. Example subscription:

SubscriptionOwner

Subscription Owner, an opaque end-user reference defined by the client application (for example user-123). Quivr stores, filters and echoes it without interpreting it. At most 128 characters without control characters; none is reserved for the listing filter (422 invalid_owner). Type: string. Minimum length 1. Maximum length 128.

SubscriptionPage

Example owned_subscription_page:

SubscriptionPreviewRequest

A proposed Subscription to preview. Give either definition, an inline Saved Query definition, or saved_query_id with saved_query_version_id, an existing Saved Query Version; not both.

SubscriptionPreviewMatch

A Record Version the proposed Subscription would have matched, with the evidence a Match would carry. It is not a Match and is not stored.

SubscriptionPreview

What a proposed Subscription would have matched among recent Record Versions.

MatchEvidence

Immutable evidence for a positive result, including evaluator version/configuration. Details are plugin-defined, bounded to 16 KiB and schema-validated by its adapter; core checks referenced Parts. Access is rechecked on reads.

Match

Immutable positive historical determination, not a claim of current eligibility. Unique subscription-version/record-version. Correction/withdrawal notifications reference history; no Match is fabricated for negative decisions. owner is the Subscription’s owner, absent when global. Example positive_match:

MatchPage

MonitoringReferences

owner is the Subscription Owner, so a client routes the notice to its user; absent for a global Subscription and in notices committed before owners existed. match_id is the new Match for created/corrected, prior positive Match for no_longer_matches/withdrawn. record_version_id is the causal correction version for corrected/no_longer_matches, otherwise the matched version. References alone confer no access.

WebhookEvent

Immutable reference-only notification. Retries preserve event_id and the exact stored body bytes; signing timestamp changes per attempt. No document content, excerpt, explanation, cursor or secret is embedded. Example reference_webhook:
Example owned_reference_webhook:

DeliveryAdmission

Current derived admission view, separate from durable Delivery state. A disallowed pending Delivery makes no new network attempt; it does not become a new lifecycle state. destination_unavailable means its destination is no longer configured for the Organization. subscription_disabled lasts until a re-enable; subscription_deleted is permanent. record_withdrawn refuses match.created, match.corrected and match.no_longer_matches; match.withdrawn is admitted for a withdrawn Record. superseded refuses an undelivered match.created or match.corrected once a later match.corrected or match.no_longer_matches exists for the same Subscription and Record, and an undelivered match.no_longer_matches once a later match.corrected exists; match.withdrawn is never superseded.

Delivery

Example delivery:

DeliveryAttempt

Read view of append-only admission/outcome facts. Unknown network result can be retried with the same event ID; no response body, signature or signing key is exposed.

DeliveryAttemptPage

Example attempt_page:

SearchRequest

Text-only top-k query. Resolve all Corpora in the authenticated Organization and require read/search permission for every requested Corpus before querying. Never silently drop an unauthorized Corpus. Unknown/unsupported profile or mode returns 422; a dependency outage is an error, not an empty successful result. Query token limits are checked against the resolved profile; no silent truncation. An optional filter narrows candidates inside the engine query, before ranking and the limit, in every mode. Other metadata filters and pagination are outside this surface. Example text_search:

SearchFilter

Candidate filter applied before ranking. Every present condition must hold. A requested Corpus served by a Projection Generation built before source filtering existed returns 422 source_filter_unavailable; rebuild that Corpus once (rebuildCorpusProjection) to enable it. Unfiltered search is unaffected.

SearchProfile

Resolved retrieval profile identity. Name is the profile that answered (default when the request named none or the deprecated balanced). Version identifies what ranked; the built-in path’s immutable profile version, or plugin:<plugin id>@<version>/<profile> for a retrieval plugin.

SearchProfileList

Example search_profiles:

SearchProfileDescription

SearchUsage

What a search answered by a retrieval plugin spent; rounds of the plugin, elapsed time, and the paid calls and cost the plugin reported.

SearchExcerpt

Exact canonical normalized Part text slice [start,end), using Unicode code points, not UTF-8 bytes or UTF-16 units. End must be >= start and end-start must equal the excerpt code-point length. Bounds are checked against the referenced immutable Part. No synthetic highlights or rewritten snippets.

SearchHit

One authorized segment hit. Rehydrate from canonical storage and recheck Organization/Corpus access, currentness, quarantine and Tombstone before returning. Rank is contiguous and one-based after hydration/filtering. Projection Generation, segmentation, segment and optional Embedding Artifact/Vector Space are logical durable IDs, not physical collection names or workflow IDs. Embedding references are omitted when that segment has lexical coverage only. They do not assert that the dense branch contributed to its rank. All hits inherit the response retrieval profile. Raw scores/explainScore stay internal. Further rules (conditional requirements or combinations) are in the full schema below.

SearchResponse

Bounded top-k results after canonical rechecks. May contain fewer hits than requested; no total count, completeness promise or stable pagination snapshot. Empty results still name the resolved profile. Example canonical_search_results:
Example lexical_search_without_embedding:
Example plugin_ranked_search_results:

ProjectionRebuildResult

Logical generation activated for the requested Corpus. Opaque ID, never a physical search collection name.