Affirm signs the webhook events it sends to your endpoints. We do so by including a signature in each event’s "Affirm-Signature" header. This allows you to verify that the events were sent by Affirm, not by a third party. You can verify signatures manually using your own solution.

A webhook signature can be configured by Affirm only. Please reach out to Affirm via the support widget.

## Preventing replay attacks

A replay attack is when an attacker intercepts a valid payload and its signature, then re-transmits them. To mitigate such attacks, Affirm includes a timestamp in the Affirm-Signature header. Because this timestamp is part of the signed payload, it is also verified by the signature, so an attacker cannot change the timestamp without invalidating the signature. If the signature is valid but the timestamp is too old, you can have your application reject the payload.

Timestamp tolerance

We recommend that you set a default tolerance (e.g., five minutes) between the timestamp and the current time, and use Network Time Protocol (NTP) to ensure that your server’s clock is accurate and synchronizes with the time on Affirm’s servers.

Affirm generates the timestamp and signature each time we send an event to your endpoint. If Affirm retries an event (e.g., your endpoint previously replied with a non-2xx status code), then we generate a new signature and timestamp for the new delivery attempt.

## Verifying signatures manually

The X-Affirm-Signature header contains a timestamp and one or more signatures. The timestamp is prefixed by `t=`, and each signature is prefixed by a scheme. Schemes start with `v`, followed by an integer. Currently, the only valid signature scheme is `v0`.

You perform the verification by providing the webhook payload, the `X-Affirm-Signature` header, and the endpoint’s secret. If verification fails, you can return an error.

Make sure to check our recommended [Tools](🔗) to get started.

  • For handling webhook over HTTPS, we recommend using this [tool more specifically](🔗).

  • You can find a working [webhook signature code example on our codepen space](🔗).

Affirm generates signatures using a hash-based message authentication code (HMAC) with SHA-512. To prevent downgrade attacks, you should ignore all schemes that are not `v0`.

## Step 1: Extract the timestamp and signatures from the header

Split the header, using the`,` character as the separator, to get a list of elements. Then split each element, using the `=` character as the separator, to get a prefix and value pair.

The value for the prefix `t` corresponds to the timestamp, and `v1` corresponds to the signature(s). You can discard all other elements.

## Step 2: Prepare the signed_payload string

You achieve this by concatenating:

  • The timestamp, i.e. the value of "t" (as a string).

  • The character `.`.

  • The actual raw payload (i.e., the request’s body).

For checkout events, the requests sent from Affirm to your webhook endpoint come with the `content-type` `application/x-www-form-urlencoded` and a `application/x-www-form-urlencoded` version of the data in the body field. Prequal events are sent with the `content-type` `application/json` and a `JSON` version of the data in the body field.

## Step 3: Determine the expected signature

Compute an HMAC with the SHA512 hash function. Use the endpoint’s signing secret (your private key) as the key, and use the `signed_payload` string as the message.

## Step 4: Compare signatures

Compare the signature(s) in the header to the expected signature. If a signature matches, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.

To protect against timing attacks, use a constant-time string comparison to compare the expected signature to each of the received signatures.