API ReferenceErrors
Errors
Errors are JSON with an error message, and
sometimes a detail or
valid_options field with more context.
{ "error": "\"cyan\" is not a valid icon", "valid_options": [ "boxes", "rocket", … ] }
| 200 / 201 | Success. 201 for a create, 200 for everything else. |
| 400 | Missing or invalid fields in the request body. |
| 401 | Missing, invalid, or revoked API key. |
| 404 | The record doesn't exist, or belongs to a different account. |
| 409 | Blocked: another record still depends on this one (e.g. deleting a category still used by an item), or an invoice is no longer in the state the write requires. |
| 422 | Blocked by content moderation — the same safety check the main app and Flus AI use on every write. |
| 429 | Rate limit exceeded: 100 requests/minute per key. |
| 502 | An upstream service (data storage, or PDF generation) failed. Safe to retry. |
Why a write got rejected
400/404/409 all mean "your request was well-formed but can't be applied right now" — the difference is why. 400 is a bad shape (wrong type, missing required field). 404 is a bad reference (wrong id, or an id that belongs to someone else's account — both look identical on purpose, so a guessed id never confirms whether a record exists). 409 is a bad moment: the fields were fine, but another record still depends on this one, or the resource is in the wrong state (an invoice that's already Paid, for instance).
Best practices
- Surface
errordirectly to end users where reasonable — the messages are written in plain language on purpose, not internal jargon. - Treat
502as retryable (with backoff) and everything else as not — a 400/404/409/422 won't succeed on retry without changing the request itself. - When you get a
valid_optionsarray, use it to build your own dropdown/validation instead of hardcoding a copy — it reflects the current live enum.
Common mistakes
- Don't treat every non-2xx the same. A blanket "retry on any failure" loop will hammer a permanently-blocked 409 forever instead of surfacing it.
- Don't parse
errorstrings to branch your code — wording can change; branch on the HTTP status code instead, and useerror/detailonly for logging or display. - Don't assume a 404 means "never existed." It's also what you get for a real id that belongs to a different company's key — useful to know when debugging a "missing" record that you're sure you created.