Events & Payloads
The webhook event types, the event envelope, and an example body for each job kind.
Event types
| Event type | Sent when |
|---|---|
fingerprint_addition_job.succeeded | A registration (addFingerprints) job succeeded. |
fingerprint_addition_job.failed | A registration job failed. |
verification_job.succeeded | A verification job succeeded. |
verification_job.failed | A verification job failed. |
identification_job.succeeded | An identification job succeeded. |
identification_job.failed | An identification job failed. |
webhook.test | You click Send test event in the Console. You cannot subscribe to it. |
You choose which of the six job event types an endpoint receives, or select All events (including ones added later).
Jobs created by a hosted session send no events. Jobs that Web Integration sessions create send no webhook events today. Webhooks cover jobs started through the Server API.
Ignore event types you do not know. Petify can add event types later, and an endpoint that subscribes to All events receives them. Acknowledge an unknown type with a 2xx status and do nothing else. Do not answer with an error.
Event envelope
Every event is a JSON object with four fields.
| Field | Type | Description |
|---|---|---|
id | string | Unique event ID, such as evt_3f2a9c1d0b8e4f6a9d7c5b3a1e0f2d4c. It equals the webhook-id header and stays the same across retries and resends. |
type | string | The event type. |
createdAt | string | When Petify emitted the event (ISO 8601). This is not the time of a delivery attempt. |
data | object | The job result. See below. |
data always carries jobId. It mirrors what the job's poll endpoint returns in its data at the time of the event, with these additions:
- Registration and verification events also carry
petId. - On a failure, result fields that a poll would not fill are
null. - Field names are camelCase, as in the v2 API responses.
The event carries the job's status and result at the moment it was emitted. In a rare re-run, a job can send *.failed first and *.succeeded later. When in doubt, trust the latest answer from the job's poll endpoint.
Example bodies
Registration
fingerprint_addition_job.succeeded and fingerprint_addition_job.failed share one shape. Only type and status differ.
{
"id": "evt_3f2a9c1d0b8e4f6a9d7c5b3a1e0f2d4c",
"type": "fingerprint_addition_job.succeeded",
"createdAt": "2026-10-20T09:14:52.318Z",
"data": {
"jobId": "6b1f0c1e-7d3a-4c58-9b0e-2f4a8d6c1e35",
"petId": "0d4e7a92-5c31-4f8b-a6d7-91b3c2e8f470",
"status": "SUCCESS"
}
}Verification
{
"id": "evt_9a7c5e3b1d2f4a6c8e0b1d3f5a7c9e2b",
"type": "verification_job.succeeded",
"createdAt": "2026-10-20T09:21:07.642Z",
"data": {
"jobId": "c2d84f1a-93b6-4e0d-8a57-6f1b3c9d2e48",
"petId": "0d4e7a92-5c31-4f8b-a6d7-91b3c2e8f470",
"status": "SUCCESS",
"isVerified": true,
"score": 95
}
}When a verification job fails, isVerified and score are null.
{
"id": "evt_1b3d5f7a9c2e4b6d8f0a2c4e6b8d0f1a",
"type": "verification_job.failed",
"createdAt": "2026-10-20T09:22:31.105Z",
"data": {
"jobId": "e7a19b3c-4d52-4f86-b0c1-8a3d5e7f9b21",
"petId": "0d4e7a92-5c31-4f8b-a6d7-91b3c2e8f470",
"status": "FAILED",
"isVerified": null,
"score": null
}
}Identification
pets lists every result row of the job, highest score first, as the poll endpoint returns it. metadata is a JSON string.
{
"id": "evt_5c7e9a1b3d4f4c6e8a0b2d4f6c8e0a1b",
"type": "identification_job.succeeded",
"createdAt": "2026-10-20T09:30:44.870Z",
"data": {
"jobId": "4f8a2c6e-1b9d-4e73-a5c0-3d7f9b1e2a64",
"status": "SUCCESS",
"pets": [
{
"id": "0d4e7a92-5c31-4f8b-a6d7-91b3c2e8f470",
"score": 95,
"metadata": "{\"name\": \"Buddy\", \"owner\": \"John Doe\"}"
},
{
"id": "a93c5e71-2b4d-4f60-8e1a-7c9d3b5f0e82",
"score": 78,
"metadata": "{\"name\": \"Max\", \"owner\": \"Jane Smith\"}"
}
]
}
}When an identification job fails, pets is null.
{
"id": "evt_7e9a1c3b5d6f4e8a0c2b4d6f8a0c2e3b",
"type": "identification_job.failed",
"createdAt": "2026-10-20T09:31:12.236Z",
"data": {
"jobId": "8d2f6a0c-5e3b-4a91-b7d4-1c9e3f5a7b20",
"status": "FAILED",
"pets": null
}
}Test event
webhook.test has a data.message field and no job fields.
{
"id": "evt_2d4f6a8c0e1b4d3f5a7c9e1b3d5f7a9c",
"type": "webhook.test",
"createdAt": "2026-10-20T09:05:00.000Z",
"data": {
"message": "This is a test event from Petify."
}
}Handling an event
- Verify the signature against the raw request body.
- Check
type. Ignore types you do not handle, and answer2xx. - Deduplicate on
webhook-id(theidfield), because delivery is at least once. - Store or queue the work, then answer
2xxwithin 10 seconds.