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


---

# 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/en/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.
