eu-complyv1

For external & API users

API documentation

Everything you need to submit invoices to InvGuard, retrieve fraud decisions, and independently verify that a decision and its compliance record were not altered after the fact.

Overview

The Compliance Toolkit API exposes three capabilities behind one REST surface: score an invoice (InvGuard), verify a decision's cryptographic anchor (rify-AI), and generate EU AI Act artifacts (the Compliance Toolkit). Every response is JSON. All write operations are anchored and persisted, so the decision trail is durable and auditable.

Base URL & environments

All endpoints are versioned under /api/v1.

textProduction   https://api.compliant.eu/api/v1
Staging      https://staging.api.compliant.eu/api/v1
Local        http://127.0.0.1:8000/api/v1

Health probes live at the root: GET /health (liveness) andGET /health/ready (readiness, checks the database).

Authentication

Read endpoints are public. Write endpoints (POST /api/v1/decisions) require an API key when the deployment is configured with one. Send it in thex-api-key header. Keys are issued per integrator; treat them as secrets and never expose them in browser code.

bashcurl -X POST https://api.compliant.eu/api/v1/decisions \
  -H "x-api-key: $COMPLIANT_API_KEY" \
  -H "content-type: application/json" \
  -d @invoice.json

Rate limits

Requests are limited per client IP using a fixed window (default 120 requests / 60s). When exceeded you receive 429 Too Many Requests with a Retry-Afterheader (seconds). Health probes are exempt.

Errors

All errors share a stable envelope. Branch on code, not on prose.

json{
  "error": {
    "code": "not_found",
    "message": "Decision 'dec_123' not found.",
    "request_id": "9f2c…"
  }
}
  • validation_error — 422, request body failed schema validation (see details).
  • unauthorized — 401, missing or invalid API key.
  • not_found — 404, unknown decision id.
  • rate_limited — 429, back off and retry after Retry-After.
  • internal_error — 500, transient; the request_id ties it to our logs.

Every response also returns an x-request-id header — include it in support requests.

Decisions

POST/api/v1/decisions
Submit an invoice. Returns the scored decision, its explanation, and the rify-AI anchor.
json// request body
{
  "invoice_id": "INV-2026-001",
  "vendor_id": "vendor-acme",
  "buyer_id": "buyer-eu-payments",
  "amount": 18450.0,
  "currency": "EUR",
  "invoice_date": "2026-07-20",
  "due_date": "2026-08-19",
  "bank_account": "DE89370400440532013000",
  "vendor_region": "DE",
  "company_size": "sme"
}
json// 201 Created (truncated)
{
  "decision_id": "dec_a1b2c3…",
  "invoice_id": "INV-2026-001",
  "model_version": "invguard-heuristic-v1",
  "score": 0.35,
  "risk_level": "medium",
  "decision": "review",
  "explanation": {
    "summary": "Invoice scored medium risk by InvGuard v1 heuristics.",
    "rule_triggers": [
      { "code": "HIGH_VALUE_INVOICE", "description": "…", "weight": 0.35 }
    ],
    "feature_contributions": { "amount": 0.369, "payment_timing": 0.0 }
  },
  "input_hash": "…",
  "proof": {
    "commitment_hash": "…",
    "payload_signature": "sig-…",
    "ipfs_cid": "bafy…",
    "chain_network": "local-testnet",
    "transaction_hash": "0x…",
    "anchored_at": "2026-07-20T10:00:00Z"
  }
}

Field notes: amount > 0, currency is a 3-letter code, dates are ISO YYYY-MM-DD, company_size ∈ {micro, sme, mid_market, enterprise}.

GET/api/v1/decisions?limit={1-200}&offset={n}
Paginated list, newest first. Returns { items, total, limit, offset }.
GET/api/v1/decisions/{decision_id}
Fetch a single decision record.

Verification

GET/api/v1/decisions/{decision_id}/verification
Re-derive the commitment from the anchored content and check the signature.

The status field is one of:

  • valid — content hash matches the commitment and the signature verifies.
  • tampered — the anchored content no longer hashes to the recorded commitment.
  • signature_invalid — commitment is intact but the signature does not verify.
  • unanchored — the decision has no anchor proof.

Compliance reports

GET/api/v1/compliance/model-card
Templated model card generated from live pipeline metadata.
GET/api/v1/compliance/bias-report
Demographic-style parity metrics over labeled proxy attributes.
GET/api/v1/compliance/audit-report
Combined artifact (model card + bias report + sample verified decisions).

Verifying a decision independently

You do not have to trust our verification endpoint. The commitment is a SHA-256 over a canonical JSON serialization (sorted keys, no insignificant whitespace) of the committed fields. Given the anchored content, anyone can reproduce the hash:

pythonimport hashlib, json

# 'content' is the anchored canonical JSON string for the decision.
commitment = hashlib.sha256(content.encode("utf-8")).hexdigest()
assert commitment == proof["commitment_hash"]  # integrity holds

In production the anchored content lives on IPFS (addressed by ipfs_cid) and the commitment is recorded on-chain (transaction_hash), so verification does not depend on our database.