API reference · Moving money

Escrow

Two-party agreements with staged release that both sides approve. About escrow Live

POST Open an escrow agreement

POST /escrow

Creates an agreement and its payment gates. No money moves - funding is a separate call, and it is funding that freezes the terms. Omit gates entirely for a single gate covering the full amount; the simple escrow is the same model, not a special case. The payee is named by mobile number, email address or username and is resolved within the caller's tenant to exactly one existing user.

Headers

NameNotes
AuthorizationBearer token
X-TenantYour tenant
X-Environmenttest or live
Content-Typeapplication/json

Example

Request body: EscrowRequest · Response: EscrowResponse

curl -X POST "https://api.bridgemoni.com/escrow" \
  -H "Authorization: Bearer $BRIDGEMONI_TOKEN" \
  -H "X-Tenant: $BRIDGEMONI_TENANT" \
  -H "X-Environment: $BRIDGEMONI_ENV" \
  -H "Content-Type: application/json" \
  -d '{
    "payeeIdentifierType": "MSISDN",
    "payeeIdentifier": "text",
    "amount": 250000.0,
    "currencyCode": "NGN",
    "expiresAt": "2027-03-14T14:30:01",
    "narrative": "March payroll",
    "gates": [
      {
        "name": "Ada Obi",
        "amount": 250000.0,
        "criteriaDescription": "March payroll",
        "dueAt": "2027-03-14T14:30:01"
      }
    ]
  }'

Responses

StatusWhen
200Agreement created
404No account matches the payee identifier supplied
409Escrow is not enabled for this tenant and currency, or the tenant's ESCROW_BACKOFFICE role has no members - a disputed escrow would have nobody able to resolve it

GET Fetch one escrow agreement

GET /escrow/{reference}

Visible to the payer and the payee only. Anyone else gets 404, not 403.

Headers

NameNotes
AuthorizationBearer token
X-TenantYour tenant
X-Environmenttest or live

Path parameters

Name
reference

Example

Response: EscrowResponse

curl -X GET "https://api.bridgemoni.com/escrow/b3f1c2d4-5e6a-4b7c-8d9e-0f1a2b3c4d5e" \
  -H "Authorization: Bearer $BRIDGEMONI_TOKEN" \
  -H "X-Tenant: $BRIDGEMONI_TENANT" \
  -H "X-Environment: $BRIDGEMONI_ENV"

Responses

StatusWhen
200Agreement returned

POST Cancel a draft agreement

POST /escrow/{reference}/cancel

Abandons an agreement before it is funded. Payer only. No money is involved, so nothing is refunded and no case is opened - this is the one abandonment that resolves itself. A funded agreement cannot be cancelled: the way out is for both parties to reject, or for an operator to resolve it.

Headers

NameNotes
AuthorizationBearer token
X-TenantYour tenant
X-Environmenttest or live

Path parameters

Name
reference

Example

Response: EscrowResponse

curl -X POST "https://api.bridgemoni.com/escrow/b3f1c2d4-5e6a-4b7c-8d9e-0f1a2b3c4d5e/cancel" \
  -H "Authorization: Bearer $BRIDGEMONI_TOKEN" \
  -H "X-Tenant: $BRIDGEMONI_TENANT" \
  -H "X-Environment: $BRIDGEMONI_ENV"

Responses

StatusWhen
200Cancelled
409Already funded - there is money held

POST Fund an escrow agreement

POST /escrow/{reference}/fund

Moves the principal into the tenant's escrow account and charges the payer the flat escrow fee. Always for the full amount - gates divide the release, not the deposit. This is also the lock-in: from here the gate set is frozen permanently.

Headers

NameNotes
AuthorizationBearer token
X-TenantYour tenant
X-Environmenttest or live
Content-Typeapplication/json

Path parameters

Name
reference

Example

Request body: FundEscrowRequest · Response: EscrowResponse

curl -X POST "https://api.bridgemoni.com/escrow/b3f1c2d4-5e6a-4b7c-8d9e-0f1a2b3c4d5e/fund" \
  -H "Authorization: Bearer $BRIDGEMONI_TOKEN" \
  -H "X-Tenant: $BRIDGEMONI_TENANT" \
  -H "X-Environment: $BRIDGEMONI_ENV" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotencyKey": "text"
  }'

Responses

StatusWhen
200Funded
409Already funded

POST Approve one payment gate

POST /escrow/{reference}/gate/{gateReference}/approve

Records the caller's approval of one gate. The approval that makes the pair unanimous releases that gate's amount to the payee in the same request - there is no separate release call, because a gate that is fully approved but unreleased is a state nobody asked for. Gates are independent: gate 2 may be approved and released while gate 1 is still pending. Approving again is idempotent, and a party who previously rejected has their vote replaced.

Headers

NameNotes
AuthorizationBearer token
X-TenantYour tenant
X-Environmenttest or live
Content-Typeapplication/json

Path parameters

Name
reference
gateReference

Example

Request body: EscrowVoteRequest · Response: EscrowVoteResponse

curl -X POST "https://api.bridgemoni.com/escrow/b3f1c2d4-5e6a-4b7c-8d9e-0f1a2b3c4d5e/gate/b3f1c2d4-5e6a-4b7c-8d9e-0f1a2b3c4d5e/approve" \
  -H "Authorization: Bearer $BRIDGEMONI_TOKEN" \
  -H "X-Tenant: $BRIDGEMONI_TENANT" \
  -H "X-Environment: $BRIDGEMONI_ENV" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "March payroll"
  }'

