SwitchLock Docs
Escrow / Milestones

Milestone-Based Escrow

Split a single escrow into sequential payment gates. Each milestone releases independently — the seller earns as they deliver, not only when everything is done.

What Are Milestones?

A milestone is a named percentage slice of the total escrow amount. When you add milestones to an escrow, the full amount is still locked upfront — but it is only released in portions as each milestone is completed. This gives buyers protection across long-running contracts, and gives sellers a clear payment schedule with no ambiguity about what triggers each payout.

Milestones are defined at creation time and cannot be added after an escrow is initiated. Each milestone has a title, an optional description, and a percentage. The percentages across all milestones must add up to exactly 100.

Software Projects

Design → Build → QA → Handover. Pay each phase without exposing the full contract amount.

Construction

Foundation → Structure → Fit-out. Payments tied to inspected site progress.

Phased Deliveries

Batch 1 → Batch 2 → Batch 3. Release funds as each shipment is confirmed.

Milestone Fields

Pass the milestones array inside the POST /v1/escrow/initiate body. Omitting the array creates a standard single-release escrow.

FieldTypeRequiredNotes
titlestringYesHuman-readable name, e.g. Phase 1 — Design
descriptionstringNoOptional detail about what deliverables trigger this release
percentageintegerYesShare of the total escrow, 0–100. All milestones must sum to exactly 100

Milestone percentages must total exactly 100. A sum of 99 or 101 will return a validation error. The last milestone absorbs any cent-level rounding remainder so the full locked amount is always distributed.

Milestone Statuses

StatusMeaning
PENDINGFunds allocated to this milestone. Release not yet triggered.
RELEASEDPayout distributed to seller. This milestone is closed.
DISPUTEDAn adjustment proposal has been raised against this milestone.
CANCELLEDMilestone cancelled via an accepted zero-payout adjustment. Buyer refunded.

Creating a Milestone Escrow

The example below creates a four-phase software contract worth $10,000. Each milestone maps to a project phase. Funds for all four phases are locked immediately; each releases only when triggered.

curl -X POST "https://api.switchlock.co.zw/v1/escrow/initiate" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "x-company-id: YOUR_COMPANY_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "buyerId": "usr_buyer_uuid",
    "sellerId": "usr_seller_uuid",
    "buyerAccountId": "acc_buyer_usd_uuid",
    "externalReference": "contract-DEV-2026-001",
    "feePayer": "SELLER",
    "items": [
      {
        "name": "Custom ERP System — Full Build",
        "quantity": 1,
        "pricePerUnit": 1000000
      }
    ],
    "milestones": [
      {
        "title": "Phase 1 — Discovery & Design",
        "description": "Wireframes, architecture diagrams, and approved tech spec",
        "percentage": 20
      },
      {
        "title": "Phase 2 — Core Backend",
        "description": "API, database schema, authentication, and core modules",
        "percentage": 35
      },
      {
        "title": "Phase 3 — Frontend & Integration",
        "description": "UI implementation and end-to-end integration tests passing",
        "percentage": 30
      },
      {
        "title": "Phase 4 — UAT & Handover",
        "description": "User acceptance testing sign-off and production deployment",
        "percentage": 15
      }
    ]
  }'
Response
{
  "id": "esc_02jy...",
  "status": "INITIATED",
  "totalAmount": 1000000,
  "milestones": [
    { "id": "ms_01", "title": "Phase 1 — Discovery & Design", "percentage": 20, "amount": 200000, "status": "PENDING" },
    { "id": "ms_02", "title": "Phase 2 — Core Backend",        "percentage": 35, "amount": 350000, "status": "PENDING" },
    { "id": "ms_03", "title": "Phase 3 — Frontend & Integration", "percentage": 30, "amount": 300000, "status": "PENDING" },
    { "id": "ms_04", "title": "Phase 4 — UAT & Handover",      "percentage": 15, "amount": 150000, "status": "PENDING" }
  ]
}

Releasing a Specific Milestone

Pass milestoneId as a query parameter to release a single milestone. Without it, all remaining pending milestones are released at once.

curl -X POST "https://api.switchlock.co.zw/v1/escrow/esc_02jy/release?milestoneId=ms_01" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "x-company-id: YOUR_COMPANY_ID"
curl -X POST "https://api.switchlock.co.zw/v1/escrow/esc_02jy/release" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "x-company-id: YOUR_COMPANY_ID"
ParameterTypeRequiredNotes
idpathYesThe escrow ID.
milestoneIdqueryNoThe specific milestone to release. If omitted, all eligible milestones are released.
Response — 200 OK
{
  "message": "Successfully released milestone(s)",
  "escrowId": "esc_02jy...",
  "status": "COMPLETED",
  "releasedAmount": 200000
}

Milestones release in sequence. The auto-release on GRN confirmation and the daily 24-hour sweep both respect milestone boundaries — they will only release the milestones that are currently eligible.

How Fees Work With Milestones

Fees are distributed proportionally as each milestone releases — not all upfront or all at the end. Each milestone's release pays its fair share of the total platform and service fee. The final milestone absorbs any rounding remainder to ensure the full locked amount is always distributed with no dust left in escrow.

Milestone% of TotalLocked AmountSeller Payout
Phase 120%$200.00$196.00
Phase 235%$350.00$343.00
Phase 330%$300.00$294.00
Phase 4 (final)15%$150.00$147.00 + rounding

Example assumes a 2% total fee rate on a $1,000 escrow. Actual amounts depend on your configured platform and service fee rates.

Next Steps