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 when on_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