이벤트와 페이로드
Webhook 이벤트 유형, 이벤트 봉투(envelope) 구조, 작업 종류별 본문 예시
이벤트 유형
| 이벤트 유형 | 전송 시점 |
|---|---|
fingerprint_addition_job.succeeded | 등록(addFingerprints) 작업이 성공했을 때 |
fingerprint_addition_job.failed | 등록 작업이 실패했을 때 |
verification_job.succeeded | 검증 작업이 성공했을 때 |
verification_job.failed | 검증 작업이 실패했을 때 |
identification_job.succeeded | 식별 작업이 성공했을 때 |
identification_job.failed | 식별 작업이 실패했을 때 |
webhook.test | Console에서 테스트 이벤트 보내기를 클릭했을 때. 구독할 수 없습니다. |
엔드포인트마다 작업 이벤트 6종 중 받을 유형을 고르거나 **모든 이벤트 (나중에 추가되는 이벤트 포함)**를 선택할 수 있습니다.
호스팅 세션이 만든 작업은 이벤트를 보내지 않습니다. Web Integration 세션이 만든 작업은 현재 Webhook 이벤트를 보내지 않습니다. Webhooks는 Server API로 시작한 작업에 적용됩니다.
모르는 이벤트 유형은 무시하세요. Petify는 이벤트 유형을 나중에 추가할 수 있고, 모든 이벤트를 구독한 엔드포인트는 새 유형도 받습니다. 알 수 없는 type은 2xx 상태로 응답하고 다른 처리는 하지 마세요. 오류로 응답하면 안 됩니다.
이벤트 봉투(envelope)
모든 이벤트는 네 개의 필드를 가진 JSON 객체입니다.
| 필드 | 타입 | 설명 |
|---|---|---|
id | string | 이벤트 고유 ID (예: evt_3f2a9c1d0b8e4f6a9d7c5b3a1e0f2d4c). webhook-id 헤더와 같고, 재시도와 재전송에서도 바뀌지 않습니다. |
type | string | 이벤트 유형 |
createdAt | string | Petify가 이벤트를 만든 시각 (ISO 8601). 전송 시도 시각이 아닙니다. |
data | object | 작업 결과. 아래를 참고하세요. |
data에는 항상 jobId가 있습니다. 이벤트 시점에 해당 작업의 폴링 엔드포인트가 data로 돌려주는 값을 그대로 담고, 다음이 추가됩니다.
- 등록·검증 이벤트에는
petId도 있습니다. - 실패한 경우 폴링에서 채워지지 않는 결과 필드는
null입니다. - 필드 이름은 v2 API 응답처럼 camelCase입니다.
이벤트에는 이벤트를 만든 시점의 작업 상태와 결과가 담깁니다. 드물게 작업이 다시 실행되면 *.failed가 먼저 오고 *.succeeded가 나중에 올 수 있습니다. 헷갈리면 작업 폴링 엔드포인트의 최신 응답을 기준으로 삼으세요.
본문 예시
등록
fingerprint_addition_job.succeeded와 fingerprint_addition_job.failed는 모양이 같고 type과 status만 다릅니다.
{
"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"
}
}검증
{
"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
}
}검증 작업이 실패하면 isVerified와 score는 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
}
}식별
pets에는 폴링 엔드포인트가 돌려주는 것과 같이, 작업의 모든 결과 행이 점수 높은 순으로 들어 있습니다. metadata는 JSON 문자열입니다.
{
"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\"}"
}
]
}
}식별 작업이 실패하면 pets는 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
}
}테스트 이벤트
webhook.test에는 작업 필드 대신 data.message가 있습니다.
{
"id": "evt_2d4f6a8c0e1b4d3f5a7c9e1b3d5f7a9c",
"type": "webhook.test",
"createdAt": "2026-10-20T09:05:00.000Z",
"data": {
"message": "This is a test event from Petify."
}
}이벤트 처리 순서
- 원본 요청 본문으로 서명을 검증합니다.
type을 확인합니다. 처리하지 않는 유형은 무시하고2xx로 응답합니다.- 전송은 최소 한 번(at-least-once)이므로
webhook-id(id필드)로 중복을 걸러 냅니다. - 작업을 저장하거나 큐에 넣은 뒤 10초 이내에
2xx로 응답합니다.