Skip to content

Status API

Availability: coming soon — sandbox rollout is targeted for late August. This page is the contract of record, published ahead of rollout; field names and state enums may still change until frozen.

Query the current state and full transition history of a single execution — one end-to-end fill spanning up to three phases: intent (acceptance), offramp (JIT FX conversion), and payout (fiat delivery to the beneficiary).

This API is the authoritative source for resolving timeouts and undetermined results: if you miss a webhook or a submission response, re-query here rather than re-submitting. It returns both the aggregate status and the per-phase event history, so callers can reconstruct exactly where an execution stands.

Get execution status

GET /v1/executions/{reference}

Returns the aggregate status of one execution, with the per-phase transition history (events[]) and, when failed, a structured failure block.

Read endpoints are authenticated with an API key (X-API-Key) — see Authentication.

Path & query parameters

ParameterInRequiredDescription
referencepathYesYour own reference (clientReference, echoed from submission) or the Ezys-issued ID (intent / order ID)
refTypequeryNoclient or ezys. Disambiguates when a value could match both namespaces; by default the ID prefix is used to infer the type

Response

json
{
  "clientReference": "NR-2026-000123",
  "reference": "INT-2F8A3B1C",
  "providerReference": "whn_pay_9f2c1d",
  "status": "in_progress",
  "phase": "payout",
  "events": [
    {
      "phase": "intent",
      "state": "accepted",
      "occurredAt": "2026-07-15T02:10:04.113Z",
      "observedAt": "2026-07-15T02:10:04.113Z",
      "isTerminal": false,
      "isReversible": false
    },
    {
      "phase": "offramp",
      "state": "completed",
      "occurredAt": "2026-07-15T02:10:11.902Z",
      "observedAt": "2026-07-15T02:10:12.048Z",
      "isTerminal": false,
      "isReversible": false
    },
    {
      "phase": "payout",
      "state": "initiated",
      "occurredAt": "2026-07-15T02:10:14.330Z",
      "observedAt": "2026-07-15T02:10:15.101Z",
      "isTerminal": false,
      "isReversible": true
    }
  ],
  "failure": null
}
FieldTypeDescription
clientReferencestringYour reference key, echoed back verbatim on every surface (status, webhooks, receipts, reconciliation)
referencestringEzys-issued execution ID
providerReferencestringDownstream rail / payout-provider reference, when one exists
statusstringAggregate status derived from the latest event (e.g. in_progress, completed, failed)
phasestringThe phase the execution is currently in: intent, offramp, or payout
eventsarrayOrdered transition history. See Events
failureobject | nullPresent when the execution failed. See Failure

Events

Each events[] entry is one observed state transition:

FieldTypeDescription
phasestringintent, offramp, or payout
statestringPhase-specific state. See Phase & state model
occurredAtstringWhen the transition happened at the source (e.g. vendor webhook created timestamp)
observedAtstringWhen Ezys recorded it. occurredAtobservedAt; a large gap indicates delayed vendor notification
isTerminalbooleanNo further transitions will occur for this execution
isReversiblebooleanThis state can still be undone (e.g. a payout that a rail can later reverse)

Events are appended, never rewritten. Out-of-order vendor delivery is resolved internally — the recorded state never regresses.

Phase & state model

Note. The state enums below are representative; the final per-phase lists are being confirmed and will be frozen in this page before sandbox opens.

PhaseStates (representative)Terminal states
intentacceptedfailed, cancelled, expired
offrampinitiatedin_progresscompletedfailed
payoutinitiatedin_progresscompletedcompleted, failed, cancelled, reversed

Two properties of this model worth noting:

  • The offramp track is driven internally by the JIT FX stages (quote → trade → filled), but is exposed as the common lifecycle states shared with the Webhooks surface — so push and pull always use the same vocabulary. Event order within the phase is stable.
  • completed → reversed exists on some payout rails (chargeback-style reversal). This is why completed can report isReversible: true for those rails — the per-rail matrix of irreversibility points ships with the final spec.
  • rejected is not an event-stream state. A synchronously rejected submission (HTTP 422, status: "rejected" — see Error Handling & Retries) never starts executing, so it never enters the event store: no events, no webhooks, and this endpoint returns 404 for it. The intent phase's terminal states are the asynchronous pre-leg outcomes — failed, cancelled, expired — exactly the webhook intent.* terminal events.
  • Mapping to webhooks: the Webhooks overall status is always the composite <phase>.<state> of exactly these values (e.g. phase: "payout" + state in_progress ⇔ webhook status: "payout.in_progress"). The {status, phase} pair here and the webhook composite carry the same information — the two surfaces never disagree.

Failure

When status is failed, the failure block identifies where and why:

json
{
  "failure": {
    "stage": "payout",
    "code": "beneficiary_account_closed",
    "message": "Beneficiary bank rejected the credit: account closed.",
    "retryable": false
  }
}
FieldTypeDescription
stagestringPhase that failed: offramp or payout
codestringStable, machine-readable code (provider-original codes are mapped, not passed through raw)
messagestringHuman-readable detail
retryablebooleanWhether re-submitting the same request can succeed. false codes are deterministic rejections

Get intent status (lightweight)

GET /v1/intents/{intentId}/status

A lightweight, intent-only status check — returns the aggregate status without the full events[] history. This endpoint is planned for public exposure (reduced authentication scope relative to the execution endpoint above; the exact auth split is defined with the gateway authentication work).

Relationship to webhooks

Status-change webhooks push the same transitions this API serves; both read from the same store, so they never disagree. Recommended pattern:

  • Consume webhooks for latency; verify signature and de-duplicate by event ID.
  • Treat this API as the source of truth — on timeout, missed events, or any undetermined state, re-query here (or backfill via the event-query API) instead of guessing.

Errors

Failed lookups return the standard error envelope. An unknown reference is 404; an ambiguous reference without refType is 400.

Notes

  • All timestamps are ISO-8601 UTC strings.
  • clientReference is echoed on every read surface — status, webhooks, receipts, and reconciliation — so your ledger can join on a single key.
  • Batch lookup (multiple references per call) is planned alongside the reconciliation surface — see Receipts & Reconciliation.