Skip to content

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 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.

webhooks-aba-credenciais

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

ItemBasic AuthOAuth2
FormFixed username + passwordTemporary tokens
SecurityLow (static)High (tokens expire)
ComplexitySimpleMore complex to configure
Recommended forLegacy systems, simple internal integrationsModern integrations, exposed APIs, corporate environments

How to fill in an OAuth2 credential?

webhooks-editar-credenciais

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 2 - Subscription Creation:

  1. Click on the Subscriptions tab.
  2. Click Create New and choose the event you would like to receive alerts for.
  3. 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.
  4. Give a name to the event you would like to be notified about.
  5. In the Callback Url field, add the address of your API where you want to be notified.
  6. Select the Credential created in the previous step and 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

FieldDescription
EndpointThe address of your API that was provided in the Callback Url field when you registered the webhook in the Partner's Portal.
Delivery DateDate and time of the request.
Status/AttemptDelivery 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

FieldDescription
X-ME-ATTEMPTInformation on which attempt the request is based (see more details above in "Clarification on the Status/Attempt field").
X-ME-TOPICTopic selected in the Partner's Portal corresponding to the event to be notified.
X-ME-EVENT-IDInternal identifier of the event in the platform.
X-ME-EVENT-KEYBusiness identifier of the event in the platform. (In many cases this may be the Correlation Id)
X-ME-WEBHOOK-IDInternal identifier of the webhook that generated the event.
X-ME-WEBHOOK-SIGNATURESignature 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:

FieldDescription
topicTopic selected in the Partner's Portal corresponding to the event to be notified.
dataPayload 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#

csharp
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();

ME Webhook IP Addresses

The IP addresses from which webhook 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.

Delivery Retry Logic

❗️ 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, 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-Signature header.

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.