> ## Documentation Index
> Fetch the complete documentation index at: https://docs.grailpay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Events

## 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. Webhooks may be sent to both vendors and processors, and the payloads are tailored to each recipient’s
role and financing type (e.g., credit, debit, or alternate flows) to ensure accurate processing and traceability.

<Note>
  All webhook payloads are shown in JSON format and from the perspective of a vendor receiving an event.  If a processor
  is receiving the event, the payload will be the same, but it will include the `vendor_uuid` field to identify which
  vendor the event is related to.  This is true for all webhook events unless the event denotes a Processor only event.
</Note>

### Authenticating Webhooks

To verify that a webhook really came from GrailPay and not a malicious actor, every webhook request includes a special
signature header: `X-Caller-Auth`.

This header contains a `SHA-256` hash of your API key, and it should be validated in your server-side code to ensure the
authenticity of the request.

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

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 subscribing to webhook events, 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

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
may result in delayed event delivery or eventual webhook deactivation.

To ensure reliable communication, your webhook handler should be:

* Idempotent – able to handle duplicate event deliveries without side effects.
* Efficient – respond quickly, even if additional processing is handled asynchronously.

Properly handling responses and retries ensures smooth, real-time integration with your systems.

***

## Available Webhook Events

<Note>
  Our webhooks are not specific to any particular entity in our Payments Application.  So for
  example, you would not want to register an individual webhook for every merchant that you onboard.  Each of those
  webhooks urls will get the same data each time an event is triggered.  The approach we recommend is to register a
  single webhook url to the events you wish to subscribe to.  Then you can use the event data to determine which
  entity the event is related to.
</Note>

***

### Bank Account Events

Bank accounts are foundational to ACH transactions within the GrailPay platform, serving as the endpoints for debits
and credits between payors and payees. Whether added through direct input, or our Bank Link SDK, these accounts must be
tracked and maintained throughout their lifecycle. GrailPay provides webhook events that notify you when a bank account
has been successfully linked, failed to link, or has been deleted. These events allow your system to react to key
account changes in real time—helping to keep records accurate and ensuring smooth payment processing.

By subscribing to bank account-related webhooks, your integration gains full visibility into the account lifecycle. For
example, a failed bank link may prompt you to notify a user, while a successful link may trigger onboarding flows or
transaction enablement. These webhooks are essential for keeping your application responsive, user-friendly, and
compliant with modern financial workflows.

#### Bank Account Removed Event

This webhook event is triggered whenever a bank account is deleted from the GrailPay system. It allows your integration
to stay in sync with the current state of user-linked financial accounts, ensuring that your records remain accurate and
up-to-date.

When this event occurs, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "BankAccountRemoved",
      "account_uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "user_uuid": "ce334276-3a2e-4db6-8e67-600ed1fcd397",
      "aggregator_type": "bank_link",
      "account_number": "45287159",    
      "provider_name": "chase",
      "routing_number": "011401533"
  }
  ```
</CodeGroup>

#### Bank Link Failed Event

This webhook event is triggered whenever a bank account fails to link successfully using GrailPay’s [Bank Link SDK](/docs/technical/bank-link/overview).
This allows your application to track and respond to failed bank connection attempts—whether due to user cancellation,
timeouts, or external provider errors.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "BankLinkFailed",
      "user_uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
    	"aggregator_type": "bank_link",
      "vendor_id": "123456",
      "failed_reason": ".....",
      "source": "api",
      "ui_notified": true|false
  }
  ```
</CodeGroup>

#### Bank Linked Successfully Event

This event is triggered when a bank account is successfully linked using GrailPay’s [Bank Link SDK](/docs/technical/bank-link/overview).
flow. It confirms that the user has completed the linking process and the account is now available for transactions or
balance checks.

You can use this event to update your internal records, unlock funding workflows, or display confirmation messages to the
user.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "BankLinkedSuccessfully",
      "account_uuid": "becdf333-53cc-4db1-a6bd-a01b1ba9585c",
      "user_uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "aggregator_type": "bank_link",
      "source": "api",
      "account_id": "acc_9Dw8QmdZtcXrEMDuZWLyfi",
      "account_number": "45287159",
      "routing_number": "011401533",
      "provider_name": "chase",
      "vendor_id": "12345",
      "ui_notified": true|false
  }
  ```
</CodeGroup>

***

### Batch Payout Events

Batch payouts are a key mechanism in the GrailPay Payments platform, allowing multiple transactions to be grouped together
and disbursed to a single entity’s linked bank account in one consolidated action. This not only streamlines the
movement of funds but also simplifies reconciliation and reporting for partners managing high transaction volumes.

GrailPay emits batch payout webhook events for four entity types: Business, Merchant, Person, and Processor. These
events provide visibility into when a payout batch is created and initiated, enabling partners to track disbursement
activity and trigger downstream processes like ledger updates or partner notifications. Each event includes a structured
payload specific to the entity type, which is outlined in the sections below.

#### Batch Payout Business Event

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "BatchPayoutBusiness",
      "uuid": "9bd53fe1-ac74-4e81-b6f2-be88b7c86a68",
      "amount": 10100,
      "created_at": "2024-04-18 01:00:20",
      "updated_at": "2024-04-18 01:00:20"
  }
  ```
</CodeGroup>

#### Batch Payout Merchant Event

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "BatchPayoutMerchant",
      "uuid": "9bd53fe1-ac74-4e81-b6f2-be88b7c86a68",
      "amount": 10100,
      "created_at": "2024-04-18 01:00:20",
      "updated_at": "2024-04-18 01:00:20"
  }
  ```
</CodeGroup>

#### Batch Payout Person Event

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "BatchPayoutPerson",
      "uuid": "9bd53fe1-ac74-4e81-b6f2-be88b7c86a68",
      "amount": 10100,
      "created_at": "2024-04-18 01:00:20",
      "updated_at": "2024-04-18 01:00:20"
  }
  ```
</CodeGroup>

