API reference
A JSON REST API for creating transactions and reacting to their lifecycle. Base URL: https://escrow.org.in/api/v1
Authentication
Generate a key under Profile › API keys. Send it as a bearer token on every request. Keys are shown once and stored hashed; revoke a key at any time.
Authorization: Bearer esk_YOUR_API_KEYRequests act as the key’s owner: you can only see and change transactions you are a party to.
Create a transaction
/transactionsFields: type (domain, vehicle, service, milestone, general), title, description, amount, currency (USD, EUR, GBP, AUD, CAD, INR), role (your side: buyer or seller), counterparty_email, fee_payer (buyer, seller, split), inspection_period_days, optional draft (true to save without inviting) and, for milestone type, a milestones array of {title, amount, due_date} that adds up to amount.
curl -X POST https://escrow.org.in/api/v1/transactions \
-H "Authorization: Bearer esk_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type":"general","title":"Vintage camera","description":"Leica M3, serviced 2025","amount":"1250.00","currency":"USD","role":"seller","counterparty_email":"buyer@example.com","fee_payer":"split","inspection_period_days":3}'<?php
$ch = curl_init('https://escrow.org.in/api/v1/transactions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer esk_YOUR_API_KEY',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'type' => 'general',
'title' => 'Vintage camera',
'amount' => '1250.00',
'currency' => 'USD',
'role' => 'seller',
'counterparty_email' => 'buyer@example.com',
'fee_payer' => 'split',
]),
]);
$response = json_decode(curl_exec($ch), true);
echo $response['data']['reference'];import requests
response = requests.post(
'https://escrow.org.in/api/v1/transactions',
headers={'Authorization': 'Bearer esk_YOUR_API_KEY'},
json={
'type': 'general',
'title': 'Vintage camera',
'amount': '1250.00',
'currency': 'USD',
'role': 'seller',
'counterparty_email': 'buyer@example.com',
'fee_payer': 'split',
},
timeout=30,
)
response.raise_for_status()
print(response.json()['data']['reference'])require 'net/http'
require 'json'
uri = URI('https://escrow.org.in/api/v1/transactions')
request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json',
'Authorization' => 'Bearer esk_YOUR_API_KEY')
request.body = {
type: 'general', title: 'Vintage camera', amount: '1250.00', currency: 'USD',
role: 'seller', counterparty_email: 'buyer@example.com', fee_payer: 'split'
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(request) }
puts JSON.parse(response.body)['data']['reference']Returns 201 with the transaction:
{
"data": {
"id": 42,
"reference": "ESC-2026-00042",
"type": "general",
"title": "Vintage camera",
"status": "awaiting_payment",
"currency": "USD",
"amount": 1250,
"escrow_fee": 40.63,
"fee_payer": "split",
"buyer_total": 1270.32,
"seller_net": 1229.68,
"buyer": {"id": 7, "email": "buyer@example.com", "kyc_status": "not_started"},
"seller": {"id": 3, "email": "you@example.com", "kyc_status": "verified"},
"inspection_period_days": 3,
"inspection_deadline": null,
"created_at": "2026-09-20 10:15:00"
}
}Fetch a transaction
/transactions/{id}{id} is the numeric ID or the reference (for example ESC-2026-00042).
curl https://escrow.org.in/api/v1/transactions/ESC-2026-00001 \
-H "Authorization: Bearer esk_YOUR_API_KEY"<?php
$ch = curl_init('https://escrow.org.in/api/v1/transactions/ESC-2026-00001');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer esk_YOUR_API_KEY'],
]);
$transaction = json_decode(curl_exec($ch), true)['data'];
echo $transaction['status'];import requests
r = requests.get('https://escrow.org.in/api/v1/transactions/ESC-2026-00001',
headers={'Authorization': 'Bearer esk_YOUR_API_KEY'}, timeout=30)
print(r.json()['data']['status'])require 'net/http'
require 'json'
uri = URI('https://escrow.org.in/api/v1/transactions/ESC-2026-00001')
req = Net::HTTP::Get.new(uri, 'Authorization' => 'Bearer esk_YOUR_API_KEY')
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
puts JSON.parse(res.body)['data']['status']List transactions
/transactions?page=1&per_page=20&status=in_escrowNewest first. per_page is capped at 100. The response includes meta.total and meta.pages.
Add an event
/transactions/{id}/eventsMoves a transaction forward. Body: {"event": "..."} plus event fields. The same rules as the website apply, so an invalid move returns 422.
| Event | Who | Extra fields |
|---|---|---|
publish | Creator | Invites the other party (for drafts) |
pay | Buyer | Returns approve_url; send the buyer there to pay with PayPal. milestone_id for milestones |
ship | Seller | carrier, tracking_number |
deliver | Buyer or seller | Starts the inspection period |
accept | Buyer | Releases funds to the seller |
request_release | Seller | Asks the buyer to accept |
dispute | Buyer or seller | reason (20+ characters), milestone_id for milestones |
cancel | Any party | reason; only before payment |
curl -X POST https://escrow.org.in/api/v1/transactions/ESC-2026-00042/events \
-H "Authorization: Bearer esk_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"event":"ship","carrier":"UPS","tracking_number":"1Z999AA10123456784"}'Create a customer
/customersRegisters a counterparty by email so you can reference them before they sign up. Body: email, optional first_name, last_name. Returns 201 for a new customer or 200 if the email already exists. The customer sets a password with “Forgot password”.
Fee schedule
/fees?amount=1000Returns the current tiers and, when amount is given, a quote. No transaction is created.
Errors and limits
{
"error": {
"code": "validation_failed",
"message": "The transaction could not be created.",
"details": {"amount": "Enter an amount greater than zero..."}
}
}Status codes: 400 bad JSON, 401 missing or invalid key, 404 not found, 405 wrong method, 422 validation or rule failure, 429 rate limited (60 requests per minute per key; see the Retry-After header).
Webhooks
The platform receives PayPal webhooks at https://escrow.org.in/api/webhook.php. Register that URL in the PayPal developer dashboard for these events and put the resulting Webhook ID in Admin › Settings:
PAYMENT.CAPTURE.COMPLETED: confirms a buyer’s payment even if they never return to the sitePAYMENT.CAPTURE.DENIEDandPAYMENT.CAPTURE.REVERSED: flags the transaction for admin reviewPAYMENT.PAYOUTS-ITEM.*: flags failed, blocked or returned payouts
Every delivery is verified with PayPal’s signature verification API before it is trusted, and duplicate deliveries are ignored. Outbound webhooks to your own systems are not part of this demo; poll GET /transactions/{id} for status changes.