# REST API reference

Every route of the hosted DSAIL service, rendered from its published OpenAPI document, so an agent can read the contract before connecting.

Base URL: `https://agents.jaxon.ai`. Every request and response is JSON. Every error is one envelope — `{ok: false, error: {code, message, docs, ...}, versions}` — and `error.docs` is the page on this site that resolves it (see [Errors](errors.md)).

Authentication: the header `x-jaxon-credential`. Obtain an evaluation credential with no sign-up from `POST /v1/credentials/evaluation`; the response's `credential` field is the token, shown once. Evaluation credentials are scoped to compile, check and the prompt pack, and capped; a full credential is issued by Jaxon.

The document below is rendered from the published OpenAPI specification. The specification itself is `GET https://agents.jaxon.ai/openapi.json`, and a copy ships inside the `dsail` Python package as `dsail.contract.openapi()`.

## `GET /health`

Health

Response `200`:

## `GET /v1/account`

Entitlement and usage position (permissive stub in this release)

Response `200`:

## `POST /v1/approvals`

Save under a name and bind a human approval to an exact ruleset hash

Request body:

- `approver`: string (required)
- `label`: any — Optional application-domain label from YOUR model (TJP-642): {domain: <a level-one id from GET /v1/vocabulary>, topic: <a short free-text level-two term>, confidence: high|medium|low, declined: bool}. Inert — it never changes a result. Stored and reported as ids only; the topic string is matched against the vocabulary and then dropped. Off-list domains are refused. Omit it, or send {declined: true}, to not label.
- `name`: any — Save the ruleset under this name as part of approving it. The binding happens BEFORE the approval is recorded, so what a person approves is findable afterwards rather than reachable only by a hash. Omit for a hash that is already saved under a name.
- `note`: any
- `ruleset_hash`: string (required)

Response `200`:

- `approval`: object (required)
  - `approved_at`: string (required) — UTC, ISO 8601.
  - `approver`: string (required)
  - `hash`: string (required) — The exact bytes signed for. An approval follows the hash, never a name: a later revision is not covered by it.
  - `note`: string | null
- `approvals`: array (required) — Every approval on this hash, including the new one.
  - `approved_at`: string (required) — UTC, ISO 8601.
  - `approver`: string (required)
  - `hash`: string (required) — The exact bytes signed for. An approval follows the hash, never a name: a later revision is not covered by it.
  - `note`: string | null
- `label`: object | null — The ruleset's stored application-domain label (TJP-642), as ids under `vocabulary_version`. Null when the ruleset carries none, or when this account has labeling disabled. A label never alters a result; the level-two proposal text a caller sent is matched and dropped, never stored or returned.
  - `confidence`: "high" | "medium" | "low" | null (required)
  - `declined`: boolean (required)
  - `level_one`: "finance" | "consumer_finance" | "capital_markets" | "insurance" | "regulatory_compliance" | "hr_workforce" | "security_access" | "security_classification" | "healthcare" | "legal_contracts" | "procurement" | "engineering_release" | "content_safety" | "other" | null (required) — Level-one domain id. Null only when declined.
  - `level_two`: string | null (required) — Level-two term id, from GET /v1/vocabulary. Null when the proposal matched no published term (the proposal was counted toward promotion instead) or none was offered.
  - `updated_at`: string (required) — UTC, ISO 8601.
  - `vocabulary_version`: string (required)
- `name`: string | null (required) — The name these bytes are saved under after this call. Null only when none was supplied and none was already bound.
- `namespace`: string (required) — Service-internal scope identifier. For clients, not for display: never show this to a person, who identifies a ruleset by name.
- `ok`: boolean (required)
- `ruleset_hash`: string (required)
- `saved`: boolean (required) — Whether this call bound a name. The binding happens BEFORE the approval is recorded, so a refused name records no approval at all.
- `versions`: object (required) — Which engine and which wire contract produced this response.
  - `engine`: string (required)
  - `engine_version`: string (required)
  - `language_version`: string (required) — DSAIL language version.
  - `service_version`: string (required)
  - `supported_language_versions`: array
  - `wire_version`: string (required)

Response `400`: the error envelope.

Response `404`: the error envelope.

Response `413`: the error envelope.

## `POST /v1/check`

Validate a claim dictionary and solve it, in one call

