01What a data source is
One command, one web address, one value the bot reads out loud.
A data source is a web address you save once. When a viewer runs a command that quotes it, the bot calls that address, takes one value out of the answer, and says it in chat. Weather, a game stat, the queue length on your own server: if it answers over https and returns JSON or plain text, a command can read it.
sesame_sam !weather
ItsBagelBot It is 21°C in Montreal right now.
Behind that line is an ordinary custom command. Its response, as typed in the editor:
It is {urlfetch:weather}°C in Montreal right now.
The token names the source, not the value. Which value the bot pulls out is saved on the
source itself, as a path: an address inside the answer. The response is
the building, current is the floor, temperature_2m is the
door. Write it out with dots and you get current.temperature_2m. Section
three does that clicking for you, and the analogy can go home now.
Note Data sources are free on every plan. A premium channel is served by a different internal lane, and every cap on this page is the same for both.
02Add one from the command editor
Six clicks, without leaving the command you are writing.
Everything happens inside Commands, in the editor that docks beside your command list.
- Put the cursor where the value goes
Open a command, click into Response, and leave the cursor at the spot the number belongs in the sentence.
- Open the palette
Under the response, beside the
{user}and{args}pills, sits a chip labelled Data source. Its tooltip reads "Insert a fetched value from a saved API definition". - Start a new one
+ New data source opens the modal titled Add a data source: "Point it at any web API, fetch one real response, then click the value you want to show in chat."
- Name it and paste the address
Display name is for you. It auto-slugs into Definition name, which is the word that goes inside the token: "Lower-case letters, digits and underscores. Used inside {urlfetch:name}." Then Web address, https, up to 512 characters.
- Fetch one real response
Fetch a sample calls your API for real, about once every 10 seconds. If it answers in a shape the modal cannot read, take the link or paste a response instead and paste one in by hand.
- Click the value, then add the source
The answer becomes a tree under "Click the value you want to show in chat." Click
temperature_2mand the modal reads Showing current.temperature_2m. Add source saves it, and the palette row inserts{urlfetch:weather}at your cursor.
Point it at any web API, fetch one real response, then click the value you want to show in chat.
Lower-case letters, digits and underscores. Used inside {urlfetch:name}.
Click the value you want to show in chat.
- 01 Display name is the one you read in lists. It auto-slugs into the definition name below.
- 02 Definition name is the word inside the token: lower-case letters, digits and underscores, up to 32 characters.
- 03 Web address: https, absolute, up to 512 characters. The bot sends it exactly as typed, every time.
- 04 Fetch a sample makes a real request against your API. Roughly one test every 10 seconds.
- 05 Clicking a value saves its path on the source. "Use the whole response instead" switches to plain text.
Once a source exists, the same chip lists it. Every saved source shows its path so you can tell two weather feeds apart at a glance, and clicking a row drops the token where your cursor was.
Insert variable
- 01 The Data source chip sits with the token pills under Response, next to Counter.
- 02 Each row shows the path saved on the source, or "Plain text" when it prints the whole answer.
- 03 + New data source opens the modal without losing the command you are writing.
Tip A channel holds 20 definitions. Past that the editor says "You've reached the 20-definition limit for your channel. Delete one to make room." Deleting is a two-tap control, and the server names the commands that quote the source before it lets go: "These commands quote it. They lose this data if you delete:".
03Picking the value
A path is dots between steps. Click a value below and watch the token write itself.
This is the same tree the dashboard shows, with the same rules. Only values are
clickable; a branch like current holds other things, so it cannot be the
end of a path. Edit the response on the left and the tree follows, which is the fastest
way to rehearse your own API before you save anything.
Saved on the source
Token you type
Path spelled in the token
Chat would showcut here, 100 bytes
Plain text mode skips the path entirely. The bot trims the answer and shows its first 100 bytes.
| Rule | What it means |
|---|---|
| Dots between steps | current.temperature_2m opens current, then takes temperature_2m out of it. |
| Lists use bare digits | items.0.name is the first entry. Square brackets are not part of the grammar. |
| Depth | Up to 8 steps. Past that the tree refuses the value: "Deeper than 8 levels. Pick something closer to the top." |
| Each step | Letters, digits, underscore and hyphen, up to 64 characters each. |
| The end of the path | Lands on a value: text, a number, true or false. Stopping on an object, a list or an empty field counts as a broken definition, and chat gets the raw token. |
| A path inside the token | Wins over the one saved on the source. {urlfetch:weather.current.wind_speed_10m} reads a different value from the same address. |
| The name | Case-insensitive. {URLFETCH:Weather} and {urlfetch:weather} are the same source. |
| The value | Cleaned, trimmed, then cut at 100 bytes before it reaches chat. |
Tip
One saved address can feed several commands. Save
{urlfetch:weather} on current.temperature_2m for
!weather, then write
{urlfetch:weather.current.wind_speed_10m} in !wind.
Same source, same 20-definition budget, two different answers.
04APIs that need a key
Keys live on your account, sealed, and travel as an Authorization header.
Some APIs want a key before they answer. Add it once under Settings, on the API keys panel: a label up to 32 characters so you recognise it later, and the secret itself, up to 512 characters. The panel's own hint says it best: "Account-level secrets for data sources. Delegates can spend them, never read them."
The secret is sealed before it is written down and it is never shown back. You get the
label and the last four characters, which is enough to tell two keys apart when you
rotate one. When a data source is attached to a key, the bot sends it as an
Authorization: Bearer header on every fetch, and the address itself stays
clean.
In the "Add a data source" modal, the API key field only appears once you have at least one key on file. Until then it reads "No key needed", which is also the right answer for most public APIs.
Watch out Keep the key out of the Web address and out of the command response. An address is stored as text and anyone with dashboard access can read it, and a response goes to chat where everyone can. If your API only accepts the key as a query parameter, treat that key as public and rotate it on a schedule.
05Limits and timing
Everything is capped, and the cache does most of the work.
The numbers below are the live ones. You will meet the cache first: an answer the bot liked is reused for 30 seconds, so a command that runs 40 times in a minute still calls your API twice.
| Limit | The number |
|---|---|
| Definitions per channel | 20. |
| Data sources in one response | 3. The editor refuses to save a fourth. |
| Web address | https only, absolute, up to 512 characters. |
| Addresses refused | IP literals, localhost, and anything ending in .local or .internal. Checked when you save and again on every fetch. |
| Response size | 1 MiB, measured after decompression. |
| Content type | application/json or text/*. |
| Timeouts | The API gets 2.5 seconds, the fetch service 3 seconds, and the bot stops waiting at 3.5 seconds. |
| Cache | A good answer is held 30 seconds. A refusal, like a 404 or a path that found nothing, is held 15 seconds. An outage is not cached. |
| Requests per channel | 6 a minute, counted across every definition you own. |
| Requests per definition | 30 a minute. |
| Requests per API host | 120 a minute, counted across every channel pointed at that host. |
| Redirects | Up to 3 hops, each one staying on https. |
| A host that keeps failing | Five transport failures in a row and that host is rested for 60 seconds. |
| "Fetch a sample" | About one test every 10 seconds: "Too many test runs. Each one calls the real API. Wait about 10 seconds and try again." |
- Requests your API actually receives
- 2 per minute
- Answered from the 30-second cache
- 10 per minute
- Refused by the 6 per minute channel cap
- 0 per minute
Those runs print [source unavailable] in chat.
The cache exists for your API quota. Without it, one raid could spend a month of calls in an evening, and every other channel pointed at the same host would feel it too.
Note
Two seconds of the bot's patience is a long time in chat. If your API is slow, expect
[source timed out] during a busy stream and write the sentence so it still
reads if the number is missing.
06What chat shows when it fails
Four fallbacks, all short, all in English wherever your chat is.
A command never goes silent because of a data source. The rest of the sentence is sent and the value is replaced with one of four strings, so you can read chat and tell what broke.
| What happened | What chat shows |
|---|---|
| The API refused, it rate limited you, or the message is a replay of an older one | [source unavailable] |
| The API returned an error, or the path found nothing usable | [source error] |
| The API took longer than the bot waits | [source timed out] |
| The source is missing, paused, or the token names one that was never saved | The token, printed exactly as typed: {urlfetch:weather} |
sesame_sam!weather
ItsBagelBotIt is [source unavailable]°C in Montreal right now.
Your key was rejected, or the endpoint turned the request away. Test it in the dashboard and you get the same verdict: "The API refused the request. Check the key or the URL."
A cap was reached: 6 fetches a minute for the channel, 30 for this definition, or 120 a minute for that API across every channel using it. Nothing is broken and the next minute works again.
The bot waits 3.5 seconds and then speaks without the value. A slow API under load is the usual reason.
The path was fine but the answer had nothing at the end of it, usually because the API renamed a field. Open the source, fetch a sample, and click the value again.
A paused or deleted source has nothing to expand, so the token is printed as typed. The dashboard test says it plainly: "Definition missing or paused. Chat would show the raw token until it is active."
Three data sources in one response is the editor limit and it refuses to save a fourth. The bot keeps its own ceiling at eight and prints every token past it exactly as typed, like this one.
Note
These four strings are not translated. A French channel sees
[source unavailable] too, which keeps them searchable and keeps this page
honest about what your viewers will read.
07What it will not do
The edges, in one screenful, before you design a command around one.
-
The address is fixed when you save it.
{args}and{user}are left alone inside a web address, so a viewer cannot steer the request at your API. -
Requests are
GET, and headers are not yours to set. The one the bot adds isAuthorization: Bearer, and only when the source carries a key. - Tokens expand in custom command responses only, after the permission, live and cooldown checks have passed. A timer posts its text raw, and counters leave the token alone.
-
A replayed chat message never fetches twice. If the bot re-reads an older event,
chat gets
[source unavailable]rather than a second call to your API. - Private and local addresses are turned down at both ends: when you save, and again at fetch time.
Tip
Quote the same source twice in one response and the bot fetches once. Write
{urlfetch:weather} in the sentence and
{urlfetch:weather.current.wind_speed_10m} right after it: two
values, one request, one line of your quota.