Webhooks
The webhook integration allows you to receive notifications about events that occur about your subscriptions and claims.
Available event types
The following events are available for the webhook integration.
| Event | Description |
|---|---|
subscription.created | A subscription has been created |
subscription.updated | A subscription has been updated |
subscription.archived | A subscription has been archived |
claim.opened | A claim has been requested by the customer (for example after the issue form completion) |
claim.processed | The request has been accepted or refused by an operator. Note that the status may change until event 'refused' or 'refunded'. Also tt can be an automatic acceptance or refusal. |
claim.refunded | The request has been validated by an operator and refund notification has been sent to the customer. |
claim.refused | The request has been rejected by an operator. |
Manage your webhook subscriptions
You can create and manage your webhook subscriptions in the manager panel or use the API.
To create a webhook subscription from the API, you need to send a POST request to the following endpoint:
You can have multiple webhook urls for the same account.
Webhook body example
For the event subscription.created
{
"event": {
"type": "subscription.created",
"id": "0e38f4ce-37b8-4b7f-b219-6e2ddfbf9301",
"created_at": "2025-01-10T10:46:11+01:00"
},
"resource": "subscription",
"data": {
"subscription": {
"reference": "12345678",
"product_id": "prod_abc123",
"organization": "Organization Name",
"product_type": "cancellation",
"checkout_mode": "unique",
"order_reference": "ORD_123ABC",
"order_date": "2024-11-01 17:35",
"status": "active",
"currency": "EUR",
"insurance_amount": 10,
"order_amount": 380,
"buyer_gender": "M",
"buyer_firstname": "John",
"buyer_lastname": "Doe",
"buyer_email": "example@meetch.io",
"buyer_phone": "+33601020304",
"buyer_date_of_birth": "1979-06-18",
"buyer_address": "Allée Napoléon III",
"buyer_zipcode": "18000",
"buyer_city": "Bourges",
"buyer_country": "FR",
"preferred_locale": "fr_FR",
"created_at": "2025-01-10T10:46:11+01:00",
"deleted": false,
"additional_data": []
}
}
}
For the event claim.refunded
{
"event": {
"type": "claim.refunded",
"id": "7d3560b6-f0fd-48d0-8ee1-24498fd3971e",
"created_at": "2023-07-28T16:44:44+02:00"
},
"resource": "refund_request",
"data": {
"transaction": {
"id": "tra_a1z2e3r4t5y6",
"amount": 100,
"currency": "EUR",
"payment_mode_id": "tra_a6z5e4r3t2y1",
"payment_mode_method": "bank_transfer",
"created_at": "2025-01-14T09:17:00+02:00",
"status": "success",
"transaction_type": "credit",
"issuance_date": "2025-01-14",
"scheduled": null
},
"items": [
{
"item_id": "itm_a1z2e3r4t5y6",
"item_number": "123456789",
"item_price": "100.00",
"status": "cancelled",
"asked_by_customer": true,
"transaction_id": "tra_a1z2e3r4t5y6",
"cancellation_date": "2025-01-13T16:44:0+02:00",
"requested_amount": 100,
"refunded_amount": 100
}
],
"refund_request": {
"id": "issue_a1z2e3r4t5y6",
"subscription_reference": "11223344",
"order_reference": "ORD_123ABC",
"reason_key": "insured-corporal-accident",
"reason_category": "annulation",
"comment": "",
"status": "refund",
"status_formatted": "Indemnisé",
"status_number": 2,
"created_at": "13/01/2025 10:25",
"issue_date": "13/01/2025 10:25",
"processed_at": "14/01/2025 9:17",
"requested_amount": 100,
"refund_amount": 100,
"refusal_reason": "",
"payment_mode_id": "tra_a6z5e4r3t2y1",
"payment_mode_method": "bank_transfer",
"refund_mode_selected": "100",
"additional_data": [],
"currency": "EUR",
"target_currency": "EUR"
}
}
}
Webhook signature
To improve security, we encourage the use of a webhook signing key shared between your application and us.
Each webhook will produce a Webhook-Signature header which you can use to compare against an expected signature.
Provide a signature key
On the webhook subscription creation request, simply provide a signing_key property (string up to 256 chars).
Verify the webhook signature
The Webhook-Signature header contains a Unix Timestamp (prefixed by t=) and the signature (prefixed by k=) separated by comma (,).
Webhook-Signature: t=1672560000,k=aFve8z10eZh81fe9910439HfzbaFve8z10ez81fe9910439HUzbfzaUpkaWw9Mkp
You need to extract the timestamp and signature from the header.
Then, create a signed payload string by concatenating :
- the signature timestamp
- the character
: - the JSON payload
Compute an HMAC with the SHA256 hash function. Use the webhook signing key as the hash key.
Finally, compare the result to the header's signature key.
You can also check the validity of the request by comparing the timestamp is the header and the current timestamp.
Code implementation
- PHP
- NodeJS
$signing_key = "abcABC123456789";
$payload = @file_get_contents('php://input');
$s_header = $_SERVER['HTTP_WEBHOOK_SIGNATURE'] ?? null;
if (empty($s_header)) {
exit('Missing webhook signature');
}
// Get timestamp and key from Webhook-Signature header.
[$t, $k] = explode(',', $s_header);
$signature_timestamp = explode('=', $t)[1] ?? null;
$signature_value = explode('=', $k)[1] ?? null;
// Compute expected signature and compare it to the signature in the header.
$expected_signature = hash_hmac('sha256', $signature_timestamp . ":" . $payload, $signing_key);
if ($signature_value !== $expected_signature) {
exit('Invalid webhook signature');
}
// Prevent replay attacks by checking signature timestamp (optional)
$tolerance = 300; // 5 minutes
if (time() - $signature_timestamp > $tolerance) {
exit('Webhook is expired');
}
// Signature OK
// Read payload event
const crypto = require('crypto');
const webhookSigningKey = "abcABC123456789";
const sHeader = req.get('Webhook-Signature');
if (!sHeader) {
throw new Error('Missing webhook signature');
}
// Get timestamp and key from Webhook-Signature header.
const { t, signature } = sHeader.split(',').reduce((acc, currentValue) => {
const [key, value] = currentValue.split('=');
if (key === 't') acc.t = value;
else if (key === 'k') acc.signature = value;
return acc;
}, {
t: '',
signature: ''
});
// Compute expected signature and compare it to the signature in the header.
const data = t + ':' + JSON.stringify(req.body);
const expectedSignature = crypto.createHmac('sha256', webhookSigningKey).update(data, 'utf8').digest('hex');
if (expectedSignature !== signature) {
throw new Error('Invalid webhook signature');
}
// Prevent replay attacks by checking signature timestamp (optional)
const tolerance = 300000; // 5 minutes (milliseconds)
if (Date.now() - Number(t) * 1000 > tolerance) {
throw new Error("Webhook is expired");
}
// Signature OK
// Read payload event