Webhook Signature Validation
To ensure the security and integrity of webhook notifications, Ripio includes an HMAC-SHA256 signature with each request. This signature allows you to verify that the webhook payload was indeed sent by Ripio and has not been tampered with during transmission.Overview of Signature Validation
Webhook requests from Ripio will include anHttp-X-Wh-Signature-256 header. This header contains the HMAC-SHA256 signature of the request payload, generated using a shared secret key provided to you by Ripio.
Validating the Signature: Step-by-Step Guide
-
Retrieve the Signature Header:
Extract the value of the
Http-X-Wh-Signature-256header from the incoming webhook request. - Read the Raw Request Body: Read the raw bytes of the webhook request body. Do not parse and re-serialize the JSON — verification must happen over the exact bytes Ripio sent.
-
Verify the Signature:
Using your shared secret key, compute the HMAC-SHA256 of the raw body bytes and compare it (after prepending
sha256=) with the value in theHttp-X-Wh-Signature-256header. If they match, the webhook is authentic.
Wire Format Reference
You do not need to re-serialize the payload yourself — verify over the raw body — but knowing the format helps if you ever need to debug a mismatch. Ripio sends the body as:- Compact JSON: no whitespace after separators (
{"key":"value"}, not{"key": "value"}). - ASCII-escaped: non-ASCII characters are encoded as
\uXXXXescapes (for example,Ñis sent asÑ). - Content-Type:
application/json.
Example Code (Python)
Here’s an example in Python demonstrating how to verify the signature over the raw request body:Important Notes for Signature Validation
- Verify Over Raw Bytes: Always run HMAC over the raw request body. Parsing the JSON and re-serializing it on your side will change the bytes (whitespace, escape sequences, key order) and cause verification to fail.
- Secure Secret Storage: Always use a secure method to store and handle your shared secret key. Do not embed it directly in your client-side code or commit it to version control.
- Reject Invalid Requests: Reject any requests with missing or invalid signatures to prevent unauthorized access or processing of tampered data.
- Timestamp Verification (Optional but Recommended): Consider checking the
issueDatetimeof the webhook event to prevent replay attacks, where an attacker resends an old, valid webhook. Define an acceptable time window for webhooks.
Webhook Event Categories
Ripio provides webhooks for three main categories of events:- On-Ramp Events: Notifications related to the process of converting fiat currency to cryptocurrency.
- Off-Ramp Events: Notifications related to the process of converting cryptocurrency back to fiat currency.
- Sell and Pay Events: Notifications related to Sell and Pay transactions, which convert cryptocurrency to fiat and complete QR code payments to merchants.
- KYC Events: Notifications related to KYC (Know Your Customer) verification status changes.
Configuring Your Webhook Endpoint
To receive webhook notifications, you need to configure a publicly accessible HTTPS URL endpoint in your Ripio partner settings. Ripio will send POST requests to this URL with a JSON payload. Key considerations for your endpoint:- HTTPS: Your endpoint URL must use HTTPS.
- Respond Quickly: Your endpoint should acknowledge receipt of the webhook by returning a
2xxHTTP status code (e.g.,200 OKor202 Accepted) as quickly as possible, ideally within 10 seconds as per Ripio’s guidelines. - Asynchronous Processing: For any time-consuming processing of the webhook data, perform it asynchronously (e.g., using a message queue) to ensure your endpoint responds promptly.
- Idempotency: Design your webhook handler to be idempotent. This means that processing the same event multiple times should not result in duplicated actions or inconsistent state, as network issues or retries might cause a webhook to be delivered more than once.
Basic Endpoint Implementation Examples
Here are basic examples of how you might set up an endpoint to receive webhooks and validate signatures.Python (Flask Example)
Node.js (Express Example)
"your_ripio_shared_secret" with the actual secret provided by Ripio.