# Event Notifications and Webhooks

The Pay.io Payment Gateway provides **real-time event notifications**, so merchants can stay up to date with deposits and withdrawals as they happen.

You can consume these events through **Webhooks**, the gateway pushes event notifications to your HTTP endpoint.

***

### Event Types for Webhooks

The gateway sends notifications for the following transaction events:

**Deposit Events**

* **Processing Event** - The deposit has been detected on the blockchain and is being processed.
* **Confirmation Event** - The blockchain has confirmed the transaction, funds are now available in the wallet.

**Withdrawal Events**

* **Successful Event** - The withdrawal was completed successfully, confirms that funds have been transferred.

***

### Webhook Integration

#### Setup Requirements

1. **Webhook URL** - Update the URL, which Payment Gateway will call in the Merchant Portal.
2. **IP Whitelisting** - Contact support for the list of IPs to allow.
3. **Public Key** - Obtain your Pay.io public key from the Merchant Console.
4. **Secure Storage** - Store the key securely in your application configuration.
5. **Signature Verification** - Implement verification on all incoming requests.

#### Webhook Security Verification

Each webhook request includes headers you must validate:

<table><thead><tr><th width="221.2265625">Header</th><th>Description</th></tr></thead><tbody><tr><td><code>X-Signature</code></td><td>Base64-encoded request signature</td></tr><tr><td><code>X-Timestamp</code></td><td>UNIX timestamp when the event was sent</td></tr><tr><td><code>X-Algorithm</code></td><td>Signing algorithm, always <code>RSA-SHA256</code></td></tr></tbody></table>

**Verification steps:**

1. Extract the raw JSON request payload.
2. Read `X-Signature`, `X-Timestamp`, and `X-Algorithm` headers.

```
signature = request.headers.get('X-Signature')
timestamp = request.headers.get('X-Timestamp')
algorithm = request.headers.get('X-Algorithm')
```

1. Build a string to verify:

   ```
   string_to_verify = json_payload + timestamp
   ```
2. Decode the Base64 signature.
3. Verify with RSA-SHA256 using the stored Pay.io public key.

#### Example: Verification in Elixir

{% code overflow="wrap" lineNumbers="true" %}

```elixir
def verify_signature(json_payload, signature, public_key_pem, timestamp) do
  case parse_public_key(public_key_pem) do
    {:ok, public_key} ->
      string_to_verify = json_payload <> to_string(timestamp)
      signature_bytes = Base.decode64!(signature)
      case :public_key.verify(string_to_verify, :sha256, signature_bytes, public_key) do
        true -> {:ok, :verified}
        false -> {:error, :signature_invalid}
      end
    {:error, reason} ->
      {:error, reason}
  end
end
```

{% endcode %}

***

### **Event Structure**

Each event payload includes:

* `event` - Type of event (`User Deposit`, `User Payout`).
* `transaction` - Full transaction details (currency, addresses, tx hash, etc.).
* `transaction_uuid` - Unique transaction ID for reconciliation.
* `user_reference` - Your internal user ID.
* `merchant_reference` - Reference configured during transaction creation.

**Example: Deposit Processing**

{% code overflow="wrap" lineNumbers="true" %}

```json
{
  "event": "User Deposit",
  "transaction": {
    "id": "43dae597-f283-4631-8e73-1e40ecfaedfa",
    "status": "processing",
    "date": "2025-08-27T14:51:53Z",
    "currency": {
      "id": "c872e749-fd56-533e-b01f-de87ae38e7f1",
      "name": "USD Coin",
      "symbol": "$",
      "network": "Base Chain",
      "token_address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "currency_icon": "https://cdn.hub88.io/hub-wallet/USDC-ic.svg",
      "network_icon": "https://cdn.hub88.io/hub-wallet/BASE-ic.svg",
      "currency_code": "USDC"
    },
    "amount": 2.35,
    "provider_transaction_id": "pay_31sINaTdZeCYWCLobzX16X6QGFm",
    "to_address": "0x6d0e5b532ba0857ca391ee2d11b02c596fcded3c",
    "from_address": "0xabf7920042335cb1fd9e7c688f99822a1d879445",
    "tx_hash": "0xcd8fba9d72c3e25d55f7f63d58fffbc3411692df611e480c6975adfb2d8938cd",
    "transaction_type": "Deposit",
    "amount_usd": 2.35
  },
  "transaction_uuid": "43dae597-f283-4631-8e73-1e40ecfaedfa",
  "user_reference": "Jon14",
  "merchant_reference": "1_hubwallet-demo_6gmma63qfxdag",
  "payment_method": "Deposit"
}
```

