Skip to content

API reference

On this page

For /v1/evaluate and /v1/recall, the optional top-level include_source_context: true adds selected records and bound short citations to reason.source_context (a JSON clause inside the reason string). The six answer fields do not change; excerpts are omitted by default. Attribution does not verify every clause of a quote and exposes no storage IDs or private execution trace. evidence_refs.recorded_at stores the source's literal recording label (up to 200 characters); event validity still belongs in validity.

Marvnor stores the records you provide and answers structured questions against them: TRUE when the evidence supports a claim, FALSE when it refutes it, and UNKNOWN when it does not settle the question. It flags conflicts and supports in-place correction and targeted deletion. No client download or SDK installation is required.

Quickstart

1. Base URL and authentication

Base URL: https://api.marvnor.com

Send UTF-8 JSON. Except for the public plan catalog, the endpoints in this document require an API key. Create a trial key from the product home without signing up, or create a key in the customer portal after signing in. Both use the same request format:

http
Authorization: Bearer <YOUR_API_KEY>
Content-Type: application/json

Use the same key to write, query, and delete the same memory. Different keys do not share memory. You do not need to supply project or environment. Keep the key in your server-side environment variables, not in browser-side code, public repositories, or LLM prompts.

This hosted API receives saved facts, and six-field results may contain stored values; they are not necessarily anonymous. Legacy document endpoints are closed. Previously staged source text follows its original retention period. See the quickstart for usage and data boundaries.

After 30 days of inactivity, the key becomes invalid and its memory enters the subsequent cleanup process.

2. Endpoints

For ordinary use, follow the quickstart: connect your existing AI and save important evidence-backed facts. Developers can integrate the endpoints below directly.

PurposeMethod and path
Verify facts, check conflicts, and query known valuesPOST /v1/evaluate
Find and verify records relevant to the current questionPOST /v1/recall
Browse records for a known subject, page by pageGET /v1/candidates
Save facts, import in chunks, or save calculation definitionsPOST /v1/relations
Check import progressGET /v1/relations/batches/{batch_id}
List record receipts in pagesGET /v1/relations
Correct by old fact, client ID or receiptPOST /v1/relations/correct
Edit a specific recordPATCH /v1/relations/{record_id}
Delete a specific recordDELETE /v1/relations/{record_id}
Delete selected records or calculation definitionsPOST /v1/relations/delete
Remove the current key's current verifiable memory and revoke itPOST /v1/relations/clear

AI tools can use the same capabilities through https://api.marvnor.com/v1/mcp. Configure it from the customer portal's Connect an AI tool page.

MCP toolPurpose
remember_factsSave facts or reusable calculations, rules and proofs
recallSearch memory or page through an exact subject's records
verifyCheck claims, calculations or proofs; return six fields
correct_factEdit one old fact
forget_factsDelete selected facts or definitions

Call tools directly. These complete requests search by question and browse by subject, respectively:

json
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"recall","arguments":{"text":"What is the status of demo-order-001?"}}}
json
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"recall","arguments":{"source":"demo-order-001"}}}

recall({}) checks connectivity for free. For memory, choose text to search or source to browse an exact subject; schema retrieves full parameters. Source browsing accepts project, relation, as_of, claim_statuses, limit, and cursor. project matches the saved context.scope; omitting it selects only unscoped records. Omit relation if its saved name is unknown.

For recall({"source":"demo-order-001"}), each answers key is an mr_... record receipt; each answer still has six fields. Select the matching record, then call correct_fact({"record_id":"mr_...","changes":{"target":"paid"}}) or forget_facts({"record_ids":["mr_..."]}) without reconstructing old fields. Follow next_cursor until complete: true before batch deletion; check ok and deleted_count to confirm the operation. Answer keys from text search and HTTP browsing are not record receipts.

/v1/evaluate checks explicit claims; /v1/recall finds and checks records relevant to the current question. Each answer from either endpoint has exactly six fields. Record-management endpoints return status, counts or receipts.

Ordinary calls need no prior schema lookup. Use recall({"schema":"compute"}) for advanced parameters; the five tool names, computations, rules, proof, and proofs are also supported. recall({"schema":"capabilities"}) checks connectivity and returns calculation capabilities without writes or charges. Old tool names remain callable for compatibility. HTTP endpoints are unchanged.

