---
updatedAt: 2026-07-10T09:31:26.000Z
agentTools:
  projectIndex: https://docs.getembed.ai/llms.txt
---

# Building Notification Streams

Build notification streams from saved algorithms and notification configs.

# Building Notification Streams

A notification stream is a saved algorithm plus a delivery config. The algorithm finds candidates. The config decides when and how they are delivered.

## Build The Candidate Algorithm

1. Open **Algo** in Console.
2. Create a new algorithm.
3. In **Search**, choose a notification index such as `dex-notifications`, `hyperliquid-notifications`, `kalshi-notifications`, or `polymarket-notifications`.
4. Require delivery fields such as `user_id`, `item_id`, `timestamp`, or the event identifier available on that index.
5. Sort by `timestamp desc`.
6. Run Search, then Hydration.
7. Save the algorithm.

Example:

```js
import mbd from "algo-dsl";

export default async function algo() {
  return mbd
    .search()
    .index("dex-notifications")
    .notNull("user_id")
    .notNull("timestamp")
    .sortBy("timestamp", "desc")
    .size(100);
}
```

## Create The Notification Config

After saving the algorithm, create a notification config that references the saved algorithm ID.

```js
import mbd from "algo-dsl";

export default async function notificationConfig() {
  return mbd
    .notification("dex-alerts")
    .algos([172])
    .webhook("https://your-app.com/webhooks/embed-notifications")
    .cooldown({ hours: 6, by: "user_id" })
    .priorityFilter("P0,P1")
    .dailyBudget(10000)
    .save();
}
```

Replace `172` with the saved algorithm ID from your Console account.

## Webhook Requirements

Your webhook should:

* Authenticate requests with a shared secret or signature.
* Treat payloads as idempotent.
* Use a stable key such as `user_id + item_id`, `user_id + signal_id`, or an event ID.
* Return `2xx` only after the notification is accepted.
* Log rejected payloads for debugging.

Example Express handler:

```js
app.post("/webhooks/embed-notifications", express.json(), async (req, res) => {
  const token = req.header("x-embed-webhook-token");
  if (token !== process.env.EMBED_WEBHOOK_TOKEN) {
    return res.sendStatus(401);
  }

  const event = req.body;
  await upsertNotification({
    idempotencyKey: `${event.user_id}:${event.item_id || event.signal_id}`,
    payload: event
  });

  return res.sendStatus(200);
});
```

## Delivery Controls

| Control                | Why it matters                                                          |
| ---------------------- | ----------------------------------------------------------------------- |
| Cooldown               | Prevents repeated notifications to the same user or about the same item |
| Priority filter        | Limits delivery to important candidates                                 |
| Daily budget           | Caps delivery volume                                                    |
| Webhook retry handling | Prevents duplicate user-visible notifications                           |

## Test Checklist

Before enabling production delivery:

* The algorithm preview returns notification candidates.
* Each candidate has a user identifier.
* Each candidate has a stable event, signal, or item identifier.
* Hydration includes fields needed by your webhook.
* The webhook accepts a test payload.
* Cooldown and budget settings are intentionally chosen.

## Next

* Build candidate algorithms in [Building Algorithms](../Algorithm/guide-building-algorithms).
* Use notification sources from [Supported Indices](../Algorithm/supported-indices).
* Review config functions in [Notification DSL Functions](./notifications-dsl-functions).