Integration · API

API and event reference

The whole integration reduces to one idea: you send claim events, we return an obligation position and any reconciliation findings, each carrying the source pages it came from. The event vocabulary below is not aspirational - it is extracted from the rules the engine actually ships.

Build status

Read this before you plan against anything below.

ComponentStatusWhere to verify
Obligation engine (Clockwork)Built - 142 rules, 6 marketsengine/clockwork.js, engine/rules/*
Event vocabularyBuilt - 84 eventsExtracted from the shipped rules; listed below
Integrity detectors (Signal)Built - 5 detectorsengine/integrity.js, examination demo
Coverage assessmentBuilt - 7 checksengine/policy.js
Compliance reports (Ledger)Builtengine/report.js
Entitlement engineBuilt - 6 schemesengine/benefits.js, entitlement demo
Decision sufficiencyBuilt - 5 decisionsengine/sufficiency.js, decision demo
Composite assessmentBuilt - 8 interactionsengine/composite.js
Document understanding (Casefile)SpecifiedDemo runs against structured fixtures, not live OCR
REST API and webhooksSpecifiedThis page

Shape of the integration

There is no batch file, no nightly extract and no replication of your claims database. Three flows carry everything:

1

You post claim events as they happen

A claim was lodged. A decision was notified. A complaint was received. One small JSON object per event, from whatever system already knows.

2

You post documents, or point us at them

Either upload bytes or hand us a pre-signed URL from your existing content store. Documents stay classified, extracted and anchored; the originals remain yours.

3

We return positions, findings and reports

Pull them when you want them, or receive a webhook when something changes. Every answer is a pure function of the events and documents you sent, so it can be recomputed and replayed.

Authentication

Server-to-server only. There is no browser-callable key, because a key that can read claim documents has no business in a browser.

MethodUseNotes
OAuth 2.0 client credentialsDefaultShort-lived bearer token, scoped per environment. Rotate the client secret without downtime.
mTLSOn requestWhere your security team requires certificate-pinned transport in addition to bearer auth.
Private connectivityOn requestAWS PrivateLink into ap-southeast-2 where traffic must not traverse the public internet.

Scopes

Scopes are separated so an ingestion service cannot read documents back out.

events:writedocuments:writepositions:read findings:readreports:readrules:readrules:admin
# Exchange client credentials for a token
curl -X POST https://api.intactly.ai/oauth/token \
  -d grant_type=client_credentials \
  -d client_id=$INTACTLY_CLIENT_ID \
  -d client_secret=$INTACTLY_CLIENT_SECRET \
  -d scope="events:write positions:read"

Endpoints

Base URL https://api.intactly.ai/v1. Australian tenants resolve to ap-southeast-2 and data does not leave it - see data residency.

MethodPathPurposeScope
POST/claims/{claimId}/eventsAppend one or more claim eventsevents:write
POST/claims/{claimId}/documentsAttach a document by upload or URLdocuments:write
GET/claims/{claimId}/positionObligation position as at a datepositions:read
GET/claims/{claimId}/findingsReconciliation findings with anchorsfindings:read
GET/claims/{claimId}/coverageCoverage assessment against the productpositions:read
GET/claims/{claimId}/reportCompliance report, JSON or textreports:read
GET/claims/{claimId}/entitlementWeekly benefit schedule with the arithmeticpositions:read
POST/claims/{claimId}/entitlement/reconcileEntitlement against payment historypositions:read
GET/claims/{claimId}/sufficiencyWhether the file supports a named decisionpositions:read
GET/claims/{claimId}/compositeEvery engine, plus the interactions between thempositions:read
GET/portfolio/positionRanked work queue across claimspositions:read
GET/portfolio/reportPortfolio compliance reportreports:read
GET/rulesActive rule set and its fingerprintrules:read
POST/rules/draftDraft a rule from a prompt for human reviewrules:admin
GET/documents/{documentId}Document classification and extracted factsdocuments:write

Event vocabulary

84 events, extracted from the obligation rules that ship today. An event either starts an obligation clock, discharges one, or both - and the marker beside each name says which. Anything not in this list is accepted and stored, but no rule currently reads it.

Claim lifecycle (31)

claim.acknowledgeddischarges
claim.clock.startstarts
claim.compliance.respondedstarts / discharges
claim.decidedstarts / discharges
claim.decision.notifieddischarges
claim.decision.pending.approvalstarts
claim.delay.notifiedstarts / discharges
claim.denial.reasons.sentdischarges
claim.deniedstarts / discharges
claim.determineddischarges
claim.fourmonth.notice.sentdischarges
claim.info.completestarts / discharges
claim.info.requestedstarts / discharges
claim.lodgedstarts
claim.progress.updateddischarges
claim.receivedstarts
claim.resolveddischarges
claim.twelvemonth.notice.sentdischarges
claim.withdrawndischarges
damages.claim.lodgedstarts
damages.liability.respondeddischarges
injury.notifiedstarts
interim.benefits.commenceddischarges
liability.declineddischarges
liability.determinedstarts / discharges
liability.dispute.referreddischarges
payments.commencedstarts / discharges
policy.cancelledstarts
recovery.on.holddischarges
refund.paiddischarges
threshold.injury.determineddischarges

Information and evidence (12)

assessor.appointedstarts
assessor.appointment.notifieddischarges
cash.settlement.info.provideddischarges
cash.settlement.offeredstarts
expert.delay.notifieddischarges
expert.engagedstarts / discharges
expert.report.receivedstarts / discharges
information.access.requestedstarts
information.provideddischarges
information.receivedstarts
information.requestedstarts
medical.examination.requestedstarts / discharges

Complaints and external dispute resolution (18)

afca.determination.acceptedstarts
afca.determination.complieddischarges
afca.referral.receivedstarts
afca.response.lodgeddischarges
complaint.acknowledgeddischarges
complaint.decidedstarts / discharges
complaint.delay.notifiedstarts / discharges
complaint.idr.response.sentstarts / discharges
complaint.information.requestedstarts
complaint.progress.updateddischarges
complaint.receivedstarts
complaint.resolvedstarts / discharges
complaint.written.response.sentdischarges
customer.enquiry.answereddischarges
customer.enquiry.receivedstarts
internal.review.completeddischarges
internal.review.requestedstarts
response.period.extendeddischarges

Vulnerability and hardship (8)

hardship.appliedstarts
hardship.decideddischarges
hardship.identifiedstarts
hardship.info.receivedstarts
hardship.info.requesteddischarges
vulnerability.identifiedstarts
vulnerability.referred.specialistdischarges
vulnerability.support.applieddischarges

Catastrophe (2)

catastrophe.claim.finalised.earlystarts
catastrophe.review.right.notifieddischarges

Governance and reporting (4)

reasonable.excuse.notifieddischarges
significant.breach.identifiedstarts
significant.breach.reporteddischarges
trustee.notifieddischarges

Other (9)

investigation.closeddischarges
investigation.commencedstarts
investigation.progress.updateddischarges
investigation.review.commencedstarts
investigation.review.completeddischarges
investigation.review.delay.notifieddischarges
investigation.revieweddischarges
investigator.appointedstarts
investigator.appointment.notifieddischarges

Posting events

An event is four fields. at is the date the thing happened, not the date you got around to telling us - obligations are computed from the former and a backdated event correctly recomputes the position.

POST /v1/claims/WC-NSW-2026-0912/events
Authorization: Bearer <token>
Idempotency-Key: "pas-evt-88401273"

{
  "events": [
    {
      "type": "claim.lodged",
      "at": "2026-08-05",
      "source": "guidewire.claimcenter",
      "sourceRef": "CC-4471902"
    },
    {
      "type": "liability.provisional.accepted",
      "at": "2026-08-11",
      "source": "guidewire.claimcenter"
    }
  ],
  "claim": {
    "productClass": "workers-compensation",
    "jurisdiction": "NSW"
  }
}

claim is optional after the first call and only carries the attributes that determine which rules apply - product class, jurisdiction, scheme. It is not a copy of your claim record and we do not want one.

Why the date matters more than it looks

Australian obligation clocks are a mixture of calendar days and business days, and business days differ by state. A five business day clock starting Friday 30 October 2026 falls due 6 November in NSW and 9 November in Victoria, because Victoria loses the Tuesday to the Melbourne Cup. The engine models eight jurisdictions including that case; you supply the jurisdiction and the date, and it handles the rest.

Reading a position

asOf is required and never defaults to today. A report generated for AFCA about a decision made in March must be computed as at March, and an API that quietly assumes "now" makes that mistake easy to make and impossible to notice.

GET /v1/claims/WC-NSW-2026-0912/position?asOf=2026-08-17

{
  "claimId": "WC-NSW-2026-0912",
  "asOf": "2026-08-17",
  "summary": {
    "breached": 0,
    "atRisk": 1,
    "open": 6,
    "discharged": 2,
    "horizonExposure": 3,
    "unverifiedRulesApplied": 9
  },
  "next": {
    "ruleId": "wc-nsw-provisional-liability",
    "obligation": "Commence provisional weekly payments",
    "status": "at-risk",
    "dueAt": "2026-08-18",
    "daysRemaining": 1,
    "triggeredBy": "injury.notified",
    "triggeredAt": "2026-08-04",
    "citation": "Workers Compensation Act 1987 (NSW) s 267",
    "verified": false
  },
  "obligations": [ /* every applicable rule, ranked */ ]
}

