Webhooks

Use webhooks to get notifications sent to your backend servers every time an Event is created, in real time.

A Webhook object consists of a destination URL and a set of events types to receive. If an event matches multiple webhooks, it will be sent to all of them.

When an event happens, the URL is sent an HTTP POST request, with the event JSON as request body.

Registering webhooks

To register a new webhook, you need to have a URL in your app that Kernel can call. You can configure a new webhook from the Kernel dashboard under Webhooks. Give your webhook a name, pick the events you want to listen for, and add your URL.

Consuming webhooks

When your app receives a webhook request from Kenel, check the type attribute to see what event caused it. The first part of the event type will tell you the payload type, e.g., a transfer, a card_payin, etc. In the payload, you will find the actual data for the event.

Example webhook payload

{
  "id": "ev_3y7cfc9mxnjjy7r7e4q1",
  "project_id": "prj_3y7c8zrgxnrvln3x8avh",
  "type": "transfer_created",
  "correlation_id": "trf_3y7cfc9jv6nubasjbtk1",
  "payload": {
    "transfer": {
      "id": "trf_3y7cfc9jv6nubasjbtk1"
      // ...
    }
  },
  "created_at": "2023-10-10T10:09:23.864322048Z"
}

In the example above, a transfer was created, and the payload type is a transfer.


Event types

  • Name
    card_payin_dispute_created
    Description
    A dispute has been created for a card payin.
  • Name
    card_payin_settled
    Description
    A card payin has been settled.
  • Name
    bank_payin_created
    Description
    A bank payin has been created.
  • Name
    bank_payout_completed
    Description
    A bank payout has been completed.
  • Name
    bank_payout_failed
    Description
    A bank payout has failed.
  • Name
    bank_payout_refunded
    Description
    A bank payout has been refunded.
  • Name
    card_payin_dispute_won
    Description
    A dispute for a card payin has been won.
  • Name
    card_payin_dispute_lost
    Description
    A dispute for a card payin has been lost.
  • Name
    card_payin_authorized
    Description
    A card payin has been authorized.
  • Name
    card_payin_declined
    Description
    A card payin has been declined.
  • Name
    transfer_created
    Description
    A transfer has been created.

Example payload

{
  "id": "ev_3y7cfc9mxnjjy7r7e4q1",
  "project_id": "prj_3y7c8zrgxnrvln3x8avh",
  "type": "transfer_created",
  "correlation_id": "trf_3y7cfc9jv6nubasjbtk1",
  "payload": {
    "transfer": {
      "id": "trf_3y7cfc9jv6nubasjbtk1",
      "meta": {},
      "value": {
        "amount": 100000,
        "currency": "EUR"
      },
      "created_at": "2023-10-10T10:09:23.813203968Z",
      "project_id": "prj_3y7c8zrgxnrvln3x8avh",
      "updated_at": "2023-10-10T10:09:23.835560371Z",
      "split_source": null,
      "source_account_id": "acc_3y7cfahqtgplzfv5bkl1",
      "split_destination": null,
      "source_transaction_id": "tx_3y7cfc9jzct9afm4rc8h",
      "destination_account_id": "acc_3y7cf5sclx1ze5fe2gv1",
      "destination_transaction_id": "tx_3y7cfc9jzct9afm4rc91"
    }
  },
  "created_at": "2023-10-10T10:09:23.864322048Z"
}

Security

Webhook delivery contents are cryptographically signed. This allows you to verify the webhook request comes indeed from Kernel Payments.

Verifying the signature and discarding incorrectly signed requests is strongly recommended. Not doing so allows any attacker on the internet to send fake events to your server. This can cause your server to think a payment has been received that in reality hasn't, for example.

The signature is included in the X-Kernel-Sig-SHA256 header, and contains the HMAC-SHA256 hash of the request body, using the webhook's secret as a key.

You can find working code snippets to validate signatures in this GitHub repo

Verifying a webhook request

const signature = Buffer.from(req.headers["x-kernel-sig-sha256"], "hex");
const expectedSignature = crypto.createHmac("sha256", secret).update(body).digest();

const ok = crypto.timingSafeEqual(signature, expectedSignature);

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

// Continue processing the request

return res.status(200).send("OK");

Delivery

Webhook delivery is 'At Least Once'.

Kernel Payments expects a HTTP 200 OK response from your application. Any other HTTP status code, as well as inability to receive a response (due to network failures, TLS certificate errors, timeouts...) are treated as failures.

In case of failures, the delivery is retried with an exponential backoff, for up to 5 days after the event occurred.

Webhooks can be delivered out-of-order, especially in the case of delivery failures.

You can view the delivery logs in the dashboard, by clicking on a webhook. The logs include the request and your server's response, which can be useful in diagnosing delivery problems.

Was this page helpful?