Manage endpoints
Use the same PayFi partner authentication headers used by the rest of the API.GET /v1/webhooksPOST /v1/webhooksGET /v1/webhooks/{webhookId}PATCH /v1/webhooks/{webhookId}DELETE /v1/webhooks/{webhookId}POST /v1/webhooks/{webhookId}/test
rotateSecret is true on update. Store it immediately.
Events
Supported events:operation.createdoperation.requirements.readyoperation.documents.partialoperation.analysis.completedoperation.action_requiredoperation.manual_review.completedoperation.callback.failed
operation.callback.failed is emitted to other subscribed endpoints when a delivery fails terminally. PayFi does not recursively emit operation.callback.failed for a failed callback-failed delivery.
Payload
The API Reference includes one schema per event:WebhookOperationCreatedPayloadWebhookDocumentsPartialPayloadWebhookAnalysisCompletedPayloadWebhookActionRequiredPayloadWebhookManualReviewCompletedPayloadWebhookCallbackFailedPayload
event first and then apply event-specific rules.
Default shape:
GET /v1/operations/{operationId}.
End-to-end flow
- The partner creates one or more webhook endpoints with
POST /v1/webhooks. - PayFi validates the signed partner request, reserves the idempotency key, validates the URL, generates a signing secret, stores the encrypted secret, and returns the plaintext secret once.
- When an operation changes state, PayFi selects active endpoints subscribed to that event.
- PayFi builds the allowlisted payload, redacts it, serializes it to raw JSON, hashes the raw body, and persists a
WebhookDeliverybefore any HTTP call. - The worker loads due deliveries, reloads the endpoint, revalidates that it is active and has a safe URL, decrypts the endpoint secret, verifies the stored payload hash, signs the exact raw JSON body, and sends the callback.
- PayFi persists every attempt with status, response status, response body hash, request header hash, duration, failure code, and attempted timestamp.
- A
2xxresponse marks the delivery asDELIVERED. A retryable failure setsRETRY_SCHEDULEDandnextAttemptAt. A terminal failure marks the delivery asFAILED.
Registration validations
Webhook management endpoints use the same partner request signing model as the rest of the API:X-PayFi-Api-KeyX-PayFi-NonceX-PayFi-SignatureIdempotency-Keyon create, update, delete, and test requests
- API key is active and scoped to the partner integration.
- Nonce has not been replayed.
- Request timestamp is inside the allowed skew.
- HMAC signature matches the exact raw request body.
- Idempotency key is reused only with the same method, path, and body hash.
- Webhook ID belongs to the signed partner integration.
- URL uses HTTPS and does not include credentials.
- URL host is not localhost, private IP, link-local, or metadata infrastructure.
eventTypescontains only supported event names.- Signing secrets are generated server-side and returned only on create or explicit rotation.
Delivery validations
Before each HTTP delivery attempt, PayFi validates the stored delivery again:- Endpoint still exists, is active, and belongs to the same organization and partner integration.
- Endpoint URL still passes SSRF validation.
- Endpoint signing secret decrypts successfully.
- Re-serialized payload hash matches the persisted
payloadHash. - Payload is signed with the exact raw JSON body that will be sent.
- Response bodies are hashed for auditability; raw response bodies are not stored.
- Authorization headers, webhook secrets, signatures, raw documents, prompts, completions, and full tax IDs are never written into delivery logs.
Signature verification
PayFi signs the exact raw JSON body and sends:Retries
PayFi retries transient partner processing failures:- network errors
- timeout
- HTTP
408 - HTTP
429 - any HTTP
5xx
- any HTTP
2xx: delivered - HTTP
4xxexcept408and429: failed
Partners should make webhook handlers idempotent by storing the
x-payfi-webhook-id header or a tuple of event and operationId.
Test delivery
POST /v1/webhooks/{webhookId}/test sends one signed sample payload to the endpoint. Test deliveries do not schedule retries, so a failed test response is terminal for that test request.