API Docs Back

Theoremic API

The Theoremic API is a deterministic reasoning engine for mathematical intelligence. Send algebraic work or entity data via HTTP POST and receive a structured decision, confidence score, and auditable proof trace.

The engine is AST-based and non-probabilistic. It parses algebraic work into a structural tree, runs misconception checks against that tree, and applies forward-chaining inference over a concept knowledge graph. It does not use a language model to produce its output. Every decision is fully inspectable via the proof trace.

https://theoremic.io/v1/

Authentication

All API requests require a Bearer token in the Authorization header. Requests without a valid key return 401 Unauthorized.

Demo API Key — use this to test the API
th_demo_4f8a2c1b9e6d3a7f
This key is public and intended for evaluation only. Do not use in production.
HTTP Header
Authorization: Bearer th_demo_4f8a2c1b9e6d3a7f

POST /v1/algebra_reason

Analyzes algebraic working for misconceptions. Returns a decision, confidence score, detected concepts, and a proof trace showing which misconception checks fired.

POST https://theoremic.io/v1/algebra_reason

Request body

FieldTypeDescription
stepsstring[]Array of algebraic steps, one per element. Either steps or text is required.
textstringRaw algebraic work as a single string with steps separated by newlines.
config.thresholdfloatOptional. Minimum misconception score to trigger detection. Default: 0.30.

Response

FieldTypeDescription
decisionstringMISCONCEPTION_DETECTED | CORRECT | INCOMPLETE | INSUFFICIENT_DATA
confidencefloatConfidence score 0–1.
misconception_signalsstring[]Signal IDs that fired. Empty if no misconceptions detected.
concepts_detectedobject[]Algebra concepts identified in the work. Each entry: { id, label }.
prerequisite_gapsstring[]Concept IDs the student likely hasn't mastered, traced through the knowledge graph.
guidanceobject[]Remediation for each fired signal — signal, title, description, correct_rule, example_wrong, example_right.
proof_traceobject[]All checks run. Each entry: { check, passed, detail }.
metadataobjectEngine version, steps parsed, steps failed, parse errors, processing time.

Code examples

curl -X POST https://theoremic.io/v1/algebra_reason \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer th_demo_4f8a2c1b9e6d3a7f" \
  -d '{
    "steps": [
      "(x + 3)^2",
      "= x^2 + 9"
    ]
  }'
import requests

response = requests.post(
    "https://theoremic.io/v1/algebra_reason",
    json={
        "steps": [
            "(x + 3)^2",
            "= x^2 + 9"
        ]
    },
    headers={
        "Authorization": "Bearer th_demo_4f8a2c1b9e6d3a7f"
    }
)

result = response.json()

print(result["decision"])      # MISCONCEPTION_DETECTED
print(result["confidence"])    # 0.70

for g in result["guidance"]:
    print(g["title"])
    print(g["description"])
    print("Correct rule:", g["correct_rule"])
    print("Wrong:  ", g["example_wrong"])
    print("Right:  ", g["example_right"])
const response = await fetch("https://theoremic.io/v1/algebra_reason", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "Authorization": "Bearer th_demo_4f8a2c1b9e6d3a7f"
    },
    body: JSON.stringify({
        steps: [
            "(x + 3)^2",
            "= x^2 + 9"
        ]
    })
});

const result = await response.json();

if (result.decision === "MISCONCEPTION_DETECTED") {
    for (const g of result.guidance) {
        console.log(g.title);
        console.log(g.description);
        console.log("Rule:", g.correct_rule);
        console.log("Wrong:", g.example_wrong);
        console.log("Right:", g.example_right);
    }
}
$response = file_get_contents("https://theoremic.io/v1/algebra_reason", false,
    stream_context_create([
        "http" => [
            "method"  => "POST",
            "header"  => implode("\r\n", [
                "Content-Type: application/json",
                "Authorization: Bearer th_demo_4f8a2c1b9e6d3a7f",
            ]),
            "content" => json_encode([
                "steps" => [
                    "(x + 3)^2",
                    "= x^2 + 9",
                ]
            ])
        ]
    ])
);