Request body:

- `claims`: object (required) — Claim name to value. Every declared claim must be present; a claim you could not determine is submitted as "unknown" or null.
- `label`: any — Optional application-domain label from YOUR model (TJP-642): {domain: <a level-one id from GET /v1/vocabulary>, topic: <a short free-text level-two term>, confidence: high|medium|low, declined: bool}. Inert — it never changes a result. Stored and reported as ids only; the topic string is matched against the vocabulary and then dropped. Off-list domains are refused. Omit it, or send {declined: true}, to not label.
- `ruleset_hash`: any — The hash returned by compile. Preferred after the first call.
- `source`: any — Source text, if you have not compiled it yet. Passing both is allowed and asserts they agree; a mismatch is refused.

Response `200`:

Every rule in the ruleset with every assertion's own result, and nothing combined on top of them. Pure over its inputs: no timestamps, no durations, no request id, so the same ruleset and claim dictionary always produce the same bytes — through either door.

- `claims`: object (required)
  - `bound`: array (required)
  - `quantities`: array — What each numeric claim was worth. Without it a check names the claims it bound and nothing about their values, so an answer of '30000 CAD' judged against a policy written in USD leaves no trace of the currency it arrived in.
    - `bound`: string (required) — The DSAIL literal it became. Verbatim: the host performs no unit arithmetic.
    - `claim`: string (required)
    - `conversion`: object — Present only when the submitted unit differs from the declared one. 'by' is always 'engine': Z3 applies the factor as an exact rational, and the factor here is reported from the same registry for a human to check, never used to compute anything.
      - `by`: string (required)
      - `factor`: number
      - `from`: string (required)
      - `status`: string (required)
      - `to`: string (required)
    - `measured_in`: string | null (required) — The claim's declared @unit, if any.
    - `submitted`: string (required) — The value as the caller sent it.
  - `unbound`: array (required) — Claims the engine had no value for — submitted as unknown, or absent. Why an assertion answered UNKNOWN is readable here.
- `ok`: boolean (required)
- `rules`: array (required)
  - `assertions`: array (required)
    - `check`: "TRUE" | "FALSE" | "UNKNOWN" | "AMBIGUOUS" (required) — The engine's own result, in the same four words the platform's run results use. TRUE = the assertion holds. FALSE = the assertion is violated. UNKNOWN = a claim the assertion needs was not determined. AMBIGUOUS = the assertion's evidence was contradicted — reserved: it needs an instance axis carrying several answers for one claim, and a claim dictionary holds one value per claim, so nothing produces it yet. Handle it now and a later release costs you no change.
    - `counterexample`: string — The assignment that violates this assertion, from the solver. Present only on FALSE: for an UNKNOWN the solver's witness is merely a model in which the assertion could fail, and publishing it would state a determination this service did not make.
    - `name`: string (required)
    - `reason_unknown`: string
    - `source`: string | null
    - `unbridged_units`: array — Unit pairs this assertion compares that no loaded converter bridges — the engine's own account of why it answered UNKNOWN.
      - `from`: string (required)
      - `to`: string (required)
    - `unknown_policy`: string
  - `rule`: string (required)
- `ruleset_hash`: string (required)
- `unit_library_hash`: string | null (required) — The other half of a result's provenance. DSAIL numerics are dimensional, and a project may add unit converters that change what a comparison resolves to, so the ruleset hash alone no longer identifies every input. Null means no project library, which is itself reproducible: it selects the six built-in standard libraries.
- `versions`: object (required) — Which engine and which wire contract produced this response.
  - `engine`: string (required)
  - `engine_version`: string (required)
  - `language_version`: string (required) — DSAIL language version.
  - `service_version`: string (required)
  - `supported_language_versions`: array
  - `wire_version`: string (required)

Response `400`: the error envelope.

Response `404`: the error envelope.

Response `413`: the error envelope.

Response `422`: the error envelope.

Response `500`: the error envelope.

## `POST /v1/compile`

Compile a ruleset; get its hash, manifest and validation contract

Request body:

- `label`: any — Optional application-domain label from YOUR model (TJP-642): {domain: <a level-one id from GET /v1/vocabulary>, topic: <a short free-text level-two term>, confidence: high|medium|low, declined: bool}. Inert — it never changes a result. Stored and reported as ids only; the topic string is matched against the vocabulary and then dropped. Off-list domains are refused. Omit it, or send {declined: true}, to not label.
- `parent_hash`: any — The revision this one supersedes. A revision is a new object with a parent, never an edit of the old one.
- `source`: string (required) — DSAIL ruleset source. Host annotations may appear in comments.

Response `200`:

- `claim_schema`: object (required) — JSON Schema for the claim dictionary.
- `diagnostics`: array (required)
  - `line`: integer | null
  - `message`: string (required)
  - `severity`: "error" | "warning" (required)
- `label`: object | null — The ruleset's stored application-domain label (TJP-642), as ids under `vocabulary_version`. Null when the ruleset carries none, or when this account has labeling disabled. A label never alters a result; the level-two proposal text a caller sent is matched and dropped, never stored or returned.
  - `confidence`: "high" | "medium" | "low" | null (required)
  - `declined`: boolean (required)
  - `level_one`: "finance" | "consumer_finance" | "capital_markets" | "insurance" | "regulatory_compliance" | "hr_workforce" | "security_access" | "security_classification" | "healthcare" | "legal_contracts" | "procurement" | "engineering_release" | "content_safety" | "other" | null (required) — Level-one domain id. Null only when declined.
  - `level_two`: string | null (required) — Level-two term id, from GET /v1/vocabulary. Null when the proposal matched no published term (the proposal was counted toward promotion instead) or none was offered.
  - `updated_at`: string (required) — UTC, ISO 8601.
  - `vocabulary_version`: string (required)
- `manifest`: object (required)
  - `claims`: array (required)
    - `boolean_subtype`: string
    - `claim`: string (required)
    - `context`: string
    - `data_type`: "boolean" | "numeric" | "enum" (required)
    - `ordered`: boolean
    - `question`: string (required) — Shown to the extracting model.
    - `range`: object
      - `max`: number
      - `min`: number
    - `required`: boolean (required)
    - `unit`: string | null
    - `unknown_allowed`: boolean (required)
    - `unknown_sentinel`: string — Present only when this claim's own vocabulary contains a member spelled like the sentinel. Then the string means that member and this names the value that means undetermined (null).
    - `vocabulary`: array
  - `rules`: array (required)
    - `assertions`: array (required)
      - `line`: integer | null
      - `name`: string (required)
      - `source`: string | null
      - `unknown_policy`: "optimistic" | "pessimistic" | "neutral" (required)
    - `rule`: string (required)
  - `ruleset_hash`: string (required)
- `ok`: boolean (required)
- `review`: string (required) — A plain-text rendering of what this ruleset asks and decides, for a person about to approve it. Derived from the manifest on every compile, never stored, so it cannot drift from the contract a caller was handed.
- `ruleset_hash`: string (required) — sha256 of the normalised source. This is the object key.
- `source`: string (required) — The normalised DSAIL source that hashed to `ruleset_hash`, so a caller that only ever compiles has something to show or diff without a separate load-by-name call.
- `stored`: object
  - `parent_hash`: string | null
  - `revision_depth`: integer
- `summary`: string (required) — The same thing in one sentence, for a row in a list rather than a page a person reads.
- `unbridged_units`: array — Unit pairs this ruleset compares that no loaded converter bridges, attributed by the engine to the rule that cannot be lowered. Each one answers UNKNOWN for every claim dictionary until a converter is added.
  - `cause`: "missing" | "ambiguous" (required)
  - `from`: string (required)
  - `rule`: string (required)
  - `to`: string (required)
- `unit_library_hash`: string | null — The project unit library this compile read. Half of a result's provenance; null selects the six built-in standards.
- `validation_contract`: object (required) — Exactly what check will reject, known before submitting.
- `versions`: object (required) — Which engine and which wire contract produced this response.
  - `engine`: string (required)
  - `engine_version`: string (required)
  - `language_version`: string (required) — DSAIL language version.
  - `service_version`: string (required)
  - `supported_language_versions`: array
  - `wire_version`: string (required)

Response `400`: the error envelope.

Response `413`: the error envelope.

Response `422`: the error envelope.

## `POST /v1/credentials/evaluation`

Obtain an evaluation credential: no sign-up, scoped to compile and check, capped, expiring (TJP-621)