#### Batch Payout Processor Event

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event ( Processor Only ) theme={"system"}
  {
      "event": "BatchPayout",
      "uuid": "9bd53fe1-ac74-4e81-b6f2-be88b7c86a68",
      "amount": 10100,
      "trace_id": "ach_11jzggrptrftyd",
      "modality": {
          "payment_rail": "ach",
          "speed": "standard"
      },
      "created_at": "2024-04-18 01:00:20",
      "updated_at": "2024-04-18 01:00:20"
  }
  ```
</CodeGroup>

***

### Batch Refund Event

This webhook event is triggered when a debit ACH is initiated from the processor’s bank account to fund a batch of
refunds. It signifies that GrailPay has begun collecting funds to fulfill refund requests that were previously grouped
and approved for processing.

This event is typically used in integrations where the processor, rather than the original payee, is responsible for
funding the refund payouts. It ensures visibility into the moment refund funding is initiated, allowing for downstream
reconciliation or tracking.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event ( Processor Only ) theme={"system"}
  {
      "event": "BatchRefund",
      "uuid": "9bd53fe1-ac74-4e81-b6f2-be88b7c86a68",
      "amount": 10100,
      "trace_id": "ach_11jzggrptrftyd",
      "created_at": "2024-04-18 01:00:20",
      "updated_at": "2024-04-18 01:00:20"
  }
  ```
</CodeGroup>

***

### Business Events

GrailPay emits webhook events when key lifecycle changes occur for business entities within the platform.
These events notify you in real time when a business is created or updated, allowing you to synchronize
entity data across your systems, trigger onboarding workflows, or audit compliance checkpoints as part of your Payments
integration.

#### Business Created Event

This webhook is triggered whenever a new Business entity is successfully created within the GrailPay system.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "BusinessCreated",
      "uuid": "401c79dd-d38c-4c3a-8edf-1afac5914d2d",
      "first_name": "Jack",
      "last_name": "Jones",
      "name": "Jack Inc.",
      "tin": "961862955",
      "user_status": "Approved|On Hold|Rejected",
      "kyb_status": "Approved|In Review|Failed|null",
      "email": "[email protected]",
      "phone": "2541234567",                    
      "address": {
          "street_address": "20 Elmora Ave",
          "additional_address": "",
          "city": "Elizabeth",
          "state": "NJ",
          "country": "US",
          "zip": "07202"
      },
      "business_owners": [],
      "financing_credit_balance": null,
      "source": "api",
      "created_at": "2023-06-10 14:15:54",
      "updated_at": "2023-06-10 14:15:54"
  }
  ```
</CodeGroup>

#### Business Updated Event

This webhook is triggered whenever a business entity is updated within the GrailPay system.
Updates may include changes to KYB information, business name, address, or other identifying details.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "BusinessUpdated",
      "uuid": "401c79dd-d38c-4c3a-8edf-1afac5914d2d",
      "first_name": "Jack",
      "last_name": "Jones",
      "name": "Jack Inc.",
      "tin": "961862955",
      "user_status": "APPROVED|ON_HOLD|REJECTED|SCHEDULED_FOR_DELETE",
      "kyb_status": "in_review|approved|failed|null",
      "kyb_rejected_reason": "Reason for KYB rejection ( ie. Cannot match TIN )",
      "email": "[email protected]",
      "phone": "2541234567",                    
      "address": {
          "street_address": "20 Elmora Ave",
          "additional_address": "",
          "city": "Elizabeth",
          "state": "NJ",
          "country": "US",
          "zip": "07202"
      },
      "business_owners": [],
      "financing_credit_balance": null,
      "source": "api",
      "created_at": "2023-06-10 14:15:54",
      "updated_at": "2023-06-10 14:15:54"
  }
  ```
</CodeGroup>

***

### Clawback Events

Clawbacks occur when a transaction that has already been disbursed to the payee fails—often due to insufficient funds,
a return from the receiving bank, or a rejection by the ACH network. In such cases, GrailPay initiates a payout return
to recover the funds, which is referred to as a clawback. These events are crucial for maintaining the integrity of your
payment workflows, ensuring that failed disbursements are properly tracked and reconciled.

GrailPay emits a series of webhook events throughout the clawback lifecycle to notify you when a return has been
initiated (ClawbackStarted), fails to complete (ClawbackFailed), or finishes successfully (ClawbackCompleted). By
subscribing to these events, you can monitor failed transactions in real time, update internal records, trigger customer
notifications, or pause related operations until resolution.

#### Clawback Capture Started Event

This webhook is triggered when a payout return ( clawback) capture has been initiated by GrailPay as part of a refund
or recovery process.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "ClawbackCaptureStarted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "CLAWBACK_ACH_PENDING",
      "capture_status": "CAPTURE_ACH_FAILED",
      "payout_status": "PAYOUT_COMPLETE",
      "clawback_status": "CLAWBACK_ACH_PENDING",
      "clawback_trace_id": "ach_11jzggrptrftyd",
      "reverse_payout_status": null,
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "type": "api",
      "failure_reason": "Insufficient funds",
      "failure_code": "R01",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Clawback Completed Event

This webhook is triggered when a payout return (clawback) has been initiated by GrailPay as part of a completed refund
or recovery process.

<Info>
  This event confirms that GrailPay has initiated the return of funds. It does not guarantee that the receiving bank
  has successfully delivered the funds.
</Info>

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "ClawbackCompleted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "CLAWBACK_COMPLETE",
      "capture_status": "CAPTURE_ACH_FAILED",
      "payout_status": "PAYOUT_COMPLETE",
      "clawback_status": "CLAWBACK_COMPLETE",
      "clawback_trace_id": "ach_11jzggrptrftyd",
      "reverse_payout_status": null,
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "type": "api",
      "failure_reason": "Insufficient funds",
      "failure_code": "R01",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Clawback Failed Event

This webhook is triggered when a payout return (clawback) attempt fails within the GrailPay system.

<Info>
  A failed clawback typically indicates that the funds could not be withdrawn from the recipient’s bank account due
  to reasons such as insufficient funds or a closed account.
