Appearance
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
| Parameter | In | Required | Description |
|---|---|---|---|
reference | path | Yes | Your own reference (clientReference, echoed from submission) or the Ezys-issued ID (intent / order ID) |
refType | query | No | client 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
}| Field | Type | Description |
|---|---|---|
clientReference | string | Your reference key, echoed back verbatim on every surface (status, webhooks, receipts, reconciliation) |
reference | string | Ezys-issued execution ID |
providerReference | string | Downstream rail / payout-provider reference, when one exists |
status | string | Aggregate status derived from the latest event (e.g. in_progress, completed, failed) |
phase | string | The phase the execution is currently in: intent, offramp, or payout |
events | array | Ordered transition history. See Events |
failure | object | null | Present when the execution failed. See Failure |
Events
Each events[] entry is one observed state transition:
| Field | Type | Description |
|---|---|---|
phase | string | intent, offramp, or payout |
state | string | Phase-specific state. See Phase & state model |
occurredAt | string | When the transition happened at the source (e.g. vendor webhook created timestamp) |
observedAt | string | When Ezys recorded it. occurredAt ≤ observedAt; a large gap indicates delayed vendor notification |
isTerminal | boolean | No further transitions will occur for this execution |
isReversible | boolean | This 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.
| Phase | States (representative) | Terminal states |
|---|---|---|
intent | accepted | failed, cancelled, expired |
offramp | initiated → in_progress → completed | failed |
payout | initiated → in_progress → completed | completed, 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 → reversedexists on some payout rails (chargeback-style reversal). This is whycompletedcan reportisReversible: truefor those rails — the per-rail matrix of irreversibility points ships with the final spec.rejectedis not an event-stream state. A synchronously rejected submission (HTTP422,status: "rejected"— see Error Handling & Retries) never starts executing, so it never enters the event store: no events, no webhooks, and this endpoint returns404for it. The intent phase's terminal states are the asynchronous pre-leg outcomes —failed,cancelled,expired— exactly the webhookintent.*terminal events.- Mapping to webhooks: the Webhooks overall
statusis always the composite<phase>.<state>of exactly these values (e.g.phase: "payout"+ statein_progress⇔ webhookstatus: "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
}
}| Field | Type | Description |
|---|---|---|
stage | string | Phase that failed: offramp or payout |
code | string | Stable, machine-readable code (provider-original codes are mapped, not passed through raw) |
message | string | Human-readable detail |
retryable | boolean | Whether re-submitting the same request can succeed. false codes are deterministic rejections |
Get intent status (lightweight)
GET /v1/intents/{intentId}/statusA 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.
clientReferenceis 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.
