Webhook Events
Overview
Section titled “Overview”Webhooks allow your application to react in real time to important events across the GrailPay platform without the need to constantly poll the API. Whenever a subscribed event occurs (like a payout being sent or a transaction status changing), GrailPay sends a secure HTTP POST request directly to your server with the event details.
This push-based architecture enables you to automate workflows, synchronize data, and trigger time-sensitive actions the moment something happens.
Each webhook is sent to a configured HTTPS endpoint, and your server is expected to return an HTTP 200 OK response to confirm receipt. You register a single webhook URL and GrailPay delivers every event to it. There is no per-event subscription: your handler receives all events, routes on the event field, and ignores any it doesn’t need.
Authenticating Webhooks
Section titled “Authenticating Webhooks”To verify that a webhook really came from GrailPay and not a malicious actor, every delivery carries a Signature header. When you register a webhook through POST /api/v3/webhooks, the response includes a secret generated for that registration. Keep it: it is the key GrailPay uses to sign every event sent to that URL. Each registration has its own secret, and you can read it again at any time with GET /api/v3/webhooks/{uuid}.
The signature is the hex-encoded HMAC-SHA256 of the JSON request body, keyed with that secret. To verify a delivery, compute the same HMAC over the body exactly as you received it—before parsing or re-serialising it—and compare the result with the Signature header using a constant-time comparison. Reject any delivery that does not match.
We strongly recommend implementing this verification step. It helps protect your application from spoofed requests and ensures that only genuine GrailPay events are processed.
Security
Section titled “Security”GrailPay requires all webhook endpoints to use HTTPS to guarantee the secure delivery of sensitive financial event data. This applies across both sandbox and production environments. Non-secure HTTP URLs will be rejected, and no webhook events will be delivered until a valid HTTPS endpoint is configured.
Requiring HTTPS helps protect against man-in-the-middle attacks and ensures compliance with industry-standard security practices. Before registering a webhook, make sure your server is accessible via a secure, publicly reachable HTTPS URL with a valid SSL certificate.
If your environment isn’t properly configured, webhook notifications will silently fail to deliver.
Response & Retry Logic
Section titled “Response & Retry Logic”To acknowledge receipt of a webhook event, your server must respond with an HTTP 200 OK status code. This tells GrailPay that the event was received and processed successfully.
If a 200 OK response is not returned, we consider the delivery attempt a failure. In such cases, GrailPay will automatically retry sending the webhook at increasing intervals for a limited number of attempts. Repeated failures delay delivery, and a registration whose deliveries fail 30 times in a row is deactivated automatically; see Manage Webhooks for how that is reported.
To ensure reliable communication, your webhook handler should be:
- Idempotent: able to handle duplicate event deliveries without side effects. Use
event_uuidto detect duplicates. - Efficient: respond quickly, even if additional processing is handled asynchronously.
Event Envelope
Section titled “Event Envelope”Every event shares the same top-level structure. The event-specific content is always under data.
{ "event": "transaction.created", "event_uuid": "019d072d-1203-7695-842b-a15567fbb0d8", "event_occurred_at": "2026-04-05 14:28:33", "event_version": 3, "vendor_uuid": "019e2711-5a92-735d-a7d5-669aec76b54f", "data": { }}| Field | Description |
|---|---|
event | The event name, in group.action form. Use this to route the event in your handler. |
event_uuid | Unique identifier for this delivery. Use it to de-duplicate retried deliveries. |
event_occurred_at | When the event occurred, as YYYY-MM-DD HH:MM:SS. |
event_version | The webhook schema version. Always 3 for the events on these pages. |
vendor_uuid | The vendor the event relates to. |
data | The event-specific payload. Its shape is documented per event. |
Available Events
Section titled “Available Events”Events are grouped by the entity they describe. Each group has its own page with every event’s description and full example payload.
- Bank Account Events:
bank_account.removed,bank_account.link_failed,bank_account.link_success - Batch Refund Events:
batch_refund.created - Business Events:
business.created,business.updated - Clawback Events:
clawback.created,clawback.processing,clawback.failed,clawback.completed - Compliance Status Events:
compliance_status.processing,compliance_status.in_review,compliance_status.approved,compliance_status.rejected - Merchant Events:
merchant.created,merchant.updated - NOC Events:
noc.received,noc.processed - Payout Events:
payout.processing,payout.failed,payout.completed - Person Events:
person.created,person.updated,person.status_changed - Processor Payout Events:
processor_payout.processing,processor_payout.failed,processor_payout.completed - Refund Events:
refund.created,refund.cancelled,refund.capture_processing,refund.capture_failed,refund.capture_completed,refund.payout_processing,refund.payout_failed,refund.payout_completed - Reverse Payout Events:
reverse_payout.created,reverse_payout.cancelled,reverse_payout.processing,reverse_payout.failed,reverse_payout.completed - Transaction Events:
transaction.created,transaction.awaiting_cancellation,transaction.paused,transaction.resumed,transaction.cancelled,transaction.processing,transaction.failed,transaction.completed,transaction.declined - FBO Funding Events:
fbo.funding_created,fbo.funding_processing,fbo.funding_completed,fbo.funding_failed,fbo.funding_canceled - FBO Account Events:
fbo.account_snapshot
Testing
Section titled “Testing”At this time, GrailPay does not support direct simulation of webhook events in the Sandbox environment. However, you can test your webhook integration by registering a webhook URL in Sandbox and performing actions that naturally trigger webhook events. This approach allows you to validate that your endpoint receives and processes real webhook payloads as expected.
For more details on testing in Sandbox, refer to our Technical Overview guide.
Questions?
Section titled “Questions?”If you’re encountering any issues, please reach out to support@grailpay.com.
Maintained by EkLine