Webhooks

Webhooks lets you to integrate with CriptanPay by allowing you to subscribe to a set of charge events. You can subscribe to the events by going to your settings page and adding a new webhook subscription.

Events

Below is the list of all available webhook events:

EventDescription
charge:paidCharge has been paid, but hasn't been confirmed yet
charge:confirmedCharge has been confirmed and the associated payment is completed
charge:expiredCharge has expired without a payment being made
charge:delayedThe payment was made after the specified time
charge:underpaidThe payment was made for an inferior quantity of what was requested
charge:refund_pendingA refund has been requested, but it hasn't been resolved yet
charge:refundedThey payment has been sucessfully refunded

Fields

The payload of the webhook has the following structure:

{
"event": string, // Name of the event
"id": string // Charge identifier,
"description": string // description of the payment
"fiatCurrency": string // Fiat currency in which the payment was requested,
"payment": {
"amount": string // amount paid
"currencyCode": string // code of the currency used (BTC, ETH...)
}
"createdAt": string // ISO string with the creation timestamp of the payment
"updateAt": string // ISO string with the last update timestamp of the payment
"metadata": object // Object with any metadata you passed during charge creation
}

An example of a payload would be this:

{
event: "charge:confirmed",
id: "768298de-f922-4663-8c3d-110098e65446",
fiatCurrency: "EUR",
fiatAmount: "20",
payment: {
currencyCode: "BTC",
amount: "1.0"
},
createdAt: "2020-10-09T11:51:46Z",
updateAt: "2020-10-09T11:55:21Z",
metadata: {order_id: "001-003", tags: ["blackfriday", "vip"]}
}
caution

We send amount as strings for both fiat and cryptocurrency amount for consistency. Bear in mind that cryptocurrency payments can (and will) be numbers larger than what many programming languages can support safely. As an example, an ETH payment can have up to 18 decimals, so you will need to treat those numbers with cautions to avoid rounding errors.

Security

Every CriptanPay webhook request includes an x-signature header. This header contains the SHA256 HMAC signature of the raw request payload, computed using your webhook shared secret as the key. You can obtain your shared webhook secret from your settings page.

warning

Make sure that you verify the webhook signature before acting on it inside your system!!

Using Typescript, you can verify a webhook like this:

import crypto from "crypto";
/**
* Perform a verification of an object and a sha256 HMAC hash
* @param secret shared secret used to sign the initial hash
* @param payload object to verify
* @param hash provided hash for the payload
*/
const verifyPayload = (
secret: string,
payload: Record<string, unknown>,
hash: string
): boolean => {
const signature = crypto
.createHmac("sha256", secret)
.update(JSON.stringify(payload))
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(signature));
};
// You can check the above function works by trying to check this payload against its signed hash
const secret = "foobar";
const payload = {
event: "charge:confirmed",
id: "768298de-f922-4663-8c3d-110098e65446",
fiatCurrency: "EUR",
fiatAmount: "20",
payment: {
currencyCode: "BTC",
amount: "1.0",
},
createdAt: "2020-10-09T11:51:46Z",
updateAt: "2020-10-09T11:55:21Z",
metadata: { order_id: "001-003", tags: ["blackfriday", "vip"] },
};
const hash = "0fc952e11ed477a17a7bc2ca08335bb05fbb49845de811daa439afd6a4e45ce5";