Webhooks
The ME E-Procurement platform offers webhooks so you can be notified about events that occur on the platform.
Webhooks are a technology for transmitting real-time notifications between two software systems.
All issues related to logs (continuous records with date and time of the event), key generation, and management of events notified via webhooks from our APIs are handled in the Partner's Portal.
With webhooks, you can be notified about events that happen within ME’s E-Procurement, whether you are a buying client or a supplier, for example:
- Order received by the supplier;
- Request approved;
- Pre-order approved;
- Service registration sheet approved;
- Results of integrations with all our public APIs. These results can be entities successfully created with their generated IDs or integration errors.
Webhook Types
The platform offers two types of webhooks to accommodate different integration scenarios:
1. Traditional Webhook (Callback)
The traditional webhook works with the "push" model, where Mercado Eletrônico sends real-time notifications to an HTTP endpoint configured by the client.
Characteristics:
- Communication flow: ME → Client (ERP)
- Requirements: Client must expose an HTTP/HTTPS endpoint accessible from the internet
- Delivery: Immediate when the event occurs
- Ideal for: Clients with infrastructure prepared to receive external HTTP requests
2. Bucket-type Webhook (Polling)
The Bucket-type webhook works with the "pull" model, where events are stored in a "bucket" and the client actively fetches these events when desired.
Characteristics:
- Communication flow: Client (ERP) → ME
- Requirements: Only the ability to make HTTP requests to the ME API
- Delivery: On-demand, when the client queries the bucket
- Ideal for:
- Clients who cannot or do not want to expose HTTP endpoints
- ERPs with firewall or security restrictions
- Legacy systems without the capability to receive webhooks
- Environments with lower technical maturity to support callbacks
Webhook Registration
❗️ Prerequisite:
If you don't yet have access to the Partner's Portal, go to the Credentials page.
To register Webhooks, go to Partner's Portal > Webhooks.

Step 1: Credential Creation:
Using credentials in webhooks is optional but highly recommended for clients who want to increase security in integrations, ensuring that only authorized systems receive ME notifications.
Credentials allow the client application to be validated before receiving any event, preventing unauthorized access and maintaining the integrity of the transmitted information.

We offer two types of authentication: Basic Auth and OAuth2. Below are the differences between them:
Basic Auth:
With Basic Auth, the system sends username and password (or ID + Secret) encoded in Base64 in the request header.
Example of a request header:
Authorization: Basic dXN1YXJpbzpwYXNzd29yZA==
Typical use:
- Simple integrations;
- Legacy environments;
- When the provider does not offer OAuth2.
Limitations:
- Less secure: credentials are static and must be protected with great care.
- No automatic expiration: if leaked, they can be used indefinitely.
OAuth2:
OAuth2 uses a token grant flow. First, the system obtains an access_token (based on client_id, client_secret, grant type, etc.). In ME’s case, it is based on client_secret. Then, each request uses a token like this in the header:
Authorization: Bearer eyJhbGciOi...
Typical use:
- Modern integrations;
- APIs that follow OpenID Connect, Keycloak, Auth0, Azure AD, etc.
Advantages:
- Tokens expire automatically (lower risk if leaked);
- Supports scopes (granular permissions);
- Much more secure and recommended for corporate/B2B environments.
Quick Comparison between Basic Auth and OAuth2
| Item | Basic Auth | OAuth2 |
|---|---|---|
| Form | Fixed username + password | Temporary tokens |
| Security | Low (static) | High (tokens expire) |
| Complexity | Simple | More complex to configure |
| Recommended for | Legacy systems, simple internal integrations | Modern integrations, exposed APIs, corporate environments |
How to fill in an OAuth2 credential?

