Payout API
Senden Sie Auszahlungen von Ihrem Händlerguthaben an eine beliebige Blockchain-Adresse.
Mit der Payout API können Sie programmatisch Mittel von Ihrem Händlerguthaben an eine beliebige Blockchain-Adresse auszahlen.
Für alle Payout-Endpoints müssen Sie einen separaten Payout-API-Schlüssel verwenden, um die sign-Signatur zu erzeugen. Dieser Schlüssel unterscheidet sich von Ihrem regulären API-Schlüssel und muss in den Projekteinstellungen erzeugt werden.
Auszahlung erstellen
Erzeugt eine Auszahlungsanfrage von Ihrem Händlerguthaben.
/v1/payoutAnfrageparameter
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
currency | string | ja | Auszahlungswährung (siehe References) |
network | string | ja | Netzwerkcode (siehe References) |
amount | string | ja | Auszahlungsbetrag |
to_address | string | ja | Blockchain-Adresse des Empfängers |
order_id | string | nein | Idempotenzschlüssel — innerhalb eines Projekts eindeutig. Ein wiederholter POST mit derselben order_id erzeugt keine neue Auszahlung — stattdessen wird die bestehende zurückgegeben |
url_callback | string | nein | URL für Payout-Webhooks. Auslassen, um Webhooks für diese Auszahlung zu deaktivieren |
memo | string | null | nein | Destination-Tag / Memo. Wird derzeit nur in den Netzwerken TON und SOL verwendet; max. 255 Zeichen |
from_currency | string | nein | Quell-Guthaben, von dem zum Zeitpunkt der Auszahlung abgebucht und automatisch in currency umgerechnet wird. Ermöglicht Auszahlungen in volatilen Assets (BTC, ETH, …), während Ihr Guthaben in einem Stablecoin wie USDT bleibt — Sie müssen die volatile Krypto nicht selbst halten. Übergeben Sie "USDT", um vom USDT-Guthaben abzubuchen |
fee_option | string | nein | Wie Gebühren berechnet werden. deduct (Standard) — Netzwerk- und Plattformgebühren werden vom amount abgezogen, der Empfänger erhält amount - fees. add — Gebühren werden oben aufgeschlagen, dem Händler werden amount + fees belastet, der Empfänger erhält exakt amount |
Idempotenz. Innerhalb eines Projekts ist eine Auszahlung über die order_id eindeutig. Erneutes Senden desselben POST mit derselben order_id ist sicher — die API gibt die bestehende Auszahlung zurück, statt ein Duplikat zu erstellen. Übergeben Sie für produktive Auszahlungen stets eine order_id.
Anfragebeispiele
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()
}Antwortbeispiel
{
"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"
}
}Gebühren. Standardmäßig fee_option: deduct — Netzwerk- und Plattformgebühren werden vom amount abgezogen (der Empfänger erhält amount - fees). Übergeben Sie fee_option: add, um die Gebühren oben aufzuschlagen — der Empfänger erhält exakt amount und dem Händler werden amount + fees belastet.
Auszahlung berechnen
Schätzt Auszahlungsbeträge und Gebühren ohne eine Auszahlung anzulegen oder das Guthaben zu belasten. So kannst du dem Nutzer vor der Bestätigung den exakten Betrag anzeigen, den er erhält (oder zahlt).
/v1/payout/calcAnfrageparameter
Identisch zu Auszahlung erstellen — gleiche Felder, gleiche Signatur. order_id, url_callback, to_address und memo werden akzeptiert, aber ignoriert: es wird keine Auszahlung gespeichert und keine Callbacks gesendet.
Anfragebeispiel
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"}'Antwortbeispiel
{
"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"
}
}Nur Vorschau. Dieser Endpoint ist nur lesend — es wird kein Guthaben belastet und kein Auszahlungsdatensatz erstellt. Rufe ihn so oft auf, wie du brauchst, um Gebührendetails in der Oberfläche darzustellen.
Auszahlungsstatus
Status einer Auszahlungsanfrage abrufen.
/v1/payout/status/{uuid}Pfadparameter
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
uuid | string | ja | Auszahlungs-UUID (aus result.uuid bei der Erstellung) |
Antwortbeispiel
{
"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"
}
}Bei dieser GET-Anfrage wird die Signatur über einen leeren Body berechnet:
hash_hmac('sha256', base64_encode(''), $apiKey)
Antwortfelder
Felder, die in result von POST /v1/payout und GET /v1/payout/status/{uuid} zurückgegeben werden:
| Feld | Typ | Beschreibung |
|---|---|---|
uuid | string | Vom System vergebene Auszahlungs-UUID |
order_id | string | Ihre interne Auszahlungs-ID (innerhalb des Projekts eindeutig) |
status | string | Aktueller Auszahlungsstatus (siehe unten) |
currency | string | Auszahlungswährung |
network | string | Netzwerkcode |
amount | string | Angeforderter Auszahlungsbetrag |
merchant_amount | string | Vom Händlerguthaben abgebuchter Betrag |
network_amount | string | Tatsächlich on-chain gesendeter Betrag (nach Netzwerk- und Plattformgebühren) |
amount_usd | string | USD-Gegenwert des Auszahlungsbetrags |
to_address | string | Blockchain-Adresse des Empfängers |
memo | string | null | Destination-Tag / Memo (TON, SOL). Andernfalls null |
txid | string | null | Hash der Blockchain-Transaktion. null, bis die Transaktion gesendet wurde |
block_number | int | null | Blocknummer, in der die Transaktion enthalten ist. null, bis sie aufgenommen wurde |
error_type | string | null | Fehlerursache, wenn status = failed (siehe unten Fehlertypen). Andernfalls null |
created_at | string (ISO 8601) | Erstellungszeitpunkt der Auszahlung |
updated_at | string (ISO 8601) | Zeitpunkt der letzten Statusänderung |
from_currency | string | null | Quell-Guthaben, von dem die Auszahlung bei automatischer Umrechnung abgebucht wurde (z. B. USDT für eine BTC-Auszahlung). null, wenn keine Umrechnung erfolgte |
debited_amount | string | null | Tatsächlich vom Quell-Guthaben nach Umrechnung abgebuchter Betrag. Nur vorhanden, wenn die automatische Umrechnung verwendet wird |
debited_currency | string | null | Währung von debited_amount — das Guthaben, von dem die Mittel abgebucht wurden |
Auszahlungsstatus-Werte
Das Feld status kann folgende Werte annehmen:
| Status | Beschreibung |
|---|---|
pending | Erstellt, wartet auf Verarbeitung |
completed | Erfolgreich abgeschlossen — txid ist gesetzt |
failed | Sendefehler — siehe error_type |
cancelled | Storniert |
Fehlertypen
Wenn status = failed, beschreibt das Feld error_type den Grund:
| Code | Beschreibung |
|---|---|
aml_risk | Auszahlung durch AML-Risikoprüfungen blockiert (Empfängeradresse als hohes Risiko gekennzeichnet) |
Webhook-Benachrichtigungen
Wenn sich der Status einer Auszahlung ändert, sendet das System einen POST-Webhook an die url_callback-URL, die bei der Erstellung der Auszahlung übergeben wurde. Wurde keine url_callback angegeben, werden für diese Auszahlung keine Webhooks gesendet.
- Methode:
POST - Content-Type:
application/json - Signatur: Feld
signim Anfrage-Body, berechnet mit dem Payout-API-Schlüssel (demselben Schlüssel, mit dem auch Auszahlungsanfragen signiert werden).
Der payload spiegelt das result-Objekt aus GET /v1/payout/status/{uuid} wider, ergänzt um ein sign-Feld zur Verifizierung.
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"
}Signatur verifizieren. Verwenden Sie denselben Algorithmus wie bei Zahlungs-Webhooks, signieren Sie aber mit Ihrem Payout-API-Schlüssel statt dem regulären API-Schlüssel. Entfernen Sie das Feld sign, JSON-codieren Sie den verbleibenden payload, base64-codieren Sie ihn und berechnen Sie anschließend hash_hmac('sha256', $base64, $payoutApiKey). Vergleichen Sie das Ergebnis mit der erhaltenen sign.