Responses

StatusWhen
200Vote recorded, and released if unanimous
404No such agreement or gate for this caller. Returned rather than 403 when the caller is not a party: a 403 would confirm the reference names a real agreement
409The gate has already settled

POST Raise a dispute on one payment gate

POST /escrow/{reference}/gate/{gateReference}/dispute

Escalates a gate to the back office deliberately, without waiting for a deadline and without needing the other party to have voted. Useful precisely where rejecting is not: a party who has APPROVED, or who has not voted at all, and wants a human. The payee who approved and has waited a fortnight on a silent payer has nothing to reject. Mechanically a flag rather than a vote - the votes are untouched, so the parties can still reach unanimity and settle it themselves without an operator.

Headers

NameNotes
AuthorizationBearer token
X-TenantYour tenant
X-Environmenttest or live
Content-Typeapplication/json

Path parameters

Name
reference
gateReference

Example

Request body: EscrowVoteRequest · Response: EscrowVoteResponse

curl -X POST "https://api.bridgemoni.com/escrow/b3f1c2d4-5e6a-4b7c-8d9e-0f1a2b3c4d5e/gate/b3f1c2d4-5e6a-4b7c-8d9e-0f1a2b3c4d5e/dispute" \
  -H "Authorization: Bearer $BRIDGEMONI_TOKEN" \
  -H "X-Tenant: $BRIDGEMONI_TENANT" \
  -H "X-Environment: $BRIDGEMONI_ENV" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "March payroll"
  }'

Responses

StatusWhen
200Case raised
409The gate has already settled

POST Reject one payment gate

POST /escrow/{reference}/gate/{gateReference}/reject

Records the caller's rejection. ANY rejection opens a case immediately, from the first one, whatever the other party has done - so rejecting is a heavier act than approving, and a client presenting the two as equal buttons will generate cases nobody meant to open. If the other party had also rejected, the pair is unanimous and the gate's amount is refunded to the payer in the same request, with no operator involved. If they had approved, the votes genuinely disagree and the case is a dispute. Rejecting after approving replaces your own vote.

Headers

NameNotes
AuthorizationBearer token
X-TenantYour tenant
X-Environmenttest or live
Content-Typeapplication/json

Path parameters

Name
reference
gateReference

Example

Request body: EscrowVoteRequest · Response: EscrowVoteResponse

curl -X POST "https://api.bridgemoni.com/escrow/b3f1c2d4-5e6a-4b7c-8d9e-0f1a2b3c4d5e/gate/b3f1c2d4-5e6a-4b7c-8d9e-0f1a2b3c4d5e/reject" \
  -H "Authorization: Bearer $BRIDGEMONI_TOKEN" \
  -H "X-Tenant: $BRIDGEMONI_TENANT" \
  -H "X-Environment: $BRIDGEMONI_ENV" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "March payroll"
  }'

Responses

StatusWhen
200Vote recorded; refunded if unanimous
404No such agreement or gate for this caller
409The gate has already settled

PUT Amend a draft agreement's terms

PUT /escrow/{reference}/gates

Replaces the amount, expiry and gate set outright. Payer only, and only while the agreement is DRAFT - funding is the lock-in, and from it the gate set is frozen permanently. The whole set is replaced rather than patched because gate amounts must sum to the agreement amount: editing one gate in isolation is almost never valid on its own, so a per-gate PATCH would reject most single calls and callers would route around it with sequences that are invalid at every step. Gate references are reissued - any reference shown against the previous draft becomes meaningless.

Headers

NameNotes
AuthorizationBearer token
X-TenantYour tenant
X-Environmenttest or live
Content-Typeapplication/json

Path parameters

Name
reference

Example

Request body: AmendEscrowGatesRequest · Response: EscrowResponse

curl -X PUT "https://api.bridgemoni.com/escrow/b3f1c2d4-5e6a-4b7c-8d9e-0f1a2b3c4d5e/gates" \
  -H "Authorization: Bearer $BRIDGEMONI_TOKEN" \
  -H "X-Tenant: $BRIDGEMONI_TENANT" \
  -H "X-Environment: $BRIDGEMONI_ENV" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 250000.0,
    "expiresAt": "2027-03-14T14:30:01",
    "gates": [
      {
        "name": "Ada Obi",
        "amount": 250000.0,
        "criteriaDescription": "March payroll",
        "dueAt": "2027-03-14T14:30:01"
      }
    ]
  }'

Responses

StatusWhen
200Terms replaced
400Gate amounts do not sum to the agreement amount, or a gate is due after it
409The agreement is already funded, so its terms are frozen

GET List the caller's escrow agreements

GET /escrows

Agreements where the caller is the payer or the payee, and no one else's. Note the consequence: an operator calling this sees an empty list, which looks broken but is correct - they are not a party to anything.

Headers

NameNotes
AuthorizationBearer token
X-TenantYour tenant
X-Environmenttest or live

Example

Response: List<EscrowResponse>

curl -X GET "https://api.bridgemoni.com/escrows" \
  -H "Authorization: Bearer $BRIDGEMONI_TOKEN" \
  -H "X-Tenant: $BRIDGEMONI_TENANT" \
  -H "X-Environment: $BRIDGEMONI_ENV"

Responses

StatusWhen
200Agreements returned

Generated from the OpenAPI document. Branch on the HTTP status: there is no machine-readable error code on the wire. Errors