{% endcode %}

**Example: Deposit Confirmation**

{% code overflow="wrap" lineNumbers="true" %}

```json
{
  "event": "User Deposit",
  "transaction": {
    "id": "43dae597-f283-4631-8e73-1e40ecfaedfa",
    "status": "succeeded",
    "date": "2025-08-27T14:53:59Z",
    "currency": {
      "id": "c872e749-fd56-533e-b01f-de87ae38e7f1",
      "name": "USD Coin",
      "symbol": "$",
      "network": "Base Chain",
      "token_address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "currency_icon": "https://cdn.hub88.io/hub-wallet/USDC-ic.svg",
      "network_icon": "https://cdn.hub88.io/hub-wallet/BASE-ic.svg",
      "currency_code": "USDC"
    },
    "amount": 2.35,
    "provider_transaction_id": "pay_31sINaTdZeCYWCLobzX16X6QGFm",
    "to_address": "0x6d0e5b532ba0857ca391ee2d11b02c596fcded3c",
    "from_address": "0xabf7920042335cb1fd9e7c688f99822a1d879445",
    "tx_hash": "0xcd8fba9d72c3e25d55f7f63d58fffbc3411692df611e480c6975adfb2d8938cd",
    "transaction_type": "Deposit",
    "amount_usd": 2.35
  },
  "transaction_uuid": "43dae597-f283-4631-8e73-1e40ecfaedfa",
  "user_reference": "Jon14",
  "merchant_reference": "1_hubwallet-demo_6gmma63qfxdag",
  "payment_method": "Deposit"
}
```

{% endcode %}

**Example: Withdrawal Successful**

{% code overflow="wrap" lineNumbers="true" %}

```json
{
  "event": "User Payout",
  "transaction": {
    "id": "492bcb88-149e-4d18-bfd4-2d2c2b29e87d",
    "status": "succeeded",
    "date": "2025-08-27T15:04:28Z",
    "currency": {
      "id": "c872e749-fd56-533e-b01f-de87ae38e7f1",
      "name": "USD Coin",
      "symbol": "$",
      "network": "Base Chain",
      "token_address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "currency_icon": "https://cdn.hub88.io/hub-wallet/USDC-ic.svg",
      "network_icon": "https://cdn.hub88.io/hub-wallet/BASE-ic.svg",
      "currency_code": "USDC"
    },
    "amount": 2.0,
    "provider_transaction_id": "pay_31sJg9321pd5yAWKOhVAIffWqVX",
    "to_address": "0xabf7920042335cB1FD9e7C688F99822a1D879445",
    "from_address": "0x09b8c5b24bcdd91af5a7d32f6a4ae9fa4183d4f4",
    "tx_hash": "0x76088442e6ce9524ead531be4296a379cf772dc96cddc9cbb9b2b01d5f0be7fa",
    "transaction_type": "Payout",
    "amount_usd": 1.9804985390232988
  },
  "transaction_uuid": "492bcb88-149e-4d18-bfd4-2d2c2b29e87d",
  "user_reference": "Jon14",
  "merchant_reference": "1_hubwallet-demo_6gmma63qfxdag",
  "payment_method": "Payout"
}
```

{% endcode %}

[<br>](https://app.gitbook.com/o/MwHZPoGUGWLMhDstYN8v/s/1WTxkRy2d4cjH3G9U45M/~/changes/25/~/revisions/Gg7xT98iJO8McsiRhs9O/core-concepts/pagination)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.pay.io/api-reference/core-concepts/event-notifications-and-webhooks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
