---
title: "Agent notes: streams and longpoll"
description: "Gotcha notes for AI agents wiring up AudD stream monitoring — the account-wide callback URL, stream URL shortcuts, the longpoll callback-URL requirement, and notification codes."
slug: "/resources/agents/streams"
section: "agents"
keywords: [audd, streams, longpoll, callback, agent, addStream, notifications]
---

# Agent notes: streams and longpoll

Terse gotchas for an agent monitoring live audio with AudD streams. The
streams API lives on `api.audd.io` and works by callback: you register a
stream, AudD recognizes songs as they play, and it POSTs results to a URL
you set. Read these before you write the integration.

## 1. The callback URL is set once, per account — not per stream

`setCallbackUrl` sets **one** URL for the whole account. Every stream you
add delivers to that same URL. There is no per-stream callback URL.

```bash
curl -s https://api.audd.io/setCallbackUrl/ \
  -F api_token=your-api-token \
  -F url=https://yourwebsite.com/callbacks_handler/
```

> **Don't call `setCallbackUrl` on every `addStream`.** Set it once at
> setup. Calling it again just overwrites the account-wide URL — which
> silently redirects callbacks for *all* existing streams, not only the new
> one. Route per-stream by the `radio_id` in the callback body instead.

## 2. `addStream` accepts direct URLs and three shortcuts

`addStream` (with the `url` parameter) takes:

- **Direct stream URLs** — HLS, Icecast, `.m3u` / `.m3u8`, plain MP3
  streams, etc.
- **`twitch:<channel>`** — e.g. `twitch:monstercat`.
- **`youtube:<video_id>`** — e.g. `youtube:5qap5aO4i9A` (a specific live
  video).
- **`youtube-ch:<channel_id>`** — e.g.
  `youtube-ch:UC3zwjSYv4k5HKGXCHMpjVRg`, the channel's *current* live
  stream.

Use the shortcut form for Twitch/YouTube rather than pasting a watch URL —
the shortcut is what the API resolves.

## 3. Longpoll still needs a callback URL configured

This is the gotcha that makes agents think longpoll is broken. `GET
https://api.audd.io/longpoll/` lets you pull results without running a
public web server — but it **only works if the account already has a
callback URL set**. No callback URL, no results in longpoll, no error that
explains why.

> **Set the callback URL even when you only use longpoll.** Point it at the
> no-op receiver `https://audd.tech/empty/`, which always returns
> `200 OK`. Then longpoll delivers.

```bash
# one-time setup, even for a longpoll-only integration
curl -s https://api.audd.io/setCallbackUrl/ \
  -F api_token=your-api-token \
  -F url=https://audd.tech/empty/
```

Treat longpoll as a way to *consume* the stream-monitoring you set up — it
groups with streams, it is not a standalone feature. If a song never shows
up in your longpoll loop, check the callback URL first.

## 4. A callback body carries a result OR a notification, never both

Each POST to your callback URL is one of two shapes. Branch on which key is
present.

A **result** callback carries a recognized song:

```json
{ "status": "success", "result": { "artist": "...", "title": "...", "song_link": "..." } }
```

A **notification** callback carries a stream-health event — no song:

```json
{
  "status": "-",
  "notification": {
    "radio_id": 3,
    "stream_running": false,
    "notification_code": 650,
    "notification_message": "Recognition failed: can't connect to the audiostream"
  },
  "time": 1587939136
}
```

Notification codes you must handle:

| Code | Meaning |
|---|---|
| `0` | Everything's fine |
| `650` | Can't connect to the stream — the URL is dead or unreachable |
| `651` | Connected, but only white noise / no music coming through |

> **Don't assume every callback has a `result`.** Code that reads
> `body["result"]` unconditionally throws on every `650` / `651`
> notification. Check for the `notification` key first; surface `650` (fix
> or re-set the stream URL) and `651` (the source isn't playing music)
> rather than crashing on them.

## 5. `callbacks="before"` flips delivery to song start

By default a result callback fires when a song **ends**, and includes the
total time the song streamed. Pass `callbacks=before` to `addStream` to
fire **as soon as a song starts** instead.

```bash
curl -s https://api.audd.io/addStream/ \
  -F api_token=your-api-token \
  -F url=twitch:monstercat \
  -F callbacks=before
```

Trade-off: with `callbacks=before` you get the match earlier but you do
**not** get the total played time in the callback (the song hasn't finished,
so there's nothing to total). Pick `before` for now-playing displays, the
default end-of-song for play-duration logging.

## 6. The test token does not work on streams

`api_token=test` is standard-endpoint only (10 requests/day). It does not
work on `setCallbackUrl`, `addStream`, or `longpoll`. There's no
hello-world shortcut for streams — use a real token from
[dashboard.audd.io](https://dashboard.audd.io) from the first call.

---

**Related**

- [Callbacks vs. longpoll](/resources/concepts/callback-vs-longpoll)
- [Standard vs. enterprise vs. streams](/resources/concepts/standard-vs-enterprise-vs-streams)
- [Recipe: now-playing widget](/resources/recipes/now-playing-widget)
- [Streams (API reference)](https://docs.audd.io/streams)