Webhooks and events
Learn how to safely receive, persist, and process Asaas Webhooks, handling duplicates, failures, and reprocessing.
Webhooks allow Asaas to notify your application of changes that happen after the initial response to a request.
In asynchronous operations, they are a central part of the architecture: they keep the local system up to date as payments, charges, and other entities change state.
By the end of this page, you will understand how to receive, persist, and process Webhooks in a resilient way, including handling duplicates, failures, and reprocessing.
When to use
Implement Webhooks when your integration needs to:
- track state changes that happen after the initial request;
- react to confirmations, failures, or other changes to an operation;
- keep the local state up to date without depending exclusively on periodic queries;
- execute business actions based on events that occurred in Asaas;
- identify and recover from failures in processing updates.
Before you start
Before implementing Webhook reception:
- identify which events your integration needs to track;
- provide an endpoint reachable by Asaas;
- define how received events will be persisted;
- prepare a processing mechanism separate from reception;
- define how duplicate events will be identified;
- establish how failures can be reprocessed and monitored.
How it works
The Webhook endpoint should do only what is necessary to receive the event safely and confirm its receipt.
Business logic processing should happen separately.
%%{init: {"flowchart": {"nodeSpacing": 28,"rankSpacing": 32,"diagramPadding": 8,"padding": 10}}}%%
flowchart TD
A["Receive Webhook"] --> B["Validate request"]
B --> C{"Can the event be accepted?"}
C --> CSim(("Yes"))
C --> CNao(("No"))
CSim --> D["Persist event"]
D --> E["Respond with success"]
E --> F["Process event"]
F --> G{"Processing completed?"}
G --> GSim(("Yes"))
G --> GNao(("No"))
GSim --> H["Update event status"]
GNao --> I["Record failure"]
I --> J["Reprocess safely"]
CNao --> K["Reject request"]
classDef inicio fill:#DBEAFE,stroke:#2563EB,color:#1E3A8A,stroke-width:3px,font-size:17px
classDef processo fill:#E0F2FE,stroke:#0284C7,color:#0C4A6E,stroke-width:2px,font-size:17px
classDef decisao fill:#FEF3C7,stroke:#D97706,color:#78350F,stroke-width:2px,font-size:17px
classDef sucesso fill:#DCFCE7,stroke:#16A34A,color:#14532D,stroke-width:3px,font-size:17px
classDef recuperacao fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D,stroke-width:2px,font-size:17px
classDef respostaSim fill:#22C55E,stroke:#15803D,color:#FFFFFF,stroke-width:3px
classDef respostaNao fill:#EF4444,stroke:#B91C1C,color:#FFFFFF,stroke-width:3px
class A inicio
class B,D,E,F processo
class C,G decisao
class H sucesso
class I,J,K recuperacao
class CSim,GSim respostaSim
class CNao,GNao respostaNao
linkStyle default stroke:#94A3B8,stroke-width:2px
The recommended order is:
receive → validate → persist → respond → process
This separation reduces the dependency between the endpoint's response time and the complexity of the business logic executed from the event.
1. Receive and validate the event
When receiving a Webhook, your application should first check whether the request can be accepted.
This step should be limited to the validations needed to protect the endpoint and ensure the content can proceed to persistence.
Avoid running external queries, complex calculations, or extensive business logic at this point.
The goal is to keep the reception path short and predictable.
The more processing is executed before the endpoint responds, the greater the risk of a timeout and of the event being resent.
2. Persist before processing
After validating receipt, record the event before executing the corresponding business logic.
Persistence lets your application know the event arrived even if a later step fails.
Keep enough information to:
- identify the event;
- identify its type;
- link it to the corresponding entity;
- record when it was received;
- track its processing state;
- store the information needed for diagnosis and reprocessing.
Without this step, a failure during processing may cause the application to lose the record that the event was received.
Treat receiving the Webhook and processing the business logic as different steps. First ensure the event has been stored; then process its effects.
3. Respond before executing the business logic
After validating and persisting the event, respond to the Webhook without waiting for all the subsequent logic.
Avoid keeping the request open while your application:
- queries other systems;
- sends notifications;
- executes financial operations;
- updates multiple services;
- performs extensive calculations or processing.
These actions should happen after receipt has already been confirmed.
This reduces the risk of your application's processing time causing failures in Webhook reception.
4. Process the event separately
After reception, send the persisted event to the mechanism responsible for the business logic.
This processing can:
- retrieve the stored event;
- identify the corresponding entity;
- check the currently known state;
- evaluate whether that update still needs to be applied;
- execute the business logic;
- update the local state;
- record the processing result.
This separation also allows better control of concurrency, retries, and temporary failures.
5. Handle duplicate events
Your application must be prepared to receive the same event more than once.
This can happen when a previous attempt is not recognized as completed or when a resend is needed.
Before executing a business action again, check whether the event or its effect has already been processed.
%%{init: {"flowchart": {"nodeSpacing": 28,"rankSpacing": 32,"diagramPadding": 8,"padding": 10}}}%%
flowchart TD
A["Event available for processing"] --> B{"Has the event already been processed?"}
B --> BSim(("Yes"))
B --> BNao(("No"))
BSim --> C["Do not repeat the action"]
BNao --> D["Validate current state"]
D --> E["Execute business logic"]
E --> F["Record as processed"]
classDef inicio fill:#DBEAFE,stroke:#2563EB,color:#1E3A8A,stroke-width:3px,font-size:17px
classDef processo fill:#E0F2FE,stroke:#0284C7,color:#0C4A6E,stroke-width:2px,font-size:17px
classDef decisao fill:#FEF3C7,stroke:#D97706,color:#78350F,stroke-width:2px,font-size:17px
classDef sucesso fill:#DCFCE7,stroke:#16A34A,color:#14532D,stroke-width:3px,font-size:17px
classDef respostaSim fill:#22C55E,stroke:#15803D,color:#FFFFFF,stroke-width:3px
classDef respostaNao fill:#EF4444,stroke:#B91C1C,color:#FFFFFF,stroke-width:3px
class A inicio
class B decisao
class C,F sucesso
class D,E processo
class BSim respostaSim
class BNao respostaNao
linkStyle default stroke:#94A3B8,stroke-width:2px
Receiving the same event again should not produce a new consequence when that consequence has already been applied.
This care is especially important for actions such as:
- releasing products or services;
- sending notifications;
- moving inventory;
- executing financial operations;
- triggering integrations with other systems.
6. Control the processing state
The event should also have an internal state that allows tracking its lifecycle within your application.
A simple structure can differentiate:
| State | Purpose |
|---|---|
| Received | The event was validated and persisted |
| Processing | The business logic is being executed |
| Processed | Processing was completed successfully |
| Error | Processing failed and needs further analysis or a new attempt |
The names may vary according to the application's architecture. What matters is being able to distinguish an event that has just arrived from an event whose business logic has already been completed.
7. Reprocess failures safely
Failures during processing should not result in silent loss of the event.
When an error occurs:
- record the failure;
- keep the event available for a new attempt;
- record how many attempts have already occurred;
- avoid re-executing effects that have already been completed;
- identify situations that require intervention.
Before reprocessing, consider the current state of the entity and the effects already executed.
An old event may be reprocessed after newer updates have already occurred.
That is why reprocessing should not simply repeat the previous logic without validating the current situation.
8. Protect the endpoint
The endpoint responsible for receiving Webhooks should be treated as an external entry point to the application.
Implement the authentication and validation mechanisms available for the flow used and do not unnecessarily expose sensitive information.
Also avoid using the Webhook endpoint for other application purposes.
This separation makes it easier to handle:
- access control;
- monitoring;
- traceability;
- applying limits;
- investigating unexpected behavior.
9. Monitor the flow
Persisting events makes it possible to monitor the health of the integration.
Monitor indicators such as:
- number of events received;
- number of events with errors;
- events awaiting processing;
- number of reprocessing attempts;
- time between receipt and processing;
- unexpected increase in failures;
- events that remain in processing for too long.
The goal is to identify problems before they turn into state mismatches across a larger volume of operations.
An unrecorded processing failure is harder to recover from than a known failure. Always keep enough traceability to identify the event, the related entity, and the point at which processing failed.
Attention — common mistakes
Avoid implementations that:
- execute all business logic before responding to the Webhook;
- process the event before persisting its receipt;
- depend on external queries to be able to respond to the request;
- assume each event will be received only once;
- re-execute already completed actions when receiving a duplicate;
- do not differentiate received, processed, and failed events;
- discard events when a failure occurs;
- reprocess events without checking the current state of the entity;
- do not monitor response time or processing failures.
Confirm your architecture
Before go-live, confirm that your application can answer:
- Does the endpoint do only what is necessary before responding?
- Is the event persisted before the business logic is executed?
- Does processing happen separately from reception?
- Can a duplicate event be received without repeating an unintended action?
- Is there an internal state to track processing?
- Does a failure remain recorded for investigation?
- Can a failed event be reprocessed safely?
- Is the current state of the entity considered before reprocessing?
- Are there indicators to track failures and delays?
- Is it possible to link a problem to the corresponding event and entity?
If these conditions are not met, a temporary failure in reception or processing may cause a lost update or a mismatch between the systems.
Best practices
- keep the reception endpoint simple and fast;
- validate and persist the event before executing its business logic;
- respond to the Webhook before starting heavier processing;
- process events decoupled from reception;
- design processing to tolerate duplicates;
- keep internal states to track each event;
- allow safe reprocessing of failures;
- validate the current state before reapplying an old update;
- monitor failures, delays, and pending events;
- keep enough data to trace the flow end to end.
Next steps
After structuring event reception and processing, define how your integration will safely repeat operations when failures occur:
Updated 2 days ago
