Search in documentation
ctrl+4K
Modules
Authentication
Merchant
Catalog
Order
Events
Logistics
Shipping
Review
Financial
Solutions

Overview

Webhook URLs are exposed on the internet. To ensure that a request really came from iFood, we implement the X-IFood-Signature header in all webhook requests. This header allows validating the authenticity of received messages.Reject requests with invalid signatures. This validation is mandatory for webhook homologation. iFood may send events with invalid signatures to test your integration. This check also protects against fraud. We audit all delivered events, delivery attempts, and discarded events.

Validation

The webhook uses (HMAC) with SHA256 to sign each message. The final value is encoded in hexadecimal. The signature uses the application's client secret (the same one used to generate tokens), available in the "Credentials" tab of the Developer Portal. Each request includes this signature in the X-IFood-Signature header. To validate, generate the HMAC of the received message using your secret (in a secure location) and compare with the received signature using secure comparison (example). Most languages have libraries with native support:
Fields can be added to any event at any time, without causing breaking changes. Therefore, validate the signature before converting the message content to an object. Generate the signature using the body byte array exactly as received.This care is essential in JSON, since {"prop1": "value1", "prop2": "value2"} and {"prop2": "value2", "prop1": "value1"} are equivalent for parsers, but form different byte arrays. Special characters may also vary according to the library or language.

Examples

All examples are valid for the same JSON, but with different formatting and should be supported by your integration:
{
    "code":"PLC",
    "createdAt":"2023-02-20T18:19:03.20162269Z",
    "fullCode":"PLACED",
    "id":"a38ba215-f949-4b2c-982a-0582a9d0c10e",
    "merchantId":"cad65e8f-6fc6-438a-b159-e64a902a6b9a",
    "orderId":"2c97e104-35ed-4c18-85d7-854a40b6b9e3"
}
The examples show how formatting affects the signature:
X-IFood-Signature: 6f9ed23a7b505a3b6907c5f6eb2ad1b056fbf35a643d365a9a072ed7aabca153. Payload:
{"code":"PLC","createdAt":"2023-02-20T18:19:03.20162269Z","fullCode":"PLACED","id":"a38ba215-f949-4b2c-982a-0582a9d0c10e","merchantId":"cad65e8f-6fc6-438a-b159-e64a902a6b9a","orderId":"2c97e104-35ed-4c18-85d7-854a40b6b9e3"}
'X-IFood-Signature: cf7e092c9148a48f5ee5f12b947f46b331eac6bf0745e1e1d0f3df722e219df3'. Payload:
{ "code":"PLC", "createdAt":"2023-02-20T18:19:03.20162269Z", "fullCode":"PLACED", "id":"a38ba215-f949-4b2c-982a-0582a9d0c10e", "merchantId":"cad65e8f-6fc6-438a-b159-e64a902a6b9a", "orderId":"2c97e104-35ed-4c18-85d7-854a40b6b9e3" }
'X-IFood-Signature: adf5446334f754e73588f3ae10b308306307f0c797f7f678912d740c6deddf6a'. Payload:
{
    "code":"PLC",
    "createdAt":"2023-02-20T18:19:03.20162269Z",
    "fullCode":"PLACED",
    "id":"a38ba215-f949-4b2c-982a-0582a9d0c10e",
    "merchantId":"cad65e8f-6fc6-438a-b159-e64a902a6b9a",
    "orderId":"2c97e104-35ed-4c18-85d7-854a40b6b9e3"
}
X-IFood-Signature: e2d26f22f89932ff3d23a699031b22d6f30323501430dc08c3a971dd875e23b5. Payload:
{"merchantId":"cad65e8f-6fc6-438a-b159-e64a902a6b9a","orderId":"2c97e104-35ed-4c18-85d7-854a40b6b9e3","code":"PLC","createdAt":"2023-02-20T18:19:03.20162269Z","fullCode":"PLACED","id":"a38ba215-f949-4b2c-982a-0582a9d0c10e"}
Here's a Java snippet of how to validate the message:
private String bytesToHexString(byte[] bytes) {
    var sb = new StringBuilder();
    for (var b : bytes) {
        var hex = String.format("%02x", b);
        sb.append(hex);
    }
    return sb.toString();
}

private boolean verifyHmacSHA256(String secret, String data, String expectedSignature) {
    try {
        var mac = Mac.getInstance("HmacSHA256");
        var secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        mac.init(secretKeySpec);
        var hmacBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return bytesToHexString(hmacBytes).equals(expectedSignature);
    } catch (NoSuchAlgorithmException | InvalidKeyException e) {
        return false;
    }
}
See an example snippet of an endpoint in Go:
http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) {
  body, err := io.ReadAll(r.Body)
  if err != nil {
    fmt.Printf("could not read body")
    w.WriteHeader(400)
    return
  }

  headerSignature := r.Header.Get("X-IFood-Signature")

  signature, err := hex.DecodeString(headerSignature)
  if err != nil {
    panic(err)
  }

  hasher := hmac.New(sha256.New, SECRET)
  hasher.Write(body)
  expected := hasher.Sum(nil)

  if !hmac.Equal(expected, signature) {
    fmt.Printf("invalid signature")
    w.WriteHeader(401)
    return
  }

  // Message validated...
})

See also

Was this page helpful?
Rate your experience in the new Developer portal: