Platform · 1. Crux Engine

This chapter is reference. It documents the external contracts of the hosted CueCrux platform service: what you send, what comes back, which failures are worth retrying, and which guarantees stop where.

Crux Engine is closed source. Everything here is a contract or an observable behaviour. Nothing here describes how a result is computed, and that omission is deliberate, see 1.21.

1.0 In plain English

Crux Engine is the hosted half of CueCrux: a service we run, that you send documents to and ask questions of, and that answers with text plus a record of what the answer was built from. If you have used any hosted search or retrieval API, the shape will be familiar. What is different is the second half of every response.

That second half is the reason the service exists. A conventional retrieval stack returns text and asks you to trust it, and when someone later asks where an answer came from, the honest reply is usually that nobody kept the receipt. Crux Engine returns a record alongside the answer: what was retrieved, and what the answer was built from. A third party can check that record without being given access to your data, because citations carry a hash of the quoted span rather than the span itself. That last detail is what makes it possible to hand the evidence to someone you do not want reading your corpus.

The other half of the problem is operational rather than intellectual, and it is the part people underestimate. Running retrieval over somebody else's private documents means keeping tenants apart, metering usage, delegating narrow authority to a backend without handing over the keys, and deleting data properly when asked, including verifying afterwards that it actually went.

You will read this chapter when you are deciding whether to build against the hosted plane rather than run the daemon yourself, and then repeatedly as a lookup while you build. Two sections carry most of that weight: §1.5, the full error contract with retry semantics, which is what your client's failure handling should be written from; and §1.18 and §1.19 read together, where the limits it does not promise are stated as plainly as the guarantees.

The thing people get wrong is treating a response record as proof that the answer is correct. It is not that, and it does not claim to be. It is a record of what the answer stood on, which is a different and more modest thing: it lets a reviewer check whether the evidence supports the conclusion, rather than removing the need for anyone to check. The second misreading is subtler and this chapter is written to prevent it: nothing here describes how a result is computed, so do not infer ranking behaviour from a contract. If a property is not stated as a guarantee, it is not one, however consistently you observe it.

1.1 Which system this chapter documents

Two different things in this platform have been called "the engine". They are not the same component and conflating them will send you to the wrong endpoint.

Crux Engine (this chapter)Daemon-side retrieval
What it isThe hosted platform service, one service estate behind an HTTP APIA retrieval and reasoning path that runs inside the Crux Daemon binary
Where it runsOn CueCrux infrastructure, reached over the public internet through an edgeOn your own machine, as part of the daemon you installed
How you reach it/v1 HTTP routes, an API key or an OAuth bearer, a tenant headerLocal HTTP, MCP and gRPC listeners on loopback
Documented inThis chapterThe Crux Daemon set, starting at Architecture

Two consequences, stated plainly because earlier copy got both wrong:

  • Crux Engine does not ship inside the Crux Daemon. It is the hosted counterpart to the daemon, not a component of it.
  • token_budget is a daemon property. The hosted retrieval route has no token_budget. It has limit, and limit is capped at 50. If you have been building against a server-enforced token budget on the hosted API, you have been building against something that does not exist there.

They do share contracts, the receipt formats and the capability-token scheme are the same on both sides, which is the whole point. A workload can move between local and hosted without changing its verification story.

1.2 What it is, and the problem it solves

Crux Engine is the hosted platform service behind CueCrux. One service estate handles ingest, retrieval, answer generation, receipts, identity and tenancy for customers who do not run the local Crux Daemon themselves.

It exists for one problem: evidence-backed answers over private corpora, where the answer is accountable. A conventional retrieval stack returns text and asks you to trust it. Crux Engine returns text plus a receipt, a record of what was retrieved, how it was ranked, and what the answer was built from. A third party can check that receipt without access to your data, because citations carry a hash of the quoted span rather than the span itself.

It also solves the operational half of that problem: multi-tenant isolation, per-tenant corpora, capability-scoped delegation to a hosted backend, credit metering, and erasure that is verified after it commits.

1.3 Position in the architecture

The one-line version: Crux Engine is the hosted plane. CoreCrux is the substrate it reads. The Crux Daemon is the same capability, local.

