Reconciliation
Webhook payloads are prompts, not canonical snapshots. Track every signing-request id relevant to your integration and periodically read:
GET /v1/club/compliance/signing-requests/{id}It requires a valid signed request plus club.compliance.read; foreign-club ids return 404. The result is { "data": ... }: request state is status, items use itemStatus and signedAt, and signed evidence identifies finalFileAssetId. Resolve a file only through /v1/club/compliance/files/{fileId}/signed-url, which separately needs club.compliance.read_files.
The list route's since and until filter creation time, not update time. It is not a change feed and cannot replace detail reads for ids already tracked. /v1/club/compliance/signing-requests/{id}/events is the signing audit timeline, not webhook-delivery history.
Permanent capture gap
Signing business state commits before the post-commit bridge opens a fresh transaction to persist the webhook outbox row. If the bridge fails in that interval, the signing response remains committed. A sweep can recover only rows that were persisted; it cannot invent a row that was never captured. Therefore no-polling or webhook-complete promises would be false. Canonical detail reconciliation is required.