Underwritetenant/underwrite-demo
Role
Request a demo

Operator surfaces: queues, clocks, correspondence, billing.

API reference, v3

Everything the interface does is an API call, including every refusal. This reference documents the shapes a compliance officer is most likely to be asked about.

Stable since 4.0.0. Current build 4.12.0. Breaking changes ship behind a new major path, never behind a flag.

Base URL and versioning

All requests go to a tenant host. The version is in the path and never in a header, because a header is easy to forget and a path is visible in every log line you will later be asked about.

https://{tenant}.underwrite.example/v3

A major version is supported for eighteen months after its successor ships. Additive changes appear inside a major version and are listed on the changelog.

Authentication

A tenant scoped bearer key, sent on every request. Keys carry a seat identity so the audit trail can name an actor for an API write exactly as it does for an interface write.

curl https://northgate.underwrite.example/v3/cases/CR-2026-04187 \
  -H "Authorization: Bearer uw_live_..." \
  -H "Underwrite-Seat: seat/di.okafor"

A key without a seat header is rejected rather than attributed to the tenant, becauseactor: tenant is not an answer to who did this.

Idempotency

Every write accepts Idempotency-Key. Replaying a key returns the original response, including the original refusal. A retry after a network timeout therefore cannot start a second statutory clock on the same dispute.

Errors and refusals

A refusal is not an error in your integration. It is the compliance engine doing its job, and it carries the rule, the control and the object it refused.

Refusal codes
CodeRuleMeaning
409 fee_before_performanceCROA 1679b(b)A billing call referenced a service line that has not reached a performed state.
409 disclosure_missingCROA 1679cNo delivery receipt exists for the statutory disclosure on this consumer.
409 cancellation_window_openCROA 1679eAn outbound action was requested during the three business day window. It has been queued, not rejected.
422 contract_incompleteCROA 1679dA required contract term is absent. The response body names each missing term.
409 despatch_evidence_missingFCRA 611(a)(1)A dispute was sent without proof of despatch attached.
403 clock_not_writableFCRA 611(a)(1)A due date was written directly. Record the extending event instead.

Pagination

Cursor based, stable under insertion. Audit listings are ordered by entry id rather than by timestamp, so two entries written in the same millisecond never swap places between pages.

GET /v3/audit?case=CR-2026-04187&limit=50&after=AUD-2026-0918442

Endpoints

  • POST/v3/consumers

    Create a tokenised consumer record.

    Identity fields are stored encrypted and returned as a token, never in plain text.

  • POST/v3/disclosures

    Serve the statutory disclosure and record its delivery receipt.

    Returns the document hash the consumer received. Required before a contract will create.

  • POST/v3/contracts

    Generate a written contract with the cancellation form in duplicate.

    422 if any required term under CROA 1679d is absent, naming the term.

  • GET/v3/contracts/{id}/cancellation-window

    The three business day window, its calendar and its expiry.

  • POST/v3/cases

    Open a dispute case against one or more reported items.

  • GET/v3/cases/{id}

    The full case record: parties, clock, state, documents, audit.

  • POST/v3/cases/{id}/disputes

    Despatch a dispute and start the statutory clock.

    409 unless proof of despatch is attached first.

  • PATCH/v3/cases/{id}/clock

    Record an event that extends the window.

    The due date is not writable. Only the extending event is, and it must name its rule.

  • POST/v3/cases/{id}/mov-requests

    Request a description of the procedure used to determine accuracy.

    Opens a separate fifteen day clock under FCRA 611(a)(7).

  • POST/v3/cases/{id}/statements

    File a consumer statement of dispute.

    Enforces the one hundred word limit at the API boundary.

  • POST/v3/invoices

    Issue an invoice against performed service lines.

    409 with the unperformed line named if any line is not yet fully performed.

  • GET/v3/audit

    Append only audit entries, filterable by case, seat, rule and window.

  • GET/v3/exports/{id}

    A signed, hash chained export of a case or a date range.

  • POST/v3/webhooks

    Subscribe to clock, state and control events.

    Signed with a per tenant secret. Replay window is five minutes.

Webhooks

Signed with a per tenant secret using HMAC SHA256 over the raw body and the timestamp. Anything outside a five minute window is rejected. Verify before you parse.

Underwrite-Timestamp: 1787059320
Underwrite-Signature: v1="9f1c0a4e..."

signature = HMAC_SHA256(secret, timestamp + "." + raw_body)

Events: clock.started, clock.extended,clock.expired, control.blocked,document.delivered, case.state_changed,export.generated.

Rate limits

600 requests per minute per tenant, 60 per minute for export generation. Exceeding a limit returns 429 with Retry-After. Limits are per tenant rather than per key, so rotating a key does not buy headroom.

Sandbox

Every tenant gets a sandbox tenant with the same controls and no production data. Clocks in the sandbox can be advanced with POST /v3/sandbox/advance, which is the only place in the platform where time is writable, and it is unavailable in production by construction rather than by permission.

Request sandbox access