Fill in the fields on the OAuth2 credential screen as follows:
Name: Internal label to identify the credential. Use a clear name to know which integration is using it, e.g., keycloak, me-app, auth-mercadoeletronico;
Type: Defines the authentication protocol. Select
OAuth2;Authorization Service: URL of the Authorization Server responsible for issuing the token. Provide the IdP login URL (Identity Provider, e.g., Keycloak, Auth0, Azure AD). It usually ends with /auth/realms/{realm}/protocol/openid-connect/token;
Client ID: The public identifier of the application registered in the IdP. Copy the Client ID registered in Keycloak (or another IdP). Example: me-webhooks-integracao.
Client Secret: The private key associated with the Client ID. Paste the secret generated in the IdP.
Grant Type: Defines the OAuth2 flow used to obtain the token. How to fill in:
client_credentials→ when authentication is machine-to-machine (APIs, backend integrations).authorization_code→ when it involves interactive user login.
Scope: Defines the privileges associated with the token. Provide the scopes the application needs. Example: profile, openid, email, or a custom scope defined in the IdP.
Token Request Type: The way parameters are sent in the token request. How to fill in:
URL Encoded Form→ most common (sent via application/x-www-form-urlencoded).- JSON Body may also be available, depending on the IdP.
OAuth2 Customization (Add override): Allows overwriting advanced parameters. Use if you need to send additional fields such as: audience, resource, realm, etc. If not needed, leave blank.
Test Button → Performs the authentication call with the filled-in data to validate if the token is issued correctly.
After filling in all these fields, click Save and your credential will appear in the list of registered credentials.
Step 2A - Bucket Creation (For Bucket-type Webhooks):
ℹ️ Note
This step is required only if you wish to use Bucket-type webhooks (polling). If you're going to use traditional webhooks (callback), skip to Step 2B.
Buckets are containers that store events to be consumed later through polling. Before creating a Bucket-type webhook, you need to create the bucket where events will be stored.

How to create a Bucket:
- Go to the Buckets tab in Partner's Portal > Webhooks
- Click Create new
- Fill in the fields:
- Name: Bucket identification (e.g., "ERP Orders Bucket", "Purchase Events")
- Click Save
After creating the bucket, you will receive a Bucket ID that will be used when creating the webhook and querying events.
Step 2B - Subscription Creation:

- Click on the Subscriptions tab.
- Click Create New and choose the event you would like to receive alerts for.
- In Topic, there are some predefined events, for example:
- Notify when an order has been received by a supplier, or when a request has been approved in the portal.
- In addition to these events, the user can choose to be notified of all integration results from the portal.
- Give a name to the event you would like to be notified about.
- Choose the webhook Type:
- Callback: For traditional webhooks, fill in the Callback Url field with your API address
- Bucket: For polling-type webhooks, select the Bucket created in the previous step
- Select the Credential (optional, but recommended for Callback-type webhooks)
- Click Save.
Viewing Sent Notifications
In this example, we will show an Order Created notification sent through the Event Log page.

Below we highlight the main fields of the event divided by sections: request details (1), header (2), and content (3).
1 - Request Details
| Field | Description |
|---|---|
| Endpoint | The address of your API that was provided in the Callback Url field when you registered the webhook in the Partner's Portal. |
| Delivery Date | Date and time of the request. |
| Status/Attempt | Delivery status (learn more in the following section "Clarification on the Status/Attempt field") |
Clarification on the Status/Attempt field
The Status/Attempt field exclusively indicates the result of the attempt to send the notification (webhook) to the client system.
In other words, it shows whether ME was able to deliver the message to the client’s configured endpoint and how many attempts were made.
It is important to highlight:
It does not represent the result of the operation in ME.
Example: if an order was created or a supplier updated successfully in our platform, this information will be in the payload.It represents only the communication with the client.
If it shows Success / 1, it means the webhook was sent and the client’s endpoint responded correctly (HTTP 2xx status).
If it shows Failure / N or Exhausted, it means we tried to communicate the event, but the client’s endpoint did not respond within the timeout or returned an error, and ME retried until the configured limit.
Thus, if there is a failure or error in Status/Attempt, this does not mean there was a problem executing the operation in ME, but rather that the notification did not reach or was not accepted by the client system.
2 - Headers
| Field | Description |
|---|---|
| X-ME-ATTEMPT | Information on which attempt the request is based (see more details above in "Clarification on the Status/Attempt field"). |
| X-ME-TOPIC | Topic selected in the Partner's Portal corresponding to the event to be notified. |
| X-ME-EVENT-ID | Internal identifier of the event in the platform. |
| X-ME-EVENT-KEY | Business identifier of the event in the platform. (In many cases this may be the Correlation Id) |
| X-ME-WEBHOOK-ID | Internal identifier of the webhook that generated the event. |
| X-ME-WEBHOOK-SIGNATURE | Signature of the message payload using the verification token. For more information, see Webhook Authentication. |
3 - Payload
In this section we have a json describing the generated event:
| Field | Description |
|---|---|
topic | Topic selected in the Partner's Portal corresponding to the event to be notified. |
data | Payload of the event generated by the platform. The properties presented here are dynamic and based on the generated event. |
| For more information about events and payload examples, see Overview. |
Webhook Authentication
ME uses a hash-based message authentication algorithm (HMAC) with SHA-256 to generate signatures. To avoid possible downgrade attacks, it is important to discard any message that does not match a valid signature.
In Partner's Portal > Webhooks > Authentication you can generate your verification token.
❗️ Warning
The provided token will be used as the key in generating the signature. It is important to ensure that this token is kept secret and properly protected, as it is essential for verifying the authenticity of received messages. Keep the token in a safe place and do not share it with unauthorized third parties.

