# Webhooks ConnectPSP sends asynchronous HTTP POST events to your `webhookUrl` when transactions change status. ## Event Structure All events share the same envelope: ```json { "eventType": "CASHIN_PAID", "eventAt": "2026-03-10T14:22:18Z", "data": { ... } } ``` | Field | Description | | --- | --- | | `eventType` | Identifies the event (see list below) | | `eventAt` | ISO 8601 UTC timestamp of when the event was dispatched | | `data` | Transaction details — mirrors the equivalent `GET` endpoint response | The `data` object for each event type always matches the response you'd get from `GET /cash-in/{id}` or `GET /cash-out/{id}`, making it easy to parse consistently. ## How to Receive Webhooks ConnectPSP will POST to your `webhookUrl` using: - **Method:** `POST` - **Content-Type:** `application/json` - **Headers sent:** - `X-Connect-Signature` — HMAC-SHA256 hash of the request body using your `CryptoToken`. Use this to verify the request is genuine. - `X-Event-Id` — Unique UUID for each delivery attempt. ### Expected Response Your endpoint **must respond with HTTP `200 OK`** in **under 5 seconds**. No response body is required. If your endpoint fails (timeout, 5xx, etc.), ConnectPSP will retry with **exponential backoff**. ## Verifying the Signature ```javascript const crypto = require('crypto'); function isValidWebhook(rawBody, signatureHeader, cryptoToken) { const expected = crypto .createHmac('sha256', cryptoToken) .update(rawBody) // rawBody = the raw request body string, NOT parsed JSON .digest('hex'); return expected === signatureHeader; } // Express example app.post('/webhooks/connectpsp', (req, res) => { const signature = req.headers['x-connect-signature']; const rawBody = req.rawBody; // ensure you capture raw body before JSON parsing if (!isValidWebhook(rawBody, signature, process.env.CRYPTO_TOKEN)) { return res.status(401).send('Invalid signature'); } const event = req.body; // process event... res.status(200).send(); }); ``` ## Cash-In Events ### `CASHIN_PAID` Fired when a PIX payment is confirmed by the banking network. ```json { "eventType": "CASHIN_PAID", "eventAt": "2026-03-10T11:22:18Z", "data": { "transactionId": "kk6g232xel65a0daee4dd13kk2912714964", "internalCode": "US7B1JQ", "externalReference": "order_abc123", "endToEndId": "E00416968202603101827cemeFscF6AG", "status": "PAID", "amount": 150.50, "payer": { "name": "João Silva", "document": "12345678909", "bankData": { "ispb": "00000000", "bank": "Banco do Brasil S.A.", "branch": "0001", "account": "123456" } }, "requestedAt": "2026-03-10T11:20:00-03:00", "paidAt": "2026-03-10T11:22:15-03:00" } } ``` ### `CASHIN_REFUNDED` Fired after a paid Cash-In is refunded (via API, ConnectPSP panel, or a banking devolution). ```json { "eventType": "CASHIN_REFUNDED", "eventAt": "2026-03-11T09:30:17Z", "data": { "transactionId": "kk6g232xel65a0daee4dd13kk2912714964", "internalCode": "US7B1JQ", "externalReference": "order_abc123", "endToEndId": "D00416968202603101827cemeFscF6AG", "originalEndToEndId": "E00416968202603101827cemeFscF6AG", "status": "REFUNDED", "amount": 150.50, "payer": { "name": "João Silva", "document": "12345678909", "bankData": { "ispb": "00000000", "bank": "Banco do Brasil S.A.", "branch": "0001", "account": "123456" } }, "requestedAt": "2026-03-10T11:20:00-03:00", "paidAt": "2026-03-10T11:22:15-03:00", "refundedAt": "2026-03-11T09:30:15-03:00" } } ``` ## Cash-Out Events ### `CASHOUT_COMPLETED` Fired when BACEN/SPI confirms the payment was successfully settled in the payee's account. ```json { "eventType": "CASHOUT_COMPLETED", "eventAt": "2026-03-10T14:02:35Z", "data": { "transactionId": "dd30446e-6cc5-4664-bf3f-6b7f5e55a1a9", "internalCode": "IVKPRMOCDY", "externalReference": "withdraw_xyz789", "endToEndId": "E00416968202603101827cemeFscF6AG", "status": "COMPLETED", "amount": 500.00, "payee": { "name": "Maria Silva", "document": "12345678909", "destination": { "type": "PIX", "pixKeyType": "CPF", "pixKey": "12345678909" }, "bankData": { "ispb": "00000000", "bank": "Banco do Brasil S.A.", "branch": "0001", "account": "123456" } }, "requestedAt": "2026-03-10T14:00:00-03:00", "paidAt": "2026-03-10T14:02:30-03:00" } } ``` ### `CASHOUT_FAILED` Fired when a Cash-Out fails — e.g. invalid PIX key, frozen destination account, or banking network rejection. ```json { "eventType": "CASHOUT_FAILED", "eventAt": "2026-03-10T14:00:20Z", "data": { "transactionId": "dd30446e-6cc5-4664-bf3f-6b7f5e55a1a9", "internalCode": "IVKPRMOCDY", "externalReference": "withdraw_xyz789", "status": "FAILED", "amount": 500.00, "failure": { "code": "PIX_KEY_NOT_FOUND", "message": "The provided PIX key did not resolve to a valid account." }, "payee": { "name": "Maria Silva", "document": "12345678909", "destination": { "type": "PIX", "pixKeyType": "CPF", "pixKey": "12345678909" } }, "requestedAt": "2026-03-10T14:00:00-03:00", "failedAt": "2026-03-10T14:00:15-03:00" } } ``` ### `CASHOUT_REFUNDED` Fired when a previously completed Cash-Out is returned asynchronously by the payee's bank via SPI. ```json { "eventType": "CASHOUT_REFUNDED", "eventAt": "2026-03-11T09:30:20Z", "data": { "transactionId": "dd30446e-6cc5-4664-bf3f-6b7f5e55a1a9", "internalCode": "IVKPRMOCDY", "externalReference": "withdraw_xyz789", "endToEndId": "D00416968202603101827cemeFscF6AG", "originalEndToEndId": "E00416968202603101827cemeFscF6AG", "status": "REFUNDED", "amount": 500.00, "payee": { "name": "Maria Silva", "document": "12345678909", "destination": { "type": "PIX", "pixKeyType": "CPF", "pixKey": "12345678909" }, "bankData": { "ispb": "00000000", "bank": "Banco do Brasil S.A.", "branch": "0001", "account": "123456" } }, "requestedAt": "2026-03-10T14:00:00-03:00", "paidAt": "2026-03-10T14:02:30-03:00", "refundedAt": "2026-03-11T09:30:15-03:00" } } ``` ## Event Reference | Event | Trigger | | --- | --- | | `CASHIN_PAID` | PIX received and confirmed by BACEN/SPI | | `CASHIN_REFUNDED` | A paid Cash-In was fully refunded | | `CASHOUT_COMPLETED` | Cash-Out settled successfully | | `CASHOUT_FAILED` | Cash-Out rejected at origin or destination | | `CASHOUT_REFUNDED` | A completed Cash-Out was returned by the payee's bank |