</Info>

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "ClawbackFailed",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "CLAWBACK_ACH_FAILED",
      "capture_status": "CAPTURE_ACH_FAILED",
      "payout_status": "PAYOUT_COMPLETE",
      "clawback_status": "CLAWBACK_ACH_FAILED",
      "clawback_trace_id": "ach_11jzggrptrftyd",
      "reverse_payout_status": null,
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "type": "api",
      "failure_reason": "Insufficient funds",
      "failure_code": "R01",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Clawback Started Event

This webhook is triggered when a payout return (clawback) has been initiated by the GrailPay system, but the ACH debit
has not been created. A clawback is required when a transaction fails (e.g., due to an ACH return) after the payout
(credit) has already been disbursed to the recipient.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "ClawbackStarted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "CLAWBACK_PENDING",
      "capture_status": "CAPTURE_ACH_FAILED",
      "payout_status": "PAYOUT_COMPLETE",
      "clawback_status": "CLAWBACK_PENDING",
      "clawback_trace_id": null,
      "reverse_payout_status": null,
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "type": "api",
      "failure_reason": null,
      "failure_code": null,
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

***

### Compliance Status Events

GrailPay provides webhook events to notify you when the compliance status of a merchant entity changes. These events
are crucial for maintaining up-to-date records and ensuring that your operations align with regulatory requirements. By
subscribing to these events, you can automate workflows that respond to compliance status updates, such as pausing
transactions, triggering additional verification steps, or notifying relevant stakeholders.

#### Compliance Status Changed Event

This webhook event is triggered whenever a merchant's compliance status is changed within the GrailPay platform.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "ComplianceStatusChanged",
      "entity": {
          "type": "merchant",
          "uuid": "8f5a6e9d-2c41-4f90-bb3f-9e8a9a3b7f1c"
      },
      "compliance": {
          "status": "rejected",
          "kyb": {
              "status": "approved",
              "message": null,
              "updated_at": "2025-12-11 13:59:21"
          },
          "kyc": [
              {
                  "uuid": "7f4e8a02-3d5a-4c3b-b823-d8c3125b3f8d",
                  "first_name": "John",
                  "last_name": "Doe",
                  "status": "approved",
                  "message": null,
                  "updated_at": "2025-12-11 13:59:21"
              },
              {
                  "uuid": "9e2a7cb7-34c1-4c52-a0df-4f9f5704e6e2",
                  "first_name": "Jane",
                  "last_name": "Doe",
                  "status": "rejected",
                  "message": "Invalid Address",
                  "updated_at": "2025-12-11 13:59:21"
              }
          ]
      }
  }
  ```
</CodeGroup>

***

### Merchant Events

GrailPay emits dedicated webhook events when a merchant entity is created or updated on the platform. These events provide
real-time notifications that allow you to synchronize merchant records, trigger onboarding or verification flows, and
monitor compliance status.

Merchants in GrailPay are a distinct type of business that must complete Know Your Business (KYB) verification. While
merchants were previously tracked using shared business webhooks, we now offer merchant-specific events—such as
**MerchantCreated** and **MerchantUpdated** to give platforms finer control and visibility into merchant lifecycle changes.
Each payload includes detailed metadata, enabling accurate reconciliation of merchant status across your systems.

#### Merchant Created Event

Our Payments API emits a MerchantCreated webhook event each time a new merchant has been successfully onboarded and registered
within the GrailPay platform.

For more information about KYB verification and requirements, refer to the [KYB Overview](/docs/resources/kyb-overview) guide.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "MerchantCreated",
      "merchant": {
          "uuid": "b8f1e132-3bfc-4e23-89f7-9e541e8ffb33",
          "business_type": "merchant",
          "kyb_status": "pending|approved|in_review|rejected",
          "kyb_rejected_reason": "Reason for KYB rejection ( ie. Cannot match TIN )",
          "name": "Acme Incorporation",
          "tin": "123456789",
          "trading_name": "Acme Inc",
          "entity_type": "LLC",
          "incorporation_date": "2024-02-02",
          "incorporation_state": "CO",
          "address_type": "Registered",
          "address": {
              "line_1": "123 Main St",
              "line_2": "Apt 4B",
              "city": "Denver",
              "state": "CO",
              "zip": "80203"
          },
          "transaction_fee_percent": 2.5,
          "transaction_fee_fixed": 100,
          "maximum_transaction_fee": 5000,
          "payout_type": "individual",
          "client_reference_id": "bus_123456789",
          "timestamps": {
              "created_at": "2025-06-01 13:57:03",
              "updated_at": "2025-06-01 13:57:09"
          }
      },
      "beneficial_owners": [
          {
              "first_name": "Jane",
              "last_name": "Doe",
              "dob": "2023-04-11",
              "ssn9": "123456789",
              "address": {
                  "line_1": "123 Main St",
                  "line_2": "Apt 4B",
                  "city": "Denver",
                  "state": "CO",
                  "zip": "80203"
              },
              "is_beneficial_owner": true,
              "is_director": false,
              "is_significant_control_person": false,
              "ownership_percentage": 25,
              "email": "owner@test.com",
              "phone": "2457856490",
              "occupation": "Co-founder",
              "timestamps": {
                  "created_at": "2025-06-01 13:57:03",
                  "updated_at": "2025-06-01 13:57:09"
              }
          }
      ],
      "relations": {
          "person": { "uuid": "e7b8f1e1-3bfc-4e23-89f7-9e541e8ffb33" }
      }
  }
  ```
</CodeGroup>

#### Merchant Updated Event

Our Payments API emits a MerchantUpdated webhook event whenever a merchant’s details have been updated within the GrailPay
platform. This may include changes to business name, address, or other KYB-related fields.

For more information about KYB verification and requirements, refer to the [KYB Overview](/docs/resources/kyb-overview) guide.

<Note>
  This webhook should be actively monitored to detect changes in the merchant’s KYB status. Updates to KYB status may
  impact the merchant’s ability to send or receive funds and should trigger appropriate compliance or onboarding
  workflows on your end.
