# Agreement signing outcome **POST EmployerAgreementSigningCompleted** 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. 1. Read the `X-Penfold-Signature` header. It contains comma-separated key/value pairs: `t` (Unix timestamp in seconds when Penfold sent the request) and `v1` (lowercase hex-encoded HMAC-SHA256). 2. Construct the signing payload (UTF-8): `{t}.{raw_body}` — the string value of `t`, a literal `.`, then the raw JSON body bytes. 3. Compute `HMAC-SHA256(secret, signing_payload)`, hex-encode, and compare to `v1` in constant time. 4. Reject if `|now_unix - t| > 300` (5-minute replay window). 5. Upsert by `eventId` for idempotency. ## Delivery semantics - Return `2xx` within 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. ## Servers - Production: https://partner-api.getpenfold.com/v4 (Production) - Staging: https://partner-api.getpenfold.dev/v4 (Staging) ## Authentication methods - Bearer auth ## Parameters ### Body: application/json (object) - **eventId** (string) Globally unique event id. Use for idempotent processing. - **eventType** (string) Always `EmployerAgreementSigningCompleted` for this flow. - **occurredAt** (string(date-time)) When Penfold recorded the terminal outcome (ISO 8601 UTC). - **employerId** (string) Penfold employer id. - **signingSessionId** (string) Same id as returned from create-session. - **result** (string) 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. - **failureCode** (string) 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. ## Responses ### 200 Webhook acknowledged. [Powered by Bump.sh](https://bump.sh)