Trumis For organisations

Trumis / Developers

Integrate Trumis

Two integration paths, both live today: a one-line embeddable widget, and a retained-record JSON API. This page is the full contract. The buyer's view — pricing model, security posture, record-keeping — lives at business.trumis.com.au.

Embed · API · Request · Response · Stages · Errors · Rate limits · Partner tiers · Receiving complaints · Versioning · OpenAPI · Changelog

Option 1 — the one-line embed

Paste this where your complaint form lives. Works today, no registration — that's the evaluation (pilot) tier:

<script src="https://trumis.com.au/embed.js"
        data-partner="Acme Energy"
        data-email="complaints@acme-energy.example"
        data-height="640"></script>
  • data-partner — your organisation's name; the complaint is addressed to you and framed under your complaint-handling policy.
  • data-email — optional; pre-addresses the send button to your complaints inbox. The widget always shows people where their complaint will go — quiet misdirection isn't possible.
  • data-height — iframe height in pixels, default 640.
  • data-lang — optional opening language hint (zh, vi, ar, el).
  • Microphone: the widget's Talk button records a short clip in the visitor's browser and sends it to the Trumis transcription endpoint, where our AI provider (OpenAI) turns it into text with automatic language detection — transcribed and discarded, never stored (disclosed at /privacy/). The iframe ships with allow="microphone". If your site sends a restrictive Permissions-Policy header, include microphone=(self "https://trumis.com.au") or the Talk button quietly disappears — everything else works regardless.

Pilot embeds carry a small “Powered by Trumis” mark. Licensed embeds swap the page-supplied attributes for a registered partner id:

<script src="https://trumis.com.au/embed.js"
        data-partner-id="acme-energy"
        data-height="640"></script>

With data-partner-id, the organisation name, complaints inbox and branding (including watermark removal) resolve server-side from your licence configuration via /api/embed-config, and the widget verifies it is running on one of your registered origins. Copying the id onto another site fails that check and falls back to the watermarked pilot behaviour — branding cannot be spoofed or stripped from page HTML. Licensing: info@trumis.com.au.

The embed is a sandboxed iframe served from trumis.com.au. It adds no scripts to your page context. The visitor keeps a browser copy and Trumis retains the server-processed intake encrypted for up to 24 months (security, privacy).

Option 2 — the retained-record API

One endpoint drives the whole conversation. Send the visible transcript each turn plus the facts returned last turn; render the reply. When the person confirms, the response carries the finished complaint. Each response returns an intake_id; echo it on later turns so the encrypted archive keeps every revision together. Records are retained for up to 24 months.

curl -X POST https://trumis.com.au/api/v1/companion \
  -H 'Content-Type: application/json' \
  -d '{
    "history":     [{"role":"user","content":"They cut my power off with no warning."}],
    "known_facts": {},
    "client_done": false,
    "partner":     { "name": "Acme Energy" }
  }'

JavaScript, each turn feeding the previous response back:

const r = await fetch('https://trumis.com.au/api/v1/companion', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },   // add 'X-Trumis-Key' when licensed
  body: JSON.stringify({
    history: transcript,          // [{role:'user'|'assistant', content}]
    known_facts: lastTurn.facts,  // echo the previous turn's facts verbatim
    client_done: false,
    partner: { name: 'Acme Energy' },
  }),
});
const turn = await r.json();
transcript.push({ role: 'assistant', content: turn.reply });

Python:

import requests

turn = requests.post(
    "https://trumis.com.au/api/v1/companion",
    json={"history": transcript, "known_facts": last_facts, "client_done": False,
          "partner": {"name": "Acme Energy"}},
    timeout=30,
).json()

CORS is open and requests carry no cookies, so the API can be called directly from your own complaint page's front end. Responses are synchronous JSON (no streaming); a turn typically returns in one to three seconds — the deterministic rules run first and the AI layer only phrases conversation.

Request fields

