Skip to main content

States

A claim is always in one of four states:
StateDescription
OPENAccepting events. The fulfillment condition is evaluated on every POST /v1/events.
PENDINGFulfillment condition was satisfied, or the activity window elapsed. Waiting for the review window to expire before final resolution.
CONFIRMEDThe claim was confirmed. Terminal state.
FAILEDThe claim failed. Terminal state.

Transitions

All transitions happen in one of two ways:
  1. Event submission — when you call POST /v1/events with a claim_id and the fulfillment condition evaluates to true, the claim transitions OPEN → PENDING with scheduled_outcome = CONFIRMED in the same atomic database operation.
  2. Scheduled jobs — pg_cron jobs run every minute and check time-based conditions:
    • activity_window elapsed → OPEN → PENDING (using timeout_outcome)
    • review_window elapsed → PENDING → CONFIRMED or PENDING → FAILED

Key fields

status_since

Timestamp of when the claim entered its current status. For OPEN claims this equals the creation time. All time-window calculations (activity_window, review_window) are measured from status_since of the relevant state, not from claim creation.

scheduled_outcome

Set when a claim enters PENDING. Tells you what the final resolution will be once the review window expires:
  • CONFIRMED — claim is confirmed (set when fulfillment condition was satisfied)
  • FAILED — claim fails (set when activity/expiration window fired and timeout_outcome = "fail")
  • null while the claim is OPEN

Contract windows

All windows are defined in seconds on the contract:
{
  "activity_window": 3600,
  "review_window": 86400
}

Event submission rules

  • Only OPEN claims accept events. Submitting to any other status returns CLAIM_NOT_OPEN (422).
  • Events are evaluated as a set — order does not matter, only presence. Submitting the same event type twice has no additional effect on condition evaluation.
  • The fulfillment condition is re-evaluated from scratch on every submission against the full event log, including the new event.

System-generated events

The platform appends synthetic events to the claim’s event log at each time-based transition. These are visible in GET /v1/claims/:id:
Event typeWhen appended
activity_window_elapsedactivity_window expires → claim transitions OPEN → PENDING
review_window_elapsedreview_window expires → claim transitions PENDING → CONFIRMED or PENDING → FAILED
You cannot submit these event types yourself — they are reserved for internal use. If your fulfillment condition references either of them, it will never be satisfied by a user-submitted event.

Race conditions

If your system submits events concurrently, a race is possible: two submissions arrive close together, the first satisfies the condition and transitions the claim to PENDING, and the second arrives after. The second submission returns CLAIM_NOT_OPEN. Handle this by checking the claim status before deciding whether to create a new claim:
const res = await fetch(`/v1/claims/${claimId}/events`, {
  method: 'POST',
  body: JSON.stringify({ type: 'signed' }),
})

if (res.status === 422) {
  const claim = await fetch(`/v1/claims/${claimId}`).then(r => r.json())
  // claim.status tells you what happened
}