Skip to main content
Use the REST API when you’re building your own backend, dashboard, or custom workflow — a lending application that calls /decide on every form submission, a compliance portal that displays current rule explanations, or a custom authoring pipeline. Base URL: https://api.aethis.ai/api/v1/public/ Decision endpoints (no auth required) are safe to call client-side from a browser or mobile app.
Authoring endpoints require an x-api-key header and should be called from your server.

Authentication

x-api-key: ak_live_...
Get an API key: sign up Omitting the header on decision endpoints works fine. Including it on decision endpoints is also fine — it’s ignored.

Scopes

API keys carry a set of scopes. Each authoring endpoint requires a specific scope; a key without that scope receives 403 Forbidden.
ScopeGrants
decidePOST /decide on private rulesets
rulesets:readGET /rulesets, GET /rulesets/{id}/schema
rulesets:explainGET /rulesets/{id}/explain, POST /rulesets/{id}/explain-failure
rulesets:sourceGET /rulesets/{id}/source (DSL export)
rulesets:writePATCH /rulesets/{id}/visibility, POST /rulesets/{id}/archive
projects:readGET /projects, /status, /guidance list/export
projects:writeAll project authoring: sources, tests, guidance, field/section discovery, generate, publish
rulebooks:readGET /rulebooks (your tenant’s listing), /schema, /explain, /graph
rulebooks:writeRulebook CRUD, /activate, /archive, PATCH /rulebooks/{id}/visibility
Decision endpoints (/decide, /schema, /explain on public rulesets) require no scope and accept anonymous requests. GET /rulebooks/ also accepts anonymous requests: without a key it returns the cross-tenant public catalogue (rulebooks with visibility=public and status=active); with a key it returns your tenant’s rulebooks as before.
Rulebook lookups and decisions require an API key. Anonymous /decide resolves a ruleset_id or ruleset slug against public rulesets only. The separate rulebook_id field (for composed multi-section rulebooks like aethis/uk-fsm) is always scope-gated — anonymous callers get a 401. Anonymous access to rulebooks is limited to the GET /rulebooks/ catalogue listing; to evaluate one, hit each section by slug instead, or pass an x-api-key header with a key that has the decide scope. See Nomenclature for the full distinction.

Rate-limit tiers

