# Автоматический POSTBACK

После успешного подтверждения счета на указанный в настройках проекта URL для уведомлений отправляется POST запрос с информацией о платеже.

В системе предусмотрено 2 варианта формата отправки POSTBACK:

1. JSON
2. application/x-www-form-urlencoded

Для настройки типа получаемого POSTBACK необходимо перейти в настройки вашего проекта, далее раздел «Интеграция и API».

### Что делает метод:

* Автоматически отправляет POST запрос на указанную вами ссылку после подтверждения счета системой
* Формат POSTBACK можно настроить

### Параметры POSTBACK

| Name           | Type   | Example                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Description                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| -------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| status         | string | success                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Статус выполнения запроса                                                                                                                                                                                                                                                                                                                                                                                                                                |
| invoice\_id    | string | 89UX09KA                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | Уникальный идентификатор платежа без префикса INV                                                                                                                                                                                                                                                                                                                                                                                                        |
| amount\_crypto | float  | 0.000113                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | Сумма платежа в криптовалюте                                                                                                                                                                                                                                                                                                                                                                                                                             |
| currency       | string | BNB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | <p>Код валют:</p><p></p><p>BTC, LTC, TRX, SOL, TON, BNB, ETH, ETH\_ARB, ETH\_BASE, ETH\_OPT, USDT\_ARB, USDT\_BSC, USDT\_ERC20, USDT\_OPT, USDT\_SOL, USDT\_TON, USDT\_TRC20, USDC\_ARB, USDC\_BASE, USDC\_BSC, USDC\_ERC20, USDC\_OPT, USDC\_SOL, DAI\_ARB, DAI\_BASE, DAI\_BSC, DAI\_ERC20, DAI\_OPT, USDD\_TRC20, PYUSD\_ERC20, PYUSD\_SOL, XAUT\_ERC20, XAUT\_TON, ARB\_ARB, OP\_OPT, PEPE\_BSC, PEPE\_ERC20, SHIB\_BSC, SHIB\_ERC20, TRUMP\_SOL</p> |
| order\_id      | string | ORDER\_93223                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Произвольный номер счета во внешней системе                                                                                                                                                                                                                                                                                                                                                                                                              |
| token          | string | eyJ0eXAiOiJKV1QiLCJhbGciOiJIAcI1NiJ9.eyJpZCI6MTMsImV4cCI6MTYzMTc4NjQyNn0.HQavV3z8dFnk56bX3MSY5X9lR6qVa9YhAoeTEHkaAzs                                                                                                                                                                                                                                                                                                                                                                                                                                                            | JWT токен – подпись ответа от сервера                                                                                                                                                                                                                                                                                                                                                                                                                    |
| invoice\_info  | dict   | <p>"invoice\_info": {</p><p>        "uuid": "INV-ILRAJE1Q",</p><p>        "created": "2026-01-01 10:20:04.222439",</p><p>        "address": "0x635DBa<...>2Ec029fc555af05d2",</p><p>        "currency": {</p><p>            "id": 20,</p><p>            "code": "BNB",</p><p>            "fullcode": "BNB",</p><p>            "network": {</p><p>                "code": "BSC",</p><p>                "id": 20,</p><p>                "icon": "<https://cdn.cryptocloud.plus/img/network/BSC.svg>",</p><p>                "fullname": "BNB Smart Chain"</p><p>            }</p> | Подробная информация о счете. Читается только в JSON.                                                                                                                                                                                                                                                                                                                                                                                                    |

{% hint style="info" %}
JWT токен — подпись ответа от сервера. Подписывается секретным ключом (SECRET KEY), который генерируется в настройках проекта. Токен действителен в течение 5 минут после создания уведомления. Генерируется каждый раз при отправке уведомления об оплате.

Алгоритм шифрования — HS256.
{% endhint %}

### Пример JSON Postback

{% tabs %}
{% tab title="POSTBACK JSON" %}

```json
{
    "status": "success",
    "invoice_id": "ILRAJE1Q",
    "amount_crypto": 0.000113,
    "currency": "BNB",
    "order_id": null,
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJ<...>hPirF9kHCx3ZXEspVfGNGuK7cZ8",
    "invoice_info": {
        "uuid": "INV-ILRAJE1Q",
        "created": "2026-01-27 10:20:04.222439",
        "address": "0x635DBa9c6e5E9<...>6f8Bed2Ec029fc555af05d2",
        "currency": {
            "id": 20,
            "code": "BNB",
            "fullcode": "BNB",
            "network": {
                "code": "BSC",
                "id": 20,
                "icon": "https://cdn.cryptocloud.plus/img/network/BSC.svg",
                "fullname": "BNB Smart Chain"
            },
            "name": "BNB",
            "is_email_required": false,
            "stablecoin": false,
            "icon_base": "https://cdn.cryptocloud.plus/img/currency/BNB.svg",
            "icon_network": "https://cdn.cryptocloud.plus/img/currency/BNB.svg",
            "icon_qr": "https://cdn.cryptocloud.plus/img/stroke/BNB_STROKE.svg",
            "order": 13
        },
        "date_finished": "2026-01-01 10:23:14.000940",
        "expiry_date": "2026-01-02 10:20:04.197389",
        "side_commission": "client",
        "type_payments": "crypto",
        "amount": 0.000113,
        "amount_": 0.000113,
        "status": "paid",
        "invoice_status": "success",
        "is_email_required": false,
        "project": {
            "id": 1,
            "name": "Test",
            "fail": "https://test.com/failed-payment",
            "success": "https://test.com/successful-payment",
            "logo": ""
        },
        "tx_list": [
            "0x12fb777c41b58b8304278416e5a<...>c1e7708b2160745af56403641522"
        ],
        "amount_in_crypto": null,
        "amount_in_fiat": 0.1,
        "amount_usd": 0.1,
        "amount_to_pay": 0.000113,
        "amount_to_pay_usd": 0.1,
        "amount_paid": 0.000113,
        "amount_paid_usd": 0.1,
        "fee": 0,
        "fee_usd": 0,
        "service_fee": 0.000002,
        "service_fee_usd": 0,
        "received": 0.000111,
        "received_usd": 0.1,
        "to_surcharge": 0,
        "to_surcharge_usd": 0,
        "total_rub": 0,
        "step": 3,
        "test_mode": false,
        "type": "up",
        "aml_enabled": false,
        "aml_side": "merchant",
        "aml_checks": [],
        "links_invoice": null
    }
}
```

{% endtab %}

{% tab title="POSTBACK application/x-www-form-urlencoded" %}

```json
{
    "status": "success",
    "invoice_id": "ILRAJE1Q",
    "amount_crypto": 0.000113,
    "currency": "BNB",
    "order_id": null,
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJ<...>hPirF9kHCx3ZXEspVfGNGuK7cZ8",
}
```

{% endtab %}
{% endtabs %}

### Пример обработчика POSTBACK JSON

Эти примеры показывают, как вы можете обрабатывать POSTBACK в формате JSON на стороне вашего проекта.

{% tabs %}
{% tab title="Python" %}

```python
from flask import Flask, request, jsonify
import os
import jwt  # pip install PyJWT

app = Flask(__name__)

JWT_SECRET = os.getenv("JWT_SECRET", "super-secret")
JWT_ALGORITHMS = ["HS256"]


def validate_token(token: str) -> bool:
    """
    Validate HS256 JWT only if token is present and not empty.
    Token is expected to be a raw JWT string (no "Bearer " prefix).
    """
    if token is None:
        return True
    if not isinstance(token, str):
        return False

    token = token.strip()
    if token == "":
        return True

    try:
        jwt.decode(token, JWT_SECRET, algorithms=JWT_ALGORITHMS)
        return True
    except jwt.PyJWTError:
        return False


@app.route("/postback", methods=["POST"])
def handle_postback():
    # 1) Read JSON body
    data = request.get_json(silent=True)
    if not isinstance(data, dict):
        return jsonify({"error": "Invalid JSON"}), 400

    # 2) Top-level fields
    status = data.get("status")
    invoice_id = data.get("invoice_id")
    amount_crypto = data.get("amount_crypto")
    currency = data.get("currency")
    order_id = data.get("order_id")
    token = data.get("token")

    # Basic validation
    if not invoice_id or not order_id:
        return jsonify({"error": "Missing invoice_id or order_id"}), 400

    # 3) Validate JWT token (only if provided)
    if not validate_token(token):
        return jsonify({"error": "Invalid token"}), 401

    # 4) Nested invoice_info object
    invoice_info = data.get("invoice_info") or {}

    uuid = invoice_info.get("uuid")
    created = invoice_info.get("created")
    address = invoice_info.get("address")

    invoice_status = invoice_info.get("invoice_status")
    invoice_amount = invoice_info.get("amount")
    amount_paid = invoice_info.get("amount_paid")
    fee = invoice_info.get("fee")

    # 5) Deeper nesting: invoice_info.currency.network
    inv_currency = invoice_info.get("currency") or {}
    network = inv_currency.get("network") or {}
    network_code = network.get("code")

    # 6) Project info
    project = invoice_info.get("project") or {}
    project_name = project.get("name")

    # 7) Business logic should be implemented here:
    # - idempotency by invoice_id / uuid
    # - update invoice status in the database
    # - amount / currency validation
    # - logging (avoid logging token)

    return jsonify({"message": "Postback received"}), 200


if __name__ == "__main__":
    app.run(port=5000, debug=True)
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const express = require("express");
const jwt = require("jsonwebtoken");

const app = express();
app.use(express.json());

// HS256 secret (store in ENV in production)
const JWT_SECRET = process.env.JWT_SECRET || "super-secret";

/**
 * Validate HS256 JWT token only if it is present and not empty.
 * Token is expected to be a raw JWT string (no "Bearer " prefix).
 */
function validateToken(token) {
  // Token is optional
  if (token === undefined || token === null) return true;
  if (typeof token !== "string") return false;

  const t = token.trim();
  if (t === "") return true;

  try {
    jwt.verify(t, JWT_SECRET, { algorithms: ["HS256"] });
    return true;
  } catch (err) {
    return false;
  }
}

app.post("/postback", (req, res) => {
  // 1) Read JSON body
  const data = req.body;
  if (!data || typeof data !== "object" || Array.isArray(data)) {
    return res.status(400).json({ error: "Invalid JSON" });
  }

  // 2) Basic required fields (adjust as needed)
  const invoice_id = data.invoice_id;
  const order_id = data.order_id;

  if (!invoice_id || !order_id) {
    return res.status(400).json({ error: "Missing invoice_id or order_id" });
  }

  // 3) Validate JWT token (only if provided)
  const token = data.token;
  if (!validateToken(token)) {
    return res.status(401).json({ error: "Invalid token" });
  }

  // 4) Nested invoice_info object
  const invoice_info = data.invoice_info || {};

  const uuid = invoice_info.uuid;
  const created = invoice_info.created;
  const address = invoice_info.address;

  const invoice_status = invoice_info.invoice_status;
  const invoice_amount = invoice_info.amount;
  const amount_paid = invoice_info.amount_paid;
  const fee = invoice_info.fee;

  // 5) Deeper nesting: invoice_info.currency.network
  const inv_currency = invoice_info.currency || {};
  const network = inv_currency.network || {};
  const network_code = network.code;

  // 6) Project info
  const project = invoice_info.project || {};
  const project_name = project.name;

  // 7) Business logic goes here (examples):
  // - idempotency by invoice_id / uuid
  // - update invoice status in DB
  // - validate amounts/currency
  // - logging (avoid logging token)
  //
  // Example (pseudo):
  // await db.invoices.upsert({ invoice_id, order_id, uuid, invoice_status, amount_paid, fee, network_code, project_name, created, address })

  // 8) Minimal response (as requested)
  return res.status(200).json({ message: "Postback received" });
});

app.listen(5000, () => {
  console.log("Server running on http://127.0.0.1:5000");
});
```

{% endtab %}

{% tab title="PHP 7.4 +" %}

```php
<?php
// postback.php

header('Content-Type: application/json; charset=utf-8');

$JWT_SECRET = getenv('JWT_SECRET') ?: 'super-secret';

/**
 * Base64URL decode (JWT uses base64url without padding)
 */
function base64url_decode($data) {
    $remainder = strlen($data) % 4;
    if ($remainder) {
        $data .= str_repeat('=', 4 - $remainder);
    }
    $data = strtr($data, '-_', '+/');
    return base64_decode($data);
}

/**
 * Validate HS256 JWT only if token is present and not empty.
 * Token is expected to be a raw JWT string (no "Bearer " prefix).
 */
function validateToken($token, $secret) {
    // Token is optional
    if (!isset($token)) return true;
    if (!is_string($token)) return false;

    $t = trim($token);
    if ($t === '') return true;

    $parts = explode('.', $t);
    if (count($parts) !== 3) return false;

    [$headerB64, $payloadB64, $sigB64] = $parts;

    $headerJson = base64url_decode($headerB64);
    $payloadJson = base64url_decode($payloadB64);
    if ($headerJson === false || $payloadJson === false) return false;

    $header = json_decode($headerJson, true);
    $payload = json_decode($payloadJson, true);
    if (!is_array($header) || !is_array($payload)) return false;

    // Ensure HS256
    if (($header['alg'] ?? null) !== 'HS256') return false;

    // Verify signature
    $dataToSign = $headerB64 . '.' . $payloadB64;
    $expectedSigRaw = hash_hmac('sha256', $dataToSign, $secret, true);
    $sigRaw = base64url_decode($sigB64);
    if ($sigRaw === false) return false;

    if (!hash_equals($expectedSigRaw, $sigRaw)) return false;

    // Optional: validate exp/nbf if present
    $now = time();
    if (isset($payload['nbf']) && is_numeric($payload['nbf']) && $now < (int)$payload['nbf']) {
        return false;
    }
    if (isset($payload['exp']) && is_numeric($payload['exp']) && $now >= (int)$payload['exp']) {
        return false;
    }

    return true;
}

// 1) Read raw JSON body
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);

if (!is_array($data)) {
    http_response_code(400);
    echo json_encode(['error' => 'Invalid JSON'], JSON_UNESCAPED_UNICODE);
    exit;
}

// 2) Basic required fields
$invoice_id = $data['invoice_id'] ?? null;
$order_id   = $data['order_id'] ?? null;

if (!$invoice_id || !$order_id) {
    http_response_code(400);
    echo json_encode(['error' => 'Missing invoice_id or order_id'], JSON_UNESCAPED_UNICODE);
    exit;
}

// 3) Validate JWT token (only if provided)
$token = $data['token'] ?? null;
if (!validateToken($token, $JWT_SECRET)) {
    http_response_code(401);
    echo json_encode(['error' => 'Invalid token'], JSON_UNESCAPED_UNICODE);
    exit;
}

// 4) Nested invoice_info object
$invoice_info = $data['invoice_info'] ?? [];

$uuid    = $invoice_info['uuid'] ?? null;
$created = $invoice_info['created'] ?? null;
$address = $invoice_info['address'] ?? null;

$invoice_status = $invoice_info['invoice_status'] ?? null;
$invoice_amount = $invoice_info['amount'] ?? null;
$amount_paid    = $invoice_info['amount_paid'] ?? null;
$fee            = $invoice_info['fee'] ?? null;

// 5) Deeper nesting: invoice_info.currency.network
$inv_currency = $invoice_info['currency'] ?? [];
$network      = $inv_currency['network'] ?? [];
$network_code = $network['code'] ?? null;

// 6) Project info
$project      = $invoice_info['project'] ?? [];
$project_name = $project['name'] ?? null;

// 7) Business logic goes here (examples):
// - idempotency by invoice_id / uuid
// - update invoice status in DB
// - validate amounts/currency
// - logging (avoid logging token)
//
// Example (pseudo):
// save_postback($invoice_id, $order_id, $uuid, $invoice_status, $amount_paid, $fee, $network_code, $project_name, $created, $address);

// 8) Minimal response
http_response_code(200);
echo json_encode(['message' => 'Postback received'], JSON_UNESCAPED_UNICODE);
```

{% endtab %}
{% endtabs %}

### Пример обработчика POSTBACK application/x-www-form-urlencoded:

Эти примеры показывают, как вы можете обрабатывать POSTBACK в формате `application/x-www-form-urlencoded` на стороне вашего проекта.

{% tabs %}
{% tab title="Python" %}

```python
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/postback', methods=['POST'])
def handle_postback():
    # Изменено на request.form для обработки данных в формате x-www-form-urlencoded
    status = request.form.get('status')
    invoice_id = request.form.get('invoice_id')
    amount_crypto = request.form.get('amount_crypto')
    currency = request.form.get('currency')
    order_id = request.form.get('order_id')
    token = request.form.get('token')
    
    # ... ваш код для обработки postback ...
    
    return jsonify({'message': 'Postback received'}), 200

if __name__ == '__main__':
    app.run(port=5000)
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const express = require('express');
const app = express();

// Добавляем middleware для обработки JSON
app.use(express.json());

// Добавляем middleware для обработки данных в формате x-www-form-urlencoded
app.use(express.urlencoded({ extended: true }));

app.post('/postback', (req, res) => {
    const { status, invoice_id, amount_crypto, currency, order_id, token } = req.body;
    
    // ... ваш код для обработки postback ...
    
    res.json({ message: 'Postback received' });
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$body = file_get_contents('php://input');
$data = [];
parse_str($body, $data);

$status = $data['status'] ?? null;
$invoice_id = $data['invoice_id'] ?? null;
$amount_crypto = $data['amount_crypto'] ?? null;
$currency = $data['currency'] ?? null;
$order_id = $data['order_id'] ?? null;
$token = $data['token'] ?? null;

// ... ваш код для обработки postback ...

echo json_encode(['message' => 'Postback received']);
?>
```

{% endtab %}
{% endtabs %}

> Мы регулярно работаем над улучшением документации сервиса для разработчиков. Пожалуйста, оцените качество и полезность материалов [по ссылке](https://survey.zohopublic.eu/zs/G6TdRh).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.cryptocloud.plus/ru/api-reference-v2/postback.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
