Money movement, orchestrated
Compose multi-step payment workflows as durable, event-driven programs — reliable across every provider.
name: payout
stages:
- send
- wait_event:
event: ${event}
- delay:
seconds: 7dDeclare the whole journey, stages, waits and delays, as code.
Bind a flow to any event and filter it, matches start a run.
A durable instance advances stage by stage, waiting as long as needed.
Each stage moves value between ledgers, wallets and payments.
Workflows as code
Declare the whole journey, end to end.
Describe splits, fees, holds and payouts as a single declarative program. Version it, review it, and ship money movement like any other code.
One send, any rail
Move value between ledgers, wallets and payments.
A single send stage moves value between internal ledgers, wallets and external payments. Source and destination interchange freely — the engine resolves the route, including provider-specific paths like Stripe.
one send stage, ledgers, wallets and payments interchange
Durable by default
Every run survives time and failure.
A workflow instance is a durable program: each stage is tracked with its status and timing, and long waits or delays hold their place for days without losing state. The run resumes exactly where it left off.
a durable instance, each stage tracked with status and timing
Durable orchestration
Long-running flows that never lose state.
Each stage runs as a durable step. Flows can wait for external events for minutes or months, then resume exactly where they left off — no lost work.
Retries & idempotency
Exactly-once, even when rails fail.
Transient failures are retried automatically with idempotency keys, so a flaky provider never double-charges or double-pays. Every attempt is recorded.
Event-driven by design
Observe every step in real time.
Flows emit a typed event stream you can subscribe to — drive notifications, analytics, and downstream systems from a single source of truth.
EVT | flow.started collect-and-payout |
EVT | stage.ok send → deposits:pending |
WAIT | stage.wait payout.confirmed |
RETRY | stage.retry payout 2/3 |
EVT | event.received payout.confirmed |
EVT | stage.ok send → wallet:main |
DONE | flow.terminated idempotent |
Every run, inspectable
Follow a workflow instance, stage by stage.
Each run is a live instance you can inspect end to end — what has executed, what is waiting and why. Durable stages hold their place until the event arrives, so nothing is lost between steps.
send · wait_event · delay, across ledgers, wallets and payments
Triggered by events
Start a workflow the moment it matters.
Bind a flow to any platform event and filter it with expr-lang. When an incoming payment matches, its data is forwarded straight into the run as typed variables — no glue code, no polling.
a payment event fires a workflow, matched variables forwarded
Questions, answered
01 / DURABILITY
Each stage runs as a durable step. A flow can wait for an external event for minutes or months, then resume exactly where it left off.
02 / IDEMPOTENCY
Retries use idempotency keys, so a flaky provider never double-charges or double-pays. Every attempt is recorded.
03 / EVENT-DRIVEN
Flows wait on typed events and emit their own, so notifications, analytics and downstream systems run off one source of truth.
04 / AUTHORING
Workflows are declared as code — versioned, reviewed and shipped like any other program, not built in an opaque visual editor.
05 / OBSERVABILITY
Every stage transition is logged with its inputs and outputs, so a stuck or retrying flow stays inspectable in real time.
Orchestrate money movement that survives failure
Durable, idempotent, event-driven workflows — reliable across every provider.