ComponentRelationship to Crux Engine
CoreCruxThe proprietary retrieval and event-storage engine. Crux Engine reads from it and writes receipts back. It stays a separate process by design, see 2. CoreCrux.
Crux DaemonThe local-first counterpart. Same receipt formats, same capability-token scheme. The daemon answers locally the question Crux Engine answers hosted.
EmbedderCruxThe embedding service. A separate service; Crux Engine does not host embedding models.
ReasonerCruxLocal model inference. A separate service.
VaultCruxNow names the trust and verification plane and the public credibility surfaces. It was once a separate hosted product; that product was retired and its code consolidated into this service. Many identifiers still carry the old name. That is history, not architecture.
WikiCruxA consumer of the same receipt and capability-token contracts, through its own backend identity.
FeatureCruxThe internal control plane that resolves which runtime behaviours apply to a tenant and a request, and records the decision. There is no public endpoint and no account reaches it, see 3. FeatureCrux.

Deployment shape. Stateless API and background-worker processes over a shared database. Horizontal scale is by process count; state lives in the database. Schema changes are ledgered per subsystem and forward-only. Public traffic reaches the service through an edge; the service itself is not directly internet-exposed. That is the whole of what is published about the topology, and it is enough to reason about failure modes.

Secrets fail closed at deploy. The deployment has no default values for its API key, signing secret or database password. A deploy that forgets one refuses to start rather than quietly running on development credentials.

1.4 The response envelope

Base path is /v1. OpenAPI 3.0.3 is generated and served at /docs/reference and /docs/reference/openapi.json where enabled.

Every /v1 route returns the same envelope. Success:

{ "ok": true, "data": { }, "meta": { } }

Failure:

{ "ok": false, "error": { "type": "...", "message": "..." }, "meta": { } }

Transport-level failures additionally follow RFC 7807 Problem Details, with these fields:

FieldMeaning
typeThe error type. One of the 22 values in 1.5.
titleShort human-readable summary.
statusThe HTTP status code, repeated in the body.
detailHuman-readable explanation of this occurrence. Read it, where a limit was breached, the limit is stated here.
instanceIdentifier for this occurrence.
request_idCorrelation id. Quote it in a support request.
codeMachine-readable code.
retryableWhether the condition is recoverable. Mirrors the split in 1.5.

Individual error types carry additional fields. Those are listed per type below.

1.5 The error contract

There are 22 error type values. Only two are recoverable. Everything else describes a condition on your side, and retrying it without changing the request will produce the same result.

typeHTTPRecoverableExtra fieldsWhat it means
RateLimited429YesretryAfterSecYou exceeded the limit on your credential. Honour Retry-After.
UpstreamDown5xxYesupstreamA dependency the request needed was unavailable. Retry with backoff.
ValidationError400, 422Noissues[] on 422The request was malformed. 422 carries per-field issues.
AuthMissing401No-No usable credential, or a required identity header was absent.
Forbidden403No-The credential is valid but not for this tenant, resource or operation.
Conflict409NodetailsThe request conflicts with current state.
NotFound404No-No such resource.
InsufficientCredits402NocreditBalanceThe call was priced and the balance did not cover it. The balance is in the body.
SponsorRequired402NocreditBalance, dailyRemaining, upgradeUrl, agentPrincipalIdA self-registered agent principal has exhausted its allowance and needs a sponsor.
IdempotencyConflict409NoidempotencyKeyThe same idempotency key was replayed with a different body.
FeatureDisabled-NofeatureThe requested behaviour is not enabled on this deployment.
UpstreamContractDrift501Noupstream, expected, available[]A dependency answered in a shape this version does not accept. Not a transient fault.
PolicyBlocked412NopolicyA policy refused the request before any work was done.
RcxCapabilityTokenMissing403NocruxA capability token was required for this route and none was presented.
RcxCapabilityTokenRefused403Noreason_code, token_hash, receipt_hash, issues[], cruxA capability token was presented and refused. reason_code names why, see 1.12.
DeniedCapability-NodecisionIdThe acting principal is not permitted this capability.
DeniedTaint-NodecisionIdThe request carried data whose provenance is not permitted here.
ApprovalRequired-NoapprovalRequestId, decisionIdThe action needs a human approval that has not been given.
SandboxViolation-NoviolationId, decisionIdThe action left the boundary it was permitted to act inside.
TrustRevoked451Nodigest, decisionIdTrust in the named artefact has been revoked.
DigestUntrusted-Nodigest, decisionIdThe artefact's digest is not on the trusted set.
KillSwitchActive-NotargetType, targetRef, decisionIdAn operator kill switch is active for this target.