Verifying Signatures
Step 1 - Extract the X-ME-WEBHOOK-SIGNATURE header
At this stage, you must store the hash value received in the request header. This will allow you to later compare this value with the calculated hash to verify the integrity of the received message.
Step 2 - Determine the expected signature
At this stage, you must calculate the HMAC SHA256 of the request payload using the "Verification Token" as the key. HMAC SHA256 is a secure hashing algorithm that ensures data integrity.
Step 3 - Compare the signatures
At this stage, you must compare the received signature with the generated signature. If the signatures differ, you should reject the request, as this indicates that the integrity of the data may have been compromised.
Example written in C#
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Security.Cryptography;
using System.Text;
var app = WebApplication.Create();
const string SharedSecret = "YOUR_VERIFICATION_TOKEN_HERE";
app.MapPost("/webhook", async (HttpContext context) =>
{
string receivedSignature = context.Request.Headers["X-ME-WEBHOOK-SIGNATURE"];
string webhookContent = await context.Request.ReadAsStringAsync();
if (!VerifyWebhookSignature(webhookContent, receivedSignature))
{
await context.Response.WriteAsync("Invalid signature. The webhook may have been tampered with!");
context.Response.StatusCode = 400;
return;
}
// The signature is valid, process the webhook
await context.Response.WriteAsync("Webhook received successfully!");
});
bool VerifyWebhookSignature(string content, string receivedSignature)
{
using HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(SharedSecret));
byte[] signatureBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(content));
string calculatedSignature = Convert.ToBase64String(signatureBytes);
return calculatedSignature.Equals(receivedSignature);
}
app.Run();Consuming Bucket Events (Polling)
For Bucket-type webhooks, events are not sent automatically. Instead, you need to actively fetch events through the Mercado Eletrônico API.
How the polling flow works:
- Events are generated: When an event occurs (order created, request approved, etc.), it is stored in the configured bucket
- Client queries the bucket: Your system makes periodic requests to fetch pending events
- Events are processed: Your system processes the received events
- Events are acknowledged: After processing, you confirm receipt (acknowledge) so they are not delivered again
Step 1: List pending events from the Bucket
Endpoint:
GET https://trunk.api.mercadoe.com/v1/buckets/{bucketId}/eventsRequired headers:
Authorization: API authentication tokenContent-Type: application/json
Success response (200 OK):
{
"events": [
{
"id": "7ceb336d-0319-4d95-8d9f-77337b97a671",
"topic": "contract.approved",
"key": "1761934555034",
"payload": {
"contractId": "125154"
},
"createdAt": "2025-10-31T18:15:55.04Z"
}
]
}Response fields:
| Field | Description |
|---|---|
id | Unique event identifier |
topic | Event topic/type |
key | Business key of the event (can be used as Correlation ID) |
payload | Event data |
createdAt | Event creation date and time |
Step 2: Acknowledge processed events
After processing events, it is essential to confirm receipt so they are marked as consumed and are not returned in future queries.
Endpoint:
POST https://trunk.api.mercadoe.com/v1/buckets/{bucketId}/events/ackRequired headers:
Authorization: API authentication tokenContent-Type: application/json
Request body:
{
"ids": ["7ceb336d-0319-4d95-8d9f-77337b97a671"]
}Success response (200 OK):
{
"acknowledged": 1
}Best practices for Bucket polling
Recommended polling interval:
| Scenario | Recommended Interval |
|---|---|
| High criticality (real-time) | 30 seconds to 1 minute |
| Medium criticality | 2 to 5 minutes |
| Low criticality | 10 to 15 minutes |
⚠️ Warning: Do not poll with an interval shorter than 30 seconds to avoid server overload and possible rate limit restrictions.
Viewing events in Event Log
Events stored in buckets also appear in the Partner's Portal Event Log. The displayed status indicates whether the event was:
- Pending: Event created but not yet consumed
- Success: Event was acknowledged successfully

