One requirement sits on top of Adyen's own scheme, deliberately: the
delivery must carry credentials. Adyen's HMAC authenticates eight field
values; everything else in the payload (additionalData, reason, paymentMethod,
eventDate — all of which reach hosts through event.raw) is unauthenticated.
Basic authentication, which Adyen supports on every webhook type and hosts
enable in the Customer Area, is what authenticates the channel the rest of the
payload arrived on.
Each item's signed values are checked against the types Adyen's webhook
schema documents before anything is signed: the required ones present, every
one a string except amount.value, a safe integer. null in the two optional
values (originalReference, merchantReference) reads as absent, as Adyen's
own validators sign it. A value of another type is refused as
malformed_payload rather than coerced into the joined string.
A re-encoded body still verifies, and that is correct rather than a gap: the
signature covers values, not bytes, which is what
webhookSignatureScope: "field-values" declares. Refusing a re-encoded body
would mean guessing Adyen's wire format, and a wrong guess rejects every
legitimate delivery.
Verifies a delivery, with the reason on failure.
One requirement sits on top of Adyen's own scheme, deliberately: the delivery must carry credentials. Adyen's HMAC authenticates eight field values; everything else in the payload (additionalData, reason, paymentMethod, eventDate — all of which reach hosts through
event.raw) is unauthenticated. Basic authentication, which Adyen supports on every webhook type and hosts enable in the Customer Area, is what authenticates the channel the rest of the payload arrived on.Each item's signed values are checked against the types Adyen's webhook schema documents before anything is signed: the required ones present, every one a string except
amount.value, a safe integer.nullin the two optional values (originalReference,merchantReference) reads as absent, as Adyen's own validators sign it. A value of another type is refused asmalformed_payloadrather than coerced into the joined string.A re-encoded body still verifies, and that is correct rather than a gap: the signature covers values, not bytes, which is what
webhookSignatureScope: "field-values"declares. Refusing a re-encoded body would mean guessing Adyen's wire format, and a wrong guess rejects every legitimate delivery.