Lidando com callbacks
A Magen envia callbacks em tempo real para sua callbackUrl toda vez que uma transação muda de status. A regra principal: responda 2xx em até 5 segundos. Quem não responde rápido vira fila de retry (até 72 tentativas, backoff exponencial).
Padrão recomendado: enfileira e devolve 2xx
Processe pesado fora do handler. O handler só recebe, enfileira e responde.
import express from 'express';
const app = express();
app.post('/webhooks/magen', express.json(), async (req, res) => {
await queue.enqueue('magen-callback', req.body);
res.status(204).end();
});from flask import Flask, request
app = Flask(__name__)
@app.post('/webhooks/magen')
def magen_webhook():
queue.enqueue('magen_callback', request.get_json())
return '', 204http.HandleFunc("/webhooks/magen", func(w http.ResponseWriter, r *http.Request) {
var payload map[string]any
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
queue.Enqueue("magen-callback", payload)
w.WriteHeader(http.StatusNoContent)
})<?php
$payload = json_decode(file_get_contents('php://input'), true);
$queue->enqueue('magen-callback', $payload);
http_response_code(204);Testar localmente
Exponha seu localhost via ngrok ou Cloudflare Tunnel e dispare o payload manualmente:
curl -X POST https://seu-tunel.ngrok.io/webhooks/magen \
-H "Content-Type: application/json" \
-d '{
"id": "MAGEN20251123104518DF75D20A8F",
"type": "DEPOSIT",
"status": "COMPLETED",
"amount": 99.90,
"clientReference": "order-1234",
"virtualAccount": "loja-rj-01",
"paidAt": "2025-11-23T10:46:26.986Z"
}'await fetch('https://seu-tunel.ngrok.io/webhooks/magen', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: 'MAGEN20251123104518DF75D20A8F',
type: 'DEPOSIT',
status: 'COMPLETED',
amount: 99.90,
clientReference: 'order-1234',
virtualAccount: 'loja-rj-01',
paidAt: '2025-11-23T10:46:26.986Z',
}),
});import requests
requests.post(
'https://seu-tunel.ngrok.io/webhooks/magen',
headers={'Content-Type': 'application/json'},
json={
'id': 'MAGEN20251123104518DF75D20A8F',
'type': 'DEPOSIT',
'status': 'COMPLETED',
'amount': 99.90,
'clientReference': 'order-1234',
'virtualAccount': 'loja-rj-01',
'paidAt': '2025-11-23T10:46:26.986Z',
},
)Reenviar callback real
Para reprocessar um callback que falhou no seu lado (depois de ter ajustado o handler), use os endpoints de reenvio:
POST /user/callbacks/resend/{transactionId}, uma transação específicaPOST /user/callbacks/resend, em lote
Inspecionar o histórico
A Magen guarda todas as tentativas de entrega. Útil para investigar falha:
GET /user/callbacks, lista paginadaGET /user/callbacks/{id}, detalhe com status code, response body, response time
Armadilhas comuns
| Armadilha | Sintoma |
|---|---|
| Processamento síncrono no handler | Timeouts, retry, baixa em dobro |
| Responder 4xx por erro de validação interna | Magen não retenta, callback perdido |
Dedupe só por id | Estorno (REFUNDED) é ignorado |
| Endpoint sem proteção de IP | Endpoint pode receber payloads forjados |
Logger imprime payload sem mascarar payerDocument | Risco LGPD |
Multi-tenant com virtualAccount
Uma só conta Magen pode atender N tenants (lojas, filiais, marketplaces) usando virtualAccount. Volta em todo callback, permite filtrar listagens e dispensa criar contas filhas.
Paginação
Endpoints de listagem (transações, callbacks, infrações) usam paginação clássica por page + limit com flag hasNextPage. Para janelas grandes prefira o relatório assíncrono em CSV.