Introduction
Verifying a Webhook Request
To ensure that you only process legitimate requests from Ramp, verify the signature included with every webhook request.
All valid requests include an X-Ramp-Signature header containing an HMAC-SHA256 signature. Ramp generates this signature from the exact JSON request body using your latest active secret key.
The following Express example verifies the signature before handling the event:
const crypto = require("crypto");
const express = require("express");
const app = express();
const secretKey = process.env.RAMP_SECRET_KEY;
app.post(
"/your_webhook_url",
express.raw({ type: "application/json" }),
async (req, res) => {
const signature = crypto
.createHmac("sha256", secretKey)
.update(req.body)
.digest("hex");
if (signature !== req.get("X-Ramp-Signature")) {
return res.status(401).send("Invalid signature");
}
const payload = JSON.parse(req.body.toString("utf8"));
await handleWebhook(payload);
res.sendStatus(200);
}
);
Use the raw request body when calculating the signature. Parsing and re-serializing the JSON before verification may change the payload and cause a valid signature to be rejected. Keep your secret key in secure server-side
configuration and never expose it in client-side code.
Responding to a Webhook Request
Return an HTTP 2xx status code as soon as the webhook has been accepted. Ramp only uses the response status code to determine whether delivery succeeded; the response body is not processed.
Perform lengthy work in a background job so that your endpoint responds within the 10-second timeout.
Retries
If Ramp receives a non-2xx response, cannot connect to your endpoint, or the request times out, it retries the webhook automatically.
By default, Ramp makes five attempts in total: the initial delivery and up to four retries. Retries are scheduled after approximately 1, 2, 4, and 8 minutes. A small amount of random jitter is added to each delay.
The same webhook may therefore arrive more than once. Make your handler idempotent by storing a unique key such as event plus data.public_id, and return 200 for an event that has already been accepted.
Updated 28 days ago