Request body:

- EvaluationCredentialRequest | null

Response `200`:

An evaluation credential, minted on request with no human gate (TJP-621). The token is shown here and nowhere else — the service stores only its hash. Send it as the x-jaxon-credential header. It is scoped to compile, check and the prompt pack, capped per day and over its lifetime, and expires; every response it produces carries x-jaxon-credential-grade: evaluation.

- `credential`: string (required) — The bearer token. Store it; it is not retrievable again.
- `credential_id`: string (required) — Names the credential without unlocking anything; safe to log.
- `expires_at`: string (required) — ISO 8601, UTC.
- `grade`: "evaluation" (required)
- `header`: string (required)
- `limits`: object (required)
  - `calls_per_day`: integer (required)
  - `calls_total`: integer (required)
  - `ttl_days`: integer (required)
- `ok`: boolean (required)
- `scope`: array
- `upgrade`: string
- `versions`: object (required) — Which engine and which wire contract produced this response.
  - `engine`: string (required)
  - `engine_version`: string (required)
  - `language_version`: string (required) — DSAIL language version.
  - `service_version`: string (required)
  - `supported_language_versions`: array
  - `wire_version`: string (required)

Response `400`: the error envelope.

Response `429`: the error envelope.

## `GET /v1/flags`

This deployment's own feature flags (not the platform's)

Response `200`:

## `POST /v1/prompt-pack`

Prompt pack for source you have not compiled yet

Request body:

- `ruleset_hash`: any
- `source`: any

Response `200`:

- `assembly_notes`: array
- `claim_schema`: object (required)
- `integrity_rule`: string (required)
- `ok`: boolean (required)
- `prompts`: array (required)
  - `answer_format`: string (required)
  - `claim`: string (required)
  - `context`: string
  - `data_type`: string (required)
  - `ordered_vocabulary`: boolean — True when the enum was declared ordered, so its members compare with < and >.
  - `question`: string (required)
  - `range`: object
  - `undetermined_value`: string — The literal to send when this claim could not be determined: "unknown", or null where the vocabulary itself contains "unknown".
  - `unit`: string
  - `unknown_rule`: string (required)
  - `vocabulary`: array
- `ruleset_hash`: string (required)
- `validation_contract`: object
- `versions`: object (required) — Which engine and which wire contract produced this response.
  - `engine`: string (required)
  - `engine_version`: string (required)
  - `language_version`: string (required) — DSAIL language version.
  - `service_version`: string (required)
  - `supported_language_versions`: array
  - `wire_version`: string (required)

Response `400`: the error envelope.

Response `404`: the error envelope.

Response `413`: the error envelope.

Response `422`: the error envelope.

## `GET /v1/prompt-pack/{ruleset_hash}`

Extraction prompts, claim schema and validation contract for a ruleset

Response `200`:

- `assembly_notes`: array
- `claim_schema`: object (required)
- `integrity_rule`: string (required)
- `ok`: boolean (required)
- `prompts`: array (required)
  - `answer_format`: string (required)
  - `claim`: string (required)
  - `context`: string
  - `data_type`: string (required)
  - `ordered_vocabulary`: boolean — True when the enum was declared ordered, so its members compare with < and >.
  - `question`: string (required)
  - `range`: object
  - `undetermined_value`: string — The literal to send when this claim could not be determined: "unknown", or null where the vocabulary itself contains "unknown".
  - `unit`: string
  - `unknown_rule`: string (required)
  - `vocabulary`: array
- `ruleset_hash`: string (required)
- `validation_contract`: object
- `versions`: object (required) — Which engine and which wire contract produced this response.
  - `engine`: string (required)
  - `engine_version`: string (required)
  - `language_version`: string (required) — DSAIL language version.
  - `service_version`: string (required)
  - `supported_language_versions`: array
  - `wire_version`: string (required)

Response `400`: the error envelope.

Response `404`: the error envelope.

Response `422`: the error envelope.

## `GET /v1/rulesets`

List named rulesets, with what each one decides

Response `200`:

Every named ruleset saved for this connection, with enough per row to render a library without a second call.

