Payout API
अपने merchant बैलेंस से किसी भी blockchain address पर निकासी भेजें।
Payout API आपको अपने merchant बैलेंस से किसी भी blockchain address पर programmatically फंड निकालने की सुविधा देता है।
सभी Payout endpoints के लिए, आपको sign सिग्नेचर generate करने के लिए एक अलग Payout API key का उपयोग करना होगा। यह key आपकी सामान्य API key से अलग है और इसे आपके project settings में generate किया जाना चाहिए।
निकासी बनाएँ
आपके merchant बैलेंस से निकासी request बनाता है।
/v1/payoutRequest parameters
| Field | Type | आवश्यक | Description |
|---|---|---|---|
currency | string | हाँ | निकासी currency (देखें References) |
network | string | हाँ | Network code (देखें References) |
amount | string | हाँ | निकासी राशि |
to_address | string | हाँ | प्राप्तकर्ता का blockchain address |
order_id | string | नहीं | Idempotency key — project के भीतर unique। समान order_id के साथ दोहराए गए POST से नया payout नहीं बनता — मौजूदा payout वापस लौटाया जाता है |
url_callback | string | नहीं | payout webhook के लिए URL। इस payout के लिए webhook बंद करने हेतु इसे न दें |
memo | string | null | नहीं | Destination tag / memo. वर्तमान में केवल TON और SOL networks द्वारा उपयोग किया जाता है; अधिकतम 255 chars |
from_currency | string | नहीं | Source बैलेंस जिसे payout के समय debit करके स्वतः ही currency में convert किया जाएगा। आप अपने बैलेंस को USDT जैसी stablecoin में रखते हुए volatile assets (BTC, ETH, …) में payout कर सकते हैं — आपको खुद volatile crypto रखने की जरूरत नहीं है। USDT बैलेंस से debit करने के लिए "USDT" pass करें |
fee_option | string | नहीं | Fees कैसे लगाए जाते हैं। deduct (default) — network + platform fees amount से घटाए जाते हैं, प्राप्तकर्ता को amount - fees मिलता है। add — fees ऊपर से जोड़े जाते हैं, merchant से amount + fees debit किया जाता है, प्राप्तकर्ता को ठीक amount मिलता है |
Idempotency. Project के भीतर, एक payout order_id से unique होता है। समान order_id के साथ वही POST दोबारा भेजना सुरक्षित है — API duplicate बनाने के बजाय मौजूदा payout लौटाता है। Production payout के लिए हमेशा एक order_id pass करें।
Request examples
curl -X POST https://api.2328.io/api/v1/payout \
-H "Content-Type: application/json" \
-H "User-Agent: MyShop/1.0 (+https://myshop.example)" \
-H "project: YOUR_PROJECT_UUID" \
-H "sign: YOUR_HMAC_SIGNATURE" \
-d '{"currency":"TRX","network":"TRX-TRC20","amount":"1.00","to_address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","order_id":"9ed25264-8be4-439f-acf5-2a8732538d27","url_callback":"https://your-site.com/webhook/payout","memo":null,"fee_option":"deduct"}'<?php
function apiSign(string $body, string $apiKey): string {
return hash_hmac('sha256', base64_encode($body), $apiKey);
}
$project = 'YOUR_PROJECT_UUID';
$apiKey = 'YOUR_PAYOUT_API_KEY';
$data = [
'currency' => 'TRX',
'network' => 'TRX-TRC20',
'amount' => '1.00',
'to_address' => 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
'order_id' => '9ed25264-8be4-439f-acf5-2a8732538d27',
'url_callback' => 'https://your-site.com/webhook/payout',
'memo' => null,
'fee_option' => 'deduct',
];
$body = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$sign = apiSign($body, $apiKey);
$ch = curl_init('https://api.2328.io/api/v1/payout');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'User-Agent: MyShop/1.0 (+https://myshop.example)',
"project: $project",
"sign: $sign",
],
]);
$response = json_decode(curl_exec($ch), true);import { createHmac } from "crypto";
function apiSign(body, apiKey) {
const base64 = Buffer.from(body, "utf8").toString("base64");
return createHmac("sha256", apiKey).update(base64).digest("hex");
}
const PROJECT_UUID = "YOUR_PROJECT_UUID";
const PAYOUT_API_KEY = process.env.PAYOUT_API_KEY;
const data = {
currency: "TRX",
network: "TRX-TRC20",
amount: "1.00",
to_address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
order_id: "9ed25264-8be4-439f-acf5-2a8732538d27",
url_callback: "https://your-site.com/webhook/payout",
memo: null,
fee_option: "deduct",
};
const body = JSON.stringify(data);
const sign = apiSign(body, PAYOUT_API_KEY);
const res = await fetch("https://api.2328.io/api/v1/payout", {
method: "POST",
headers: {
"Content-Type": "application/json",
"User-Agent": "MyShop/1.0 (+https://myshop.example)",
project: PROJECT_UUID,
sign,
},
body,
});
const json = await res.json();import json
import hmac
import hashlib
import base64
import httpx
def api_sign(body: str, api_key: str) -> str:
b64 = base64.b64encode(body.encode("utf-8")).decode()
return hmac.new(api_key.encode(), b64.encode(), hashlib.sha256).hexdigest()
PROJECT_UUID = "YOUR_PROJECT_UUID"
PAYOUT_API_KEY = "YOUR_PAYOUT_API_KEY"
data = {
"currency": "TRX",
"network": "TRX-TRC20",
"amount": "1.00",
"to_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"order_id": "9ed25264-8be4-439f-acf5-2a8732538d27",
"url_callback": "https://your-site.com/webhook/payout",
"memo": None,
"fee_option": "deduct",
}
body = json.dumps(data, separators=(",", ":"), ensure_ascii=False)
sign = api_sign(body, PAYOUT_API_KEY)
r = httpx.post(
"https://api.2328.io/api/v1/payout",
headers={
"Content-Type": "application/json",
"User-Agent": "MyShop/1.0 (+https://myshop.example)",
"project": PROJECT_UUID,
"sign": sign,
},
content=body.encode("utf-8"),
)
response = r.json()package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"net/http"
)
func apiSign(body []byte, apiKey string) string {
b64 := base64.StdEncoding.EncodeToString(body)
h := hmac.New(sha256.New, []byte(apiKey))
h.Write([]byte(b64))
return hex.EncodeToString(h.Sum(nil))
}
func marshalCanonical(v any) ([]byte, error) {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(false)
if err := enc.Encode(v); err != nil {
return nil, err
}
return bytes.TrimRight(buf.Bytes(), "\n"), nil
}
type CreatePayout struct {
Currency string `json:"currency"`
Network string `json:"network"`
Amount string `json:"amount"`
ToAddress string `json:"to_address"`
OrderID string `json:"order_id"`
URLCallback string `json:"url_callback"`
Memo *string `json:"memo"`
FeeOption string `json:"fee_option"`
}
func main() {
const projectUUID = "YOUR_PROJECT_UUID"
const payoutAPIKey = "YOUR_PAYOUT_API_KEY"
data := CreatePayout{
Currency: "TRX",
Network: "TRX-TRC20",
Amount: "1.00",
ToAddress: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
OrderID: "9ed25264-8be4-439f-acf5-2a8732538d27",
URLCallback: "https://your-site.com/webhook/payout",
Memo: nil,
FeeOption: "deduct",
}
body, err := marshalCanonical(data)
if err != nil {
panic(err)
}
sign := apiSign(body, payoutAPIKey)
req, _ := http.NewRequest("POST",
"https://api.2328.io/api/v1/payout",
bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", "MyShop/1.0 (+https://myshop.example)")
req.Header.Set("project", projectUUID)
req.Header.Set("sign", sign)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}Response example
{
"state": 0,
"result": {
"uuid": "019dea62-1727-72aa-ac2c-eaf2ade193ef",
"order_id": "9ed25264-8be4-439f-acf5-2a8732538d27",
"status": "pending",
"currency": "TRX",
"network": "TRX-TRC20",
"amount": "1.00",
"merchant_amount": "1",
"network_amount": "0.89",
"amount_usd": "0.33",
"to_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"memo": null,
"txid": null,
"block_number": null,
"error_type": null,
"created_at": "2026-05-02T23:29:50+03:00",
"updated_at": "2026-05-02T23:29:50+03:00"
}
}Fees. Default fee_option: deduct — network + platform fees amount से घटाए जाते हैं (प्राप्तकर्ता को amount - fees मिलता है)। ऊपर से fees लगाने के लिए fee_option: add pass करें — प्राप्तकर्ता को ठीक amount मिलता है और merchant से amount + fees debit किया जाता है।
Payout calculate करें
Payout बनाए बिना और balance debit किए बिना withdrawal amount और fees का estimate देता है। User को confirm करने से पहले उन्हें मिलने (या pay करने) वाली exact amount दिखाने के लिए इसका इस्तेमाल करें।
/v1/payout/calcRequest parameters
Create payout से identical — same fields, same signing। order_id, url_callback, to_address और memo accept तो होते हैं लेकिन ignore किए जाते हैं: कोई payout persist नहीं होता और कोई callback नहीं भेजा जाता।
Request example
curl -X POST https://api.2328.io/api/v1/payout/calc \
-H "Content-Type: application/json" \
-H "User-Agent: MyShop/1.0 (+https://myshop.example)" \
-H "project: YOUR_PROJECT_UUID" \
-H "sign: YOUR_HMAC_SIGNATURE" \
-d '{"currency":"USDT","network":"TRX-TRC20","amount":"100","fee_option":"add"}'Response example
{
"state": 0,
"result": {
"currency": "USDT",
"network": "TRX-TRC20",
"amount": "100",
"fee_option": "add",
"merchant_amount": "103.00000000",
"network_amount": "100",
"total_fee": "3.00000000",
"total_fee_usd": "3.00000000"
}
}Preview only. यह endpoint read-only है — कोई balance debit नहीं होता और कोई payout record नहीं बनता। UI में fee breakdown दिखाने के लिए जितनी बार जरूरत हो call कर सकते हैं।
Payout status
Payout request का status प्राप्त करें।
/v1/payout/status/{uuid}Path parameters
| Field | Type | आवश्यक | Description |
|---|---|---|---|
uuid | string | हाँ | Payout UUID (creation पर result.uuid से) |
Response example
{
"state": 0,
"result": {
"uuid": "019dff1f-0dbd-7277-8d45-271e7775388f",
"order_id": "4dfdcc84402b1185b71cbe399321533e",
"status": "completed",
"currency": "TRX",
"network": "TRX-TRC20",
"amount": "3.00",
"merchant_amount": "3.00",
"network_amount": "3.00",
"amount_usd": "1.04",
"to_address": "THauRv5tcucQRohXg8NiyGTk16DX1XQG5x",
"memo": null,
"txid": "9242e533703704ef3eaba840f70b4a26333e72c943377ee375fea17badb53def",
"block_number": null,
"error_type": null,
"created_at": "2026-05-07T00:08:38+03:00",
"updated_at": "2026-05-07T00:08:54+03:00",
"from_currency": "USDT",
"debited_amount": "1.050735",
"debited_currency": "USDT"
}
}इस GET request के लिए सिग्नेचर खाली body से compute होता है:
hash_hmac('sha256', base64_encode(''), $apiKey)
Response fields
POST /v1/payout और GET /v1/payout/status/{uuid} के result में लौटाए गए fields:
| Field | Type | Description |
|---|---|---|
uuid | string | सिस्टम द्वारा assigned Payout UUID |
order_id | string | आपका आंतरिक payout identifier (project के भीतर unique) |
status | string | वर्तमान payout status (नीचे देखें) |
currency | string | निकासी currency |
network | string | Network code |
amount | string | requested निकासी राशि |
merchant_amount | string | Merchant बैलेंस से debit की गई राशि |
network_amount | string | वास्तव में on-chain भेजी गई राशि (network + platform fees के बाद) |
amount_usd | string | निकासी राशि का USD equivalent |
to_address | string | प्राप्तकर्ता का blockchain address |
memo | string | null | Destination tag / memo (TON, SOL)। अन्यथा null |
txid | string | null | Blockchain transaction hash. transaction भेजे जाने तक null |
block_number | int | null | Block number जहाँ transaction included था। शामिल होने तक null |
error_type | string | null | status = failed होने पर failure का कारण (नीचे Error types देखें)। अन्यथा null |
created_at | string (ISO 8601) | Payout creation का समय |
updated_at | string (ISO 8601) | अंतिम status परिवर्तन का समय |
from_currency | string | null | Auto-conversion का उपयोग होने पर वह source बैलेंस जिससे payout debit हुआ था (जैसे BTC payout के लिए USDT)। यदि कोई conversion नहीं हुआ तो null |
debited_amount | string | null | Conversion के बाद source बैलेंस से वास्तव में debit की गई राशि। केवल auto-conversion के उपयोग पर उपस्थित |
debited_currency | string | null | debited_amount की currency — वह बैलेंस जहाँ से फंड debit किए गए |
Payout statuses
status field निम्न values ले सकता है:
| Status | Description |
|---|---|
pending | बनाया गया, processing की प्रतीक्षा में |
completed | सफलतापूर्वक पूर्ण — txid set है |
failed | भेजने में त्रुटि — error_type देखें |
cancelled | रद्द कर दिया गया |
Error types
जब status = failed होता है, तो error_type field कारण बताता है:
| Code | Description |
|---|---|
aml_risk | AML risk checks द्वारा payout block (प्राप्तकर्ता address को high-risk के रूप में flag किया गया) |
Webhook notifications
जब किसी payout का status बदलता है, तो सिस्टम payout बनाते समय pass किए गए url_callback URL पर एक POST webhook भेजता है। यदि url_callback प्रदान नहीं किया गया था, तो उस payout के लिए कोई webhook नहीं भेजा जाता।
- Method:
POST - Content-Type:
application/json - Signature: request body में
signfield, Payout API key के साथ compute किया गया (वही key जो payout request को sign करने के लिए उपयोग की जाती है)।
Payload GET /v1/payout/status/{uuid} के result object को mirror करता है, साथ में verification के लिए एक sign field होता है।
Payload
{
"uuid": "019dff1f-0dbd-7277-8d45-271e7775388f",
"order_id": "4dfdcc84402b1185b71cbe399321533e",
"status": "completed",
"currency": "TRX",
"network": "TRX-TRC20",
"amount": "3.00",
"merchant_amount": "3.00",
"network_amount": "3.00",
"amount_usd": "1.04",
"to_address": "THauRv5tcucQRohXg8NiyGTk16DX1XQG5x",
"memo": null,
"txid": "9242e533703704ef3eaba840f70b4a26333e72c943377ee375fea17badb53def",
"block_number": null,
"error_type": null,
"created_at": "2026-05-07T00:08:38+03:00",
"updated_at": "2026-05-07T00:08:54+03:00",
"from_currency": "USDT",
"debited_amount": "1.050735",
"debited_currency": "USDT",
"sign": "925ad7bf3d6841864101f7cc2c7e30652e70a06cdb04dbe07a0129480000ce4a"
}सिग्नेचर verify करना. payment webhooks के लिए वही algorithm उपयोग करें, लेकिन सामान्य API key के बजाय अपनी Payout API key से sign करें। sign field हटा दें, बाकी payload को JSON-encode करें, Base64-encode करें, फिर hash_hmac('sha256', $base64, $payoutApiKey) compute करें और प्राप्त sign से तुलना करें।