Two fields worth understanding

FieldWhat it means
horizonExposureObligations under instruments that have not commenced yet - the 2026 Code redraft, APP 1 automated-decision transparency from 10 December 2026. Counted separately and never reported as a live breach, because being non-compliant with a rule that does not yet bind you is not a breach. It is a plan.
verifiedEvery rule ships false. It flips to true only when a named person has checked that rule against the primary instrument and recorded it. We publish the count rather than hide it - see below.

Reading findings

A finding is a reconciliation, not an allegation. It names what does not line up, shows both source pages, decomposes into factors, and states the innocent explanations alongside the conflict. The response below is the actual output of examine() against two documents - not an illustration of one.

GET /v1/claims/MOT-2026-04417/findings

{
  "id": "MOT-2026-04417:temporal:D-4417-01:D-4417-02",
  "claimId": "MOT-2026-04417",
  "kind": "temporal",
  "summary": "Incident date differs by 3 days between two documents",
  "detail": "Motor claim form records 2026-05-24; Police event report records 2026-05-21.",
  "anchors": [
    { "documentId": "D-4417-01", "documentType": "Motor claim form",
      "page": 1, "quote": "24 May 2026", "region": null },
    { "documentId": "D-4417-02", "documentType": "Police event report",
      "page": 1, "quote": "21 May 2026", "region": null }
  ],
  "confidence": "probable",
  "factors": [
    { "name": "Date discrepancy", "value": "3 days" },
    { "name": "Sources", "value": "Motor claim form vs Police event report" },
    { "name": "Benign explanations",
      "value": "Late reporting, gradual-onset injury, or transcription error at intake" }
  ],
  "recommendation": "review",
  "decidedBy": null
}

