Webhook Signature

For security reasons, every Webhook sent from Reveni includes a signed header. Thus you can make sure that the event is sent by us and not by an unknown third party. For verifying those signatures, you will need the provided REVENI_API_KEY that you use for Authentication.

Webhook requests use the POST method and include a header for the signature: X-REVENI-SIGNATURE. It contains the event timestamp and the computed signature. The timestamp is prefixed by t=, and the signature is prefixed by a scheme. Schemes start with v, then followed by an integer. The current valid signature scheme is v1.

Example:

X-REVENI-SIGNATURE:t=1654594965.749773,v1=e1676b8d4c23dc90d3729035a2c2eaecaa4fa7ffd1ad7696a4bbbed6bb8522ec

The signature is generated using a hash-based message authentication code (HMAC) with SHA-256. To prevent downgrade attacks, you should ignore all schemes that are not v1.

For verifying the provided signatures, you can do the following:

Step 1. Extract the timestamp and signature from the header

Step 2. Generate the verification payload string

  • The timestamp in string format (e.g. 1654594965.749773)
  • The character .
  • The request payload (i.e. the request body in raw format):
{"id": "c6927a921708466da5ed2b4ebadf0bdf", "event": "return.created", "created": 1661518366, "data": {"amount": "76.4800","status": "incomplete","currency": "EUR","resource": "return","resource_id": "4e26c9f08f2a468fabc16af12ae0209b","object": {...}}}

Step 3. Compute an HMAC with the SHA256 hash function

Use the REVENI_API_KEY as the key, and use the generated payload string as the message.

Step 4. Compare the signatures

Compare the computed signature with the one extracted from the header, these must match. Also, check the timestamp with the current time and decide whether that difference is within your tolerance.

Reference snippet

Use the following Python snippet for reference. The computed signature must match the signature extracted from the Webhook header.

import hashlib
import hmac

# Use the timestamp extracted from the header and the request body as received
payload = f"{timestamp}.{request.json()}".encode()

# Use the REVENI API key
key = reveni_api_key.encode()

hash = hmac.new(
        key,
        payload,
        hashlib.sha256,
)

signature = hash.hexdigest()

Basic Authentication

Reveni Webhooks support the Basic Authentication schema, which is based on a user and password. To create a Webhook with basic authentication, include the user and password credentials to the URL (e.g. https://user:[email protected]). Reveni will honor these parameters and will send the appropriate header in the request. Then you can authenticate these requests upon received in your platform.