</Note>

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "MerchantUpdated",
      "merchant": {
          "uuid": "b8f1e132-3bfc-4e23-89f7-9e541e8ffb33",
          "business_type": "merchant",
          "kyb_status": "pending|approved|in_review|rejected",
          "kyb_rejected_reason": "Reason for KYB rejection ( ie. Cannot match TIN )",
          "name": "Acme Incorporation",
          "tin": "123456789",
          "trading_name": "Acme Inc",
          "entity_type": "LLC",
          "incorporation_date": "2024-02-02",
          "incorporation_state": "CO",
          "address_type": "Registered",
          "address": {
              "line_1": "123 Main St",
              "line_2": "Apt 4B",
              "city": "Denver",
              "state": "CO",
              "zip": "80203"
          },
          "transaction_fee_percent": 2.5,
          "transaction_fee_fixed": 100,
          "maximum_transaction_fee": 5000,
          "payout_type": "individual",
          "client_reference_id": "bus_123456789",
          "timestamps": {
              "created_at": "2025-06-01 13:57:03",
              "updated_at": "2025-06-01 13:57:09"
          }
      },
      "beneficial_owners": [
          {
              "first_name": "Jane",
              "last_name": "Doe",
              "dob": "2023-04-11",
              "ssn9": "123456789",
              "address": {
                  "line_1": "123 Main St",
                  "line_2": "Apt 4B",
                  "city": "Denver",
                  "state": "CO",
                  "zip": "80203"
              },
              "is_beneficial_owner": true,
              "is_director": false,
              "is_significant_control_person": false,
              "ownership_percentage": 25,
              "email": "owner@test.com",
              "phone": "2457856490",
              "occupation": "Co-founder",
              "timestamps": {
                  "created_at": "2025-06-01 13:57:03",
                  "updated_at": "2025-06-01 13:57:09"
              }
          }
      ],
      "relations": {
          "person": { "uuid": "e7b8f1e1-3bfc-4e23-89f7-9e541e8ffb33" }
      }
  }
  ```
</CodeGroup>

***

### NOC Events

NOC (Notice of Change) events are critical notifications within the GrailPay platform that inform you when an ACH
transaction has encountered an issue requiring attention. NOCs are issued by banks or the ACH network to indicate problems
such as incorrect account information, closed accounts, or other discrepancies that need to be resolved.

By subscribing to NOC webhook events, your integration can receive real-time alerts whenever a NOC is processed by GrailPay.
This allows you to take prompt action—such as updating account details, notifying users, or initiating corrective
measures—to ensure smooth payment processing and maintain compliance with ACH regulations.

#### NOC Processed Event

This webhook is triggered whenever a Notice of Change (NOC) has been processed within the
GrailPay system.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
      {
          "event": "NocProcessed",
          "user_uuid": "550e8400-e29b-41d4-a716-446655440000",
          "bank_account_uuid": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
          "aggregator_type": "manual",
          "account_number": "1234567890",
          "routing_number": "021000021",
          "account_name": "John Doe",
          "account_type": "checking",
          "tp_counterparty_id": "cpty_abc123def456",
          "old_account_number": "9876543210",
          "old_routing_number": "987654321",
          "old_account_name": "John Doe",
          "old_account_type": "savings",
          "old_tp_counterparty_id": "cpty_old789xyz012",
          "vendor_uuid": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
      }
  ```
</CodeGroup>

***

### Payout Events

Payout events reflect the final stage in GrailPay’s transaction lifecycle, where funds are disbursed from the platform
to a payee’s linked bank account. These events are essential for tracking when money has been successfully moved out of
the system—or when something has gone wrong. Whether you’re monitoring cash flow, updating transaction statuses, or
reconciling financial data, payout events provide the real-time signals you need.

GrailPay emits webhook events for each critical state in a payout’s lifecycle: when a payout is initiated (PayoutPending),
fails (PayoutFailed), or completes (PayoutCompleted). These events help ensure transparency and operational continuity
across your systems. They allow your application to respond dynamically—such as notifying users, retrying failed
disbursements, or logging final confirmations for reporting and audit purposes.

#### Payout Completed Event

This webhook is triggered each time a payout (transfer of funds to the payee) has been completed.

<Note>
  Please note that this event indicates the payout has been initiated by GrailPay. It does not confirm final delivery
  of funds by the receiving bank.
</Note>

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "PayoutCompleted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "PAYOUT_COMPLETE",
      "capture_status": "CAPTURE_COMPLETE",
      "payout_status": "PAYOUT_COMPLETE",
      "reverse_payout_status": null,
      "clawback_status": null,
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "modality": {
          "payment_rail": "ach",
          "speed": "standard"
      },
      "type": "api",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Payout Created Event

