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

# Webhooks

> Get notified instantly when events happen on CoinGecko — no polling required

## Why Use Webhooks?

Keep your application synchronized with CoinGecko in real-time — no cron jobs or polling required. Listen to events like `cg.coin.info.updated` and react instantly to changes.

<CardGroup cols={3}>
  <Card title="Automated Asset Updates" icon="wallet">
    Update your UI when a token rebrands, changes ticker, or updates its logo.
  </Card>

  <Card title="Cross-Chain Monitoring" icon="chart-network">
    Detect when a project deploys on a new chain or migrates a contract address.
  </Card>

  <Card title="Risk & Compliance" icon="shield-halved">
    Act immediately on critical alerts — malicious activity warnings or contract migration notices.
  </Card>
</CardGroup>

<Tip>
  CoinGecko Webhooks (Beta) is available for [paid plan](https://www.coingecko.com/en/api/pricing) customers (Analyst plan & above).

  * Credit charge: **10** credits per event delivery. Retry attempts are **not charged**.
  * Maximum webhook endpoints: **5**.
  * **Enterprise** clients who need higher limits — contact your Customer Success Manager.

  CoinGecko Webhooks is a supplementary delivery mechanism for real-time notifications. Currently in beta — excluded from the SLA applicable to the CoinGecko API Platform.
</Tip>

<Card title="Share Feedback" icon="comment" href="https://forms.gle/wLTMbuMjR5XfhyS89">
  Help us improve Webhooks — share your suggestions and use cases.
</Card>

## Getting Started

<Steps>
  <Step title="Create a webhook">
    Go to the [Developer Dashboard](https://www.coingecko.com/en/developers/dashboard#webhook) and create a new webhook endpoint.

    <Frame caption="CoinGecko generates a unique Signing Secret (`whsec...`) for each webhook.">
      <img src="https://mintcdn.com/coingecko/i9l2MT4etZGYjSx8/assets/images/webhook-create.png?fit=max&auto=format&n=i9l2MT4etZGYjSx8&q=85&s=a1355e0de85fcee5efc0d34e1fc5660c" style={{ maxWidth: '400px' }} width="848" height="984" data-path="assets/images/webhook-create.png" />
    </Frame>
  </Step>

  <Step title="Get your Signing Secret">
    Use the Signing Secret to verify incoming payloads on your server.

    <Frame caption="Every request includes `x-cg-signature`, `x-cg-timestamp`, and `x-cg-event-id` headers for verification.">
      <img src="https://mintcdn.com/coingecko/i9l2MT4etZGYjSx8/assets/images/webhook-signing-secret.png?fit=max&auto=format&n=i9l2MT4etZGYjSx8&q=85&s=ce14532f00f2b17222055bd3301be6c3" width="2118" height="1258" data-path="assets/images/webhook-signing-secret.png" />
    </Frame>
  </Step>

  <Step title="Start receiving events">
    Your server will receive POST requests whenever relevant coin data changes on [CoinGecko.com](https://www.coingecko.com).
  </Step>
</Steps>

<Note>
  For team accounts, non-owner users invited to a shared dashboard have full access to view, edit, and delete webhooks.
</Note>

## Event Types

| Event Type                                               | Description                                                       |
| -------------------------------------------------------- | ----------------------------------------------------------------- |
| [cg.coin.info.updated](/webhooks/cg-coin-info-updated)   | Core coin information updated (metadata, links, categories, etc.) |
| [cg.coin.price.updated](/webhooks/cg-coin-price-updated) | Coin crosses a user-defined price target                          |
| [cg.coin.listed](/webhooks/cg-coin-listed)               | New token indexed and listed on CoinGecko                         |
| More coming soon!                                        | [Share your suggestions](https://forms.gle/wLTMbuMjR5XfhyS89)     |

## HTTP Headers

Every webhook POST request includes these headers:

| Header           | Description                                                      |
| ---------------- | ---------------------------------------------------------------- |
| `Content-Type`   | `application/json`                                               |
| `x-cg-timestamp` | UNIX timestamp of the event. Useful for replay attack prevention |
| `x-cg-signature` | HMAC SHA256 signature to verify authenticity                     |
| `x-cg-event-id`  | Unique identifier for the event                                  |

## Signature Verification

Verify that incoming payloads are genuinely from CoinGecko by computing an HMAC SHA256 hash and comparing it to the `x-cg-signature` header.

**Signing string format:** `{timestamp}:{event_id}:{json_body}`

<Warning>
  The `{json_body}` must be the **raw, unparsed request body** — not a re-stringified JSON object.<br />
  If your framework auto-parses JSON before verification, the signature will fail.
</Warning>

### Example Code

> Replace `YOUR_SIGNING_SECRET` with the `whsec_...` value from your [Developer Dashboard](https://www.coingecko.com/en/developers/dashboard#webhook).

<CodeGroup>
  ```js Node.js (Express) expandable theme={null}
  const { createHmac } = require('crypto');
  const express = require('express');
  const app = express();

  const SIGNING_SECRET = 'YOUR_SIGNING_SECRET';

  function verifySignature(body, headers, secret) {
    if (!secret) return null;

    const timestamp = headers["x-cg-timestamp"];
    const eventId = headers["x-cg-event-id"];
    const signature = headers["x-cg-signature"];

    if (!timestamp || !eventId || !signature) return null;

    const signingString = `${timestamp}:${eventId}:${body}`;
    const expected = createHmac("sha256", secret).update(signingString).digest("hex");

    return expected === signature;
  }

  app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
    const rawBodyString = req.body.toString('utf8');
    const isValid = verifySignature(rawBodyString, req.headers, SIGNING_SECRET);

    if (isValid === null) {
      return res.status(400).send('Missing required CoinGecko headers');
    }

    if (isValid) {
      const event = JSON.parse(rawBodyString);
      // Process the event...
      return res.status(200).send('Webhook received successfully');
    } else {
      return res.status(401).send('Invalid signature');
    }
  });

  app.listen(3000, () => console.log('Server listening on port 3000'));
  ```

  ```python Python (Flask) expandable theme={null}
  import hmac
  import hashlib
  from flask import Flask, request

  app = Flask(__name__)
  SIGNING_SECRET = 'YOUR_SIGNING_SECRET'

  def verify_signature(body_str, headers, secret):
      if not secret:
          return None

      timestamp = headers.get('x-cg-timestamp')
      event_id = headers.get('x-cg-event-id')
      signature = headers.get('x-cg-signature')

      if not timestamp or not event_id or not signature:
          return None

      signing_string = f"{timestamp}:{event_id}:{body_str}"

      expected = hmac.new(
          secret.encode('utf-8'),
          signing_string.encode('utf-8'),
          hashlib.sha256
      ).hexdigest()

      return hmac.compare_digest(expected, signature)

  @app.route('/webhook', methods=['POST'])
  def webhook_handler():
      raw_body_string = request.get_data(as_text=True)
      is_valid = verify_signature(raw_body_string, request.headers, SIGNING_SECRET)

      if is_valid is None:
          return "Missing required CoinGecko headers", 400

      if is_valid:
          event = request.get_json()
          # Process the event...
          return "Webhook received successfully", 200
      else:
          return "Invalid signature", 401

  if __name__ == '__main__':
      app.run(port=3000)
  ```
</CodeGroup>

<Warning>
  Treat your Signing Secret like a password — never commit it to public repos or expose it in client-side code.
</Warning>

## Managing Webhooks

Navigate to your **Webhook Details** page in the [Developer Dashboard](https://www.coingecko.com/en/developers/dashboard#webhook):

* **Send Test Event** — dispatches a mock `cg.coin.info.updated` payload. Use it to verify your server receives the request and responds with `2xx` before going live.
* **Delivery Logs** — view the latest 100 delivery attempts. Use these to identify if your endpoint is rejecting requests.

## Billing & Credits

* **10 credits** per event delivery. Retries are **not charged**.
* If you run out of credits with Hardcap enabled (Overage disabled):
  * Delivery stops immediately and all webhooks are auto-disabled.
  * You'll receive an email notification that delivery has stopped.
  * You must **manually re-activate** webhooks in the [Developer Dashboard](https://www.coingecko.com/en/developers/dashboard#webhook) after credits are replenished.

### Estimated Usage

Each delivered webhook event consumes **10 credits**. The `cg.coin.info.updated` event listens to all active coins on CoinGecko — volume fluctuates based on market activity and how frequently projects update their metadata.

* **Expected volume:** up to **200 updates/day** based on historical data.
* **Estimated monthly cost:** \~6,000 events/month = **\~60,000 credits**.
* **Plan fit:** comfortably within the [Analyst plan](https://www.coingecko.com/en/api/pricing) and above.

<Note>
  These are approximations. Extreme market volatility or mass migrations could temporarily increase daily volume.
</Note>

### 24-Hour Baseline Test

If you're concerned about unpredictable credit usage, run a short test before committing:

1. **Enable Hardcap** — turn OFF "Overage" in the Developer Dashboard to avoid unexpected charges.
2. **Run for 24–48 hours** — activate your webhook and let it collect events.
3. **Check consumption** — review credit usage in the dashboard to establish a reliable baseline.

## Retries & Failed Attempts

If your server fails to respond with a `2xx` status code, CoinGecko will retry with exponential backoff. **Retry attempts are not charged.**

A webhook is automatically disabled under either condition:

| Condition             | Threshold                              |
| --------------------- | -------------------------------------- |
| Single event backoff  | **14 failed retries** over \~24 hours  |
| Aggregate failure cap | **300 failed retries** across 12 hours |

When a webhook is disabled, you'll receive an email notification. To resume:

1. Check your server logs and resolve the issue.
2. Log in to the [Developer Dashboard](https://www.coingecko.com/en/developers/dashboard#webhook).
3. Manually toggle the webhook back to **Active**.
