Skip to main content

Deposits, Funding, Escrow & Payouts

Move funds in, verify via webhooks, and release payouts safely.

C
Written by Catalin Fetean
Updated over 3 weeks ago

Audience: PMs, Finance, Devs, Admins
Outcomes: Deposit verified; order moves to InProgress; milestone releases logged

Request deposit — Cards (Stripe)

curl -X POST $API_BASE/api/payments/intents -b cookies.txt \ -H 'Content-Type: application/json' \ -d '{"orderId":"ord_123","amount":150000,"currency":"USD"}'

Request deposit — Bank (open banking)

curl -X POST $API_BASE/api/payments/bank/link -b cookies.txt \ -H 'Content-Type: application/json' \ -d '{"orderId":"ord_123","amount":150000,"currency":"EUR","returnUrl":"https://app.example.com/return"}'

Rule of motion

  • Status moves to DepositPaid only after a verified webhook

  • From there, PM sets InProgress (or auto-move per policy)

Watch with SSE

const es = new EventSource('/api/events/stream', { withCredentials: true }); es.addEventListener('payment.succeeded', e => console.log('deposit ok', JSON.parse(e.data)));

Release funds (per milestone)

curl -X POST $API_BASE/api/escrow/release -b cookies.txt \ -H 'Content-Type: application/json' \ -d '{"orderId":"ord_123","milestoneId":"m2","amount":100000}'

Events
milestone.released, payment.succeeded (if 3rd-party), order.status.changed

Invoices
Releases generate/update invoices; download from the order or
GET /api/invoices/:orderId.pdf

Edge cases

  • Release fails → check escrow balance, crypto gas, provider outage; retry (idempotent)

  • Partial releases allowed; never exceed remaining milestone balance

QA checklist

  • Webhook with bad signature rejected; no state change

  • Duplicate release request deduped by reference/event ID

Runbook: “Deliverable accepted but no payout”

  • Verify a release was created; trigger manually or via policy and re-check webhook logs

Did this answer your question?