curl --request POST \
--url https://api.rach.finance/caas/v1/escrows/{id}/refund \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"on_behalf_of": "BUYER",
"reason": "buyer confirmed delivery"
}
'import requests
url = "https://api.rach.finance/caas/v1/escrows/{id}/refund"
payload = {
"on_behalf_of": "BUYER",
"reason": "buyer confirmed delivery"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({on_behalf_of: 'BUYER', reason: 'buyer confirmed delivery'})
};
fetch('https://api.rach.finance/caas/v1/escrows/{id}/refund', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.rach.finance/caas/v1/escrows/{id}/refund",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'on_behalf_of' => 'BUYER',
'reason' => 'buyer confirmed delivery'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.rach.finance/caas/v1/escrows/{id}/refund"
payload := strings.NewReader("{\n \"on_behalf_of\": \"BUYER\",\n \"reason\": \"buyer confirmed delivery\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.rach.finance/caas/v1/escrows/{id}/refund")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"on_behalf_of\": \"BUYER\",\n \"reason\": \"buyer confirmed delivery\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rach.finance/caas/v1/escrows/{id}/refund")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"on_behalf_of\": \"BUYER\",\n \"reason\": \"buyer confirmed delivery\"\n}"
response = http.request(request)
puts response.read_body{
"amount": "250000000",
"auto_release_at": "<string>",
"chain_id": 123,
"created_at": "<string>",
"dispute_reason": "<string>",
"disputed_at": "<string>",
"escrow_address": "<string>",
"funded_at": "<string>",
"funding_expires_at": "<string>",
"id": "<string>",
"network": "<string>",
"payout_pending": true,
"payout_tx_hash": "<string>",
"rail": "<string>",
"reference": "<string>",
"refunded_at": "<string>",
"released_at": "<string>",
"resolution_note": "<string>",
"state": "CREATED",
"token": "<string>",
"updated_at": "<string>"
}{}{}Refund an escrow to the buyer
The tenant API key authorises the full agreed amount to the buyer’s linked Rach TRON wallet, not necessarily the original funding address. No partial-refund or arbitrary refund-address parameter exists. The escrow stays FUNDED with payout_pending=true until confirmed, then becomes REFUNDED. on_behalf_of does not change the key’s authority. Poll the escrow after 202 or 409. Durable signed notifications are retried and can be replayed. Participant and tenant freezes are checked before authorization and by the TRON worker.
curl --request POST \
--url https://api.rach.finance/caas/v1/escrows/{id}/refund \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"on_behalf_of": "BUYER",
"reason": "buyer confirmed delivery"
}
'import requests
url = "https://api.rach.finance/caas/v1/escrows/{id}/refund"
payload = {
"on_behalf_of": "BUYER",
"reason": "buyer confirmed delivery"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({on_behalf_of: 'BUYER', reason: 'buyer confirmed delivery'})
};
fetch('https://api.rach.finance/caas/v1/escrows/{id}/refund', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.rach.finance/caas/v1/escrows/{id}/refund",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'on_behalf_of' => 'BUYER',
'reason' => 'buyer confirmed delivery'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.rach.finance/caas/v1/escrows/{id}/refund"
payload := strings.NewReader("{\n \"on_behalf_of\": \"BUYER\",\n \"reason\": \"buyer confirmed delivery\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.rach.finance/caas/v1/escrows/{id}/refund")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"on_behalf_of\": \"BUYER\",\n \"reason\": \"buyer confirmed delivery\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rach.finance/caas/v1/escrows/{id}/refund")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"on_behalf_of\": \"BUYER\",\n \"reason\": \"buyer confirmed delivery\"\n}"
response = http.request(request)
puts response.read_body{
"amount": "250000000",
"auto_release_at": "<string>",
"chain_id": 123,
"created_at": "<string>",
"dispute_reason": "<string>",
"disputed_at": "<string>",
"escrow_address": "<string>",
"funded_at": "<string>",
"funding_expires_at": "<string>",
"id": "<string>",
"network": "<string>",
"payout_pending": true,
"payout_tx_hash": "<string>",
"rail": "<string>",
"reference": "<string>",
"refunded_at": "<string>",
"released_at": "<string>",
"resolution_note": "<string>",
"state": "CREATED",
"token": "<string>",
"updated_at": "<string>"
}{}{}Authorizations
Your Rach B2B API key. Use rach_sk_live_* for production (on-chain) or rach_sk_test_* for sandbox (no-chain simulation).
Path Parameters
Escrow id
Body
Actor and reason
OnBehalfOf is BUYER or SELLER when the partner is acting for one of its users. It is recorded as evidence of what the partner asserted; the authority for the action remains the partner's own and is recorded separately. Omit it when the partner is acting in its own right.
"BUYER"
Reason is required to raise a dispute and optional elsewhere. It becomes part of the escrow's permanent history.
"buyer confirmed delivery"
Response
Accepted
Amount is in base units, unlike the create request's whole-token amount. For the implemented TRON USDT adapter, "250000000" means 250 USDT.
"250000000"
AutoReleaseAt is when a funded escrow releases to the seller with no further action. Absent means it never does and someone must decide.
EscrowAddress is where the buyer sends the money. It belongs to this deal alone and is never reused.
FundingExpiresAt is when an unpaid escrow closes.
PayoutPending is true while a payout has been authorised and dispatched but not yet confirmed. Surfaced rather than hidden because during this window the honest answer to "has the seller been paid" is "not yet".
PayoutTxHash is the on-chain transaction that moved the money out. It is the partner's evidence that a release or refund really happened.
Recorded admin reasoning once a disputed payout settles.
CREATED, FUNDED, DISPUTED, RELEASED, REFUNDED, EXPIRED, CANCELLED 
