Skip to main content

Monitoring System

How It Works

Alerts sent via email or webhooks are notifications dispatched according to a chosen frequency. Synchronizations must be configured through the data type sync settings to enable the completion of the events defined in the alert.
The synchronization frequency must align with the alert frequency to ensure proper functionality.
Learn more about sync settings here.

When an event is configured and triggered, a summary email is sent based on the email frequency. The email includes a section for each user.

Once alerts are defined based on the selected events and sync settings are configured accordingly, users can be assigned to alerts.

Alerts can be restricted with filters on the fields of the monitored data type — for example, only legal notices whose source is Observations RNE, or only collective procedures where an item of the administrators array matches a given type, name or city. Filters on sub-fields of array fields are supported. Ask a Qard staff member to configure them on your alert.

Key Steps:

  1. Alert creation must be coordinated with a Qard staff member.

  2. A list of configured alerts can be retrieved using the endpoint:

    GET/api/v6/notification

    Example response:

    ["notif_name_1", "notif_name_2"]
  3. To assign a user to an alert, use the following endpoint:

    PATCH/api/v6/users/{userId}

    Example request body:

    {
    "name": "string",
    "group": "default",
    "notifications": []
    }

    Add the name of the configured alert to the notifications field to associate the user with the alert.


Webhook Delivery

Every alert whose url is set is delivered as a single POST request.

When a request is sent

Pending events are collected every 5 minutes. On each pass, and for each alert, one request is sent containing everything that has accumulated since the previous send, grouped by user, then by data type. Whether a request is due depends on the alert frequency:

FrequencyA request is sent
NOWon every pass, as soon as at least one event is pending (so at most every 5 minutes)
DAILYonce a day
WEEKLYonce a week
MONTHLYonce a month

There is no "grouped" and "ungrouped" mode: the body always has the same shape. What varies is how many companies and how many events fell into the window — one company changed since the last send means one entry, ten companies mean ten entries. A very large notification is the only case where more than one request is sent; see Large notifications are split.

Request

POST https://your-app.example.com/hooks?notificationName=<alert id>&date=<unix timestamp>&nonce=<nonce>
User-Agent: Qard API
X-Webhook-Signature: sha256=<base64 hmac_sha256(secret, requestUrl)>
X-Qard-Signature: t=<unix timestamp>,v1=<base64 hmac_sha256(secret, "<t>.<raw body>")>

Two signatures are sent, both computed with your webhook secret:

HeaderCoversUse
X-Webhook-Signaturethe complete URL, query arguments includedhistorical, same rule as the lifecycle Webhooks
X-Qard-Signaturethe timestamp and the bodyprefer this one: it proves the content, not only the address

Verifying the body signature, on the raw body, before any JSON parsing:

const [stamp, signature] = request.get("X-Qard-Signature").split(",");
const timestamp = stamp.slice(2); // t=1789034891
const received = signature.slice(3); // v1=<base64>

const expected = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("base64");

const valid =
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected)) &&
Math.abs(Date.now() / 1000 - Number(timestamp)) < 300; // reject replays

Retries

A delivery that does not answer with a 2xx or 3xx is sent again, with an increasing delay: 1 min, then 5, 10, 15, 30, 45, 60 min, 2 h, 8 h and 8 h. When the last attempt fails the alert is disabled and has to be reactivated.

Every attempt carries the same notification_id: use it as an idempotency key and ignore a body you have already processed. Acknowledge quickly with any 2xx and process asynchronously — the delay of your endpoint is the delay of the delivery.

Large notifications are split

A body larger than 1 MB is delivered as several requests, cut company by company. The parts share one batch_id and are numbered by part / parts; each one is self-contained, has its own notification_id and its own retries.

caution

The parts have no delivery order: they may arrive out of order, or at the same time. Process each one on its own, and regroup on batch_id only if you really need the whole set.

Webhook Structure

An envelope, then a flat list of events. Everything you need sits on the event itself.

{
"notification_id": "9f1c4b0e-1d2a-4c77-8a0e-6b5c2d3e4f50",
"batch_id": "7a20cd91-0f3b-4d18-9f2e-1c7a5b6d8e90",
"part": 1,
"parts": 1,
"sent_at": "2026-09-10T08:50:03+00:00",
"alert": "annonces-legales",

"events": [
{
"kind": "add",
"data_type": "LEGAL_NOTICE",
"user_id": "803eb4fb-2589-4e48-b91f-e6d3b9fdba43",
"siren": "449727205",
"name": "ARIANA PHARMACEUTICALS (449727205)",
"id": "2b4690e8-0b28-4b97-a3d9-ce9fa536b7b9",
"object": { "date": "2026-09-08", "source": "Observations RNE", "category": "Redressement judiciaire", "…": "…" },
"updates": []
}
]
}