The legacy /v1/documents long-text endpoints are closed and return 410 long_text_retired; MCP no longer lists document tools. Facts saved before retirement remain available for retrieval, correction, and deletion under the same key.

3. Advanced API: save structured facts

POST /v1/relations

json
{
  "relations": [{
    "source": "demo-order-001",
    "relation": "status",
    "target": "paid",
    "client_record_id": "demo-status-001"
  }]
}

This record states that the status of order demo-order-001 is paid.

FieldRequirements and meaning
sourceRequired subject; non-empty string, up to 10,000 characters
relationRequired attribute or business relation type; non-empty string, up to 200 characters, such as status
targetRequired value or object; non-empty string, up to 10,000 characters; must differ from source
client_record_idOptional ID assigned by your application, 1–200 characters; useful for later correction or deletion
polarityOptional: 1 for positive, -1 for explicit negative; defaults to 1
confidenceOptional confidence supplied by the caller, from 0.01 to 1; defaults to 1; not a guarantee of real-world truth
contextOptional business context; see section 5
validityOptional validity period; see section 5
property_typeOptional attribute semantics: single (default), set, ordered, or rules
positionOptional position for an ordered item; integer from 0 to 1,000,000
entity_idOptional explicit canonical entity ID; use the same value when multiple sources describe the same entity
evidence_sourceOptional evidence-source label, stored separately from entity identity
unitOptional unit for a numeric value, such as hour, bed, or bed/nurse
provenanceOptional source description, up to 200 characters
evidence_refsOptional evidence locations; see section 5; referenced files or URLs are not fetched automatically

Within one key, a client_record_id cannot be assigned to another fact. You may resubmit the same ID with the same fact. A request accepts 1–10,000 records; use chunked import for larger datasets.

Query subjects and values have a maximum length of 2,000 characters. Use short, stable business names or IDs rather than entire articles. Use identical naming for writes and queries; do not depend on automatic synonym matching.

In a successful response, ok confirms the operation succeeded, accepted is the number accepted in this request, and record_ids contains record receipts in input order. A request_id is also returned; depending on the call, the response may contain a billing usage receipt. Receipt mappings are optional: you can correct a record by its old fact without one. Do not parse receipts or interpret successful acceptance as independent verification of a fact.

4. Queries and six-field answers

POST /v1/evaluate

json
{
  "questions": [
    {"id": "paid", "source": "demo-order-001", "relation": "status", "target": "paid"}
  ]
}

After saving the fact above, with no conflict:

json
{
  "answers": {
    "paid": {
      "conclusion": "TRUE",
      "conflict": false,
      "reason": "supported_evidence",
      "path": ["demo-order-001", "paid"],
      "decision": "answer",
      "evidence_kind": "direct"
    }
  }
}
FieldMeaning
conclusionTRUE: current evidence supports the claim; FALSE: current evidence refutes it; UNKNOWN: currently undetermined
conflictWhether a conflict was detected; if true, do not arbitrarily choose one value as fact
reasonVerification reason code; recall can also include the selected stored_claim, query scope, and source-record polarity, context, and validity
pathRelevant evidence path for normal verification; known candidate values when target is omitted
decisionSuggested handling, not an instruction to execute automatically or a free-text answer
evidence_kindEvidence category, such as direct, indirect, negative, or conflicting

TRUE means submitted evidence supports the claim, not an absolute guarantee about the real world. UNKNOWN is not FALSE. HTTP 200 means the request succeeded, not that the business claim is true.

Read the six fields together

These are the most common combinations for ordinary fact verification. The exact path depends on whether the answer uses a direct fact, a multi-hop path, or a candidate-value query. Do not interpret one field in isolation.

Situationconclusionconflictreasonpathdecisionevidence_kind
Direct supporting evidenceTRUEfalsesupported_evidence[subject, value]answerdirect
Explicit negative evidenceFALSEfalsecontradicting_evidence[]answerexplicit_negative
Insufficient evidenceUNKNOWNfalseinsufficient_evidence[]unknownunknown
Conflict on an explicit claimUNKNOWNtrueconflicting_evidencerelevant pathclarifyconflict
One known candidate valueTRUEfalseknown_values[value]answerdirect
Mutually exclusive candidate valuesUNKNOWNtrueconflicting_values[value A, value B]needs_reviewconflict

