Overview
If you configure a webhook endpoint, Fluidcoins will notify you about certain events that occur. Events like crypto deposits, widget payments, and others
Security
When you add a webhook address to Fluidcoins, we will generate a secret key for that endpoint. We will then sign each request we make to the address with the secret so you can verify the webhook is actually being sent by Fluidcoins.
We also add information to help you guard against replay attacks.
Verifying a webhook
We make use of Svix to send and manage our webhooks infrastructure and have linked the relevant link below. You can also find an example of what verification looks like below
const { Webhook } = require('svix');
const bodyParser = require('body-parser');
app.post(
'/v1/hook',
bodyParser.raw({ type: 'application/json' }),
(req, res) => {
res.json({});
const payload = req.body;
const headers = req.headers;
const wh = new Webhook(secret);
let msg;
try {
msg = wh.verify(payload, headers);
console.log(msg);
// Do something with the message...
} catch (err) {
console.log(err);
return;
}
}
);
http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) {
headers := r.Header
// var b = new(bytes.Buffer)
// _,err := io.Copy(b,r.Body)
payload, err := io.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
// Make sure you can reuse payload to process the request
// like retrieving details about the request body
// json.NewDecoder(r.Body).Decode(struct)
r.Body = ioutil.NopCloser(bytes.NewBuffer(b))
err = wh.Verify(payload, headers)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
// Do something with the message...
w.WriteHeader(http.StatusNoContent)
})
use Svix\Webhook;
use Svix\Exception\WebhookVerificationException;
Route::post('webhook', function(Request $request) {
$payload = $request->getContent();
$headers = collect($request->headers->all())->transform(function ($item) {
return $item[0];
});
try {
$wh = new Webhook("secret");
$json = $wh->verify($payload, $headers);
# Do something with the message...
return response()->noContent();
} catch (WebhookVerificationException $e) {
return response(null, 400);
}
});
require 'svix'
class WebhookController < ApplicationController
protect_from_forgery with: :null_session # disables CSRF middleware; required for API endpoints
def index
begin
payload = request.body.read
headers = request.headers
wh = Svix::Webhook.new("secret")
json = wh.verify(payload, headers)
# Do something with the message...
head :no_content
rescue
head :bad_request
end
end
end
More examples can be found below
Events
{
"data": {
"address_reference": "ADDR_6u_Jv9twFwrjASuty4H2P",
"amount": 10000000,
"coin": "BUSD",
"destination_tag": 0,
"domain": "live",
"from": "0xca4fd81d1785cdbd4abdfde395c799ca19c12272",
"hash": "0x8c9e9fa993bff5a5fc3d3e7d3c91ffe0090ed02a47d72e264ca346d7de73595a",
"human_readable_amount": 10,
"on_chain": {
"block_hash": "0x8c9e9fa993bff5a5fc3d3e7d3c91ffe0090ed02a47d72e264ca346d7de73595a",
"block_height": 22069640,
"block_timestamp": 62135596800,
"confirmations": 5,
"is_confirmed": false
},
"to": "0xa3244157ff31b2673377bb4c553dd275b54ffc0c",
"transaction_reference":"ADDR_TRANS_1k3go9m4T5gU23faHVzcX"
},
"event": "address.deposit"
}
{
"data": {
"customer": {
"email": "[email protected]",
"reference": "CUS_U7IX76UWXpz5sdyEbwbwz"
},
"domain": "test",
"fiat": {
"amount": 70700000,
"currency": "NGN",
"human_readable_amount": 707000
},
"metadata": {
"custom_fields": [
{
"key": "address",
"value": "dfg"
},
{
"key": "preferred phone color",
"value": "rrr"
}
]
},
"payment": {
"amount": 991863075199,
"coin": "DOGE",
"destination_tag": 0,
"expected_amount": 991863075199,
"from": "a63f4388-33ac-4fc8-87fe-60e40c7bc357",
"hash": "4f6535c3-d235-4227-a6eb-d844345cc75f",
"human_readable_amount": 9918.63075199,
"memo": "",
"paid_amount": 991863075199,
"to": "6132bb7c-d5bf-4cff-9f4e-ba5c73646837"
},
"payment_link": {
"is_payment_link": true,
"reference": "LINK_N5VYRWDQssEGUkDpTW1kK"
},
"status": "success",
"transaction_reference": "TRANS_HLuMR5ea6GKNF71FfOXDy"
},
"event": "widget.payment"
}
{
"data": {
"address_reference": "ADDR_6u_Jv9twFwrjASuty4H2P",
"amount": 10000000,
"coin": "BUSD",
"destination_tag": 0,
"domain": "live",
"from": "0xca4fd81d1785cdbd4abdfde395c799ca19c12272",
"hash": "0x8c9e9fa993bff5a5fc3d3e7d3c91ffe0090ed02a47d72e264ca346d7de73595a",
"human_readable_amount": 10,
"on_chain": {
"block_hash": "0x8c9e9fa993bff5a5fc3d3e7d3c91ffe0090ed02a47d72e264ca346d7de73595a",
"block_height": 22069640,
"block_timestamp": 62135596800,
"confirmations": 14,
"is_confirmed": true
},
"to": "0xa3244157ff31b2673377bb4c553dd275b54ffc0c",
"transaction_reference":"ADDR_TRANS_1k3go9m4T5gU23faHVzcX"
},
"event": "address.deposit"
}
an unconfirmed
address.deposit
webhook should only be used to provide your end users a pending deposit notification or credit. Only provide actual value whenon_chain.is_confirmed
is true. The confirmation time for each blockchain can be found at https://support.fluidcoins.com/en/articles/6462090-deposit-speed
Retry schedule
Webhooks are retried exponentially and the current schedule is
- Immediately
- 5 seconds
- 5 minutes
- 30 minutes
- 2 hours
- 5 hours
- 10 hours
What happens after the 7th trial?
We will no longer try to send another webhook for this particular action. Others will continue processing as normal
Updated about 2 years ago