Errors
Every failure answers the same envelope with a stable code. Here is the complete set the API can send, and what each one means you should do next.
The envelope
Every non-2xx response carries this shape, and nothing else. The code is the contract — it is stable, and it is what your integration should branch on. The message is written for a human reading a log and may be reworded at any time.
{
"error": {
"code": "unauthorized",
"message": "Provide a valid API key as an 'Authorization: Bearer wb_live_...' header.",
"docs_url": "https://webbuddy.radioworkflow.com/docs/errors#error-unauthorized"
}
}Every code
| HTTP | code | Retry? | When | What to do |
|---|---|---|---|---|
| 401 | unauthorized | Do not | No usable API key on the request. The Authorization header was missing or malformed, the token did not match any key, the key has been revoked, or the key's site is no longer active. | Check the header is exactly Authorization: Bearer wb_live_…. If it is, the key was probably revoked — mint a new one on the site's API tab. Do not retry: nothing about this request will succeed on a second attempt. |
| 403 | insufficient_scope | Do not | The API key is valid, but does not carry the scope this endpoint requires. Scopes are chosen when a key is created and cannot be changed afterwards. | Mint a new key on the site's API tab with the required scope ticked, then revoke the old one. Do not retry: the same key answers 403 forever. The message names the scope that was missing. |
| 429 | rate_limited | Retry | The key exceeded 120 requests in the current 60-second window. The same code also answers a caller that has presented too many tokens which do not resolve — that brake is counted per network address rather than per key, because a request nobody can attribute to a key has no key bucket to charge, and looking a bad token up still costs a database call. | Back off and retry — the window is at most 60 seconds long, so an exponential backoff starting around a second will clear it. If you hit this steadily, cache the responses you poll rather than raising your request rate. If the message mentions failed authentications, fix the key first: retrying the same bad token is what filled that bucket. |
| 500 | internal_error | Retry | The request failed inside the server. The cause is never disclosed to the caller — the wrapper swallows the exception so a stack trace cannot reach an API consumer. | Retry once after a short delay. If it persists for a given endpoint, it is a bug on our side rather than something your request can fix; report it with the endpoint and the time. |
That is the whole set — 4 codes, 4 of which come from the wrapper every endpoint shares rather than from any one handler. Every endpoint can therefore answer all of them, and each endpoint page lists its own on top. There is deliberately no not_found and no invalid_request here: the API does not emit them. A code published but never sent is a branch you would write and never run.
There is no error code for a bad query parameter, because the API does not reject one. A value above or below a documented range is clamped to the nearest allowed one, and a value that is not a number falls back to the default — both answer 200. Nothing in the response says the value was changed, so a success is not confirmation that the API used what you sent. Every endpoint page publishes the ranges; validate on your side if the exact window matters.
Handling them in code
This is the generated sample from Get the site — the same handling every endpoint page hands you. Two details in it are deliberate: it checks the content type before parsing, because a proxy or framework error never reaches the API and answers HTML rather than the envelope above; and the Python version does not use raise_for_status(), because that discards the body and the body is where the code lives.
curl 'https://webbuddy.radioworkflow.com/api/v1/site' \ -H "Authorization: Bearer wb_live_your_key_here"
Rate limits, the base URL and the endpoint index are on the API overview. What may change inside v1 without warning is on the versioning page.