Marvnor does not treat missing evidence as negation. If the only saved record is status=paid, asking whether status=unpaid normally returns UNKNOWN, not FALSE. FALSE requires explicit evidence against that same claim, such as a saved record with polarity: -1. Applications should preserve all six fields: inspect candidate values when there is a conflict, and obtain more evidence when the result is unknown instead of acting on conclusion alone.

Deterministic compute and draft checking

For arithmetic, ratios, date differences, comparisons or Boolean operations over saved facts, include compute in a verify question. facts selects saved inputs, plan specifies operations, and optional draft checks a proposed result. Marvnor executes these explicit inputs; the host model interprets the question, selects the facts and composes the answer.

json
{
  "questions": [{
    "id": "staff-needed",
    "compute": {
      "facts": [
        {"id": "occupied", "source": "Ward-A", "relation": "occupied_beds", "unit": "bed"},
        {"id": "capacity", "source": "Staffing-rule", "relation": "beds_per_nurse", "unit": "bed/nurse"}
      ],
      "plan": {
        "op": "ceil",
        "arg": {"op": "divide", "args": [
          {"op": "ref", "id": "occupied"},
          {"op": "ref", "id": "capacity"}
        ]},
        "unit": "nurse"
      },
      "draft": {"value": "6", "unit": "nurse"}
    }
  }]
}

Supported operations are ref, add, subtract, multiply, divide, power, ceil, floor, round, sum, count, distinct, min, max, ratio, compare, and, or, not, and date_diff. Every input must resolve to a non-conflicting fact saved under the same key. The service does not execute arbitrary code or treat plan literals as evidence. A mismatching draft returns the same six fields with reason: draft_mismatch and decision: block; without a draft, the checked deterministic result is returned. Compute is on demand; connecting a key does not automatically check every final model answer. Computation is determined by facts, plan, context and as_of.

Example of a basic addition:

json
{
  "id": "sum",
  "compute": {
    "facts": [
      {"id": "a", "source": "A", "relation": "amount"},
      {"id": "b", "source": "B", "relation": "amount"}
    ],
    "plan": {"op": "add", "args": [
      {"op": "ref", "id": "a"}, {"op": "ref", "id": "b"}
    ]}
  }
}

Code, logic, mathematics and physics

Use the same remember_facts and verify operations and the same key. recall({"schema":"capabilities"}) or GET /v1/capabilities lists the currently executable calculation operations.

TaskInputs and operation
CodeSave exact symbols with separate call, assignment and pre/postcondition records. Use property_type:"set" for multiple callees. Recall a fully qualified saved symbol such as pkg.fn; use recall({"source":"pkg.fn"}) when its field names are unknown.
LogicCheck composite claim expressions or submit multi-premise rules and ordered proof steps. Keep verified parts when a missing premise leaves the final conclusion unknown.
MathematicsUse compute for exact fraction/decimal arithmetic and integer powers over saved inputs. power.args contains base then exponent; the exponent must be a dimensionless integer, including negative integers.
PhysicsStore numbers and unit separately; specify operations and output units, such as kg × m/s^2 → N. Submit the formula's applicability conditions as proof premises.

Optional compute.facts.value_type selects string (preserves code values; 001 is not 1), boolean (parses true/false), or number (requires a number). Omitted or auto retains legacy numeric parsing. With mode:"all", the type applies to each item. A result_id input inherits its result type and cannot redeclare it. Boolean and numeric values are distinct: true is not 1.

Units support existing time conversions, SI base/common derived units, *, /, and integer powers, such as km/h, m/s^2, N, J, and Pa. SI symbols and custom units are case-sensitive. Custom units still support same-unit arithmetic; offset conversions such as Celsius/Fahrenheit are not inferred. An input unit assertion must match the saved record; request output conversion with unit on an operation node. Existing records are not rewritten; saved calculations are recomputed from current evidence.

The host model selects formulas, rules and premises. Marvnor checks explicit steps and values. A relation or axiom name is not an executable program; code execution, question interpretation and arbitrary theorem search remain with the host.

Read current source and run tests for implementation and debugging. Verify saved project history only when the task depends on information absent from the source, such as confirmed architecture decisions, version constraints, interface contracts, test conclusions, or conflicts, then give the relevant six-field results to the model. Do not turn current source into relations and inject the same information again.