$result = json_decode($response, true);
echo $result["decision"];    // MISCONCEPTION_DETECTED
echo $result["confidence"];  // 0.85

foreach ($result["guidance"] as $g) {
    echo $g["title"] . "\n";
    echo $g["correct_rule"] . "\n";
}

Example response

JSON
{
  "decision": "MISCONCEPTION_DETECTED",
  "confidence": 0.70,
  "misconception_signals": ["exponent_linearity_error"],
  "concepts_detected": [
    { "id": "exponent_rules",        "label": "Exponent Rules" },
    { "id": "expression",            "label": "Algebraic Expression" },
    { "id": "variable",              "label": "Variable" },
    { "id": "order_of_operations",   "label": "Order of Operations" }
  ],
  "prerequisite_gaps": ["exponent_rules", "distributive_property"],
  "guidance": [
    {
      "signal":        "exponent_linearity_error",
      "title":         "Exponent Linearity Error",
      "description":   "Distributing an exponent over addition: (a+b)^n ≠ a^n + b^n.",
      "correct_rule":  "(a + b)^2 = a^2 + 2ab + b^2  (FOIL or binomial expansion)",
      "example_wrong": "(x + 3)^2 = x^2 + 9",
      "example_right": "(x + 3)^2 = x^2 + 6x + 9",
      "prerequisites": ["exponent_rules", "distributive_property"]
    }
  ],
  "proof_trace": [
    { "check": "parse:(x + 3)^2 = x^2 + 9", "passed": false, "detail": "Parse error — input stripped of label" },
    { "check": "rule:exponent_linearity",     "passed": false, "detail": "Fired — signal(s): exponent_linearity_error" },
    { "check": "inference",                   "passed": false, "detail": "1 misconception signal(s) detected: exponent_linearity_error" },
    { "check": "solution_detected",           "passed": false, "detail": "No step of the form x =  detected." }
  ],
  "metadata": {
    "engine":        "theoremic-structural-v2",
    "steps_parsed":  1,
    "steps_failed":  0,
    "processing_ms": 0.94
  }
}

POST /v1/entity_resolve

Resolves whether two entity records refer to the same real-world entity. Returns a decision, confidence score with a 95% confidence interval, and a field-by-field proof trace.

POST https://theoremic.io/v1/entity_resolve

Request body

FieldTypeDescription
entity_typestring"person" or "organization". Required.
entity_aobjectFirst entity record. Required.
entity_bobjectSecond entity record. Required.
config.match_thresholdfloatConfidence above which decision is MATCH. Default: 0.85.
config.uncertain_thresholdfloatConfidence above which decision is UNCERTAIN. Default: 0.60.

Person fields

FieldTypeNotes
full_namestringSupports initial expansion (J. Smith → John Smith)
date_of_birthstringAccepts multiple date formats: YYYY-MM-DD, MM/DD/YYYY, DD/MM/YYYY, etc.
addressstringNormalises abbreviations: St → Street, Ave → Avenue, etc.
id_numberstringNear-exact match required. Partial similarity is heavily discounted.
emailstringDomain mismatch penalised.
phonestringStrips formatting; local number match supported.

Organization fields

FieldTypeNotes
namestringStrips legal suffixes: Inc, Corp, LLC, Ltd, etc.
addressstringSame normalisation as person address.
tax_idstringNear-exact match required.
registration_numberstringNear-exact match required.

Code examples

curl -X POST https://theoremic.io/v1/entity_resolve \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer th_demo_4f8a2c1b9e6d3a7f" \
  -d '{
    "entity_type": "person",
    "entity_a": {
      "full_name": "J. Smith",
      "date_of_birth": "1985-03-12",
      "email": "john.smith@acme.com"
    },
    "entity_b": {
      "full_name": "John Smith",
      "date_of_birth": "12/03/1985",
      "email": "j.smith@acme.com"
    }
  }'
import requests

