Skip to content
ESCROW.org
  • How it works
  • Pricing
  • Solutions
  • API
  • FAQ
  • Contact
Log in Get started
Contents
  • Authentication
  • Create transaction
  • Fetch transaction
  • List transactions
  • Transaction events
  • Create customer
  • Fee schedule
  • Errors & limits
  • Webhooks

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_KEY

Requests act as the key’s owner: you can only see and change transactions you are a party to.

Create a transaction

POST/transactions

Fields: 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

GET/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

GET/transactions?page=1&per_page=20&status=in_escrow

Newest first. per_page is capped at 100. The response includes meta.total and meta.pages.

Add an event

POST/transactions/{id}/events

Moves a transaction forward. Body: {"event": "..."} plus event fields. The same rules as the website apply, so an invalid move returns 422.

EventWhoExtra fields
publishCreatorInvites the other party (for drafts)
payBuyerReturns approve_url; send the buyer there to pay with PayPal. milestone_id for milestones
shipSellercarrier, tracking_number
deliverBuyer or sellerStarts the inspection period
acceptBuyerReleases funds to the seller
request_releaseSellerAsks the buyer to accept
disputeBuyer or sellerreason (20+ characters), milestone_id for milestones
cancelAny partyreason; 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

POST/customers

Registers 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

GET/fees?amount=1000

Returns 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 site
  • PAYMENT.CAPTURE.DENIED and PAYMENT.CAPTURE.REVERSED: flags the transaction for admin review
  • PAYMENT.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.

ESCROW.org

The most secure way to buy and sell online. Funds are held until both sides confirm the deal.

Platform

  • How it works
  • Pricing
  • Solutions
  • API

Company

  • About
  • Contact
  • FAQ

Legal

  • Terms of service
  • Privacy policy
X in f
© 2026 ESCROW.org. Portfolio demonstration project. Payments are processed by PayPal.