Receive Asaas events at your Webhook endpoint

Configure a webhook URL to keep your application always up to date with the API integration

Create an HTTP endpoint capable of receiving and processing the notifications sent by Asaas.

When a configured event occurs, Asaas sends a POST request to the Webhook URL with the event identifier and the data of the related resource.

Before you start

Have a Webhook configured:

Run your first tests in Sandbox and replicate the configuration in Production after validating the flow.

Understand the event object

Each notification contains:

  • id: unique identifier of the event;
  • event: type of the event that occurred;
  • object related to the resource, such as payment, transfer or subscription.

Example:

{
   "id": "evt_05b708f961d739ea7eba7e4db318f621&368604920",
   "event":"PAYMENT_RECEIVED",
   "dateCreated": "2024-06-12 16:45:03",
   "payment":{
      "object":"payment",
      "id":"pay_080225913252"
   }
}

Use the event id to identify redeliveries and implement idempotence.

The format of the related object varies according to the event. See Webhook Events to learn about the available events.

1. Create the endpoint

Provide a public URL capable of receiving HTTP POST requests with a JSON payload.

Basic receiving examples:

Node.js

const express = require('express');

const app = express();

app.post(
  '/payments-webhook',
  express.json({ type: 'application/json' }),
  (request, response) => {

    const body = request.body;
    const payment = body.payment;

    switch (body.event) {

      case 'PAYMENT_CREATED':
        createPayment(payment);
        break;

      case 'PAYMENT_RECEIVED':
        receivePayment(payment);
        break;

      default:
        console.log(`Unhandled event: ${body.event}`);
    }

    return response.json({
      received: true
    });
  }
);

app.listen(8000, () => {
  console.log('Running on port 8000');
});

PHP

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

Route::post('/payments-webhook', function (Request $request) {
    $body = $request->all();

    switch ($body['event']) {
        case 'PAYMENT_CREATED':
            createPayment($body['payment']);
            break;

        case 'PAYMENT_RECEIVED':
            receivePayment($body['payment']);
            break;

        default:
            Log::info('Unhandled event: ' . $body['event']);
    }

    return response()->json(['received' => true]);
});

Java

@RestController
@RequestMapping("/payments-webhook")
public class WebhookController {

    @PostMapping(consumes = "application/json")
    public ResponseEntity<Map<String, Boolean>> handleWebhook(@RequestBody Map<String, Object> body) {

        String event = (String) body.get("event");
        Map<String, Object> payment = (Map<String, Object>) body.get("payment");

        switch (event) {

            case "PAYMENT_CREATED":
                createPayment(payment);
                break;

            case "PAYMENT_RECEIVED":
                receivePayment(payment);
                break;

            default:
                System.out.println("Unhandled event " + event);
        }

        return ResponseEntity.ok(Map.of("received", true));
    }
}

Python

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/payments-webhook', methods=['POST'])
def payments_webhook():

    body = request.json

    if body['event'] == 'PAYMENT_CREATED':
        create_payment(body['payment'])

    elif body['event'] == 'PAYMENT_RECEIVED':
        receive_payment(body['payment'])

    return jsonify({'received': True})

The examples show only how to receive and identify the event. In Production, persist the event and run business rules asynchronously.

2. Persist the event before responding

Webhooks follow the at least once delivery model. The same event may be sent more than once.

The recommended flow is:

Receive event
↓
Persist to a queue
↓
Respond HTTP 200
↓
Process business rules

Use id as a unique key to avoid processing an event that has already been received again.

See how to implement idempotence in Webhooks.

3. Respond HTTP 200

After confirming the event has been persisted, respond:

HTTP/1.1 200 OK

Do not wait for time-consuming processing before responding to Asaas.

If delivery is not confirmed, the event enters the retry flow. After 15 consecutive failures, the Webhook queue may be interrupted.

Understand the paused queue behavior.

4. Validate authentication

If the Webhook is configured with an authToken, the value will be sent in the header:

asaas-access-token

Validate the token before accepting the notification.

📘

Defining a secure token

The token must:

  • be between 32 and 255 characters long;
  • not contain whitespace;
  • not use simple sequences;
  • not be an Asaas API Key.

If your infrastructure restricts requests by origin, see the Asaas official IPs.

5. Test receipt

If the application is running locally, expose the endpoint through a public URL to run the tests.

Tools such as:

  • ngrok;
  • Cloudflare Tunnel;

can be used to make this URL temporarily available.

In Sandbox:

  1. configure the Webhook;
  2. select the events you want to test;
  3. run the corresponding operation;
  4. confirm receipt of the POST;
  5. validate the persistence and processing of the event.

Sandbox and Production settings are independent.

6. Check the Webhook Logs

To validate deliveries or investigate failures, go to:

User Menu > Integrations > Webhook Logs

In the logs you can check:

  • the payload sent;
  • the date and time of the attempt;
  • the HTTP code returned;
  • the number of attempts;
  • communication errors and timeouts.

See the Webhook Logs.

Common errors

Duplicate event

The same id may be delivered more than once.

Implement idempotence and do not repeat the business rule when the event has already been processed.

Timeout

Time-consuming processing before the response can cause delivery failures.

Persist the event, respond HTTP 200 and process it in the background.

HTTP 500

Check the Webhook Logs to identify the exception returned by the application.

Invalid token

Confirm that the value received in asaas-access-token matches the authToken configured in the Webhook.

HTTP 403

Check your Firewall, WAF or other access rules that may be blocking Asaas requests.

In Sandbox there may be IPs in addition to those used in Production.

Next steps


Did this page help you?