response = requests.post(
    "https://theoremic.io/v1/entity_resolve",
    json={
        "entity_type": "person",
        "entity_a": {
            "full_name":     "J. Smith",
            "date_of_birth": "1985-03-12",
            "email":         "john.smith@acme.com"
        },
        "entity_b": {
            "full_name":     "John Smith",
            "date_of_birth": "12/03/1985",
            "email":         "j.smith@acme.com"
        }
    },
    headers={
        "Authorization": "Bearer th_demo_4f8a2c1b9e6d3a7f"
    }
)

result = response.json()
print(result["decision"])             # MATCH
print(result["confidence"])           # 0.87
print(result["confidence_interval"])  # [0.79, 0.95]
const response = await fetch("https://theoremic.io/v1/entity_resolve", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "Authorization": "Bearer th_demo_4f8a2c1b9e6d3a7f"
    },
    body: JSON.stringify({
        entity_type: "person",
        entity_a: {
            full_name:     "J. Smith",
            date_of_birth: "1985-03-12",
            email:         "john.smith@acme.com"
        },
        entity_b: {
            full_name:     "John Smith",
            date_of_birth: "12/03/1985",
            email:         "j.smith@acme.com"
        }
    })
});

const result = await response.json();
console.log(result.decision);            // MATCH
console.log(result.confidence);          // 0.87
console.log(result.confidence_interval); // [0.79, 0.95]
$response = file_get_contents("https://theoremic.io/v1/entity_resolve", false,
    stream_context_create([
        "http" => [
            "method"  => "POST",
            "header"  => implode("\r\n", [
                "Content-Type: application/json",
                "Authorization: Bearer th_demo_4f8a2c1b9e6d3a7f",
            ]),
            "content" => json_encode([
                "entity_type" => "person",
                "entity_a"    => [
                    "full_name"     => "J. Smith",
                    "date_of_birth" => "1985-03-12",
                    "email"         => "john.smith@acme.com",
                ],
                "entity_b"    => [
                    "full_name"     => "John Smith",
                    "date_of_birth" => "12/03/1985",
                    "email"         => "j.smith@acme.com",
                ]
            ])
        ]
    ])
);

$result = json_decode($response, true);
echo $result["decision"];    // MATCH
echo $result["confidence"];  // 0.87

Decision values

algebra_reason

ValueMeaning
MISCONCEPTION_DETECTEDOne or more misconception checks fired.
CORRECTNo misconceptions detected and an explicit solution was found.
INCOMPLETEEquations found but no explicit solution reached.
INSUFFICIENT_DATAThe input was too short or contained no recognisable algebra.

entity_resolve

ValueMeaning
MATCHConfidence is at or above the match threshold (default 85%).
UNCERTAINConfidence is between the uncertain and match thresholds (default 60–85%).
NO_MATCHConfidence is below the uncertain threshold.

Misconception signals

Signal IDs returned in misconception_signals. Each fired signal has a corresponding entry in guidance.

SignalDescription
exponent_linearity_error(a+b)^n written as a^n + b^n — missing cross terms. E.g. (x+3)² = x²+9.
product_rule_errorx^a · x^b computed as x^(a·b) instead of x^(a+b).
addition_under_root_error√(a²+b²) simplified to a+b.
division_distribution_error(a+b)/c simplified with only one term divided. E.g. (x+6)/2 = x+3.
sign_error_distribution-(a+b) written as -a+b instead of -a-b.
variable_absorption_errorConstant absorbed into coefficient. E.g. 2x+3 written as 5x.
pemdas_errorNumeric expression evaluated left-to-right ignoring operator precedence.
absolute_value_error|expr| = k solved with only one solution — missing the negative case.

Error codes

200Success. Response body contains the reasoning result.
400Bad request. Missing or malformed JSON body, or required fields absent.
401Unauthorized. Missing or invalid API key in the Authorization header.
405Method not allowed. Only POST requests are accepted.

Error response shape

JSON
{
  "error": "Unauthorized. Provide a valid API key in the Authorization header.",
  "hint":  "Authorization: Bearer YOUR_API_KEY",
  "docs":  "https://theoremic.io/docs"
}