Penfold POSTs a JSON body to your pre-registered webhook URL when a signing session reaches a terminal outcome. Exactly one event is emitted per signing session (no intermediate events).
Signature verification (X-Penfold-Signature)
Penfold signs every webhook with HMAC-SHA256 using a shared secret provisioned during onboarding.
- Read the
X-Penfold-Signatureheader. It contains comma-separated key/value pairs:t(Unix timestamp in seconds when Penfold sent the request) andv1(lowercase hex-encoded HMAC-SHA256). - Construct the signing payload (UTF-8):
{t}.{raw_body}— the string value oft, a literal., then the raw JSON body bytes. - Compute
HMAC-SHA256(secret, signing_payload), hex-encode, and compare tov1in constant time. - Reject if
|now_unix - t| > 300(5-minute replay window). - Upsert by
eventIdfor idempotency.
Delivery semantics
- Return
2xxwithin 30 seconds. - On non-2xx, timeout, or no response: exponential backoff starting at 60 seconds, doubling each attempt, max interval 3600 seconds, up to 10 attempts within 24 hours.
- After exhausted retries, events are not retried automatically.
Body
Required
-
Globally unique event id. Use for idempotent processing.
-
Always
EmployerAgreementSigningCompletedfor this flow.Value is
EmployerAgreementSigningCompleted. -
When Penfold recorded the terminal outcome (ISO 8601 UTC).
-
Penfold employer id.
-
Same id as returned from create-session.
-
Terminal outcome of a signing session. Closed enum — new values require a Partner API version bump.
success: Signing journey completed successfully.cancelled: User intentionally exited without completing.failed: Technical, validation, or signature failure.
Values are
success,cancelled, orfailed. -
Machine-readable reason when result is
failed. Closed enum — new values require a Partner API version bump.tokenExpired: Signing session or URL token past TTL.sessionNotFound: Signing session unknown or not recognised.validationFailed: Validation failed during signing.providerUnavailable: Penfold or upstream dependency unavailable.
Values are
tokenExpired,sessionNotFound,validationFailed, orproviderUnavailable.
{
"eventId": "PENEVT01999934D",
"eventType": "EmployerAgreementSigningCompleted",
"occurredAt": "2026-05-06T10:22:11.000Z",
"employerId": "cmomwb1v7000dcalz2rf7ul5d",
"signingSessionId": "cl9gujidl001o9ksfnrgr8zq1",
"result": "success"
}
{
"eventId": "PENEVT01999935E",
"eventType": "EmployerAgreementSigningCompleted",
"occurredAt": "2026-05-06T10:24:03.000Z",
"employerId": "cmomwb1v7000dcalz2rf7ul5d",
"signingSessionId": "cl9gujidl001o9ksfnrgr8zq1",
"result": "cancelled"
}
{
"eventId": "PENEVT01999936F",
"eventType": "EmployerAgreementSigningCompleted",
"occurredAt": "2026-05-06T10:25:44.000Z",
"employerId": "cmomwb1v7000dcalz2rf7ul5d",
"signingSessionId": "cl9gujidl001o9ksfnrgr8zq1",
"result": "failed",
"failureCode": "tokenExpired"
}