Skip to main content
Two different things can fail, and they look nothing alike. The call can be rejected before your API ever runs: a bad key, a function id that is not yours, a malformed body. Those come back as a non-2xx with an error envelope. The run can fail while your API is executing. Those come back as HTTP 200. The traceback is in the body.
A failed run returns 200 and "status": "closed", exactly like a successful one. status is not a verdict, it only means the run is over. Never branch on the HTTP code alone.

Telling a good run from a bad one

Look at the type of result. On success it is an object matching the API’s declared schema. On failure it is a string.
A one-line check in any language: if result is not an object, treat the run as failed and log the string.

Status codes

Every error envelope carries an X-Error-Class response header naming the exact class that fired. Quote it when you ask for help, it is far more precise than the status code.

307, and why the call needs two headers

The endpoint answers 307 and redirects to the runner, which lives on a different host. Clients drop Authorization across hosts but keep custom headers, so the key has to travel twice:
Drop --location and you get a 307 and no result. Drop x-notte-api-key and you get a 422. Send a different value in it than the bearer token and you get a 400. The SDKs handle all of this.

401 Unauthorized

Three different situations share this code. No Authorization header at all returns the bare shape, with no envelope:
A key that is wrong, revoked, or from another environment returns X-Error-Class: NotteApiInvalidApiKeyError. The key is masked in the message, which is a useful way to confirm which key your process actually loaded:
A plan limit also returns 401, not 402: Free plan limit exceeded. Please upgrade your plan to continue using Notte. If a key that worked an hour ago starts failing, read the message before assuming the key is bad. See Billing.

404 Function not found

X-Error-Class: InvalidFunctionAccess. Existence and ownership are deliberately not distinguished, so this is also what you get for someone else’s unpublished API. Check the id on the API’s page.

422 Unprocessable

Validation errors use a different body from the rest, and they name the exact field in loc:
Common causes, in order of frequency:
  • ('header', 'x-notte-api-key'): the second auth header is missing.
  • ('body', 'variables'): variables is required. Send {} when the API takes no inputs.
  • ('body', 'function_id'): the id goes in the body as well as the path.
A 422 can also mean the API reads a secret your workspace has not set. That one is written out in full, names every missing key, and tells you nothing was charged because no session started. See State and secrets.

429 Too many requests

Two limits produce this. Per-caller rate limit on APIs you do not own. Marketplace APIs are rate limited per caller, so one heavy consumer cannot exhaust someone else’s listing. Back off and retry. Active resource limits. Your plan caps concurrent browser sessions. The message states the limit and the current count. Wait for runs in flight to finish, or upgrade.

When the site changed

A traceback that reads like the page moved, rather than like a bad input, is the case self-healing exists for. The thread that built the API wakes up, re-maps the site, and deploys a fix, usually within minutes. Retry once before you rebuild anything. Self-healing only fires on a returned traceback. A wrong variable name is your side of the contract and will never heal on its own.

Before you ask for help

  1. Confirm the base URL is https://api.notte.cc and the path is POST /functions/{function_id}/runs/start.
  2. Cheap credential test: GET https://api.notte.cc/functions?limit=1 with the same key. A 200 there and a failure on your call means the problem is the request, not the key.
  3. Capture the X-Error-Class header and the function_run_id.
  4. Open the run in the Runs tab of the API’s page. Failed runs keep their session recording, so you can watch what the browser actually saw.
Still stuck: support@notte.cc, with the function_run_id.