ME Webhook IP Addresses
ℹ️ Note
This section applies only to Callback-type webhooks. For Bucket-type webhooks, you don't need to configure IP allowlists, as communication is always from your system to ME.
The IP addresses from which webhook (Callback) notifications may originate are:
- 20.102.37.227
- 191.232.73.226
- 164.152.52.63
Depending on how your integration operates, it may be necessary to add them to an allowlist in your firewall.
Delivery Retry Logic
ℹ️ Note
This section applies only to Callback-type webhooks. For Bucket-type webhooks, there is no automatic retry logic - events remain available in the bucket until consumed by the client.
❗️ Attention
Each attempt to send to the endpoint is recorded. The Status / Attempt field does not reflect the result of the operation in the system, but rather the status of the communication attempt with the client.
If our service encounters problems delivering your notifications (Callback-type webhooks), we will attempt to resend them up to 13 more times, as described below:
- 1st attempt after 5 minutes.
- 2nd attempt after 10 minutes.
- 3rd attempt after 20 minutes.
- 4th attempt after 40 minutes.
- 5th attempt after 1 hour.
- 6th attempt after 2 hours.
- Once a day up to 7 days.
The final attempt will be made 7 days after the initial attempt.
Possible issues in sending notifications:
- If your callback endpoint takes more than 10 seconds to respond. In this case, the attempt is considered failed (Request Timeout).
- If the response from your callback endpoint has a status code other than 2xx.
After a failed delivery, notifications are queued to be reprocessed. If a notification resend fails for 7 days, the notification will be marked as "exhausted" and will no longer be reprocessed.
Not recommended:
- Processing business logic before returning (it may exceed timeout);
- Returning 4XX or 5XX for business rule failures.
Best Practices for the Client:
- Do not process business rules during receipt. Save the message to a queue and respond with 200;
- Always return 200 or 204 when receiving the notification;
- Avoid returning 400/403/500, as they imply a retry by the system;
- Implement signature verification to validate the authenticity of the Webhook using the
Webhook-Signatureheader.
Difference between Event Success and Notification Success:
- The fact that an order is successfully created on the platform does not guarantee that the client was notified;
- Notification success = receipt of the Webhook with HTTP 2XX response;
- Notification failure ≠ failure of the original operation.
Event Handling
Proper handling of webhook events is crucial to ensure that your integration’s business logic works as expected.
Handling Duplicate Events
Webhook endpoints may occasionally receive the same event more than once. We recommend that you protect yourself against receiving duplicate events by making your event processing idempotent.
One way to do this is to log the events that have already been processed, and then, based on this log, avoid processing them again.
The X-ME-EVENT-ID field is a unique identifier located in the header of each event and can help with this control:

For information on the Webhooks APIs, go to API Reference > Webhooks API.