Save and reuse multi-step calculations

Send computations to POST /v1/relations (MCP: remember_facts) to save calculation definitions. Submit them separately from relations and batch-upload parameters. Assume the same key already stores non-conflicting item facts: quantity=8, rate=2, and fee=4.

json
{"computations": [
  {"id": "subtotal", "facts": [
    {"id": "q", "source": "item", "relation": "quantity"},
    {"id": "r", "source": "item", "relation": "rate"}
  ], "plan": {"op": "multiply", "args": [{"op": "ref", "id": "q"}, {"op": "ref", "id": "r"}]}},
  {"id": "total", "facts": [
    {"id": "s", "result_id": "subtotal"},
    {"id": "f", "source": "item", "relation": "fee"}
  ], "plan": {"op": "add", "args": [{"op": "ref", "id": "s"}, {"op": "ref", "id": "f"}]}}
]}

Then query with POST /v1/evaluate (MCP: verify):

json
{"questions": [{"id": "q", "compute": {"result_id": "total"}}]}

The answer keeps the six fields, with path: ["20"]. Correct the original quantity to 10 and the same query returns ["24"]; do not re-import the calculated answer as a fact. Definitions survive restarts; reuse the same id to update a definition. Each query checks current premises. Missing, conflicting, or incompatible inputs produce UNKNOWN, with conflict: true for conflicts. A batch is saved only when all submitted definitions verify; failures do not partially write it. Existing input and operation constraints still apply; references between calculations introduce no additional hop limit.

Definitions may specify context and as_of; references must respect those bindings. Your AI selects the premises and plan; Marvnor performs the calculation. Keep the calculation IDs you choose: recall currently retrieves facts, not recommended calculation definitions. Ordinary compute.facts may also reference {"id":"s","result_id":"total"}. To delete a definition, send {"computation_ids":["subtotal"]} to POST /v1/relations/delete. Original facts remain; results depending on that definition become UNKNOWN. A concurrent change during saving returns 409; check current premises before resubmitting.

Rules and proof steps

Your AI selects evidence and deduction steps; Marvnor checks each step. Multiple premises can jointly support a conclusion, and calculated results can feed later rules. The same key, existing endpoints and six answer fields apply.

This example uses the business rule “approved, and total cost within budget, implies permission to start.” First save the supported inputs with POST /v1/relations:

json
{"relations":[
  {"source":"job","relation":"approval","target":"yes","context":{"scope":"demo-proof"}},
  {"source":"job","relation":"work_cost","target":"6","context":{"scope":"demo-proof"}},
  {"source":"job","relation":"fee","target":"2","context":{"scope":"demo-proof"}},
  {"source":"job","relation":"budget","target":"10","context":{"scope":"demo-proof"}}
]}

Then save the rule and reusable proof through the same endpoint (MCP: remember_facts):

json
{"rules":[{
  "id":"launch","context":{"scope":"demo-proof"},
  "premises":[{"source":"?p","relation":"approval","target":"yes"}],
  "checks":[{
    "facts":[{"id":"cost","source":"?p","relation":"total_cost"},
             {"id":"budget","source":"?p","relation":"budget"}],
    "plan":{"op":"compare","operator":"<=","args":[{"op":"ref","id":"cost"},{"op":"ref","id":"budget"}]}
  }],
  "conclusion":{"source":"?p","relation":"can_start","target":"yes"}
}],"proofs":[{
  "id":"start-job","context":{"scope":"demo-proof"},
  "steps":[
    {"id":"cost","compute":{
      "facts":[{"id":"work","source":"job","relation":"work_cost"},
               {"id":"fee","source":"job","relation":"fee"}],
      "plan":{"op":"add","args":[{"op":"ref","id":"work"},{"op":"ref","id":"fee"}]}
    },"conclusion":{"source":"job","relation":"total_cost"}},
    {"id":"launch","rule_id":"launch","bindings":{"p":"job"}}
  ],
  "goal":{"source":"job","relation":"can_start","target":"yes"}
}]}

Query with POST /v1/evaluate (MCP: verify):

json
{"questions":[{"id":"q","proof":{"result_id":"start-job"}}]}

The result is TRUE: cost is 6 + 2 = 8, budget is 10, and approval is recorded. Correct the budget to 7 and the same query returns UNKNOWN with reason: launch: condition_not_met. This program no longer proves permission to start; it does not prove the opposite.