Envelope

FieldDescription
notification_idIdentifies this delivery. Stable across retries — your idempotency key.
batch_idShared by every part of one notification. Equal to a single delivery when parts is 1.
part / partsPosition of this part and how many there are. 1 / 1 when nothing was split.
sent_atWhen the notification was built, ISO 8601.
alertName of the alert, as returned by GET /api/v6/notification.

events

One entry per event, with everything needed on the entry itself.

FieldDescription
kindadd, update or delete.
data_typeLEGAL_NOTICE, COLLECTIVE_PROCEDURE, OFFICER
user_idThe monitored user, the same id used everywhere in the API.
sirenSIREN of the company, null for a natural person.
nameCompany name and SIREN, or first and last name.
idId of the object that changed, the one the API serves for that object.
objectThe object itself, in the same format as its data type endpoint.
updatesThe fields that changed, as {"before": …, "after": …} pairs. Always [] on an add or a delete.
note

Bodies delivered before September 2026 carried a different shape, with an event name and a users array holding the changes keyed by data type. It is no longer sent.

Examples

The four combinations below are real notifications, shortened for readability.

One event, one company

{
"alert": "annonces-legales", "part": 1, "parts": 1,
"events": [
{ "kind": "add", "data_type": "LEGAL_NOTICE", "siren": "449727205",
"name": "ARIANA PHARMACEUTICALS (449727205)", "id": "2b4690e8-…",
"object": { "date": "2026-09-08", "category": "Redressement judiciaire", "…": "…" }, "updates": [] }
]
}

Several events, one company

{
"alert": "collectives-procedures", "part": 1, "parts": 1,
"events": [
{ "kind": "update", "data_type": "COLLECTIVE_PROCEDURE", "siren": "891675829", "name": "FLEXIFAI (891675829)",
"id": "33b4b51a-…", "object": { "…": "…" },
"updates": [ { "after": { "administrators": [ { "type": "MANDATAIRE_JUDICIAIRE", "name": "Selarl Garnier-Guillouet…", "city": "Meaux" } ] },
"before": { "administrators": null } } ] },
{ "kind": "update", "data_type": "COLLECTIVE_PROCEDURE", "siren": "891675829", "name": "FLEXIFAI (891675829)",
"id": "5e70eb10-…", "object": { "…": "…" }, "updates": [ { "after": { "…": "…" }, "before": { "…": "…" } } ] }
]
}

One event, several companies

{
"alert": "annonces-legales", "part": 1, "parts": 1,
"events": [
{ "kind": "add", "data_type": "LEGAL_NOTICE", "siren": "911031409", "name": "LA COMPAGNIE DES INSECTES INDUSTRIE (911031409)", "id": "…", "object": { "…": "…" }, "updates": [] },
{ "kind": "add", "data_type": "LEGAL_NOTICE", "siren": "900276320", "name": "RFENCE (900276320)", "id": "…", "object": { "…": "…" }, "updates": [] },
{ "kind": "add", "data_type": "LEGAL_NOTICE", "siren": "884598038", "name": "ETSEME (884598038)", "id": "…", "object": { "…": "…" }, "updates": [] }
]
}

Several events, several companies

{
"alert": "annonces-legales", "part": 1, "parts": 1,
"events": [
{ "kind": "add", "data_type": "LEGAL_NOTICE", "siren": "847597143", "name": "MEDETIA (847597143)", "id": "…", "object": { "…": "…" }, "updates": [] },
{ "kind": "add", "data_type": "LEGAL_NOTICE", "siren": "480405687", "name": "SMARTLINE SYSTEMS (480405687)", "id": "…", "object": { "…": "…" }, "updates": [] },
{ "kind": "add", "data_type": "LEGAL_NOTICE", "siren": "480405687", "name": "SMARTLINE SYSTEMS (480405687)", "id": "…", "object": { "…": "…" }, "updates": [] },
{ "kind": "add", "data_type": "LEGAL_NOTICE", "siren": "480405687", "name": "SMARTLINE SYSTEMS (480405687)", "id": "…", "object": { "…": "…" }, "updates": [] },
{ "kind": "add", "data_type": "LEGAL_NOTICE", "siren": "480405687", "name": "SMARTLINE SYSTEMS (480405687)", "id": "…", "object": { "…": "…" }, "updates": [] }
]
}