recommendation is always "review". It is not a configurable field and there is no code path that sets it to anything else.

Finding kindWhat it reconciles
temporalDates that cannot all be true
capacityCertified restriction against recorded activity
quantumAmounts that do not reconcile
identityParty, vehicle or property identifiers that disagree
causationMechanism of injury or damage inconsistent across sources
coveragePolicy period, exclusion or endorsement conflict
duplicationThe same loss presented more than once
provenanceDocument integrity: metadata, alteration, template mismatch

Entitlement and decision sufficiency

The obligation engine answers when. Coverage answers whether. Two later engines answer the questions that sit either side of a decision.

How much

/entitlement returns the weekly benefit schedule for four schemes - NSW, Victorian and Queensland workers compensation, and NSW CTP - week by week, with the provision applied, the formula as written, the inputs substituted into it, and the indexed cap in force on that date. History is calculated at the rates that were in force then, not now.

GET /v1/claims/WC-NSW-2025-2214/entitlement?asOf=2026-08-17

{
  "scheme": "NSW workers compensation",
  "basis": { "label": "PIAWE", "value": 1800 },
  "periods": [
    { "fromWeek": 1,  "toWeek": 13, "provision": "s 36", "amount": 1710,
      "formula": "min(95% x PIAWE, cap)" },
    { "fromWeek": 14, "toWeek": 17, "provision": "s 37", "amount": 1440,
      "formula": "min(80% x PIAWE, cap)" },
    { "fromWeek": 18, "toWeek": 71, "provision": "s 37", "amount": 1110,
      "formula": "min(95% x PIAWE, cap) - current weekly earnings" }
  ],
  "upcoming": [ { "label": "78 weeks", "at": "2026-10-05",
                  "actionBy": "2026-07-07", "citation": "s 44A" } ],
  "limitations": [ /* stated in the payload, not in documentation */ ]
}

Three refusals rather than guesses: an unmodelled scheme, a missing earnings basis, and a date outside the rate table each throw. Indexed amounts are effective-dated and the engine will not apply a stale cap, because a stale cap produces a confident, wrong, auditable-looking number.

Whether the decision is supported

