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

# Webhook Notifications for Transfers

> Get real-time HTTP notifications for ERC-20 token transfers to trigger alerts in your application.

## Use Case

You want to receive HTTP notifications whenever a specific ERC-20 token is transferred on Base Mainnet. This enables real-time alerting, event-driven workflows, or feeding data into systems that consume webhooks (Slack, PagerDuty, custom backends).

## Pipeline Configuration

<Steps>
  <Step title="Create a new pipeline">
    In the [GoldRush Platform](https://goldrush.dev/platform/), navigate to **Manage Pipelines** and click **Create Pipeline**. Name it `transfer-alerts`.
  </Step>

  <Step title="Configure the webhook destination">
    Select **Webhook** as the destination type and configure your endpoint:

    ```yaml theme={null}
    destination:
      type: "webhook"
      url: "https://api.yourapp.com/webhooks/transfers"
      headers:
        Authorization: "Bearer ${WEBHOOK_TOKEN}"
        Content-Type: "application/json"
      batch_size: 1
      timeout_ms: 5000
      retry:
        max_attempts: 5
        backoff_ms: 2000
    ```
  </Step>

  <Step title="Select your source">
    Choose **Base Mainnet** as the chain and **Transfers** as the data type. This streams every token transfer event.
  </Step>

  <Step title="Add a SQL transform to filter">
    Filter to only USDC transfers on Base (contract `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`):

    ```yaml theme={null}
    transforms:
      transfers: >
        SELECT block_height, block_signed_at, tx_hash, contract_address,
               from_address, to_address, amount
        FROM transfers
        WHERE contract_address = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
    ```
  </Step>

  <Step title="Deploy">
    Review and deploy. Your webhook endpoint begins receiving POST requests for each matching transfer.
  </Step>
</Steps>

## Webhook Payload

Each transfer arrives as a JSON POST request:

```json theme={null}
{
  "project": "transfer-alerts",
  "stream": "transfers",
  "record": {
    "block_height": 28451023,
    "block_signed_at": "2025-03-18T14:22:05Z",
    "tx_hash": "0xabc123...",
    "contract_address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "from_address": "0x1234...",
    "to_address": "0x5678...",
    "amount": "1000000000"
  }
}
```

The request includes an `X-Idempotency-Key` header for deduplication on your end.

## Handling Idempotency

Every webhook request includes an `X-Idempotency-Key` header with a deterministic value based on the source record's position. Store this key and check for duplicates before processing:

```javascript theme={null}
app.post('/webhooks/transfers', (req, res) => {
  const idempotencyKey = req.headers['x-idempotency-key'];

  // Check if already processed
  if (await cache.has(idempotencyKey)) {
    return res.status(200).json({ status: 'duplicate' });
  }

  // Process the transfer
  const { record } = req.body;
  await processTransfer(record);

  // Mark as processed
  await cache.set(idempotencyKey, true, { ttl: 86400 });

  res.status(200).json({ status: 'ok' });
});
```

<Warning>
  Always return a 2xx status code promptly. The pipeline retries on 5xx and 429 responses with exponential backoff. A 4xx response (other than 429) causes the batch to be permanently skipped.
</Warning>

## Retry Behavior

| Response      | Pipeline Action                                                      |
| ------------- | -------------------------------------------------------------------- |
| 2xx           | Success, move to next record                                         |
| 429           | Retry with `Retry-After` header if present, else exponential backoff |
| 5xx           | Retry with exponential backoff                                       |
| 4xx (not 429) | Permanent failure, skip and log                                      |

## Production Tips

* **batch\_size: 1** sends one transfer per HTTP request - simplest to handle. Increase to 5-10 for higher throughput if your endpoint supports batch payloads.
* **timeout\_ms**: Set this lower than your endpoint's actual timeout to allow for retry overhead. 5,000 ms is a good default.
* **Filtering**: The SQL transform runs before the webhook, so you only pay for HTTP requests on records that match your filter. Add multiple WHERE conditions to narrow further.
