Skip to main content

Webhook After Certificate Validation

This webhook delivers the content of a case as soon as it is closed: collected items, media, certificate URL, and the business context you provided when the case was created (references, beneficiary, metadata).

There is a second webhook

The analysis result webhook delivers the case's trust verdict (score, tampering detection, document analyses). It is sent later, once the analysis is complete. Both are independent and can be enabled together.

When it is sent​

The webhook is sent when the case is closed, whatever the channel that triggers it:

ChannelTrigger
Mobile applicationThe user validates the case, including a case opened from a Certilink.
APIGET /cases/close/:caseId or GET /cases/close/certilink/:magicLinkToken (see Case management).
Mobile SDKsendPhoto() creates and closes the capture's case. takePhoto() only performs local capture.

A case triggers one delivery per closure.

Configuration​

From your backend​

You configure the webhook URL and token yourself through the API, without any action from Certificall.

POST /company-options/api-settings

Authentication: Authorization: Bearer <token> (see Authentication). The API account must have the permission to update the company.

Request body

NameTypeRequiredDescription
endpointStringyesHTTPS URL of your endpoint, able to receive POST requests.
authTokenStringyesToken that Certificall will present on each call.
authorizationHeaderEnumnoWhere the token goes: authorization (default, Authorization: Bearer header) or security-token (dedicated header).

Example

curl -X POST https://admin.certificall.app/certificall/api/company-options/api-settings \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"endpoint": "https://your-domain.com/webhooks/certificall/case",
"authToken": "<token Certificall will present to you>",
"authorizationHeader": "authorization"
}'

Response 200

{
"companyId": 42,
"apiSettings": [
{
"apiName": "caseHook",
"endpoints": { "sendCase": "https://your-domain.com/webhooks/certificall/case" },
"authorizationHeader": "authorization",
"hasCredentials": true
}
]
}

The token is never displayed again once saved: the response and GET /company-options only indicate whether credentials exist (hasCredentials). To change it, send the request again with the new token.

URL constraints​

The following are rejected: non-https URLs, literal IP addresses (v4 or v6), and hosts without a domain name. Your endpoint must be publicly exposed, on a resolvable domain.

By Certificall​

The HMAC-SHA256 (apiKey + apiSecretKey) and dedicated API key (Make-style integrations) authentication modes cannot be configured through the API. Send your Certificall contact the URL of your endpoint and the credentials to use; they will be registered on your company.

Authenticating the incoming call​

Depending on the configured mode, your endpoint receives one of the following headers:

# Bearer (default)
Authorization: Bearer <authToken>
Content-Type: application/json

# Dedicated header
security-token: <authToken>
Content-Type: application/json

# API key (Make-style integrations)
x-make-apikey: <apiKey>
Content-Type: application/json

# HMAC-SHA256
Authorization: HMAC-SHA256 <apiKey>:<signature>
X-Api-Key: <apiKey>
Content-Type: application/json

For the HMAC mode, the signature is an HMAC-SHA256 of the JSON body exactly as sent, computed with your apiSecretKey. Verify it against the raw request body, not a re-serialization.

No Basic authentication

Basic authentication (username and password) is not offered by this webhook.

Payload​

{
"cfRef": "CAS-12345_CMP-42",
"createdAt": "2026-05-13T08:24:15.000Z",
"reportId": "SITE-2026-001",
"frame": "Car damage report",
"closed": true,
"caseUrl": "https://admin.certificall.app/certificall/share/case/<shareToken>",
"items": [
{
"createdAt": "2026-05-13T08:22:01.000Z",
"cfRef": "<item reference>",
"title": "Vehicle photo",
"description": "vehicle_001.jpg",
"stepAction": "PHOTOGRAPHY",
"geolocLatitude": "48.8566",
"geolocLongitude": "2.3522",
"imageUrl": "https://admin.certificall.app/certificall/images/<identifier>"
},
{
"createdAt": "2026-05-13T08:23:10.000Z",
"cfRef": "<item reference>",
"title": "Plate number",
"description": "AB-123-CD",
"stepAction": "TEXT_FIELD",
"geolocLatitude": "48.8566",
"geolocLongitude": "2.3522",
"imageUrl": ""
}
],
"context": {
"beneficiaire": { "nom": "Dupont", "prenom": "Jean", "adresse": "123 rue de la Paix", "cp": "75001", "ville": "Paris" },
"emetteur": "ACME Company",
"reportRef": "FILE-2025-001",
"instructions": "Check the overall condition of the equipment",
"metadata": { "fileId": "FILE-2025-001", "agency": "PAR-09" }
}
}

