Build on a deterministic API

An API that gives the same answer twice

APODEXA is a REST API for validating and normalizing finance files. It's rule-based, so a request is reproducible — the same input returns the same output and the same output_hash.

What you get

Quickstart — from key to first 200

Create an API key in the dashboard (Settings → API keys — the free plan includes a sandbox key), then validate a bank statement. The sample file below contains fictional data, published for illustration only.

# 1) Download the sample statement (fictional data)
curl -sO https://apodexa.net/assets/sample/sample-statement.csv

# 2) Validate it (multipart upload; paste your key)
curl -s -X POST https://apodexa.net/api/v1/normalize_bank_csv \
  -H "Authorization: Bearer apdx_YOUR_KEY" \
  -F "file=@sample-statement.csv"

A successful response is the standard envelope. Trimmed to the fields most callers branch on:

{
  "data": { "currency": "USD", "row_count": 5, "rows": [ … ] },
  "validation": { "passed": true,
                  "checks": [ { "name": "running_balance_consistent", "passed": true }, … ] },
  "provenance": { "parser": "normalize_bank_csv", "transformations": [ … ] },
  "uncertain_fields": [],
  "decision": "ACCEPTED",
  "output_hash": "4acb65733e124eae0d1147785fe7be075b2a67ed42f69fe548830780403ef7d4"
}

Run it twice: the output_hash is identical, because the pipeline is deterministic. Optional form fields (locale, currency, date_format, column_mapping, template_id) are documented at /docs.

Determinism matters most when the answer is no. This second sample (also fictional) has a genuine D/M-vs-M/D conflict on every date — instead of silently guessing, the pipeline refuses to pick and returns decision: "NEEDS_REVIEW":

# 3) Download the ambiguous-dates sample (fictional data)
curl -sO https://apodexa.net/assets/sample/sample-ambiguous-dates.csv

# 4) Validate it — a deterministic refusal, not a guess
curl -s -X POST https://apodexa.net/api/v1/normalize_bank_csv \
  -H "Authorization: Bearer apdx_YOUR_KEY" \
  -F "file=@sample-ambiguous-dates.csv"

Trimmed response — the failing check, the uncertain field and the repair path are all machine-readable:

{
  "data": { "currency": "USD", "row_count": 4, "rows": [ … ] },
  "validation": { "passed": false,
                  "checks": [ …, { "name": "dates_unambiguous", "passed": false,
                                   "detail": "ambiguous dd/mm vs mm/dd" } ] },
  "uncertain_fields": [ "transaction_date" ],
  "repair_suggestions": [ "Ambiguous dates detected; supply locale or date_format (DMY/MDY) to resolve." ],
  "decision": "NEEDS_REVIEW",
  "output_hash": "ca79b0b53bb518918820c160b189c748dad2629f19b76d8d1ced44bda1ab3b76"
}

The refusal is reproducible too — every retry returns the same output_hash. Resolve it by re-sending the same file with date_format=DMY (or MDY): the run then returns ACCEPTED.

Read the reference

Interactive docs, or the raw schema for code generation.