StepUse
Apply a rulerule_id and bindings; a rule variable ?p is bound by {"p":"job"}
Calculatecompute and a conclusion with source and relation; the value is computed, including from a saved calculation result_id
Reuse a proofproof_id; recheck the program and make its results available to later steps

For an unsaved check, put steps and goal directly inside proof. The question contains only id and proof; put context and as_of inside proof. Compute steps emit scalar values; reduce collections with sum, count, or another supported operation first. All rule premises must hold and every check must return Boolean true. At least one premise or check is required. Whole-term variables may appear in claim subjects/values and compute input subjects; conclusion variables must occur in inputs. Predicates and executable plans are fixed. Explicitly mark set-valued conclusions with property_type: "set".

Within one rule application, repeated names and values must have consistent saved types and units. Variables and literals use the same check. Use compute for numerical operations with units; equal text does not make different quantities equal, and units are not converted automatically. Inconsistent types or units return UNKNOWN with incompatible_term_kinds or incompatible_term_units.

A supplied rule is a conditional assumption: Marvnor checks whether current evidence supports the goal under those rules. Custom transitivity needs an explicit rule; ordinary graph query behavior is unchanged. No new proof-step cap is added, but request size, computation-plan and server-resource constraints still apply. This is not an automatic prover for arbitrary mathematical theorems.

Rules can be saved before their premises exist; saved proofs must verify at save time. A failed batch saves nothing. Each reuse checks current facts and rules. Intermediate conclusions exist only within the proof and are not stored as permanent assertions. Temporary relations are not proof evidence. Missing premises return missing_or_refuted_premise; deleted rules or programs return missing_rule / missing_proof. reason names the failed step, and path may list missing claims. Conflicts return UNKNOWN with conflict: true. The AI can supply supported premises or revise the steps before checking again.

Reuse an id to update its definition. Delete with POST /v1/relations/delete and {"rule_ids":["launch"]} or {"proof_ids":["start-job"]}; original facts remain, and dependents are rechecked. Submit rules and proofs together or separately, but not mixed with relations, computations, or batch-upload parameters. Keep your chosen IDs; recall does not currently select proof programs for you.

Find records relevant to the current question

POST /v1/recall accepts a natural-language question and selects a bounded candidate set from saved records for verification; you do not need to know the stored source or relation first:

json
{"text": "What is the status of demo-order-001?"}

text is required, up to 2,000 characters. Optional context narrows the scope, as_of specifies a time in the question, facets splits up to 8 subquestions, and limit caps verified records (12 by default, up to 20). The response still contains only answers at the top level, with the six fields above in each answer. Answer keys may be q0, missing0, or others depending on what was found. TRUE or FALSE verifies the selected stored claim, not necessarily the entire natural-language question. Parts without evidence remain UNKNOWN. If conflict: true, check the sources before selecting a value.

When retrieval is incomplete, reason keeps the compatibility marker retrieval_incomplete=true and adds incomplete_reason_codes: query_ambiguous, limit_reached, route_incomplete, or the generic retrieval_incomplete. More than one category may apply.

Common reasonMeaning
supported_evidenceSupporting evidence exists
contradicting_evidenceRefuting evidence exists
conflicting_evidenceConflicting evidence exists
insufficient_evidenceEvidence is insufficient
known_valuesKnown candidate values were found
no_known_valuesNo known candidate values were found
conflicting_valuesMutually exclusive candidate values were found
path_omitted_limitThe path or candidate list was too large to include; this does not mean there is no evidence
no_supporting_pathNo supporting path; interpret alongside the conclusion and conflict flag

Public decision values include answer, abstain, clarify, unknown, open, allow, block, and needs_review. Where clarification, review, or further evidence is needed, obtain that evidence or ask the user. This field does not replace your application's business authorization.

Public evidence_kind values include direct, indirect, explicit_negative, conflict, incompatible_context, no_path, unknown, composite, and quarantined. The last value means the evidence was not used to establish valid support; it is not a legal judgment about the content. Treat unrecognized categories as requiring review, not as automatic approval.

Request scope