/sufficiency assesses whether the file supports a decision - not whether the decision is right. Five decisions are modelled with 22 requirements between them, each carrying a citation and a reason. It checks currency against the decision being made, source appropriateness, procedural sequence, and whether contrary material on the file has been engaged with.

DecisionWhat it turns on
Decline liabilityEvidenced ground, written reasons naming the term, s 54 considered, contrary evidence engaged, review rights
Cease or reduce weekly paymentsCurrent certificate, a recorded work capacity decision, notice elapsed, suitable employment, impairment where a limit is in play
Deny a treatment requestClinical opinion from an appropriate source addressing reasonable necessity
Cash settleItemised scope, written explanation, catastrophe review right
Classify a threshold injuryQualified assessment, psychological injury considered separately, dispute right notified

The position is one of three words - supported, supported-with-gaps, not-supported - never a percentage. A score gets rounded up by whoever reads it; a list of unmet mandatory requirements does not.

What the engines say to each other

/composite runs every engine with inputs and evaluates eight declared interactions between them. The facts that matter most sit between engines: cessation contemplated on a claim being underpaid, an integrity finding relied on beyond the confidence it carries, an adverse decision on a claim already out of time, a vulnerability signal with an adverse outcome imminent.

An interaction whose inputs were not supplied is returned as not evaluated, never as clear. There is no composite score, deliberately.

Webhooks

Polling a claim position on a timer is the wrong shape - most claims do not change most days, and the ones that do need attention within hours. Subscribe instead.

WebhookFires whenTypical destination
obligation.at_riskAn obligation enters its escalation windowHandler work queue
obligation.breachedAn obligation passes its due date undischargedTeam leader queue, breach register
finding.raisedA reconciliation finding is producedTechnical claims / review queue
document.processedA document is classified and extractedContent store metadata update
report.generatedA compliance report is producedGovernance evidence store
rule.changedThe active rule set changes fingerprintChange management, model risk register

The escalation window scales with the obligation: two days' warning on a seven day payment clock, thirty on a twelve month one. A single fixed window makes long obligations invisible until they are already lost.

Verifying a webhook

X-Intactly-Signature: t=1786982400,v1=5257a869e7...
X-Intactly-Delivery: 018f2c41-...

# HMAC-SHA256 over "{t}.{raw_body}" with your signing secret.
# Reject deliveries where |now - t| > 300 seconds.

Retries run on exponential backoff for 24 hours. Non-2xx and timeouts both retry; a duplicate delivery is expected behaviour, which is why every payload carries a stable X-Intactly-Delivery id for you to de-duplicate against.

Idempotency and replay

Claims systems retry. Middleware replays. An integration that double-counts an event under those conditions produces a wrong obligation position, which is worse than no position at all.

  • Every POST accepts an Idempotency-Key header. Repeating a key returns the original response and changes nothing.
  • Events are content-addressed on (claimId, type, at, sourceRef), so an accidental duplicate without a key is still absorbed.
  • The event log is append-only. Corrections are posted as corrections; nothing is edited in place, because a compliance artefact that can be rewritten is not evidence.

Replay

Every report carries the fingerprint of the rule set that produced it. Given the same events and the same fingerprint, regenerating the report produces the same output - which is what "show us how you reached that decision" actually requires two years later at AFCA.

GET /v1/claims/WC-NSW-2026-0912/report?asOf=2026-03-11&ruleSet=fnv1a-3c8e21b4

# Same events + same rule set fingerprint = byte-identical report.

Errors

Errors are typed and name the field. Two of them are unusual enough to explain, because they are invariants failing loudly rather than bugs.

StatusCodeMeaning
400invalid_event_typeEvent accepted into storage but no rule reads it. Advisory, not fatal.
400as_of_requiredA position or report was requested without an explicit date. There is no default.
409idempotency_conflictThe key was reused with a different body.
422unanchored_factAn extracted fact arrived without a document, page and quote. Discarded rather than stored.
422vulnerability_leakA vulnerability signal reached the integrity examination. The request fails; it is not filtered and quietly continued. See below.
429rate_limitedRetry after the interval in Retry-After.
503drafting_unavailableRule drafting is not configured on this tenant.

Rate limits and volumes

SurfaceDefault limitNotes
Event ingestion500 req/min, 100 events per requestRaised on request; backfill runs on a separate quota
Document submission60 req/min, 100 MB per documentPre-signed URL submission does not count against transfer
Position and findings reads1,000 req/minComputed, not cached - a read is always current as at the date you asked
Report generation60 req/minPortfolio reports are asynchronous above 5,000 claims