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.
| Header | Description |
|---|---|
X-keshflippay-Key | The public key of your application |
X-keshflippay-Timestamp | Unix timestamp for replay protection |
X-keshflippay-Signature | HMAC-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:
- Retrieve the
X-keshflippay-TimestampandX-keshflippay-Signatureheaders. - Compute a HMAC-SHA256 hash using your secret key and the raw request body.
- Compare it with the received signature.
Here’s an example verification implementation:
- JavaScript / TypeScript
- Python
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));
}
import hmac
import hashlib
def verify_keshflippay_signature(body, signature, timestamp, secret):
message = f"{timestamp}.{body}".encode()
expected = hmac.new(secret.encode(), message, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature, expected)
4. Event Types
| Event Type | Description |
|---|---|
deposit.created | A deposit was initiated |
deposit.completed | A deposit was confirmed |
withdrawal.created | A withdrawal was initiated |
withdrawal.completed | A withdrawal was completed successfully |
withdrawal.failed | A withdrawal attempt failed |
transaction.verified | A crypto transaction was validated |
balance.updated | Partner 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.
| Attempt | Delay |
|---|---|
| 1st | Immediate |
| 2nd | 1 minute |
| 3rd | 5 minutes |
| 4th | 30 minutes |
| 5th | 1 hour |
| 6th | 6 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 OKquickly. - 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:
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
- Node.js (Express)
- Python (FastAPI)
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"));
from fastapi import FastAPI, Request, HTTPException
import os, json
from verify_webhook import verify_keshflippay_signature
app = FastAPI()
@app.post("/webhook")
async def webhook(request: Request):
body = await request.body()
signature = request.headers.get("x-keshflippay-signature", "")
timestamp = request.headers.get("x-keshflippay-timestamp", "")
secret = os.getenv("keshflippay_SECRET", "")
if not verify_keshflippay_signature(body.decode("utf-8"), signature, timestamp, secret):
raise HTTPException(status_code=400, detail="Invalid signature")
event = json.loads(body)
print("Received Event:", event.get("type"))
return {"received": True}