The inference response contains only answers at the top level, with no extra usage or diagnostic fields. A path may contain up to 2,048 items and 131,072 characters in total. Beyond either limit, the entire path is an empty array and the reason is path_omitted_limit. Compound questions also return an empty path, so an empty array does not itself indicate query failure.

Query known values for an attribute

Omit target; do not pass an empty string:

json
{
  "questions": [
    {"id": "current-status", "source": "demo-order-001", "relation": "status"}
  ]
}

The result still has six fields. path contains deduplicated, sorted, directly known candidate values. This is not a full memory export or open-ended full-text search.

Ordinary custom attributes are single-valued by default. Different values for the same subject and single-valued attribute, in compatible contexts and overlapping validity periods, produce UNKNOWN with conflict: true. For example, an order cannot simultaneously have both paid and unpaid as its status. Types defined as multi-valued, such as supports, allow multiple objects and do not conflict merely because there is more than one value. You cannot change these rules by submitting an extra multiple: true field.

Use context.qualifiers.assertion_kind for proposed or reported records; ordinary established records use asserted. Explicit proposed_ and reported_ attribute prefixes follow the same semantics. TRUE for a proposal verifies the proposal record, not that it has been implemented.

When a conflict occurs, omit target to query the candidate values, then check your original evidence. Positive and explicitly negative statements about a multi-valued attribute may also conflict; do not ignore conflict.

Browse saved records for a subject

When you know the subject but not the saved property name, use GET /v1/candidates?source=Garden to browse unscoped records page by page. If a write included context.scope, pass the same value as project, for example project=store-a. Scopes are not merged and default is not silently added. The default includes established records only. If the question explicitly asks about proposals or reports, pass claim_status=proposed or claim_status=reported; to compare statuses, repeat the parameter, for example claim_status=established&claim_status=proposed. Each page accepts limit from 1 to 100. If complete is false, continue with next_cursor until complete. Pagination does not cap the total record range. Each record still uses the six-field answer format; internal record structure is not exposed.

5. Context, time, and compound claims

Context: context

May contain domain_id, subdomain_id, scope, and subject_version, each a non-empty string of up to 200 characters. qualifiers accepts up to 64 conditions, with keys up to 100 characters and values that are JSON scalars or lists of scalars. Nested objects are not accepted.

json
{"scope": "store-a", "subject_version": "v2"}

Supply a query context that matches the facts. A mismatch does not make a fact false. Business context also does not replace key-based isolation between customers.

Approximate event time can be saved in qualifiers.event_time_text and reference_time; do not substitute the message timestamp for the event time. Mark named generated plans or code with qualifiers.record_kind: artifact and author_role: assistant. This records the artifact's existence, not proof of every external claim in it.

Validity: validity, and query time: as_of

json
{
  "kind": "interval",
  "valid_from": "2026-10-01T00:00:00Z",
  "valid_to": "2026-10-31T23:59:59Z"
}

Use ISO 8601 timestamps, preferably with a timezone. An interval requires at least a start or an end; the start must not be later than the end. persistent means the fact does not expire based on query time and cannot be combined with a start or end time.

Omitting validity also means no time restriction. A fact does not become unknown merely because it has no timestamp, although conflicts or missing support may still affect it. Optional observed_at and recorded_at timestamps do not replace the validity period.

Use as_of to specify a query time. Omitting it does not automatically mean "now." Facts outside their validity period cannot support a claim at that time; this does not establish the opposite claim either.

Evidence locations: evidence_refs

Up to 64 entries. Each requires source_id (1–200 characters) and locator (1–500 characters). Optional fields are content_hash (1–200 characters), observed_at (ISO 8601), and role (1–80 characters, default fact_support). These are caller-supplied references; the original source text is not separately returned in six-field answers.

Compound questions

Supported operators are atom, and, or, not, and implies, plus scope to apply context and query time to a nested claim:

json
{
  "questions": [{
    "id": "ready",
    "claim": {
      "op": "scope",
      "context": {"scope": "store-a"},
      "as_of": "2026-10-09T00:00:00Z",
      "claim": {
        "op": "and",
        "claims": [
          {"op": "atom", "source": "demo-order-002", "relation": "status", "target": "paid"},
          {"op": "atom", "source": "demo-order-002", "relation": "stock_status", "target": "reserved"}
        ]
      }
    }
  }]
}