- `namespace`: string (required) — Service-internal scope identifier. For clients, not for display: never show this to a person, who identifies a ruleset by name.
- `ok`: boolean (required)
- `rulesets`: array (required)
  - `approval_count`: integer (required)
  - `bound_at`: string (required) — When this name last started pointing at these bytes — the ruleset's last-changed time.
  - `claim_count`: integer | null (required)
  - `compiles`: boolean (required) — False when the stored source no longer compiles under this engine, or its bytes are gone. The row is still returned — a listing a single unreadable entry could hide is worse than one that says so — and the counts are null.
  - `name`: string (required) — The primary handle.
  - `revision_depth`: integer (required)
  - `rule_count`: integer | null (required)
  - `ruleset_hash`: string (required)
  - `summary`: string (required) — One sentence: what this ruleset asks and what it can decide. Derived per row from the manifest, never stored beside it.
- `versions`: object (required) — Which engine and which wire contract produced this response.
  - `engine`: string (required)
  - `engine_version`: string (required)
  - `language_version`: string (required) — DSAIL language version.
  - `service_version`: string (required)
  - `supported_language_versions`: array
  - `wire_version`: string (required)

## `POST /v1/rulesets`

Store a named revision of a ruleset

Request body:

- `label`: any — Optional application-domain label from YOUR model (TJP-642): {domain: <a level-one id from GET /v1/vocabulary>, topic: <a short free-text level-two term>, confidence: high|medium|low, declined: bool}. Inert — it never changes a result. Stored and reported as ids only; the topic string is matched against the vocabulary and then dropped. Off-list domains are refused. Omit it, or send {declined: true}, to not label.
- `name`: string (required)
- `parent_hash`: any
- `source`: string (required)

Response `200`:

Response `400`: the error envelope.

Response `404`: the error envelope.

Response `413`: the error envelope.

Response `422`: the error envelope.

## `GET /v1/rulesets/{name}`

Load a named ruleset with its full contract, revision chain and approvals

Response `200`:

A stored ruleset, in the shape a compile of it would return plus what the store knows about it. This is how a saved ruleset is SHOWN — re-compiling remembered source produces a different object the moment the two disagree, and an approval follows the stored bytes.

- `approvals`: array (required)
  - `approved_at`: string (required) — UTC, ISO 8601.
  - `approver`: string (required)
  - `hash`: string (required) — The exact bytes signed for. An approval follows the hash, never a name: a later revision is not covered by it.
  - `note`: string | null
- `claim_schema`: object — JSON Schema for the claim dictionary.
- `diagnostics`: array
  - `line`: integer | null
  - `message`: string (required)
  - `severity`: "error" | "warning" (required)
- `label`: object | null — The ruleset's stored application-domain label (TJP-642), as ids under `vocabulary_version`. Null when the ruleset carries none, or when this account has labeling disabled. A label never alters a result; the level-two proposal text a caller sent is matched and dropped, never stored or returned.
  - `confidence`: "high" | "medium" | "low" | null (required)
  - `declined`: boolean (required)
  - `level_one`: "finance" | "consumer_finance" | "capital_markets" | "insurance" | "regulatory_compliance" | "hr_workforce" | "security_access" | "security_classification" | "healthcare" | "legal_contracts" | "procurement" | "engineering_release" | "content_safety" | "other" | null (required) — Level-one domain id. Null only when declined.
  - `level_two`: string | null (required) — Level-two term id, from GET /v1/vocabulary. Null when the proposal matched no published term (the proposal was counted toward promotion instead) or none was offered.
  - `updated_at`: string (required) — UTC, ISO 8601.
  - `vocabulary_version`: string (required)
- `manifest`: object (required)
  - `claims`: array (required)
    - `boolean_subtype`: string
    - `claim`: string (required)
    - `context`: string
    - `data_type`: "boolean" | "numeric" | "enum" (required)
    - `ordered`: boolean
    - `question`: string (required) — Shown to the extracting model.
    - `range`: object
      - `max`: number
      - `min`: number
    - `required`: boolean (required)
    - `unit`: string | null
    - `unknown_allowed`: boolean (required)
    - `unknown_sentinel`: string — Present only when this claim's own vocabulary contains a member spelled like the sentinel. Then the string means that member and this names the value that means undetermined (null).
    - `vocabulary`: array
  - `rules`: array (required)
    - `assertions`: array (required)
      - `line`: integer | null
      - `name`: string (required)
      - `source`: string | null
      - `unknown_policy`: "optimistic" | "pessimistic" | "neutral" (required)
    - `rule`: string (required)
  - `ruleset_hash`: string (required)
