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

# How to receive webhooks

> To receive real-time events in your app via webhooks, follow these steps.

<Steps>
  <Step title="Create a development endpoint">
    In your local app, add a route that accepts `POST` requests and responds
    with `2xx`.

    ```ts pages/api/webhooks.ts theme={null}
    export default (req, res) => {
      if (req.method === "POST") {
        const event = req.body;
        console.log(event);
        res.status(200).end();
      }
    };
    ```

    Anything other than `2xx` is treated as a failure and triggers retries.

    <Tip>
      Expose your local endpoint with a tunnel like
      [ngrok](https://ngrok.com/download) or [VS Code Port
      Forwarding](https://code.visualstudio.com/docs/debugtest/port-forwarding)
      so the dashboard can reach it.
    </Tip>
  </Step>

  <Step title="Register the endpoint in Nomos">
    Open the [Developer page in the Nomos
    dashboard](https://dashboard.nomos.energy/developer) and add a new webhook:

    1. Paste your publicly accessible HTTPS URL.
    2. Select the events you want to subscribe to.

    Saving generates a signing secret. You'll need it to verify requests in step 4.
  </Step>

  <Step title="Send a test delivery">
    From the webhook's detail page, trigger a test event. The test payload
    only carries the topic, so you can confirm reachability and signature
    verification without depending on the full envelope:

    ```json theme={null}
    {
      "topic": "test.event"
    }
    ```

    Confirm your endpoint logs the request and returns `2xx`.
  </Step>

  <Step title="Verify and handle real events">
    Before acting on an event, validate the signature header so you only
    process real Nomos deliveries. See [Verify webhook
    requests](/webhooks/verify-requests) for the full procedure.

    Then dispatch on `topic`. The `context` only carries IDs, so fetch the
    resource when you need its current state.

    ```ts pages/api/webhooks.ts theme={null}
    export default async (req, res) => {
      if (req.method !== "POST") return res.status(405).end();

      const event = req.body;

      switch (event.topic) {
        case "subscription.created":
          // event.context.subscription is the ID
          break;
        case "subscription.confirmed":
          // ...
          break;
      }

      res.status(200).end();
    };
    ```
  </Step>

  <Step title="Deploy and register the production endpoint">
    Deploy your handler, then add a second webhook in the dashboard pointing
    at the production URL. You'll get a separate signing secret for the
    production endpoint.
  </Step>
</Steps>
