Errors
Every error this API returns, what it means and what to do about it.
Tool failures come back as a normal result with isError: true and the reason as text. Protocol-level problems come back as JSON-RPC errors.
| What happened | You get |
|---|---|
| Invalid, unknown, or revoked key | HTTP 401, body {"error":"unauthorized"} — no reason given |
| Key with no scopes at all | HTTP 403, body {"error":"no_scopes"} |
| Plan does not include the API | HTTP 403, nested body {"error":{"code":"tier_required","params":{"required":"studio",…}}} — unlike the flat bodies above, code and params sit inside error — API and MCP from Studio; change your plan at ikrames.com/pricing |
| Tool not in your scope | -32602 · "Tool generate_image not found" |
| An argument the tool does not define | -32602 · unrecognized_keys |
| A brand or asset outside your workspace | isError: true · "forbidden: …" |
| Not enough credits | isError: true · insufficient_credits: N noetig, M vorhanden |
| Too many requests | isError: true · rate_limited: in Ns erneut versuchen |
| File has no C2PA signature | isError: true · c2pa_unsigned: … |
The server's error text is German.
The strings above are quoted exactly as they come back, because that is what you would match on. The machine-readable parts — HTTP status, JSON-RPC code, isError — are language-independent, and those are what you should branch on.
Unknown arguments are rejected, not ignored. Send {"days": 7} to get_costs and you get an error, not a silent all-time total. This matters most for agents: a model that guesses a plausible argument name should find out it guessed wrong, rather than receive a plausible-looking answer to a different question.
Unknown and forbidden look identical on purpose. An asset that does not exist and an asset belonging to another workspace both return "forbidden: unbekanntes Asset". Telling them apart would let a caller map what exists by trying ids.