atom requires a subject, attribute, and value. and / or take a claims list with 1–256 children. not takes one claim. implies takes if and then children; the op: "if" and when forms are also accepted. scope requires a claim and at least a non-empty context or a valid as_of.

Nested contexts must not contradict each other. An inner query time overrides only its own nested claim. Across all compound questions, a request may contain at most 512 claim nodes and a nesting depth of 64. Without submitted facts about the example order, this request does not invent a positive answer.

6. Edit, delete, and import

Correction and targeted deletion

These three requests save, correct in place, and delete one record. Use the same key throughout; no delete-and-rewrite step is needed.

POST /v1/relations:

json
{"relations":[{"source":"demo-order-101","relation":"status","target":"pending","client_record_id":"demo-status-101"}]}

POST /v1/relations/correct:

json
{"fact":{"source":"demo-order-101","relation":"status","target":"pending"},"changes":{"target":"paid"}}

POST /v1/relations/delete:

json
{"client_record_ids":["demo-status-101"]}

fact selects a unique match. Complete relations match record identity exactly: include the original context, polarity, validity, type, position, entity, source, unit, and other identity fields; omissions use defaults. If any ID in an ID list is missing, the request returns 404 without partial deletion. Complete facts with no match delete 0 records. Prefix and wildcard deletion are not supported.

Edit responses do not return record contents. Receipts and client_record_id stay unchanged; use the updated contents when deleting by complete fact. After an edit or deletion, recheck affected conclusions with /v1/evaluate: lost support normally means UNKNOWN, not FALSE; independent remaining support can still produce TRUE.

Chunked import and recovery

Send these two consecutive chunks to POST /v1/relations:

json
{"batch_id":"demo-batch-101","total":2,"offset":0,"relations":[{"source":"demo-batch-order-101","relation":"status","target":"pending"}]}
json
{"batch_id":"demo-batch-101","total":2,"offset":1,"relations":[{"source":"demo-batch-order-102","relation":"status","target":"paid"}]}

New records are not queryable until the batch completes. On completion, record_ids covers the whole batch, including reused records. After a timeout, check progress: resume partial from next_offset; for complete, do not start another batch—replay unchanged to retrieve receipts; do not resume deleted; for 404, check the key and batch ID. Retries are not necessarily free.

To clean up this batch's new test records, send to POST /v1/relations/delete:

json
{"batch_id":"demo-batch-101"}

Batch deletion removes only records newly created by that batch that have not been edited or reused by another batch. Pre-existing, edited, or reused records remain. An incomplete batch returns 409; repeated deletion of a deleted batch removes 0 records. Use a new batch ID for a new import. Finish paginating receipts before editing or deleting records.

Clear all

Targeted deletion preserves the key and other records. POST /v1/relations/clear with {"confirm":"clear_project"} removes every record for the current key from current verifiable memory and revokes the key. Operational history or backups may follow a separate retention schedule. Do not use clear-all for routine test-data cleanup.

7. Usage and troubleshooting

See the customer portal for current plans and usage rules. Applications can read the public GET /v1/plans. Use an authenticated GET /v1/quota to check account usage. Whether a call counts toward usage follows the current rules, not whether the conclusion is TRUE, FALSE, or UNKNOWN.

/v1/recall charges for submitted facets with candidate records, not separately for each internally verified candidate. Input follows the published 4KB tiers. For facts already saved with document evidence before import retirement, at most one automatically added untimed document background and its internal verification use limit slots but have no extra point charge. The internal check is not returned as a separate answer, and the background does not establish status at the requested instant. See pricing.recall_billing and pricing.recall_untimed_background in GET /v1/plans.

HTTP statusSuggested action
400Check field names, required fields, and formats; omitting target differs from passing an empty string
401Check for an incorrect, revoked, or inactivity-expired key
402Check available account quota
403Check permissions; use an API key, not website login credentials
404Check paths and IDs, and use the original write key
409Use the reason code to disambiguate or reread the old fact; for batches, check state and offset
413Reduce request size or import in chunks
500The operation has not been confirmed successful; retain the request ID and contact support rather than blindly retrying writes or edits
429 / 503Retry later, observing Retry-After when present; after a write timeout, check state first

A network timeout does not prove that a write failed. Do not retry indefinitely without checking. Keep the HTTP status, time, and any request_id already present in the response, then contact support through the customer portal. Never send your full key.