# Automatic POSTBACK

After the invoice is successfully confirmed, a POST request with payment information is sent to the notification URL specified in the project settings.

The system supports two POSTBACK formats:

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

To configure the POSTBACK format, go to your project settings and open the «Integration & API» section.

After successful payment execution, a POST request with information about the payment is sent to the notification URL specified in the project settings.

### What the method allows you to do

* Automatically sends a POST request to the URL you specified after the invoice is confirmed by the system.
* The POSTBACK format can be configured.

### Postback parameters

| Name           | Type   | Example                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Description                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| -------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| status         | string | success                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Request execution status                                                                                                                                                                                                                                                                                                                                                                                                                              |
| invoice\_id    | string | 89UX09KA                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | Unique payment identifier without the INV prefix                                                                                                                                                                                                                                                                                                                                                                                                      |
| amount\_crypto | float  | 0.000113                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | Payment amount in cryptocurrency                                                                                                                                                                                                                                                                                                                                                                                                                      |
| currency       | string | BNB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | <p>Currency code<br><br>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                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Custom invoice number in the external system                                                                                                                                                                                                                                                                                                                                                                                                          |
| token          | string | eyJ0eXAiOiJKV1QiLCJhbGciOiJIAcI1NiJ9.eyJpZCI6MTMsImV4cCI6MTYzMTc4NjQyNn0.HQavV3z8dFnk56bX3MSY5X9lR6qVa9YhAoeTEHkaAzs                                                                                                                                                                                                                                                                                                                                                                                                                                                            | JWT token — server response signature                                                                                                                                                                                                                                                                                                                                                                                                                 |
| 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> | Detailed invoice information. Available only in JSON.                                                                                                                                                                                                                                                                                                                                                                                                 |

{% hint style="info" %}
JWT token — a signature of the server response. It is signed with the secret key (SECRET KEY) generated in the project settings. The token is valid for 5 minutes after the notification is created. A new token is generated each time a payment notification is sent.

Encryption algorithm — HS256.
{% endhint %}

### JSON Postback example

{% 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" %}

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

{% endtab %}
{% endtabs %}

### JSON Postback handler examples

These examples show how you can handle POSTBACK notifications in JSON format on your project side.

{% 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 %}

### Example of a POSTBACK handler for `application/x-www-form-urlencoded`:

These examples show how you can handle POSTBACK notifications in `application/x-www-form-urlencoded` format on your project side.

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

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

app = Flask(__name__)

@app.route('/postback', methods=['POST'])
def handle_postback():
    # Changed to request.form for processing data in x-www-form-urlencoded format
    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')
    
    # ... your code for handling the 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();

// Add middleware for processing JSON
app.use(express.json());

// Add middleware for processing x-www-form-urlencoded data
app.use(express.urlencoded({ extended: true }));

app.post('/postback', (req, res) => {
    const { status, invoice_id, amount_crypto, currency, order_id, token } = req.body;
    
    // ... your code for handling the 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;

// ... your code for processing postback ...

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

{% endtab %}
{% endtabs %}
