Overview
Escrows are secure transactions where funds are held until both parties agree that the transaction is complete. The API provides endpoints to:- Create new escrow transactions
- List and filter your escrows
- Get detailed information about specific escrows
- Update, deliver, and cancel pending escrows
- Get contract details and PDF URLs
- Receive real-time notifications via webhooks
Escrow Modes
When creating an escrow, set themode field to choose the transaction flow. All modes share the same statuses (pending → paid → …) but differ in whether a contract is used and how delivery completes.
standard
Full flow with a contract both parties sign before payment. Best for services and freelance work between two users.
quick
No contract; buyer pays immediately, then releases funds via
complete. Seller deliver is optional. Best for physical or digital products between two users.instant
No contract; you are the seller (omit
sellerEmail). Buyer pays in one step; calling deliver auto-completes and releases funds. Best for in-app purchases and digital goods.Standard mode
- Set
mode: "standard"(default) withcontractTerms. - A contract is automatically created; both parties must sign before the buyer can pay.
- Checkout actions:
sign_contract→accept_pay→complete. Seller may call Deliver Escrow first, but it is optional — the buyer cancompletedirectly frompaid(early release) if they are already satisfied. - Provide
sellerEmailwhen the seller is a third party, or omit it to use your associated user as seller. - Optional
feeBearer("seller"default, or"buyer") controls who pays platform and developer fees — see Create Escrow.
pending → paid → (delivered, optional) → completed. Buyer complete is valid from paid or delivered.
Quick mode
- Set
mode: "quick". Do not sendcontractTermsorautoSign. - No contract is created; the response includes
contract: nullandescrow.mode: "quick". - Checkout actions:
accept_pay→complete. Seller may call Deliver Escrow first, but it is optional — the buyer cancompletedirectly frompaidwithout waiting for deliver. Thesign_contractaction returns 400 (QUICK_ESCROW_NO_CONTRACT). - Use when escrows are between two other parties (
sellerEmailrequired) and you want a faster checkout without a contract — e.g. product sales, digital downloads with buyer confirmation. - Minimum internal ledger value (
amountTnd) is 5 TND after FX lock (same as standard).
pending → paid → (delivered, optional) → completed. Buyer complete is valid from paid or delivered.
Quick mode with purchase proof
AddfulfillmentPolicy when you need the seller to prove purchase or shipment before delivery is unlocked — e.g. marketplaces, crowd-shipping, or product-deal apps.
- Set
mode: "quick"andfulfillmentPolicy.type: "purchase_proof_required". - After the buyer pays, escrow
statusstayspaidwhileproofInfo.phasetracks the proof gate (waiting_seller_proof→ review →accepted). - Checkout actions:
accept_pay→submit_proof(seller) →review_proof(buyer) →complete. Seller deliver is optional after proof is accepted; buyer cancompletefrompaidwithout deliver. - Fetch proof files with GET /escrows/:id/proof; handle
escrow.proof.*webhooks.
Progressive release (hourly / recurring contracts)
AddprogressiveRelease when the total is known up front but the work arrives incrementally — hourly contracts, retainers, or any arrangement billed per period.
- Include a
progressiveReleaseobject on creation (presence is the opt-in; do not sendenabled), optionally withautoApproveHours(the client’s review window). Composes withstandardorquickmode; not available forinstant. - The escrow stays
paidacross many payouts. Your backend claims each billing period with Create Payout Request — send faceamount+currencyor ledgeramountTnd. You may do this on the seller’s behalf, so the freelancer takes no weekly action. - GET and balance webhooks expose face + TND progressive balances (
availableForRelease/reserved/releasedTotaland*Tndcounterparts) plus stablefundedAmount*— do not invent face amounts withtnd / fxRateUsed. On terminal status, float fields are forced to0. - The client approves (
approve_release), rejects (reject_release, which opens a dispute for that period only), or does nothing — in which case the period releases automatically at its deadline. - Top up the same escrow with
add_funds; a zero balance emitsescrow.balance.exhaustedand leaves the escrow open. - End the contract with Close Escrow, which settles owed periods and refunds the unused balance.
pending → paid → (many partial releases, balance decreasing) → completed on close.
See the Progressive Release guide for the full walkthrough.
Instant mode
For digital goods (e.g. in-app coins, AI credits), the full standard flow has too many steps and can hurt conversion. Use instant when you are the seller:- Set
mode: "instant"and omitsellerEmail(your associated user is the seller). Do not sendcontractTermsorautoSign. - No contract is created; the response includes
contract: nullandescrow.mode: "instant". - Checkout action:
accept_payonly. The actionssign_contractandcompletereturn 400. - When you receive the
escrow.status.updatedwebhook (pending→paid), deliver the digital goods (e.g. credit the user’s balance). - Call Deliver Escrow (
POST /api/v1/escrows/:id/deliver). The escrow auto-completes and funds are released immediately (no buyer confirmation step). - Minimum internal ledger value (
amountTnd) is 0.01 TND after FX lock. - Guest checkout (buyer pays without a DHMAD account) is supported for instant escrows via
accept_pay. feeBearercan be set at create time; it cannot be changed via update after creation for instant escrows.
pending → paid → completed (the delivered state is skipped; calling deliver transitions directly to completed)
Mode comparison
estimatedDeliveryDays is a legacy optional field. Omit it for new integrations — it is not used by platform enforcement.Escrow Statuses
Escrows progress through the following statuses:pending
Escrow created, waiting for payment. The buyer needs to accept and pay.
paid
Payment received and locked in escrow. The buyer can release funds via a
complete checkout session (early release), or the seller can call deliver first (optional). A progressive-release escrow stays here across many partial payouts.delivered
Service/product delivered. Waiting for buyer to confirm completion. Skipped in instant mode.
completed
Transaction completed successfully. Funds released to seller.
cancelled
Escrow was cancelled. Funds returned to buyer if payment was made.
Buyer Handling
When creating an escrow, you provide the buyer’s email address. The system handles two scenarios:Existing User
If the buyer email corresponds to an existing user account:- The escrow is linked to their account
- They receive an in-app notification
- They receive an email notification
- They can view and interact with the escrow immediately
New User
If the buyer email doesn’t correspond to an existing user:- An invitation email is sent with a registration link
- The escrow is created with the email stored
- Once they register using the link, the escrow is automatically linked to their account
- The registration link includes a secure token for verification
API Endpoints (Direct)
These endpoints can be called directly from your server using your API key:- Create Escrow - Create a new escrow transaction
- List Escrows - Get a paginated list of escrows
- Get Escrow - Get detailed information about a specific escrow
- Get Escrow Proof - Proof attachments with
viewUrl(Quick Escrow with Proof) - Get Contract - Get contract details and PDF URL (standard mode only)
- Update Escrow - Update a pending escrow
- Deliver Escrow - Seller marks escrow as delivered
- Reject Delivery - Buyer rejects delivery and returns escrow to paid
- Create Payout Request - Claim one billing period from a progressive-release escrow
- List Payout Requests - Period history and live reservation figures
- Close Escrow - End a progressive contract, settling owed periods and refunding the remainder
- Cancel Escrow - Cancel a pending escrow
Checkout Sessions (Redirect)
For actions that require user interaction, use Checkout Sessions to redirect users to dhmad.tn:- Sign Contract — User signs the escrow contract (standard mode only)
- Accept & Pay — Buyer reviews and pays for the escrow (all modes)
- Submit proof — Seller uploads purchase/shipment proof (Quick Escrow with Proof only)
- Review proof — Buyer accepts proof or requests corrections (proof escrows only)
- Complete — Buyer releases funds (standard and quick modes; not instant). Valid when escrow is
paidordelivered; deliver is not required first. - Dispute — User opens a dispute
- Request cancellation — Buyer requests cancellation (paid or delivered; buyer email only)
- Cancel escrow — Seller cancels immediately (paid or delivered; seller email only)
- Reject / accept cancellation — Seller responds to a pending buyer cancellation request (seller email)
- Approve release — Client approves a payout request, releasing that period now (progressive release only; buyer email,
metadata.requestIdrequired) - Reject release — Client rejects a payout request, opening a dispute for that period only (progressive release only; buyer email,
metadata.requestIdrequired)
Escrow amounts support face currencies TND, USD, and EUR via the
currency field. The platform ledger uses TND only: amountTnd is locked at creation and used for fees and payouts. See Create Escrow for details.