This webhook is triggered each time a payout (transfer of funds to the payee) has been created and is pending.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "PayoutCreated",
      "payout": {
          "uuid": "8b2536c0-01c4-4699-8a97-b68eb8fb6b4f",
          "client_reference_id": "Payout_1784_1710950428",
          "type": "individual",
          "status": "PAYOUT_ACH_PENDING",
          "trace_id": "ach_11jzp20wtve6z8",
          "amount": 3245,
          "speed": "standard",
          "ach_return_code": null,
          "modality": {
              "payment_rail": "ach",
              "speed": "standard"
          },
          "payee": {
              "uuid": "1a437e1f-c112-4534-ac44-2de71cec9f1f",
              "user_uuid": "f3d8c9d1-0b8b-4e79-bc41-8998cbbd58b1",
              "type": "business",
              "name": "Acme Pest Control",
              "processor_mid": null,
              "bank_account": {
                  "aggregator_type": "manual",
                  "uuid": "9b97f121-a449-4b52-9f36-6c55f18394d6"
              }
          },
          "timestamps": {
              "created_at": "2024-06-25 13:57:03",
              "updated_at": "2024-06-25 13:57:09"
          },
          "ach_timestamps": {
              "created_at": "2024-03-20 16:00:28",
              "processed_at": null,
              "sent_at": null,
              "settled_at": "2024-03-20 17:00:27",
              "failed_at": null,
              "cancelled_at": null
          }
      }
  }
  ```
</CodeGroup>

#### Payout Failed Event

This webhook is triggered when a payout—the transfer of funds to the payee’s bank account—fails. This may occur for
several reasons, such as invalid account details, routing issues, or problems reported by the receiving financial
institution.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "PayoutFailed",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "PAYOUT_ACH_FAILED",
      "capture_status": "CAPTURE_COMPLETE",
      "payout_status": "PAYOUT_ACH_FAILED",
      "clawback_status": null,
      "reverse_payout_status": "REVERSE_PAYOUT_PENDING",
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "type": "api",
      "modality": {
          "payment_rail": "ach",
          "speed": "standard"
      },
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

***

### Person Events

GrailPay emits webhook events when key lifecycle changes occur for individual users—referred to as People in the
platform. These events notify you in real time when a person is created or updated, enabling you to synchronize user
records across your systems, trigger onboarding processes, or verify changes in identity-related data.

While people may be linked to a business or merchant, they can also exist independently as participants in ACH
transactions. Each webhook payload includes unique identifiers and metadata to help you track a person’s lifecycle
within your platform and respond appropriately to changes in their profile.

#### Person Created Event

Our Payments API emits a PersonCreated webhook whenever a new individual user is added to the platform—either as part of
onboarding or through a standalone user creation flow.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "PersonCreated",
      "person": {
          "client_reference_id": "person_98345",
          "uuid": "7c41f6a2-a4b9-4df8-9225-2c1b7312042e",
          "first_name": "Jane",
          "last_name": "Doe",
          "email": "test@grailpay.com",
          "phone": "1234567890",
          "address": {
              "line_1": "123 Main St",
              "line_2": "Apt 4B",
              "city": "Denver",
              "state": "CO",
              "zip": "80203"
          },
          "payout_type": "individual",
          "timestamps": {
              "created_at": "2025-06-01 13:57:03",
              "updated_at": "2025-06-01 13:57:09"
          }
      }
  }
  ```
</CodeGroup>

#### Person Status Changed Event

This webhook is triggered whenever a person's status is updated within the GrailPay platform due to risk, compliance,
or business rules. Status changes may include transitions such as `ON_HOLD_FRAUD_PAYEE`, `ON_HOLD_SANCTIONS`, or other
states that restrict the person's ability to transact.

These updates typically occur when GrailPay identifies a risk-related reason to suspend or restrict activity for an
individual user. This webhook allows your system to immediately respond—by disabling UI elements, blocking actions, or
initiating internal support workflows.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "PersonStatusChanged",
      "person": {
          "uuid": "7c41f6a2-a4b9-4df8-9225-2c1b7312042e",
          "status": "ON_HOLD_FRAUD_PAYEE"
      },
      "change_reason": "fraud_related_return",
      "outcome": "This person and its associated entities will no longer be able to transact within our payments api.",
      "action": "Contact support@grailpay.com to resolve the issue.",
      "relations": {
          "merchant": {
              "uuid": "fae2de1a-68c9-43a0-9c63-4daf8d16a709"
          }
      }
  }
  ```
</CodeGroup>

#### Person Updated Event

The PersonUpdated webhook is emitted whenever an existing user’s information is modified in the GrailPay platform. This
includes changes to core fields such as name, email, phone number, or address.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "PersonUpdated",
      "person": {
          "client_reference_id": "person_98345",
          "uuid": "7c41f6a2-a4b9-4df8-9225-2c1b7312042e",
          "first_name": "Jane",
          "last_name": "Doe",
          "email": "test@grailpay.com",
          "phone": "1234567890",
          "address": {
              "line_1": "123 Main St",
              "line_2": "Apt 4B",
              "city": "Denver",
              "state": "CO",
              "zip": "80203"
          },
          "payout_type": "individual",
          "timestamps": {
              "created_at": "2025-06-01 13:57:03",
              "updated_at": "2025-06-01 13:57:09"
          }
      }
  }
  ```
</CodeGroup>

***

### Processor Payout Events

Processor payout events are triggered throughout the lifecycle of payouts initiated on behalf of a specific processor.
Unlike standard payouts, processor payouts are always processed in batches, allowing multiple payouts to be grouped and
executed together.

GrailPay emits webhook events for each key milestone in the processor payout process: when a payout is created
(ProcessorPayoutCreated), and when it completes successfully or encounters a failure (ProcessorPayoutCompleted,
ProcessorPayoutFailed). These events enable your platform to monitor payout progress, reconcile processor-level
transactions, and respond promptly to any issues that arise during processing.

#### Processor Payout Created Event

This webhook is triggered when a processor payout is created.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "ProcessorPayoutCreated",
      "payout": {
          "uuid": "8b2536c0-01c4-4699-8a97-b68eb8fb6b4f",
          "type": "batch",
          "status": "PENDING",
          "amount": 5278900,
          "ach_return_code": null,
          "ledger_shared": false,
          "trace_id": "ach_11jzggrptrftyd",
          "modality": {
              "payment_rail": "ach",
              "speed": "standard"
          },
          "timestamps": {
              "created_at": "2024-06-25 13:57:03",
              "updated_at": "2024-06-25 13:57:09"
          },
          "ach_timestamps": {
              "created_at": "2024-03-20 16:00:28",
              "processed_at": null,
              "sent_at": null,
              "settled_at": null,
              "failed_at": null,
          }
      },
      "relations": {
          "vendor": { "uuid" : "fae2de1a-68c9-43a0-9c63-4daf8d16a709" }
      }
  }
  ```
</CodeGroup>

#### Processor Payout Completed Event

This webhook is triggered when a processor payout is completed.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "ProcessorPayoutCompleted",
      "payout": {
          "uuid": "8b2536c0-01c4-4699-8a97-b68eb8fb6b4f",
          "type": "batch",
          "status": "PENDING",
          "amount": 5278900,
          "ach_return_code": null,
          "ledger_shared": false,
          "trace_id": "ach_11jzggrptrftyd",
          "modality": {
              "payment_rail": "ach",
              "speed": "standard"
          },
          "timestamps": {
              "created_at": "2024-06-25 13:57:03",
              "updated_at": "2024-06-25 13:57:09"
          },
          "ach_timestamps": {
              "created_at": "2024-03-20 16:00:28",
              "processed_at": "2024-03-21 16:00:28",
              "sent_at": "2024-03-21 16:00:28",
              "settled_at": "2024-03-21 16:00:28",
              "failed_at": null,
          }
      },
      "relations": {
          "vendor": { "uuid" : "fae2de1a-68c9-43a0-9c63-4daf8d16a709" }
      }
  }
  ```
