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

# Webhook

> Send data to HTTP endpoints as JSON payloads

## Overview

Send data to HTTP endpoints as JSON payloads over HTTP `POST`. The sink guarantees at-least-once delivery and retries transient failures with exponential backoff, so your endpoint only needs to return a `2xx` status code to acknowledge the batch.

## Configuration

```yaml theme={null}
sinks:
  my_webhook_sink:
    type: webhook
    from: my_transform
    url: https://api.example.com/endpoint
    secret_name: MY_WEBHOOK_SECRET
    one_row_per_request: true # or false (default)
    headers:
      X-Custom-Header: my-value
```

## Parameters

<ParamField path="type" type="string" required>
  Must be `webhook`.
</ParamField>

<ParamField path="from" type="string" required>
  Name of the transform or source to read data from.
</ParamField>

<ParamField path="url" type="string" required>
  Fully-qualified HTTP(S) endpoint URL to send data to (for example,
  `https://api.example.com/endpoint`). The sink sends `POST` requests to this URL.
</ParamField>

<ParamField path="secret_name" type="string">
  Name of a Goldsky `httpauth` secret. Both the header name and value stored in
  the secret are injected into every outgoing request. See [Secret creation](#secret-creation)
  below.
</ParamField>

<ParamField path="one_row_per_request" type="boolean" default="false">
  If `true`, each row is sent as its own request with a single JSON object body.
  If `false` (default), rows are batched and sent as a JSON array body.
</ParamField>

<ParamField path="headers" type="object">
  Additional HTTP headers to include with each request. `Content-Type: application/json`
  is set automatically if you don't specify one. You cannot set the same header here
  that `secret_name` provides — pick one or the other.
</ParamField>

<ParamField path="primary_key" type="string">
  Column that uniquely identifies each row. Used for checkpointing and side-output
  tracking. Inherited from the upstream source or transform when omitted.
</ParamField>

## Request Format

Each request is an HTTP `POST` with `Content-Type: application/json`.

**Single row (`one_row_per_request: true`):**

```json theme={null}
{
  "id": "abc123",
  "address": "0x...",
  "value": "1000000",
  "timestamp": "2024-01-01T00:00:00Z"
}
```

**Batch (`one_row_per_request: false`):**

```json theme={null}
[
  {
    "id": "abc123",
    "address": "0x...",
    "value": "1000000"
  },
  {
    "id": "def456",
    "address": "0x...",
    "value": "2000000"
  }
]
```

## Secret creation

To securely authenticate with your webhook endpoint, create an `httpauth` secret using the Goldsky CLI:

```bash theme={null}
goldsky secret create
```

Select `httpauth` as the secret type and follow the prompts to provide a header name and value. For example, you might set the header name to `Authorization` and the value to `Bearer <your-token>`.

<Note>
  Secret names can only contain alphanumeric characters, underscores (`_`), and hyphens (`-`).
</Note>

Then reference the secret in your webhook sink configuration:

```yaml theme={null}
sinks:
  my_webhook_sink:
    type: webhook
    from: my_transform
    url: https://api.example.com/endpoint
    secret_name: MY_WEBHOOK_SECRET
```

The header name and value from the secret are automatically added to every request sent to the webhook endpoint. Setting the same header explicitly under `headers` alongside `secret_name` is a configuration error — remove one.

## Example: Send High-Value Transfers to API

```yaml theme={null}
transforms:
  high_value_transfers:
    type: sql
    primary_key: id
    sql: |
      SELECT *
      FROM erc20_transfers
      WHERE CAST(value AS DECIMAL) > 1000000000000000000000

sinks:
  webhook_alerts:
    type: webhook
    from: high_value_transfers
    url: https://alerts.example.com/high-value-transfer
    secret_name: ALERTS_API_SECRET
    one_row_per_request: true
```

## Delivery and retries

* **At-least-once delivery.** Your endpoint may receive duplicates after retries; use `primary_key` or an idempotency key on the receiving side if duplicates are a problem.
* **Retriable responses** — network errors, request timeouts, `408 Request Timeout`, `429 Too Many Requests`, and any `5xx` — are retried indefinitely with exponential backoff.
* **Non-retriable responses** (other `4xx` errors) fail the pipeline immediately.
* **Backpressure.** The pipeline paces delivery to your endpoint's responsiveness, so a slow receiver slows the pipeline rather than dropping data.
