Skip to main content

Webhooks

Webhooks

Webhooks allow your application to receive real-time notifications whenever events occur in your keshflippay account — such as completed deposits, withdrawals, or transaction status updates.


Overview

Webhooks are essential for keeping your system synchronized with keshflippay events.
Each webhook event includes a signed payload that verifies authenticity and prevents tampering.

All webhook requests are sent as POST requests to your specified URL.


1. How Webhooks Work

When an event occurs, keshflippay will send an HTTPS POST request to your webhook endpoint containing a JSON payload.
You must validate the signature included in the X-keshflippay-Signature header before processing the event.

HeaderDescription
X-keshflippay-KeyThe public key of your application
X-keshflippay-TimestampUnix timestamp for replay protection
X-keshflippay-SignatureHMAC-SHA256 signature of the payload

2. Example Webhook Event

Sample Payload

{
"id": "evt_01HXYJFG82R12X",
"type": "deposit.completed",
"createdAt": "2025-10-12T14:30:00Z",
"data": {
"depositId": "dep_001",
"amount": 500,
"currency": "USD",
"status": "COMPLETED",
"reference": "order_001"
}
}

Sample Headers

X-keshflippay-Key: pk_live_12345
X-keshflippay-Timestamp: 1734038411
X-keshflippay-Signature: 9b1d7a9ac8e39e1b5ffbc5c9...

3. Verifying Signatures

Before trusting any webhook event, your backend must:

  1. Retrieve the X-keshflippay-Timestamp and X-keshflippay-Signature headers.
  2. Compute a HMAC-SHA256 hash using your secret key and the raw request body.
  3. Compare it with the received signature.

Here’s an example verification implementation:

verifyWebhook.js
import crypto from "crypto";

export function verifykeshflippaySignature(body, signature, timestamp, secret) {
const message = timestamp + "." + body;
const expected = crypto
.createHmac("sha256", secret)
.update(message)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

4. Event Types

Event TypeDescription
deposit.createdA deposit was initiated
deposit.completedA deposit was confirmed
withdrawal.createdA withdrawal was initiated
withdrawal.completedA withdrawal was completed successfully
withdrawal.failedA withdrawal attempt failed
transaction.verifiedA crypto transaction was validated
balance.updatedPartner balance was updated

5. Responding to Webhooks

Your server must respond with HTTP 200 OK within 5 seconds to acknowledge successful receipt. If keshflippay does not receive a 200 response, it will automatically retry the request.

Recommended Response:

HTTP/1.1 200 OK
Content-Type: application/json

{ "received": true }

6. Retry Policy

keshflippay will retry failed webhook deliveries with exponential backoff for up to 24 hours.

AttemptDelay
1stImmediate
2nd1 minute
3rd5 minutes
4th30 minutes
5th1 hour
6th6 hours

If all retries fail, the webhook event will be marked as failed in the dashboard, and you can manually re-deliver it.


7. Securing Your Endpoint

Follow these best practices to secure your webhook receiver:

  • Use HTTPS only.
  • Validate all signatures using your secret key.
  • Respond with 200 OK quickly.
  • Avoid long-running logic — process asynchronously if needed.
  • Log all incoming events for traceability.

8. Testing Webhooks

You can simulate webhook events from the keshflippay developer dashboard.

Alternatively, you can manually test using the following cURL command:

Terminal
curl -X POST "https://your-server.com/webhook" \
-H "Content-Type: application/json" \
-H "X-keshflippay-Key: pk_test_12345" \
-H "X-keshflippay-Timestamp: $(date +%s)" \
-H "X-keshflippay-Signature: <computed_signature>" \
-d '{"id":"evt_01HXYJFG82R12X","type":"deposit.completed"}'

9. Handling Duplicate Events

Occasionally, webhook events may be retried due to network delays. Always ensure your handlers are idempotent — meaning multiple deliveries of the same event do not cause duplicated processing.

Use the event.id field to track processed events and ignore duplicates.


10. Example Server Implementations

webhook-server.js
import express from "express";
import bodyParser from "body-parser";
import { verifykeshflippaySignature } from "./verifyWebhook.js";

const app = express();
app.use(bodyParser.text({ type: "*/*" }));

app.post("/webhook", (req, res) => {
const signature = req.headers["x-keshflippay-signature"];
const timestamp = req.headers["x-keshflippay-timestamp"];
const secret = process.env.keshflippay_SECRET;

const isValid = verifykeshflippaySignature(req.body, signature, timestamp, secret);

if (!isValid) {
return res.status(400).send("Invalid signature");
}

const event = JSON.parse(req.body);
console.log("Received Event:", event.type);

res.json({ received: true });
});

app.listen(3000, () => console.log("Webhook server listening on port 3000"));