Subgraph Webhooks

Subgraph webhooks allow you to receive HTTP POST requests in real-time whenever an entity in your subgraph changes due to an INSERT, UPDATE, or DELETE operation. This is useful for triggering backend processes, sending notifications, or syncing data with external systems.

How it Works

When a subgraph handler executes an operation like entity.save() (resulting in an INSERT or UPDATE) or an entity is removed (resulting in a DELETE), the change is recorded. A real-time watcher detects this update and sends a payload to your configured webhook URL. The payload will indicate the type of operation: INSERT, UPDATE, or DELETE.

Creating a Webhook

You can create a new webhook through the 0xgraph dashboard.

  1. Navigate to the “Webhooks” section of your subgraph.

  2. Click on the “New Webhook” button.

  3. Fill in the required information in the “Create Webhook” modal:

    • Name: A descriptive name for your webhook (e.g., webhook_demo).
    • URL: The HTTP endpoint where the webhook payloads will be sent.
    • Entity: The specific entity you want to track (e.g., approved).
    • Number of retries: Configure the total number of retries. Defaults to 3, with a maximum of 10.
    • Retry interval: Configure the retry interval in seconds. Defaults to 60, with a maximum of 3600.
    • Retry timeout: Configure the retry timeout in seconds. Defaults to 30, with a maximum of 60.
    • “secret” header value: An optional secret string that will be sent in a designated webhook secret header. This allows your endpoint to verify that the request is authentic.
  4. Click “Create”.

Listing Webhooks

Once created, your webhook will appear in the list of webhooks for your subgraph. You can see its name, the entity it tracks, the target URL, and statistics about successful and failed deliveries.

Webhook Payload Structure

The webhook will send a JSON payload to your configured URL. The main payload object contains the following fields:

  • op (string): The type of operation that triggered the webhook. Possible values are "INSERT", "UPDATE", or "DELETE".
  • data_source (string): Identifier for the subgraph or indexer being tracked.
  • data (object): Contains the actual entity data that changed. It has two sub-fields:
    • old (object | null): The state of the entity before the change. This will be null if the op is "INSERT".
    • new (object | null): The state of the entity after the change. This will be null if the op is "DELETE".
  • webhook_name (string): The name you assigned to your webhook during creation.
  • webhook_id (string): A unique identifier for the webhook configuration.
  • id (string): A unique identifier for this specific event notification.
  • delivery_info (object): Information about the delivery attempt for this webhook. It has two sub-fields:
    • max_retries (integer): The maximum number of retry attempts configured for this webhook.
    • current_retry (integer): The current retry attempt number for this specific event (0 for the initial attempt).
  • entity (string): The name of the subgraph entity being tracked.

Example Payloads:

INSERT operation:

{
  "op": "INSERT",
  "data_source": "privateURL/v0.0.1",
  "data": {
    "new": {
      "id": "ERC20Approve-0xbb06dca3ae6887fabf931640f67cab3e3a16f4dc-w\\u001c\\u001b\\u0002\\ufffd\\ufffd\\ufffd\\u07Ջ^\\ufffdcO\\ufffd\\ufffd(7C\\u001c\\u001b-\\ufffd\\u0016僞\\ufffdm\\ufffd\\ufffdI+y\\ufffd\\ufffd^\\u0015\\ufffd\\ufffdY\\ufffd",
      "vid": 7271978,
      "owner": "\\\\x771cab02cfc4ebd58b5e9b634fe7f82837431cc6",
      "token": "0xbb06dca3ae6887fabf931640f67cab3e3a16f4dc",
      "amount": 1.157920892373162e+77,
      "is_all": false,
      "spender": "\\\\xbde5839ec36db2ac492b79e9e3b75e15fa8a59ec",
      "updated_at": 1747127781,
      "block_range": "[20405156,)"
    },
    "old": null
  },
  "webhook_name": "webhook_demo",
  "webhook_id": "fcdce3c3-b288-4bb1-a7df-0d5acd8cd447",
  "id": "5b623fd0-b539-400b-bbb3-060d95403a64",
  "delivery_info": {
    "max_retries": 3,
    "current_retry": 0
  },
  "entity": "approved"
}

UPDATE operation :

{
  "data": {
    "new": {
      "id": "ERC20Approve-0xdeaddeaddeaddeaddeaddeaddeaddeaddead0000-w  Ջ^cO(7C -w Ջ^cO(7C ",
      "vid": 7271844,
      "owner": "\x771cab02cfc4ebd58b5e9b634fe7f82837431cc6",
      "token": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0000",
      "amount": 115792089237316195423570985008687907853269984665640561215151422165121803858650,
      "is_all": false,
      "spender": "\x771cab02cfc4ebd58b5e9b634fe7f82837431cc6",
      "updated_at": 1747126465,
      "block_range": "[20405057,20405060)"
    },
    "old": {
      "id": "ERC20Approve-0xdeaddeaddeaddeaddeaddeaddeaddeaddead0000-w  Ջ^cO(7C -w Ջ^cO(7C ",
      "vid": 7271844,
      "owner": "\x771cab02cfc4ebd58b5e9b634fe7f82837431cc6",
      "token": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0000",
      "amount": 115792089237316195423570985008687907853269984665640561215151422165121803858650,
      "is_all": false,
      "spender": "\x771cab02cfc4ebd58b5e9b634fe7f82837431cc6",
      "updated_at": 1747126465,
      "block_range": "[20405057,)"
    }
  },
  "data_source": "privateURL/v0.0.1",
  "delivery_info": {
    "current_retry": 0,
    "max_retries": 3
  },
  "entity": "approved",
  "id": "dd2b6013-22e1-4e8e-a665-be5276144a68",
  "op": "UPDATE",
  "webhook_id": "fcdce3c3-b288-4bb1-a7df-0d5acd8cd447",
  "webhook_name": "webhook_demo"
}