Envelope​

FieldTypeDescription
cfRefStringPublic reference of the case, formatted CAS-<id>_CMP-<company>. Unique: this is your deduplication key.
createdAtISO 8601Case creation date.
reportIdStringThe reportToken you provided when creating the case, the Certilink or the SDK photo. This is your matching key.
frameStringName of the case's frame.
closedBooleanAlways true at delivery time.
caseUrlURLURL of the PDF certificate. null if the case has no share link.
itemsArrayThe collected items.
contextObjectThe business context provided at creation. Absent if no context was provided.

Items​

FieldTypeDescription
createdAtISO 8601Collection date of the item.
cfRefStringUnique reference of the item.
titleStringTitle of the step in the frame.
descriptionStringCollected value: entered text, date, choice, or file title for a photo.
stepActionEnumStep type: PHOTOGRAPHY, VIDEO, SIGNATURE, DOCUMENT_UPLOAD, TEXT_FIELD, NUMBER_FIELD, DATE_FIELD, TIME, EMAIL, SELECT.
geolocLatitude, geolocLongitudeStringCoordinates of the collection.
imageUrlURLImage URL for a PHOTOGRAPHY or a SIGNATURE, empty string otherwise.
extractedDataArrayPresent only if field extraction is configured on the step: list of { key, label, value }.

Context​

The content of context depends on how the case was created:

Case originContent of context
POST /cases/create or PATCH /cases/update with a caseContextThe visibleData fields under their internal keys: beneficiaire (nom, prenom, adresse, cp, ville), emetteur, photoRef, reportRef, instructions, user. Only the keys you filled in are present.
Certilink (POST /certilink/create with a context)The Certilink's context object, returned as is.
Application without contextcontext absent.

Metadata​

metadata is a field of the case, next to context: your key/value pairs exactly as supplied, whether the case comes from POST /cases/create, a Certilink or the mobile SDK. The key is absent when the case carries none.

Where to put your internal identifiers

To match the case with your system, use reportToken (returned as reportId), available on every channel and the only field the API filters on. The metadata field is a complement, returned on every channel: site identifier, agency code, file type, originating page…

Delivery guarantees​

Behaviour
RetriesNone. If your endpoint is unreachable or responds with an error, the failure is logged on Certificall's side and the delivery is not retried.
DuplicatesOne delivery per closure. Still keep an idempotent handling on cfRef.
OrderNot guaranteed across cases.

Two practical consequences:

  1. Respond with a 2xx quickly and do your business processing in the background.
  2. Plan a safety net. A periodic sweep of GET /cases?format=metadata&closed=true&hours=… (see Case management) catches cases whose webhook did not reach you.

Handling on the partner side​

// POST /webhooks/certificall/case (your route)
app.post('/webhooks/certificall/case', verifyToken, async (req, res) => {
const { cfRef, reportId, caseUrl, items, context } = req.body;

// 1) Acknowledge immediately
res.status(200).end();

// 2) Find your record: reportId = your reportToken
const record = await db.findByReference(reportId);
if (!record) return; // unknown record: ignore, no error

// 3) Idempotency on cfRef
if (await db.alreadyReceived(cfRef)) return;

// 4) Use the content
const photos = items.filter(i => i.stepAction === 'PHOTOGRAPHY').map(i => i.imageUrl);
const metadata = context?.metadata ?? context?.visibleData?.metadata ?? {};

await db.attachCertificate(record.id, { cfRef, caseUrl, photos, metadata });
});

Checklist​

  • Endpoint publicly exposed over HTTPS, on a resolvable domain.
  • URL and token registered through POST /company-options/api-settings (or sent to Certificall for HMAC and API key).
  • Authentication mode verified on reception.
  • reportToken set when creating your cases, Certilinks or SDK photos.
  • Idempotent handling on cfRef.
  • Quick 2xx response, business processing decoupled.
  • Safety net on GET /cases for sensitive cases.

Going further​