FieldTypeNotes
historyarray, required {role: "user"|"assistant", content: string} — the whole visible transcript, oldest first. Capped at 60 turns × 8,000 characters; longer input is truncated, not rejected.
known_factsobject The facts object from the previous response, echoed back verbatim. Setting a fact to false retracts it — that is how unticking a confirm claim works.
client_doneboolean true when the person indicates they have nothing more to add (your “I'm done” control).
partnerobject {name: string} switches to organisation intake: the complaint is lodged with you under your policy, no third-party routing. With a licensed X-Trumis-Key header the name is taken from your registry entry, not the body. See partner tiers.
evidenceobject A correspondence transcript from /api/v1/evidence, after the person has reviewed it: {source, transcript: [{speaker, name?, time?, text}]}.
langstring Opening-language hint (zh, vi, ar, el). The person's own words always win.
formal_requestedboolean Reserved — the paid formal tier is currently disabled (see the changelog). Accepted for wire compatibility and ignored.
payment_refstring Reserved while the paid formal tier is disabled — accepted and ignored. When the tier is live: a Stripe Checkout session id from /api/checkout, verified server-side with Stripe. No card data touches Trumis; Stripe holds the payment record.

Response fields

FieldTypeNotes
replystring The agent's next message, in the person's language. Render it and append it to history.
stageenum Where the conversation is — see stages.
methodenum "rules" or "rules+llm" — whether the AI layer was active for this turn. Merit decisions are deterministic either way.
factsobject Everything established so far. Echo it back as known_facts next turn so the conversational engine receives the complete current context; the encrypted service archive also retains each request and response revision.
groundsobject {sufficient: boolean, passed_arguments: [{id, summary}]} — the rules engine's merit decision, with the arguments that passed. Auditable: these ids map to the maintained legal knowledge base.
urgencyarray [{level: "critical"|"high"|"medium", message, action}] — route critical flags (e.g. safety) to emergency services messaging before anything else.
confirmobject | null Present at stage confirming: the exact claims the complaint would make, as tickable lines with the person's quotes — {intro, claims: [{key, label, quote?, theirs?}], about, subject?, question, ui: {tick_prompt, unsure_note, confirm_yes, you_said, their_words}}. Untick = echo that fact back false; confirm = send the ui.confirm_yes message. The card strings arrive in the person's language so thin clients stay thin.
complaintobject | null The finished complaint once the person confirms: {document, text, routing, receiver}. text is the complete complaint ready to send; document is the same content structured (title, sections, outcomes, evidence list); routing is the send-then-escalate path with response-day clocks; receiver is the recognised organisation or null.
formal_offerobject | null Currently always null — the paid formal tier is disabled. When live: {text, fee}, shown with a written account whose circumstances also clear the formal bar, presented on the draft screen rather than in the chat flow.
disclaimerstring The legal-information disclaimer. Display it with the conversation.
partner_tierenum Partner mode only: "licensed" or "pilot".

The register (licensed)

Licensed partners can read a risk-tiered view of their own intake — the governance register. A complaint produced through your embed or partner-mode API carries a Reference: TRM-XXXX-XXXX line on the document (also returned as complaint.reference), and the register records the same category codes as the anonymous statistics plus a deterministic risk tier (watch / elevated / critical). The register stores no content of its own — its schema (docs/register/ in the repository) has no free-text columns, and each licence reads only its own rows.

GET /api/v1/register?days=90
X-Trumis-Key: <your licensed key>

→ { partner, window_days,
    summary: { total, last_30_days,
               tiers: {critical, elevated, watch},
               lifecycle: {responded, resolved, overdue} },
    entries: [ { reference, produced_on, kind, dispute_type, industry_code,
                 org_id, grounds_sufficient, urgency, risk_tier, amount_band,
                 evidence_direct, evidence_documentable, evidence_asserted,
                 channel, grounds: [argument_id…],
                 facts: [{fact_key, evidence_class}…],
                 events: {sent, response_received, deadline_passed, …},
                 edr_scheme } ] }

grounds are the KB argument codes that passed (what kind of exposure); facts are the established circumstances (presence and evidence class, never a value); edr_scheme is the external dispute resolution body an unresolved complaint could reach. Errors follow the standard catalog: 401 invalid_partner_key, 503 register_unavailable (store not enabled), 502 register_failed. Rate limit: 60/min per licence. A human view lives at /register/.

Lifecycle events. The status column is driven by pings the complainant's device sends as it tracks the response clock:

POST /api/v1/register-event
{ "reference": "TRM-XXXX-XXXX",
  "event": "sent" | "response_received" | "deadline_passed"
         | "escalated" | "resolved" | "withdrawn" }
→ 204

Day-granular, idempotent per (reference, event), content-free. The endpoint reveals nothing about which references exist; a malformed shape is 400 invalid_event.

Stages

StageMeaningClient behaviour
listeningFree talk; the person is telling their story. Render the reply; keep the composer open.
probingOne gentle question is being asked. Same as listening.
confirmingThe claims card is live. Render confirm.claims as pre-ticked options.
account_readyThe written account is done. Show the account with its send path. (While the paid tier is disabled, formal_offer stays null here.)
grounds_readyThe formal complaint is built. Show complaint.text and the routing path.
no_grounds_closeThe facts don't support a formal complaint; the close is warm and explains why. Render the reply; no document exists to show.

Errors

Every error is JSON with a machine code and a human message, and every response — success or error — carries an X-Trumis-Request-Id header. Quote that id when writing to support.

StatuserrorWhen
400invalid_jsonThe body is not valid JSON.
400no_screenshots/evidence without OCR lines.
401invalid_partner_keyX-Trumis-Key doesn't match a configured partner.
404unknown_partner/embed-config pid not registered.
405method_not_allowedWrong HTTP method; Allow header lists the right ones.
422nothing_recognised/evidence OCR lines yielded no correspondence.
429rate_limitedBudget spent — honour Retry-After.
502companion_failedUpstream hiccup; safe to retry. Body includes request_id.

Rate limits

Fair-use limits protect availability. Current budgets, per rolling minute:

CallerBudgetKeyed by
Unauthenticated (consumers, pilots)30 requests/minClient address
Licensed partner key120 requests/minThe key's partner id

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (seconds). A conversation turn is one request, so 30/min is generous for a person typing; server-side integrations that multiplex many users through one address should use a licensed key. Higher budgets are a licence property — ask info@trumis.com.au.

Partner tiers and keys

Pilot (evaluation)Licensed
Howpartner.name in the body / embed attributes X-Trumis-Key header / data-partner-id embed
Organisation name on documentsAs supplied, marked pilot From the registry — server-authoritative
“Powered by Trumis” markAlways shownRemovable
Embed origin verificationRegistry allow-list
Rate budget30/min per address120/min per key (raisable)
CostFreeLicence

Keys are secrets for server-side use — never ship one in page JavaScript. Embeds don't need keys: the public data-partner-id plus the origin check does the equivalent job in the browser.

Receiving complaints into your systems

Trumis retains an encrypted complete intake record for up to 24 months; the person still controls sending, and that approval is the send. You have two ways to receive:

  • Embed: the finished complaint arrives at your complaints inbox as an email from the person's own account — plain text, structured sections, with the correspondence annex. Parse-friendly and, importantly, the timestamps and sender are the complainant's own record too.
  • API integration: your page or backend drives the conversation, so the complaint object — document, structured sections, routing, receiver — is already in your hands the moment the person confirms. Post it into your case system directly; there is no Trumis-side webhook because the complaint is never on our side to push.

Record-keeping guidance for regulated intake (RG 271 and ombudsman schemes) is on the organisations page.

Versioning and deprecation

  • /api/v1/… is the canonical path. The unversioned /api/… paths are permanent aliases of v1.
  • Additive changes (new response fields, new optional request fields, new enum values on urgency) ship without a version bump — build clients that ignore unknown fields.
  • Breaking changes (removing or renaming fields, changing semantics) ship as /api/v2/…. v1 then runs for at least 12 months, and licensed partners are notified by email before anything is scheduled for shutdown.
  • Every observable change is dated in the changelog. The machine-readable contract is /openapi.json.

Evidence endpoint

POST /api/v1/evidence — screenshots in, correspondence out. Clients run OCR on the device (tesseract.js on the web, iOS Vision, Android ML Kit) and send only text lines with geometry — images never leave the person's device. The endpoint reconstructs the conversation deterministically (who said what, when — deduplicated and stitched across scrolling captures) and returns it with proposed facts for the person to review. Limits: 25 screenshots, 500 lines each. Full schema: /openapi.json.

Health

GET /api/v1/health{ok, service, time, region} — liveness for your monitors, no AI call involved. Live state: trumis.com.au/status.

Trumis is an automated legal information service working with FairClaim — not a lawyer. Generated complaints are drafts based only on what the person shared and confirmed.