OFFER-HUB uses Trustless Work smart contracts on Stellar for non-custodial escrow. All flows ultimately resolve on-chain.
Escrow Flows
Complete guide to all escrow lifecycle flows — creation, funding, release, dispute, and refund.
This guide walks through every escrow flow in OFFER-HUB: from creating and funding a contract to releasing, disputing, and refunding. Each flow includes step-by-step diagrams and code examples.
Creating an Escrow
An escrow contract is created after an order is placed and the buyer's funds are reserved off-chain.
Steps
- Create the order — Buyer's balance is reserved
- Call the escrow creation endpoint — Deploys a Trustless Work contract on Stellar
- Wait for confirmation — Contract becomes
ESCROW_CREATED
REST
Response:
TypeScript SDK
Contract deployment is asynchronous. Use waitForStatus or subscribe to the order.escrow_created event rather than polling manually.
Funding the Escrow
Once the contract is deployed, the buyer's reserved USDC is transferred on-chain into the smart contract.
Steps
- Call the fund endpoint — Triggers an on-chain USDC transfer
- Platform signs — The buyer's encrypted key authorizes the transaction
- Stellar confirms — Transaction lands on-chain (5–10 seconds)
- Status updates — Order advances to
IN_PROGRESS
REST
TypeScript SDK
Always include an Idempotency-Key when funding. If the request times out, retrying with the same key is safe and prevents double-funding.
Balance changes during funding
| Stage | Available | Reserved | On-Chain (Wallet) | In Contract |
|---|---|---|---|---|
| After reserve | 50.00 | 50.00 | 100.00 | 0.00 |
| After funding | 50.00 | 0.00 | 50.00 | 50.00 |
Release Conditions
Funds can be released in two ways depending on how the order is configured.
Time-Based Release
The buyer approves release after a deadline or after delivery confirmation within a time window.
- Seller marks work as complete
- Buyer has a review window (e.g., 72 hours)
- If the buyer approves — or the window expires without a dispute — release is triggered
Milestone-Based Release
For larger projects, funds can be split across milestones. Each milestone follows its own create → fund → release cycle.
Model milestones as separate orders sharing the same project_id. Each order has its own escrow contract and independent lifecycle.
Releasing Funds
When the buyer approves the delivered work, funds are released to the seller in three on-chain transactions.
Steps
| Step | Transaction | Signer |
|---|---|---|
| 1 | complete_escrow | Buyer confirms delivery |
| 2 | release_escrow | Platform authorizes release |
| 3 | Claim funds | Seller receives USDC |
REST
Response:
TypeScript SDK
After release, the seller's internal balance is credited. They can withdraw to their external wallet at any time via the Withdrawals flow.
Raising a Dispute
If the buyer believes the work was not delivered as agreed, they can open a dispute while the order is IN_PROGRESS.
Steps
- Buyer opens dispute — Provides a reason
- Status changes — Order moves to
DISPUTINGthenDISPUTED - Funds remain locked — Neither party can access the escrow
- Platform reviews — Manual or automated resolution begins
REST
Response:
TypeScript SDK
Disputes can only be opened while the order is IN_PROGRESS. Once released or refunded, the order is final.
Dispute Resolution
After a dispute is opened, the platform reviews evidence and resolves with a release (seller wins) or refund (buyer wins).
Resolution Options
| Resolution | Outcome | On-Chain Transaction |
|---|---|---|
release | Funds go to seller | resolve_dispute → release |
refund | Funds return to buyer | resolve_dispute → refund |
split | Custom split between parties | resolve_dispute → split |
REST — Resolve with Refund
REST — Resolve with Release
TypeScript SDK
Only the platform (using the master API key) can resolve disputes. This requires a co-signature from the Trustless Work smart contract arbiter.
Refund Flow
A refund can result from dispute resolution or, in some configurations, from a direct cancellation before work begins.
Refund via Dispute
Two on-chain transactions are required:
| Step | Transaction | Signer |
|---|---|---|
| 1 | dispute_escrow | Buyer opens dispute |
| 2 | resolve_dispute | Platform issues refund |
Refund via Cancellation
If the order is cancelled before funding (e.g., the seller cannot fulfill), the off-chain reservation is released with no blockchain transaction:
Cancellations before escrow funding are instant — no Stellar transaction required. The buyer's reserved balance is immediately returned to available.
TypeScript SDK — Full Dispute-to-Refund Flow
Listening to Escrow Events
Subscribe to lifecycle events to keep your application in sync:
Error Reference
| Error | Cause | Fix |
|---|---|---|
ESCROW_ALREADY_EXISTS | Contract already created for this order | Check status before calling create |
ESCROW_NOT_FUNDED | Release attempted before funding | Fund the escrow first |
INVALID_STATE_TRANSITION | Action not valid in current status | Follow the state machine |
INSUFFICIENT_FUNDS | Buyer wallet has insufficient USDC | Check balance before funding |
DISPUTE_ALREADY_OPEN | Duplicate dispute on same order | Resolve existing dispute first |
FUNDING_TIMEOUT | Stellar transaction not confirmed | Check order status — do not retry blindly |
Use idempotency keys on all mutating requests (fund, release, dispute). This allows safe retries without risk of duplicate transactions.
Next Steps
- Escrow Guide — State machine reference and balance mechanics
- Disputes Guide — Full dispute management documentation
- Withdrawals Guide — Move funds off-platform after release
- SDK Quick Start — TypeScript SDK setup and usage
- API Reference — Full REST API documentation