Deflect chargebacks with alerts
Subscribe to pre-chargeback alerts, receive an alert, refund the transaction, and report the outcome to close the alert.
Pre-chargeback alerts give you a chance to refund a transaction before it becomes a chargeback. (This recipe is about the Alerts product - stopping risky orders before shipment is Prevent.) This recipe is a full, copy-paste-runnable flow for the merchant-managed model: subscribe to alert webhooks, receive an alert, refund the matching transaction in your processor, then report the outcome to Chargeflow so the alert is closed with the issuer.
Before you start
- Get your
API Access Key. Every request sends it in thex-api-keyheader. See Authentication. - All requests go to
https://api.chargeflow.iounder the/public/2025-04-01/path.
Note
This recipe covers the merchant-managed model, where you refund and report outcomes yourself. With Chargeflow Alerts (the automated model), Chargeflow matches and refunds automatically, and you do not need to call the outcome endpoint.
Steps
Subscribe to alert events
Register a webhook endpoint for the alert lifecycle events.
Each registration subscribes one endpoint to one event, so register once per event:
curl -X POST https://api.chargeflow.io/public/2025-04-01/webhooks \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"event": "alerts.created", "url": "https://your-server.com/webhooks/alerts-created"}'
curl -X POST https://api.chargeflow.io/public/2025-04-01/webhooks \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"event": "alerts.updated", "url": "https://your-server.com/webhooks/alerts-updated"}'See Subscribe to Webhook Events for the full list of events, and Webhooks for signature verification.
Receive the alerts.created webhook
When a card network raises a pre-chargeback alert, Chargeflow posts an alerts.created event to your endpoint. The payload carries the alert ID and the metadata you need to locate the transaction.
{
"id": "alert_123456789",
"account_id": "account_987654321",
"ext_account_id": "platform_acc_12345",
"transaction": "txn_abcdef123456",
"created_at": "2025-07-31T12:34:56Z",
"status": "alerted",
"status_date": "2025-07-31T13:00:00Z",
"statement_descriptor": "My Merchant Store",
"amount": 12500,
"currency": "USD",
"outcome": "pending",
"type": "fraud_warning",
"reason": "fraud",
"network_transaction": {
"id": "net_txn_78910",
"created_at": "2025-07-31T12:30:00Z",
"amount": 12500,
"currency": "USD",
"card_brand": "Visa",
"bin": "411111",
"last4": "1111",
"auth_code": "AUTH1234",
"arn": "ARN56789"
}
}Acknowledge with a 2XX quickly, then handle the alert asynchronously.
app.post('/webhooks/alerts', express.json(), (req, res) => {
const alert = req.body;
res.json({ received: true }); // acknowledge first
// The alerts.created payload is delivered flat (no envelope): the alert
// fields are at the top level. Subscribe this endpoint to alerts.created,
// so every delivery is a new alert. alert.type holds the alert type,
// for example 'fraud_warning'.
handleAlert(alert.id);
});Fetch the full alert (optional)
Some fields, such as the matched transaction reference, may be filled in after ingestion. For the current, complete alert record, read it by ID.
curl -X GET https://api.chargeflow.io/public/2025-04-01/alerts/alert_123456789 \
-H "x-api-key: YOUR_API_KEY"You can also list alerts with GET /public/2025-04-01/alerts, which supports offset, limit, created_at_min, created_at_max, type, status, reason, and sort query parameters.
Refund the matching transaction
Use the alert metadata to find the charge in your payment processor and refund it. Match on network_transaction.last4, network_transaction.arn, amount, and currency. This step happens in your own processor, not in the Chargeflow API.
// Pseudocode against your processor's SDK
const charge = await psp.findCharge({
last4: alert.network_transaction.last4,
arn: alert.network_transaction.arn,
amount: alert.amount,
currency: alert.currency,
});
await psp.refund(charge.id);Report the outcome
After processing the alert, report the outcome with POST /public/2025-04-01/alerts/{alertId}/outcome. This is what closes the alert with the issuer. The request body takes a single required outcome field.
Valid outcome values are refunded, previously_refunded, duplicate, decline, and error.
curl -X POST https://api.chargeflow.io/public/2025-04-01/alerts/alert_123456789/outcome \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"outcome": "refunded"}'A successful call returns 202 Accepted.
Warning
In the merchant-managed model, always call the outcome endpoint after handling an alert, even if you could not find the transaction. Without this step, Chargeflow cannot close the alert with the issuer and the chargeback may still be filed.
React to alerts.updated
As the alert moves through its lifecycle, Chargeflow fires alerts.updated. Use it to keep your records in sync. For example, when outcome is prevented, record the successful prevention.
{
"id": "alert_123456789",
"account_id": "account_987654321",
"status": "prevented",
"status_date": "2025-07-31T14:00:00Z",
"amount": 12500,
"currency": "USD",
"outcome": "prevented",
"type": "fraud_warning",
"reason": "fraud"
}If outcome is chargebacked, the alert escalated to a chargeback despite mitigation. Watch for dispute.created if you want to begin enrichment. See Automate a chargeback dispute.