</CodeGroup>

#### Processor Payout Failed Event

This webhook is triggered when a processor payout fails.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "ProcessorPayoutFailed",
      "payout": {
          "uuid": "8b2536c0-01c4-4699-8a97-b68eb8fb6b4f",
          "type": "batch",
          "status": "PENDING",
          "amount": 5278900,
          "ach_return_code": null,
          "ledger_shared": false,
          "trace_id": "ach_11jzggrptrftyd",
          "modality": {
              "payment_rail": "ach",
              "speed": "standard"
          },
          "timestamps": {
              "created_at": "2024-06-25 13:57:03",
              "updated_at": "2024-06-25 13:57:09"
          },
          "ach_timestamps": {
              "created_at": "2024-03-20 16:00:28",
              "processed_at": null,
              "sent_at": null,
              "settled_at": null,
              "failed_at": "2024-03-21 16:00:28"
          }
      },
      "relations": {
          "vendor": { "uuid" : "fae2de1a-68c9-43a0-9c63-4daf8d16a709" }
      }
  }
  ```
</CodeGroup>

***

### Refund Events

Refund events are triggered throughout the lifecycle of a refund transaction—starting from the moment a refund is
created, through the capture of funds from the payee or processor, and concluding with the delivery of funds back to the
original payer. These events help ensure your platform can track, audit, and respond to refunds in real time.

GrailPay emits webhook events for each key milestone in the refund process: when a refund is initiated (RefundPending),
when the corresponding debit ACH is started, completed, or fails (RefundCaptureStarted, RefundCaptureCompleted, RefundCaptureFailed),
and when the outbound credit to the payer is initiated, completed, or fails (RefundPayoutPending, RefundPayoutCompleted, RefundPayoutFailed).
Together, these events provide a complete picture of refund flow—enabling you to keep users informed, automate
reconciliation, and ensure accurate financial reporting.

#### Refund Cancelled Event

This webhook is triggered when a refund has been cancelled.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "RefundCancelled",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "transaction_uuid": "7049f46f-8502-402e-952b-b29ad5ec8a55",
      "amount": 12000,
      "capture_delay_days": 1,
      "payout_delay_days": 2,
      "status": "REFUND_CANCELLED",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "cancel_reason": "The transaction has failed",
      "client_reference_id": "",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Refund Capture Completed Event

This webhook is triggered when a debit ACH transaction has been successfully completed from either the payee’s or
processor’s bank account to fund a refund.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "RefundCaptureCompleted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "transaction_uuid": "7049f46f-8502-402e-952b-b29ad5ec8a55",
      "capture_delay_days": 1,
      "payout_delay_days": 2,
      "amount": 12000,
      "status": "REFUND_ACH_PENDING",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "client_reference_id": "",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Refund Capture Failed Event

This webhook is triggered when a debit ACH fails while attempting to collect funds for a refund from either the payee’s
or processor’s bank account.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "RefundCaptureFailed",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "transaction_uuid": "7049f46f-8502-402e-952b-b29ad5ec8a55",
      "amount": 12000,
      "capture_delay_days": 1,
      "payout_delay_days": 2,
      "status": "REFUND_FAILED",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "client_reference_id": "",
      "failure_reason": "No account or unable to locate account",
      "failure_code": "R03",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Refund Capture Started Event

This webhook is triggered each time a refund request has been initiated and a debit ACH has been created from either the
payee’s or processor’s bank account.

* For individual payouts, a debit ACH is created for each refund request from the payee or processor.
* For batch payouts, a single debit ACH is created from the processor’s account to cover all refund requests for the day.
* In both cases, this webhook will be triggered for each individual refund request.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "RefundCaptureStarted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "transaction_uuid": "7049f46f-8502-402e-952b-b29ad5ec8a55",
      "amount": 12000,
      "capture_delay_days": 1,
      "payout_delay_days": 2,
      "status": "REFUND_CAPTURE_ACH_PENDING",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "client_reference_id": "",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Refund Payout Completed Event

This webhook is triggered each time a refund has been completed and the funds have been sent to the payer’s bank account.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "RefundPayoutCompleted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "transaction_uuid": "7049f46f-8502-402e-952b-b29ad5ec8a55",
      "amount": 12000,
      "capture_delay_days": 1,
      "payout_delay_days": 2,
      "status": "REFUND_COMPLETE",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "client_reference_id": "",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Refund Payout Failed Event

This webhook is triggered when a credit ACH transfer to the payer’s bank account has failed during the refund process.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "RefundPayoutFailed",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "transaction_uuid": "7049f46f-8502-402e-952b-b29ad5ec8a55",
      "amount": 12000,
      "capture_delay_days": 1,
      "payout_delay_days": 2,
      "status": "REFUND_FAILED",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "client_reference_id": "",
      "failure_reason": "No account or unable to locate account",
      "failure_code": "R03",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Refund Payout Pending Event

This webhook is triggered when a credit ACH transfer has been initiated to the payer’s bank account as part of a refund.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "RefundPayoutPending",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "transaction_uuid": "7049f46f-8502-402e-952b-b29ad5ec8a55",
      "amount": 12000,
      "capture_delay_days": 1,
      "payout_delay_days": 2,
      "status": "REFUND_ACH_PENDING",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "client_reference_id": "",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Refund Pending Event

This webhook is triggered when a refund request is first created in the system.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "RefundPending",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "transaction_uuid": "7049f46f-8502-402e-952b-b29ad5ec8a55",
      "amount": 12000,
      "capture_delay_days": 1,
      "payout_delay_days": 2,
      "status": "REFUND_PENDING",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "client_reference_id": "",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

***

### Reverse Payout Events

Reverse payout events are emitted when GrailPay must return funds to the original payer because a payout to the intended
payee could not be completed. This can happen due to reasons like an invalid or closed bank account, or a failed delivery
attempt after the payout was initiated.

These events help your platform stay aligned with the refund and reconciliation flow for failed disbursements. GrailPay
provides webhook events for when a reverse payout is initiated (ReversePayoutStarted), successfully completed
(ReversePayoutCompleted), or fails during processing (ReversePayoutFailed). These allow you to track the full lifecycle
of the reversal process, update transaction statuses, and notify relevant users or systems of the outcome.

#### Reverse Payout Completed Event

This webhook is triggered when a reverse payout has been successfully completed.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "ReversePayoutCompleted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "PAYOUT_ACH_FAILED",
      "capture_status": "CAPTURE_COMPLETE",
      "payout_status": "PAYOUT_ACH_FAILED",
      "clawback_status": null,
      "reverse_payout_status": "REVERSE_PAYOUT_COMPLETE",
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "type": "api",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Reverse Payout Failed Event

This webhook is triggered when a reverse payout attempt fails due to an error or issue during processing.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "ReversePayoutFailed",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "PAYOUT_ACH_FAILED",
      "capture_status": "CAPTURE_COMPLETE",
      "payout_status": "PAYOUT_ACH_FAILED",
      "clawback_status": null,
      "reverse_payout_status": "REVERSE_PAYOUT_ACH_FAILED",
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "type": "api",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Reverse Payout Started Event

This webhook is triggered when a reverse payout has been successfully initiated and is in the process of being completed.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "ReversePayoutStarted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "PAYOUT_ACH_FAILED",
      "capture_status": "CAPTURE_COMPLETE",
      "payout_status": "PAYOUT_ACH_FAILED",
      "clawback_status": null,
      "reverse_payout_status": "REVERSE_PAYOUT_ACH_PENDING",
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "type": "api",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

***

### Transaction Events

Transaction events provide visibility into the full lifecycle of the debit side of a payment—when funds are pulled from
the payer’s bank account. These events allow your platform to monitor the status of ACH debits as they move through
creation, processing, completion, or failure.

Each webhook corresponds to a specific stage of the transaction journey, from initial creation (TransactionStarted) to
settlement (TransactionCompleted), including events for cancellation, failure, and capture. By subscribing to these
events, you can build real-time audit trails, trigger status updates, and automate downstream actions tied to the
movement of funds from the payer.

#### Transaction Awaiting Cancellation Event

This webhook is triggered when a cancellation request for a transaction has been received and the debit ACH has not settled yet.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "TransactionAwaitingCancellation",
      "transaction": {
          "uuid": "9b97f15d-83bc-41ad-9514-0437180d0192",
          "client_reference_id": "2",
          "status": "AWAITING_CANCELLATION",
          "currency": "USD",
          "trace_id": "ach_11jzggrptrftyd",
          "amount": 3245,
          "transaction_fee": 0,
          "payout_delay_days": 0,
          "company_name": "MoneyOne",
          "description": "sending money",
          "addenda": null,
          "type": "api",
          "ach_return_code": null,
          "cancel_reason": null,
          "payor": {
              "uuid": "f3d8c9d1-0b8b-4e79-bc41-8998cbbd58b1",
              "user_uuid": "f3d8c9d1-0b8b-4e79-bc41-8998cbbd58b1",
              "type": "person",
              "name": "John Doe",
              "processor_mid": null,
              "bank_account": {
                  "aggregator_type": "manual",
                  "uuid": "9b97f121-a449-4b52-9f36-6c55f18394d6"
              }
          },
          "payee": {
              "uuid": "1a437e1f-c112-4534-ac44-2de71cec9f1f",
              "user_uuid": "f3d8c9d1-0b8b-4e79-bc41-8998cbbd58b1",
              "type": "business",
              "name": "Acme Pest Control",
              "processor_mid": null,
              "bank_account": {
                  "aggregator_type": "manual",
                  "uuid": "9b97f121-a449-4b52-9f36-6c55f18394d6"
              }
          },
          "timestamps": {
              "created_at": "2024-06-25 13:57:03",
              "updated_at": "2024-06-25 13:57:09",
              "canceled_at": null
          },
          "ach_timestamps": {
              "created_at": "2024-03-20 16:00:28",
              "processed_at": "2024-03-20 17:00:27",
              "sent_at": null,
              "settled_at": null,
              "failed_at": null,
              "cancelled_at": null
          }
      }
  }
  ```