Where the HTTP column is -, the type is raised in the response body by a route rather than mapped from a bare status code. Every one of them is non-recoverable.

The enum carries a small further family of credit-conversion variants. They belong to billing behaviour that is not live, see limit 6 in 1.19, and you will not encounter them.

Status-code mapping, in full. A client that only sees the status code can reconstruct the type:

StatusMaps to
400ValidationError
401AuthMissing
402SponsorRequired when the body's type says so, otherwise InsufficientCredits
403Forbidden
404NotFound
409IdempotencyConflict when the body carries idempotencyKey, otherwise Conflict
412PolicyBlocked
413Payload too large. The permitted size is stated in the message.
422ValidationError with issues[]
429RateLimited, with retryAfterSec taken from the Retry-After header
451TrustRevoked
501UpstreamContractDrift
5xxUpstreamDown
anything elseValidationError

The rule that matters at 3am: retry RateLimited and UpstreamDown. Do not retry anything else. A 401 will still be a 401 in thirty seconds; a 503 may not be.

1.6 Authentication

Five mechanisms. Pick one per request.

MechanismCredentialNotes
API keyx-api-key and x-tenant-id, both requiredThe primary mechanism. Rate limit is carried on the key.
OAuth bearerAuthorization: Bearer <token>Session-backed. Issuer and audience are validated. Optional team-seat role resolution.
Self-signup sessionAuthorization: Bearer <token>The agent self-registration path. Credit-capped and sponsorable.
Frontdoor session cookieCookieBrowser surfaces only. Cross-origin mutations are blocked.
RCX capability tokenx-rcx-capability-tokenDelegated and capability-scoped. Substitutes for tenant auth on retrieval. See 1.12.

Four documented behaviours you should build against, not discover:

x-tenant-id is mandatory with an API key. Omitting it is 401 AuthMissing with the message "x-tenant-id is required". It is not inferred from the key.

Header and body tenant disagreement is fatal. If x-tenant-id says one tenant and the request payload or query says another, the request is refused with 403 Forbidden and the message "Tenant mismatch between x-tenant-id header and request payload/query". It is not silently resolved in either direction. There is no precedence rule to learn, because there is no precedence.

A key presented for the wrong tenant is refused, not downgraded: 403 Forbidden, "API key is not valid for tenant".

Auth-backend unavailability is distinguishable from auth failure. If the credential store cannot be reached, the response is 503 UpstreamDown with the failing dependency named in upstream, not a 401. This distinction is the point: a 503 is safe to retry and a 401 is not, and a system that returns 401 when its database is down will send every client into a credential-rotation panic during an outage. Build your client to treat them differently, because the API does.

Deprecated API keys keep working and announce themselves. A response to a deprecated key carries x-api-key-deprecated: true. Watch for that header in your client logs; it is the migration signal, and it arrives before anything breaks.

1.7 The public, unauthenticated surface

These paths require no credential:

