Introduction
A webhook is a URL on your server where we send a JSON payload over HTTP as such events occur. Webhooks are important in integrating FlashPay, they allow FlashPay notify you once an event occurs. For example, when you set webhook URL on your FlashPay dashboard, once a payment transaction is successful, we will immediately notify your server.
When your webhook URL receives an event, it needs to acknowledge the event with an HTTP response. The request times out if a response is not received in 10 seconds, acknowledging an event means returning a 200 OK
HTTP response. Without a 200 OK
response, we will keep sending events every 30 minutes for a maximum of five(5) times.
Webhook Payload Structure
Webhook Payload Structure
Webhook events follow the same structure:
field | description |
---|---|
txn_reference | Unique transaction reference of the successful transaction. |
asset | Asset ID. |
sender | Algorand address of the sender. |
recipient | Algorand address of the recipient. |
txn_type | Transaction type (normal , payment_link ) |
txn_hash | Hash of the transaction on the Algorand blockchain. |
amount | The total amount paud. |
status | Transaction status (usually success because we only send webhook notifications when a transaction is successful |
network | Transaction network (testnet , mainnet ) |
Here is sample webhook payloads for successful payment:
{
"txn_reference": "fp_399c37cbd2824aed891738a033a1ad5b_03ef72",
"asset": 10458941,
"sender": "XQ52337XYJMFNUM73IC5KSLG6UXYKMK3H36LW6RI2DRBSGIJRQBI6X6OYI",
"txn_type": "payment_link",
"recipient": "J7ZIYHAHBSNHO5SDR44WY3R4GKSBA6DWJGNUNYB2F3SNMEU2WAVY6OTFNQ",
"txn_hash": "F23RSTSTWEWMX3LWZ3ZEUHRWFPOIXXAPOWS2DJ7YHK5NC3VKKTDA",
"amount": "10.0000",
"status": "success",
"created_at": "2022-10-02T22:26:35.843598Z",
"updated_at": "2022-10-02T22:26:35.843618Z",
"network": "testnet"
}
Verifying Webhook Origin
Verifying Webhook Origin
Since your webhook URL is publicly accessible and anyone can send a fake payload, you need to verify that events sent to your webhook URL are from FlashPay.
Webhook events from FlashPay have an x-flashpay-signature
header. The value of this header is a HMAC 512
hash of the webhook payload signed with your secret key. Check if the header is present in the request headers and verify the value before processing the event.
var crypto = require('crypto');
var secret = process.env.SECRET_KEY;
// Using Express
app.post("/my/webhook/url", function(req, res) {
// Verify event is from Flashpay
const hash = crypto.createHmac('sha512', secret).update(JSON.stringify(req.body)).digest('hex');
if (hash == req.headers['x-flashpay-signature']) {
// Retrieve the request's body
const payload = req.body;
// Do something with event
}
res.send(200);
});
import hmac
import hashlib
import os
import request
secret = os.environ['SECRET_KEY']
// Using Flask
@app.route("/my/webhook/url", methods=['POST'])
def my_webhook_url():
# Verify event is from Flashpay
hash = hmac.new(secret, msg=request.json, digestmod=hashlib.sha512).hexdigest()
if hash == request.headers['x-flashpay-signature']:
# Retrieve the request's body
payload = request.json
# Do something with event
return ('', 200)
$secret = getenv('SECRET_KEY');
// Using Express
$app->post("/my/webhook/url", function($req, $res) {
// Verify event is from Flashpay
$hash = hash_hmac('sha512', json_encode($req->body), $secret);
if ($hash == $req->headers['x-flashpay-signature']) {
// Retrieve the request's body
$payload = $req->body;
// Do something with event
}
$res->send(200);
});
String secret = System.getenv("SECRET_KEY");
// Using Spring (MVC)
@PostMapping("/my/webhook/url")
public ResponseEntity<String> post(@RequestBody String payload, @RequestHeader("X-Flashpay-Signature") String hash) {
// Verify event is from Flashpay
String hash = HmacUtils.hmacSha512Hex(secret, payload);
if (hash == req.headers['x-flashpay-signature']) {
// Retrieve the request's body
// Do something with event
}
return ResponseEntity.ok().build();
}
func main() {
// Verify event is from Flashpay
hash := crypto.Hmac512(os.Getenv("SECRET_KEY"), []byte(req.Body))
if hash == req.Header("X-Flashpay-Signature") {
// Retrieve the request's body
payload := req.Body
// Do something with event
}
res.Send(200)
}