</CodeGroup>

#### Transaction Capture Started Event

This webhook is triggered when an ACH debit has been successfully initiated as part of a transaction. It indicates that
the funds capture process has begun from the payor’s bank account.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "TransactionCaptureStarted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "CAPTURE_ACH_PENDING",
      "capture_status": "CAPTURE_ACH_PENDING",
      "capture_trace_id": "ach_11jzggrptrftyd",
      "payout_status": null,
      "clawback_status": null,
      "reverse_payout_status": null,
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "cancel_reason": null,
      "type": "api",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Transaction Canceled Event

This webhook is triggered whenever a transaction is canceled before it is processed. It confirms that no funds will be
captured or disbursed for the canceled transaction.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "TransactionCanceled",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "CANCELED",
      "capture_status": "CANCELED",
      "capture_trace_id": "ach_11jzggrptrftyd",
      "payout_status": null,
      "clawback_status": null,
      "reverse_payout_status": null,
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "type": "api",
      "cancel_reason": "Unable to link bank account.",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Transaction Completed Event

This webhook is triggered when a transaction has been successfully debited from the payer—meaning the ACH debit from the
payor has been settled, and we have begun the payout process to the payee.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "TransactionCompleted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "PAYOUT_PENDING_ACH",
      "capture_status": "CAPTURE_COMPLETE",
      "capture_trace_id": "ach_11jzggrptrftyd",
      "payout_status": null,
      "clawback_status": null,
      "reverse_payout_status": null,
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "cancel_reason": null,
      "type": "api",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Transaction Failed Event

This webhook is triggered when a transaction fails at any stage of processing—whether due to account issues, validation
errors, or ACH return codes.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<Note>
  If for some reason the payment cannot be successfully processed the error details will be sent in the payload through a
  variable called `ach_return_code` along with the corresponding R code in 'ach\_return\_code'.  For a list of ACH return
  codes see our [Return Codes](/docs/resources/return-codes) documentation.