/healthz · /livez · /readyz · /metrics · /docs/* · /openapi.json · /.well-known/oauth-authorization-server · /.well-known/crown-keys · /v1/receipts/verify · /v1/receipts/anchor/* · /v1/proof/* · /v1/benchmarks/* · /v1/passports/* · /v1/usage-receipts* · /v1/auth/* · /v1/agents/register · /v1/org/accept-invite · /v1/memory/capabilities

The verification surface is public on purpose. Receipt verification and signing-key discovery do not require an account, because a proof that only the issuer can check is not a proof. You do not need a relationship with us to check our work, and neither does your auditor.

One caveat on that list. /metrics needs no credential but is additionally IP-allowlisted, and /build-info is IP-allowlisted and not on the public list at all. Both exist; neither is an invitation.

1.8 Tenancy and isolation

A tenant is identified by x-tenant-id and cross-checked against the credential.

Corpora are tenant-scoped. GET /v1/corpora returns only the calling tenant's corpora. Corpus visibility is either private or commons.

Retrieval re-checks tenancy at the route, after authentication has already resolved a tenant. A tenantId in the request body that disagrees with the authenticated tenant is 403 Forbidden, "Tenant mismatch for retrieval request".

The guarantee: tenant scoping is enforced at both the credential layer and the query layer, and a mismatch is refused rather than reconciled. The limit of that guarantee: it is a property of this service's request path. It says nothing about what an operator with database access can see, and it is not a claim about encryption at rest.

1.9 Retrieval: POST /v1/retrieve

Hybrid retrieval over the tenant's corpora, and optionally the commons.

Request fields:

FieldTypeDefaultNotes
querystring, minimum 2 characters-Required.
tenantIdstringfrom the credentialMust match the authenticated tenant, or 403.
agentIdstringdefault-agentAttribution for the call.
corpusIdsstring array[]Empty means the tenant's default scope.
limitinteger 1–508Hard maximum 50. Values above it are rejected, not clamped silently.
lanelight, verified or auditlightThe assurance mode. Selects how much verification work the request pays for.
includeCommonsbooleantrueAffects cost, see cost_reason below.
backendlegacy or corecrux-v5server defaultPer-request override of the retrieval backend.

Response body: a results[] array. Each result carries chunkId, docId, tenantId, corpusId, content, title, url, score, source (tenant or commons), and scoreComponents with the named members vector, lexical, recency and laneWeight.

Top level, alongside results[]: credit_cost, cost_reason (one of tenant_only_query, paid_tier_commons_query, free_tier_commons_rate), and meta with lane, vectorBackend and tookMs.

scoreComponents tells you which signals contributed to a result's position. It does not tell you how they combine, and that is not an oversight. Treat tookMs as an observation of one request, never as a target.

Declared status codes: 200, 401, 402, 403, 412, 422, 429, 451, 503.

The pointer-first default, and the opt-out

This is the single most likely thing to surprise you. The default response is a pointer-first envelope (crc_v1) in which result content is suppressed. The default payload is cheap on purpose: you get identity, ranking and cost metadata, and you fetch text only for the results you actually want.

To get the full legacy payload with content inline, send the request header:

Accept-Contract: legacy

Old response shapes remain reachable. If you wrote a client against a response with content populated and it suddenly looks empty, you are on the pointer-first default and one header will put it back.

What is safe to say about how retrieval works

Retrieval runs multiple lanes in parallel, lexical and keyword matching, dense vector similarity, with graph and entity signals, and fuses the ranked lists into a single result set. The assurance lane selects how much verification work the request pays for. Each result carries its per-signal score components so a caller can see why something ranked.

That is the whole of the published description. Fusion weighting, per-corpus tuning, query rewriting and the composition of the score are not published, and no future version of this page will publish them.

1.10 Answers: POST /answers

The answer product surface. Evidence for a produced answer is retrievable at GET /answers/:id/evidence.

FieldTypeDefaultNotes
qstring, 3–2000 characters-Required. The question.
question_dateYYYY-MM-DD-Anchors relative-date resolution to your clock rather than the service's.
topKinteger 1–10010Hard maximum 100.
rerankKinteger 1–100-Hard maximum 100.
hydratepointer, summary or fullfullHow much evidence text comes back inline.
modelight, verified or auditverifiedThe proof mode. Note the default.
allowLightFallbackbooleanfalseSee below. This default is the guarantee.
freshnessobject-since, sinceDays, bias, max_snapshot_age.
audiencetenant or external_sharetenantGoverns what may be included for an external reader.
dataRegionenum-See below.
corpusIdsstring array, maximum 200-Scope restriction.
filtersobject-domain[], since, licenseAllow[], excludeRisk[].

mode defaults to verified, and allowLightFallback defaults to false. Together these mean: if you ask for a verified or audit answer and the proof dependencies for that mode are unavailable, the request fails with 503. It does not quietly return a light answer wearing a verified label. Weakening the proof contract requires you to opt in explicitly by sending allowLightFallback: true.

That is the behaviour an auditor should ask about, so it is stated here rather than buried: a failed verified answer is a 503 you can see, not a weaker answer you cannot.

dataRegion is a first-class request field. The enum the contract accepts is eu-west, eu-central, uk, us-east, us-west, ap-southeast.

Read that precisely. The enum is what the API accepts, not a statement of what is provisioned. Confirm the regions available to your account with us in writing before you design a residency posture around a value in this list. Publishing the accepted enum without that caveat would be the kind of silence that reads as a promise.

1.11 Ingest: POST /v1/ingest

Ingest is asynchronous. A successful submission returns 202 Accepted; the work happens on a background worker.

Declared status codes: 202, 401, 403, 409, 412, 413, 422, 429, 451, 503.

Body size is capped by configuration, and the cap is discoverable from the error. A breach returns 413 with the applicable limit stated in the message. You do not need to guess it or find it in a table that may have drifted, provoke it once and read the response.

Ingest modes are light, verified and audit, matching the retrieval and answer lanes. The semantic difference is trust metadata: light stages documents with incomplete trust metadata; verified and audit require the full metadata set and reject a document that cannot supply it.

1.12 Capability tokens (rcx-ct)

An rcx-ct is the delegation scheme by which a holder, typically a Crux Daemon acting for a tenant, is authorised to call a hosted backend on that tenant's behalf. It is presented as x-rcx-capability-token and, on retrieval, substitutes for tenant authentication.

Spec versions: rcx-ct/1.0 is the base; rcx-ct/1.1 adds delegation. Both are accepted. Signatures are Ed25519, 128 hex characters; hashes in the token are 64 hex characters.

Token structure:

FieldContents
spec_versionrcx-ct/1.0 or rcx-ct/1.1
token_idUnique identifier for this token
issued_at, expires_at, refresh_hint_atValidity window, plus the point at which the holder should refresh
issuerpassport_kid, issuer_org
subjectpassport_fpr, daemon_instance_id
tenant_scopeThe tenant this token acts for
team_scope, enterprise_scopeOptional broader scopes
tierThe entitlement tier the token carries
receipt_classThe class of receipt calls under this token produce
backends[]The permitted backends. Each carries backend_id, trust_root_kid, endpoint_url, permitted_capabilities[] and credit_cost.
creditsThe credit allowance bound to the token

Each entry in permitted_capabilities[] carries a capability, a set of data_egress_classes[], and any required_attestations[].

Data-egress classes are the safety property worth understanding. A token names exactly which classes of data may leave under it:

ClassMeaning
noneNothing leaves
vectorsEmbeddings only
receipt_hashesReceipt hashes only
constraint_recordsConstraint records
decision_recordsDecision records
encrypted_blobOpaque encrypted payloads
textPlain text

Anything not named is refused with egress_not_permitted. A token that permits only receipt_hashes cannot be used to move your prose off the machine, and that is enforced at validation rather than promised in a policy document.

Refusal codes are a published enum. A refused call tells you which one applies:

token_invalid · token_expired · token_signature_invalid · token_revoked · tenant_mismatch · principal_not_scoped · issuer_not_trusted · backend_not_permitted · trust_root_mismatch · capability_not_permitted · egress_not_permitted · insufficient_credits

Revocation reasons are published too, so a revoked token says why it was revoked:

revoked:principal_terminated · revoked:superseded · revoked:suspected_compromise · revoked:policy_change · revoked:credit_default

Degradation is observable. Every RCX-mediated response carries an X-Crux-Mode header with one of:

X-Crux-ModeMeaning
localServed locally
hostedServed by the hosted plane
customer_hostedServed by a backend the customer runs
degraded-localThe hosted path was unavailable; a local path served it
degraded-queuedThe call was queued rather than served
refusedThe call was refused

You can always tell which mode served you. A degraded answer does not arrive disguised as a normal one. The queue has a default time-to-live of 300 seconds; that is a default, overridable per token, and not a delivery guarantee.

Error behaviour on retrieval: a missing token where one is required is 403 RcxCapabilityTokenMissing; a malformed token is 422; a refused token is 403 RcxCapabilityTokenRefused carrying reason_code, token_hash and receipt_hash.

Endpoints:

EndpointPurpose
POST /v1/rcx-ct/validateValidate a token. The verification side of the scheme.
POST /v1/rcx-ct/refreshExchange a token approaching expiry for a fresh one.
POST /v1/rcx-ct/revokeRevoke a token.
POST /v1/rcx-ct/issueMint a token. Issuer-only.
POST /v1/rcx-ct/issue-delegationMint a narrowed delegated token. Issuer-only.
POST /v1/rcx-ct/refundReturn credits reserved against a token.

The boundary: anyone can verify a token; only the issuer can mint one. Verification takes a public key, the canonical token fields and Ed25519; everything a third party needs. Issuer key custody, how a delegated token is narrowed, and how credits are debited and refunded are not published and will not be.

1.13 Receipts and the verification plane

Two receipt kinds, two different guarantees. Collapsing them into one stronger claim is the most common error made about this system, including in our own earlier copy. Do not do it.

Execution receipts are Ed25519-signed and chained. POST /v1/receipts/verify returns a signature object carrying crown_signature, signing_kid, signing_pub, verified and algorithm: "ed25519". The chain[] walks parent_receipt_hash links and reports signature_verified per entry. When an execution receipt is unsigned, valid comes back false with reason: "receipt_unsigned". It does not fudge.

Retrieval receipts are not signed. The API states this itself, and this is its wording:

Retrieval receipts are content-addressed via blake3(canonical inputs). They are not Ed25519-signed; verification is membership in the public benchmark receipts table.

Read what that does and does not give you. Content addressing gives you tamper-evidence: the same canonical inputs produce the same hash, so a changed input produces a different hash. It does not give you an issuer attestation, because nothing signed it. If your control requires a signature, you need an execution receipt.

POST /v1/receipts/verify, unauthenticated, deliberately.

Request: receipt_hash (32–128 hex characters), optional chain_depth (1–100, default 20).

Response: valid, kind, chain_proof_format (currently "v1"), receipt, signature (or null), chain[], reason.

Response headers: Cache-Control: public, max-age=60 and X-Robots-Tag: noindex, nofollow. The cache header is a caching hint, not a freshness guarantee.

An unknown hash returns 404 NotFound, "Receipt not found in any public benchmark set".

GET /.well-known/crown-keys, public signing-key discovery, cached 300 seconds. Returns { keys: [{ kid, algorithm: "ed25519", publicKeyB64, keyVersion }] }. This is what a third-party verifier fetches to check a signature without asking us anything.

GET /v1/receipts/anchor/:receiptId, public anchor lookup for a receipt.

POST /v1/invocation/verify, verification of an invocation record.

The CROWN receipt payload, at field level:

GroupFields
timingsretrieveMs, rerankMs, llmMs, totalMs
retrievaltopK, rerankK, filters, audience, allowed_corpora
selectioncitationIds[], coverage, distinctDomains, fragilityScore, loadBearingCitations
counterfactualfound, note, citations[]
citations{ id, quoteHash }

Citations carry quoteHash, not the quote. The receipt proves provenance without carrying your content. That is what makes it safe to hand a receipt to a third party who is not entitled to see the corpus.

What a receipt does not prove. A receipt is a verifiable record of what was stored and retrieved. It is tamper-evidence, not attestation of conduct; it does not prove that an agent did a thing in the world, only that this evidence set produced this output under this configuration. And there is no customer-facing replay endpoint. If you have read a claim that an auditor can replay any past query against the historical corpus state and confirm the same inputs produce the same outputs, that claim was wrong; there is no such endpoint on this API today. Verification is what is offered, and verification is what 1.7 makes public.

1.14 Health and readiness

PathAccessResponse
GET /livezpublic{ "status": "ok" }
GET /healthzpublic{ "status": "ok" }
GET /readyzpublic200 with status and checks, or 503 with status: "error", reason and checks
GET /healthpublicservice, status (healthy or degraded), checks
GET /build-infoIP-allowlistedBuild metadata
GET /metricsIP-allowlistedPrometheus text

Use /livez, /healthz and /readyz as your integration contract. /readyz returns 503 when the service is not ready to serve; it is a gate, not a diagnostic, and what it checks internally is not published.

1.15 Rate limiting

Rate limits are per credential, not per account and not per route. An API key carries its own limit, set when the key is issued; session-backed credentials carry a standard session limit.

Do not hard-code a number. Read it from the response. The limiter emits IETF draft-form headers on every response:

RateLimit-Policy: <limit>;w=<window>
RateLimit: <remaining>;w=<window>

On breach you get 429 with retry-after in seconds and error type RateLimited, which is one of the two recoverable types. Back off by the stated interval.

Limits are a per-key operational parameter and may change at issuance. They are not a throughput commitment.

1.16 Client compatibility: idempotency and versioning

Idempotency. Mutating endpoints accept an idempotency key. Replaying the same key with the same body is safe; replaying the same key with a different body returns 409 IdempotencyConflict with the offending idempotencyKey in the body. That is a client bug being surfaced, not a transient condition, do not retry it.

Versioning policy, as observed, so you can plan against it:

MechanismPolicy
API versionBy path prefix. Everything in this chapter is /v1.
Response contractContent-negotiated. The pointer-first default and the legacy shape are both reachable; Accept-Contract: legacy selects the older one. Old shapes stay reachable rather than being removed.
Capability tokensVersioned in band. rcx-ct/1.0 and rcx-ct/1.1 are both accepted.
API keysA deprecated key keeps working and announces itself with x-api-key-deprecated: true. Deprecation is a signal before it is a break.
Receipt chainsCarry chain_proof_format, currently "v1". A verifier should branch on it rather than assume it.
New behaviourShips disabled by default and is enabled deliberately. The only behaviour on by default is behaviour that is there for safety or correctness.

The practical consequence: read chain_proof_format, set Accept-Contract explicitly rather than relying on a default, and treat x-api-key-deprecated in your logs as work to schedule rather than noise to filter.

1.17 Lifecycle of a request

Described behaviourally. This is what happens to your request, in order, and where it can stop.

  1. Admission. Authentication resolves a credential to a tenant. A mismatch refuses with 401 or 403. A failure of the credential backend itself is a distinct 503, never a 401.
  2. Guarding. A policy layer may refuse before any work is done, 412 PolicyBlocked, 451 TrustRevoked, or one of the denial family. Nothing has been retrieved or charged at this point.
  3. Capability check. If the call is capability-mediated, the token is validated against backend, capability and egress class. A refusal carries a named reason_code and the response is stamped with X-Crux-Mode.
  4. Retrieval. Multiple lanes run in parallel over the tenant's corpora, plus the commons if requested, and are fused into a single ranked set. The assurance lane governs verification depth.
  5. Selection and synthesis (answers path only). Candidates are reduced to a citation set and the answer is generated with explicit links to the supporting evidence.
  6. Metering. The call is priced and charged. An insufficient balance is a 402 with the balance included in the body, a visible refusal, not a silent degradation.
  7. Receipting. A receipt is written recording the query, evidence identity, ranking and timing. Execution receipts are signed and chained; retrieval receipts are content-addressed and are not signed.
  8. Response. Pointer-first envelope by default; full payload on Accept-Contract: legacy.

1.18 What it guarantees

Eight guarantees. Each one is stated with its boundary in 1.19, and the two sections are meant to be read together.

  1. Tenant isolation is enforced twice, at the credential layer and again at the query layer. A mismatch is refused, never reconciled.
  2. Proof modes do not silently degrade. A verified or audit request whose proof dependencies are unavailable fails with 503. Weakening it requires allowLightFallback: true from you.
  3. Receipts are verifiable without access to your data. Citations carry quoteHash, not quotes.
  4. Verification is public and unauthenticated. /v1/receipts/verify and /.well-known/crown-keys need no account. You do not need a relationship with us to check our work.
  5. Data egress is capability-scoped. A capability token enumerates the exact egress classes permitted; anything else is refused with egress_not_permitted.
  6. Degradation is observable, never silent. X-Crux-Mode is stamped on every capability-mediated response.
  7. Deletion is verified after commit. Document deletion runs a post-commit erasure verification and reports erasure_verified. A tenant-wide erasure path exists. A failed verification is raised as an alarm condition, not swallowed.
  8. Secrets fail closed at deploy. The deployment carries no default credentials. A deploy missing a required secret refuses to start.

1.19 What it does not promise

Six limits. They are published here at the same volume as the guarantees, because a guarantee without its boundary is marketing.

1. There is no latency or availability SLA. None exists. Any number you have seen, a tookMs in a response, a benchmark figure, a cache TTL, a healthcheck interval, is an observation or a configuration value, not a commitment. If you need a service level, it has to be a commercial agreement written deliberately, and you should ask for one rather than infer one.

2. Retrieval receipts are not signed. Content-addressed only. The API says so in its own response body and 1.13 quotes it. If your control requires an issuer signature, use an execution receipt.

3. The result caps are hard. limit on /v1/retrieve is capped at 50. topK and rerankK on /answers are capped at 100. There is no request that lifts them and no tier that raises them.

4. Governance-tier entitlements are granted but not enforced. A set of governance capability keys is reserved and inert by design. They are granted on the entitlement record and nothing gates on them. Do not treat them as live controls, do not build an assurance argument on them, and do not accept them being described as active capabilities. When they become enforcing, that will be a documented change.

5. Billing features are default-OFF and not live. The subscription credit-grant and payment-provider integrations are implemented and gated off. No live pricing is configured. Nothing in that surface should be treated as available today.

6. The substrate-backed fact store does not support aggregation by category. Where a deployment routes the fact store to the substrate engine, a request to aggregate facts by category is refused with an explicit unsupported-operation error rather than degrading to a partial or approximate count. A wrong number would be worse than a refusal.

One further boundary, not a limit so much as a scope statement: which fact-store backend a deployment runs is an operator choice, not a property of the product. Do not assume either one from this page.

1.20 Claims corrected from earlier published copy

Earlier public pages carried the following. Each is wrong or over-stated for this service, and none of them should be quoted from an archived copy.

Claim that was publishedStatus
"Adaptive Manifest Routing decides per query which lanes earn their tokens, learning from outcomes rather than knobs"Not a feature of this service. Withdrawn.
"The exit is a hard token_budget enforced server-side"A daemon property, not this API. This API has limit, capped at 50.
"The fusion weights are tunable per corpus class and query intent"Withdrawn. Fusion configuration is not published.
"Candidates are re-ranked on relevance, recency, source authority, and coverage diversity"Withdrawn. The ranking signal set is not published.
"An auditor can replay any past query against the historical corpus state and confirm the same inputs produce the same outputs"Withdrawn; this is the important one. There is no customer-facing replay endpoint. As written it was an auditable promise that could not be honoured.
"The receipt captures the original query, the retrieved chunks with their ranking scores, the synthesis rationale, and a BLAKE3 content-hash chain"Withdrawn. It collapsed signed execution receipts and unsigned content-addressed retrieval receipts into one stronger guarantee, and "retrieved chunks" overstates a receipt that carries quoteHash rather than content. See 1.13.
"Ships inside the Crux Daemon"Category error. See 1.1.
"Two lanes run in parallel: sparse keyword matching (BM25) and dense vector similarity"Understated for this service, whose response exposes four score components. See 1.9.

1.21 Grounding, and what is deliberately absent

Crux Engine is a closed system. This chapter carries no source links, because the paths would themselves be the disclosure. Every claim above is grounded on something you can observe from outside: a route, a request field, a response field, a header, a status code or an error type. If a statement here is wrong, a request will prove it wrong, which is the only kind of grounding that is worth anything to a reader who cannot read the source.

What is deliberately absent, and will stay absent: scoring formulas and fusion constants; query rewriting and expansion strategy; the full lane inventory and which lanes are gated; ranking-signal weighting; internal module, table and column names; hosts, addresses, container names and internal ports; feature-flag names; issuer key custody and delegation derivation; and credit debit and refund accounting.

What is not absent, and should never be: request fields, response fields, status codes, headers and error codes. Those are contracts. Withholding a contract helps nobody.

Next: 2. CoreCrux for the substrate this service reads, 3. FeatureCrux for the internal control plane, and 4. How they fit together for the whole picture and what stays yours in each deployment shape.