- `name`: string (required) — The name that was asked for.
- `namespace`: string (required) — Service-internal scope identifier. For clients, not for display: never show this to a person, who identifies a ruleset by name.
- `ok`: boolean (required)
- `review`: string — A plain-text rendering of what this ruleset asks and decides, for a person about to approve it. Derived from the manifest on every compile, never stored, so it cannot drift from the contract a caller was handed.
- `revision_chain`: array (required) — This hash, then its parent, back to the root.
- `ruleset_hash`: string (required) — sha256 of the normalised source. This is the object key.
- `source`: string (required) — The normalised DSAIL source that hashed to `ruleset_hash`, so a caller that only ever compiles has something to show or diff without a separate load-by-name call.
- `stored`: object
  - `parent_hash`: string | null
  - `revision_depth`: integer
- `summary`: string — The same thing in one sentence, for a row in a list rather than a page a person reads.
- `unbridged_units`: array — Unit pairs this ruleset compares that no loaded converter bridges, attributed by the engine to the rule that cannot be lowered. Each one answers UNKNOWN for every claim dictionary until a converter is added.
  - `cause`: "missing" | "ambiguous" (required)
  - `from`: string (required)
  - `rule`: string (required)
  - `to`: string (required)
- `unit_library_hash`: string | null — The project unit library this compile read. Half of a result's provenance; null selects the six built-in standards.
- `validation_contract`: object — Exactly what check will reject, known before submitting.
- `versions`: object (required) — Which engine and which wire contract produced this response.
  - `engine`: string (required)
  - `engine_version`: string (required)
  - `language_version`: string (required) — DSAIL language version.
  - `service_version`: string (required)
  - `supported_language_versions`: array
  - `wire_version`: string (required)

Response `400`: the error envelope.

Response `404`: the error envelope.

Response `422`: the error envelope.

## `GET /v1/units`

Which unit standards are loaded and what this project added

Response `200`:

## `GET /v1/units/bridge`

Whether one unit converts to another, and by what factor

Response `200`:

Response `400`: the error envelope.

## `POST /v1/units/converters`

Add a converter to this project's unit library

Request body:

- `attribution`: any — Where this figure came from. Recorded alongside the edit; deliberately not part of the library hash.
- `factor`: number (required) — to = from * factor + offset. Required, and never inferred: a rate is a policy decision, so it is supplied by a person.
- `from_unit`: string (required) — The unit being converted FROM.
- `offset`: number — Affine offset; 0 for every scale but temperature.
- `to_unit`: string (required) — The unit being converted TO.

Response `200`:

Response `400`: the error envelope.

Response `413`: the error envelope.

## `GET /v1/vocabulary`

The application-domain vocabulary: level one, level-two terms with provenance, version history, K and the promotion rule (TJP-642)

Response `200`:

The application-domain vocabulary as a machine-readable, versioned document. Level one is closed and published in full; level two lists every term that is currently in the vocabulary, with its provenance (seeded for cold start, or promoted by K distinct external accounts). Unpromoted proposals are not here — they are counts, not vocabulary.

- `confidence_buckets`: array
- `counts`: object
- `description`: string | null
- `level_one`: array (required)
  - `description`: string
  - `id`: string (required)
  - `name`: string (required)
- `level_two`: array (required)
  - `aliases`: array
  - `id`: string (required)
  - `promoted_at`: string | null
  - `provenance`: "seeded" | "promoted" (required)
  - `since_version`: string (required)
  - `term`: string (required)
- `ok`: boolean (required)
- `promotion`: object (required)
  - `k`: integer (required) — Distinct external accounts that must independently propose a term before it is published.
  - `proposal_ttl_days`: integer (required)
  - `rule`: string (required)
- `published_at`: string | null
- `version`: string (required)
- `version_history`: array (required)
- `versions`: object (required) — Which engine and which wire contract produced this response.
  - `engine`: string (required)
  - `engine_version`: string (required)
  - `language_version`: string (required) — DSAIL language version.
  - `service_version`: string (required)
  - `supported_language_versions`: array
  - `wire_version`: string (required)

## `GET /version`

Version

Response `200`:
