POSTBACK automático
O método permite receber automaticamente notificações sobre a confirmação da fatura.
Última atualização
Isto foi útil?
Isto foi útil?
{
"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.trybit.com/img/network/BSC.svg",
"fullname": "BNB Smart Chain"
},
"name": "BNB",
"is_email_required": false,
"stablecoin": false,
"icon_base": "https://cdn.trybit.com/img/currency/BNB.svg",
"icon_network": "https://cdn.trybit.com/img/currency/BNB.svg",
"icon_qr": "https://cdn.trybit.com/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": "pago",
"invoice_status": "sucesso",
"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
}
}{
"status": "success",
"invoice_id": "ILRAJE1Q",
"amount_crypto": 0.000113,
"currency": "BNB",
"order_id": null,
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJ<...>hPirF9kHCx3ZXEspVfGNGuK7cZ8",
}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:
"""
Valide o JWT HS256 apenas se o token estiver presente e não estiver vazio.
Espera-se que o token seja uma string JWT em bruto (sem o prefixo "Bearer ").
"""
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) Ler o corpo JSON
data = request.get_json(silent=True)
if not isinstance(data, dict):
return jsonify({"error": "JSON inválido"}), 400
# 2) Campos de nível superior
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")
# Validação básica
if not invoice_id or not order_id:
return jsonify({"error": "Falta invoice_id ou order_id"}), 400
# 3) Validar o token JWT (apenas se fornecido)
if not validate_token(token):
return jsonify({"error": "Token inválido"}), 401
# 4) Objeto invoice_info aninhado
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) Aninhamento mais profundo: invoice_info.currency.network
inv_currency = invoice_info.get("currency") or {}
network = inv_currency.get("network") or {}
network_code = network.get("code")
# 6) Informações do projeto
project = invoice_info.get("project") or {}
project_name = project.get("name")
# 7) A lógica de negócio deve ser implementada aqui:
# - idempotência por invoice_id / uuid
# - atualizar o estado da fatura na base de dados
# - validação de montante / moeda
# - registo (evite registar o token)
return jsonify({"message": "Postback recebido"}), 200
if __name__ == "__main__":
app.run(port=5000, debug=True)const express = require("express");
const jwt = require("jsonwebtoken");
const app = express();
app.use(express.json());
// Segredo HS256 (guarde em ENV em produção)
const JWT_SECRET = process.env.JWT_SECRET || "super-secret";
/**
* Valide o token JWT HS256 apenas se estiver presente e não estiver vazio.
* Espera-se que o token seja uma string JWT em bruto (sem o prefixo "Bearer ").
*/
function validateToken(token) {
// O token é opcional
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) Ler o corpo JSON
const data = req.body;
if (!data || typeof data !== "object" || Array.isArray(data)) {
return res.status(400).json({ error: "JSON inválido" });
}
// 2) Campos básicos obrigatórios (ajuste conforme necessário)
const invoice_id = data.invoice_id;
const order_id = data.order_id;
if (!invoice_id || !order_id) {
return res.status(400).json({ error: "Falta invoice_id ou order_id" });
}
// 3) Validar o token JWT (apenas se fornecido)
const token = data.token;
if (!validateToken(token)) {
return res.status(401).json({ error: "Token inválido" });
}
// 4) Objeto invoice_info aninhado
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) Aninhamento mais profundo: invoice_info.currency.network
const inv_currency = invoice_info.currency || {};
const network = inv_currency.network || {};
const network_code = network.code;
// 6) Informações do projeto
const project = invoice_info.project || {};
const project_name = project.name;
// 7) A lógica de negócio vai aqui (exemplos):
// - idempotência por invoice_id / uuid
// - atualizar o estado da fatura na BD
// - validar montantes/moeda
// - registo (evite registar o token)
//
// Exemplo (pseudocódigo):
// await db.invoices.upsert({ invoice_id, order_id, uuid, invoice_status, amount_paid, fee, network_code, project_name, created, address })
// 8) Resposta mínima (como pedido)
return res.status(200).json({ message: "Postback recebido" });
});
app.listen(5000, () => {
console.log("Servidor em execução em http://127.0.0.1:5000");
});<?php
// postback.php
header('Content-Type: application/json; charset=utf-8');
$JWT_SECRET = getenv('JWT_SECRET') ?: 'super-secret';
/**
* Decodificação Base64URL (o JWT usa base64url sem preenchimento)
*/
function base64url_decode($data) {
$remainder = strlen($data) % 4;
if ($remainder) {
$data .= str_repeat('=', 4 - $remainder);
}
$data = strtr($data, '-_', '+/');
return base64_decode($data);
}
/**
* Valide o JWT HS256 apenas se o token estiver presente e não estiver vazio.
* Espera-se que o token seja uma string JWT em bruto (sem o prefixo "Bearer ").
*/
function validateToken($token, $secret) {
// O token é opcional
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;
// Garantir HS256
if (($header['alg'] ?? null) !== 'HS256') return false;
// Verificar assinatura
$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;
// Opcional: validar exp/nbf se presentes
$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) Ler o corpo JSON bruto
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
if (!is_array($data)) {
http_response_code(400);
echo json_encode(['error' => 'JSON inválido'], JSON_UNESCAPED_UNICODE);
exit;
}
// 2) Campos básicos obrigatórios
$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' => 'Falta invoice_id ou order_id'], JSON_UNESCAPED_UNICODE);
exit;
}
// 3) Validar o token JWT (apenas se fornecido)
$token = $data['token'] ?? null;
if (!validateToken($token, $JWT_SECRET)) {
http_response_code(401);
echo json_encode(['error' => 'Token inválido'], JSON_UNESCAPED_UNICODE);
exit;
}
// 4) Objeto invoice_info aninhado
$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) Aninhamento mais profundo: invoice_info.currency.network
$inv_currency = $invoice_info['currency'] ?? [];
$network = $inv_currency['network'] ?? [];
$network_code = $network['code'] ?? null;
// 6) Informações do projeto
$project = $invoice_info['project'] ?? [];
$project_name = $project['name'] ?? null;
// 7) A lógica de negócio vai aqui (exemplos):
// - idempotência por invoice_id / uuid
// - atualizar o estado da fatura na BD
// - validar montantes/moeda
// - registo (evite registar o token)
//
// Exemplo (pseudocódigo):
// save_postback($invoice_id, $order_id, $uuid, $invoice_status, $amount_paid, $fee, $network_code, $project_name, $created, $address);
// 8) Resposta mínima
http_response_code(200);
echo json_encode(['message' => 'Postback recebido'], JSON_UNESCAPED_UNICODE);from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/postback', methods=['POST'])
def handle_postback():
# Alterado para request.form para processar dados no formato 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')
# ... o seu código para tratar o postback ...
return jsonify({'message': 'Postback recebido'}), 200
if __name__ == '__main__':
app.run(port=5000)const express = require('express');
const app = express();
// Adicionar middleware para processar JSON
app.use(express.json());
// Adicionar middleware para processar dados 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;
// ... o seu código para tratar o postback ...
res.json({ message: 'Postback recebido' });
});
app.listen(3000, () => {
console.log('O servidor está a correr na porta 3000');
});
<?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;
// ... seu código para processar o postback ...
echo json_encode(['message' => 'Postback recebido']);
?>