Keys are assigned a daily-quota tier. Counters reset at UTC midnight. A 429 is returned with Retry-After: 86400.
Tier/decide/rulesets/*/projects/*
Anonymous (no key)500/day per IP500/day per IP
free500500500
starter10,000500100
pro100,0005,000500
Tier is set at key creation and can be changed by contacting support. Contact support@aethis.ai to upgrade.

Decision envelope

Every /decide response includes audit fields (decision_id, inputs_hash, engine_version, ruleset_version) for reproducible replay without the server echoing your inputs. See Decision envelope → for the full contract.

Evaluate eligibility

No API key required.
curl -X POST https://api.aethis.ai/api/v1/public/decide \
  -H "Content-Type: application/json" \
  -d '{
    "ruleset_id": "aethis/uk-fsm/child-eligibility",
    "field_values": {
      "child.age": 10,
      "child.school_type": "state_funded"
    },
    "include_trace": true
  }'
{
  "decision": "eligible",
  "fields_provided": 2,
  "fields_evaluated": 2,
  "trace": {
    "age_check": "PASS — age 10 is within 4–15 (Regulation 3)",
    "school_type_check": "PASS — school type is state_funded (Section 512ZA)"
  }
}
Parameters:
  • ruleset_id — the published ruleset to evaluate against
  • field_values — map of field names to values (types must match the ruleset schema)
  • include_trace (optional) — when true, returns a trace object showing how each criterion was evaluated and the source clause it references
  • include_explanation (optional) — when true, returns a structured explanation object: gate-level checklist (groups[].criteria[].status), the supporting facts that proved each satisfied criterion (supporting_facts), the satisfied requirement name (decision_path), and any provided fields the ruleset never references (unused_facts — useful for catching field-name typos). See Debug a /decide for the full payload shape.
Decisions:
  • eligible — all criteria satisfied
  • not_eligible — one or more criteria failed
  • undetermined — the engine could not reach a decision (missing field, discretionary clause, or case outside compiled rules)

Inspect a ruleset

# Get the field schema — what fields does this ruleset expect?
curl https://api.aethis.ai/api/v1/public/rulesets/aethis/uk-fsm/child-eligibility/schema
{
  "ruleset_id": "aethis/uk-fsm/child-eligibility",
  "slug": "aethis/uk-fsm/child-eligibility",
  "name": "UK FSM Child Eligibility",
  "fields": [
    {
      "field_id": "child.age",
      "field_type": "int",
      "description": "Child's age in whole years at start of academic year",
      "question": "How old will the child be on 1 September of the relevant academic year?",
      "weight": 1,
      "enum_values": null,
      "notes": [
        {
          "note_text": "WHY: Compulsory-school-age status — and therefore FSM eligibility — is determined by age on 1 September.",
          "source": "DfE Free School Meals: guidance for local authorities",
          "metadata": { "type": "why", "section": "child_eligibility" }
        }
      ]
    },
    {
      "field_id": "child.school_type",
      "field_type": "enum",
      "description": "Type of school the child attends",
      "weight": 2,
      "enum_values": ["state_funded", "independent", "home_educated"],
      "notes": []
    }
  ]
}
notes (each FieldNoteOut: { note_text, source, metadata }) is the structured guidance the ruleset author attached during /fields/discover. Conversational front-ends (e.g. a paralegal bot) typically render metadata.type='why' notes when the user asks “why are you asking this?” and draw on metadata.type='legal_background' notes for edge-case follow-ups. Older bundles return "notes": [] — treat the array as optional. weight is the question-ordering hint used by the constraint solver (higher = less preferred to ask). Used by /decide’s optimal_path to surface cheap questions before expensive ones when multiple ways to satisfy the ruleset exist.
# Get human-readable rule descriptions
curl https://api.aethis.ai/api/v1/public/rulesets/aethis/uk-fsm/child-eligibility/explain

Author rules

Authoring is invite-only private beta (request access). API key required; do all authoring server-side. Pass an X-Anthropic-Key header on generation requests — used for that request only, never stored.

Step 1 — Create a project

curl -X POST https://api.aethis.ai/api/v1/public/projects/ \
  -H "Content-Type: application/json" \
  -H "x-api-key: ak_live_..." \
  -d '{
    "name": "Income eligibility check",
    "section_id": "income_eligibility",
    "source_text": "Section 3: An applicant qualifies if annual net income is below £30,000...",
    "test_cases": [
      { "name": "Below threshold", "field_values": { "applicant.annual_income": 25000 }, "expected_outcome": "eligible" },
      { "name": "Above threshold", "field_values": { "applicant.annual_income": 35000 }, "expected_outcome": "not_eligible" }
    ]
  }'
{ "project_id": "proj_abc123" }

Step 2 — Generate and test

curl -X POST https://api.aethis.ai/api/v1/public/projects/proj_abc123/generate-and-test \
  -H "x-api-key: ak_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "anthropic_key": "sk-ant-..." }'
{
  "ruleset_id": "income_eligibility:20260416-a1b2c3d4",
  "tests_passing": 2,
  "tests_total": 2,
  "failures": []
}
If tests are failing:
{
  "ruleset_id": "income_eligibility:20260416-a1b2c3d4",
  "tests_passing": 1,
  "tests_total": 2,
  "failures": [
    {
      "name": "At exact threshold",
      "expected": "eligible",
      "got": "not_eligible",
      "hint": "The threshold condition may be using strict < rather than ≤"
    }
  ]
}
Add guidance and regenerate:
curl -X POST https://api.aethis.ai/api/v1/public/projects/proj_abc123/guidance \
  -H "x-api-key: ak_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "guidance_text": "The £30,000 threshold is inclusive — use ≤ not <.",
    "process_type": "rule_generation"
  }'
Then repeat generate-and-test.

Incremental refine (minimal edit)

Both generate and generate-and-test accept an optional mode body. mode: "refine" seeds generation from the section’s active ruleset and makes the minimal edit to fix failing tests, instead of re-authoring the section from scratch. Omitting the body (or mode: "fresh") is the default from-scratch behaviour.
curl -X POST https://api.aethis.ai/api/v1/public/projects/proj_abc123/generate-and-test \
  -H "x-api-key: ak_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "anthropic_key": "sk-ant-...", "mode": "refine" }'
seed_ruleset_id may be supplied to refine from a specific ruleset; when omitted, the section’s active ruleset is used.

Step 3 — Publish

curl -X POST https://api.aethis.ai/api/v1/public/projects/proj_abc123/publish \
  -H "x-api-key: ak_live_..."
{
  "ruleset_id": "income_eligibility:20260416-b2c3d4e5",
  "version": "v2",
  "tests_passing": 2,
  "tests_total": 2
}
Now evaluate with /decide using the returned ruleset_id.

Error responses

CodeMeaning
200OK
201Created (project or ruleset)
202Accepted — generation queued, poll /status
422Validation error — wrong field type, missing required field, or invalid ruleset ID
429Rate limit exceeded
404Ruleset or project not found
422 detail format:
{
  "detail": [
    {
      "loc": ["body", "field_values", "child.age"],
      "msg": "Expected an integer, got str",
      "type": "type_error.integer"
    }
  ]
}
429 with rate limit headers:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1714000000

{ "error": "rate_limit_exceeded", "retry_after": 1714000000 }
Date fields take an ISO "YYYY-MM-DD" string or an integer ordinal on ruleset evaluations (ISO accepted since engine 0.31.0). Rulebook evaluations (rulebook_id) still require ordinals. See Date field values.

Full endpoint reference

All endpoints with schemas, parameter details, and example responses: API Reference →
Help improve this pageIf something here is unclear or missing an example, use the feedback button at the bottom of the page.Found a bug? Open a GitHub issue. Evaluating Aethis for a regulated workflow? Contact us directly.