</Note>

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "TransactionFailed",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "CAPTURE_ACH_FAILED",
      "capture_status": "CAPTURE_ACH_FAILED",
      "capture_trace_id": "ach_11jzggrptrftyd",
      "payout_status": null,
      "clawback_status": null,
      "reverse_payout_status": null,
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "cancel_reason": null,
      "type": "api",
      "failed_reason": "Insufficient funds",
      "ach_return_code": "R01",
      "failure_reason": "Insufficient funds",
      "failure_code": "R01",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

#### Transaction Paused Event

This webhook is triggered when a transaction has been paused, typically due to compliance or risk review processes.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "TransactionPaused",
      "transaction": {
          "uuid": "9b97f15d-83bc-41ad-9514-0437180d0192",
          "client_reference_id": "2",
          "status": "PAUSED",
          "currency": "USD",
          "trace_id": "ach_11jzggrptrftyd",
          "amount": 3245,
          "transaction_fee": 0,
          "payout_delay_days": 0,
          "company_name": "MoneyOne",
          "description": "sending money",
          "addenda": null,
          "type": "api",
          "ach_return_code": null,
          "cancel_reason": null,
          "payor": {
              "uuid": "f3d8c9d1-0b8b-4e79-bc41-8998cbbd58b1",
              "user_uuid": "f3d8c9d1-0b8b-4e79-bc41-8998cbbd58b1",
              "type": "person",
              "name": "John Doe",
              "processor_mid": null,
              "bank_account": {
                  "aggregator_type": "manual",
                  "uuid": "9b97f121-a449-4b52-9f36-6c55f18394d6"
              }
          },
          "payee": {
              "uuid": "1a437e1f-c112-4534-ac44-2de71cec9f1f",
              "user_uuid": "f3d8c9d1-0b8b-4e79-bc41-8998cbbd58b1",
              "type": "business",
              "name": "Acme Pest Control",
              "processor_mid": null,
              "bank_account": {
                  "aggregator_type": "manual",
                  "uuid": "9b97f121-a449-4b52-9f36-6c55f18394d6"
              }
          },
          "timestamps": {
              "created_at": "2024-06-25 13:57:03",
              "updated_at": "2024-06-25 13:57:09",
              "canceled_at": null
          },
          "ach_timestamps": {
              "created_at": "2024-03-20 16:00:28",
              "processed_at": null,
              "sent_at": null,
              "settled_at": "2024-03-20 17:00:27",
              "failed_at": null,
              "cancelled_at": null
          }
      }
  }
  ```
</CodeGroup>

#### Transaction Resumed Event

This webhook is triggered when a paused transaction has been resumed and is back in processing.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "TransactionResumed",
      "transaction": {
          "uuid": "9b97f15d-83bc-41ad-9514-0437180d0192",
          "client_reference_id": "2",
          "status": "CAPTURE_ACH_PENDING",
          "currency": "USD",
          "trace_id": "ach_11jzggrptrftyd",
          "amount": 3245,
          "transaction_fee": 0,
          "payout_delay_days": 0,
          "company_name": "MoneyOne",
          "description": "sending money",
          "addenda": null,
          "type": "api",
          "ach_return_code": null,
          "cancel_reason": null,
          "payor": {
              "uuid": "f3d8c9d1-0b8b-4e79-bc41-8998cbbd58b1",
              "user_uuid": "f3d8c9d1-0b8b-4e79-bc41-8998cbbd58b1",
              "type": "person",
              "name": "John Doe",
              "processor_mid": null,
              "bank_account": {
                  "aggregator_type": "manual",
                  "uuid": "9b97f121-a449-4b52-9f36-6c55f18394d6"
              }
          },
          "payee": {
              "uuid": "1a437e1f-c112-4534-ac44-2de71cec9f1f",
              "user_uuid": "f3d8c9d1-0b8b-4e79-bc41-8998cbbd58b1",
              "type": "business",
              "name": "Acme Pest Control",
              "processor_mid": null,
              "bank_account": {
                  "aggregator_type": "manual",
                  "uuid": "9b97f121-a449-4b52-9f36-6c55f18394d6"
              }
          },
          "timestamps": {
              "created_at": "2024-06-25 13:57:03",
              "updated_at": "2024-06-25 13:57:09",
              "canceled_at": null
          },
          "ach_timestamps": {
              "created_at": "2024-03-20 16:00:28",
              "processed_at": null,
              "sent_at": null,
              "settled_at": null,
              "failed_at": null,
              "cancelled_at": null
          }
      }
  }
  ```
</CodeGroup>

#### Transaction Started Event

This webhook is triggered when a transaction has been successfully created in the GrailPay system but ACH processing has
not yet begun. It marks the initial step in the transaction lifecycle.

When this event is triggered, GrailPay sends a webhook payload to your configured URL with the following structure:

<CodeGroup>
  ```json Event theme={"system"}
  {
      "event": "TransactionStarted",
      "uuid": "b5c337d8-d886-11ed-afa1-0242ac120002",
      "payer_uuid": "aae3664b-db18-428c-9a2f-a876f259a7c3",
      "payee_uuid": "54f964d4-7ade-4cd1-a278-4f21cad18a2b",
      "status": "CAPTURE_PENDING",
      "capture_status": "CAPTURE_PENDING",
      "capture_trace_id": "ach_11jzggrptrftyd",
      "payout_status": null,
      "clawback_status": null,
      "reverse_payout_status": null,
      "currency": "USD",
      "amount": 12000,
      "transaction_fee": 300,
      "client_reference_id": "",
      "payout_delay_days": 2,
      "cancel_reason": null,
      "type": "api",
      "created_at": "2023-04-11 14:25:26",
      "updated_at": "2023-04-11 18:25:26"
  }
  ```
</CodeGroup>

***

## 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](/docs/technical/overview#testing) guide.

***

## Questions?

If you're encountering any issues, please reach out to [support@grailpay.com](mailto:support@grailpay.com).

***
