Modulify

Errors

Every status code the API answers with, what causes it, and what to do about it.

On this page

A call that does not succeed comes back with success set to false, an HTTP status code of 400 or above, and a message that says what went wrong in plain English. The status code is repeated in the body as code, so your code can branch on either.

{
  "success": false,
  "message": "The \"workspaceId\" argument is required!",
  "data": null,
  "code": 400,
  "version": "0.0.1740"
}

Read the message before you retry. It usually names the argument, scope or limit at fault.

Every status code

Code Meaning What to do
400 The request itself is wrong: the body, an argument, or a header Fix the request. Repeating it unchanged gets the same answer
401 No token, or a token that is invalid, revoked or expired Check the Authorization header, or create a new token
402 The workspace has no AI credits left for this work Add credits or change the plan, then try again
403 The token or your role may not do this here, or a plan or site limit stops it Read the message. Add the scope, use another workspace or raise the limit
404 No method by that name, or the thing an argument points at does not exist Check the method name and the ids you sent
405 A method's address was called with something other than POST Send a POST
409 The same work is already running Wait for it to finish, then read the result
413 The body is larger than 150 MB Send less in one call
422 The request is well formed, but the method or the idempotency key refuses it Read the message. Repeating it unchanged gets the same answer
429 Too many calls for now, or a queue or quota is full Wait, then try again. See below
500 Something went wrong on Modulify's side Try again after a pause, with an Idempotency-Key for writes

400: the request is wrong

The body and the arguments are checked before a method runs, and the message names what is wrong:

  • The body is not a JSON object, or is not valid JSON.
  • The body is nested more than 64 levels deep.
  • An argument holds a list of more than 10,000 items.
  • An argument the method does not take, such as a misspelt name.
  • A required argument is missing, null or an empty string.
  • An argument has the wrong type, such as a number where text is expected, or a fraction where a whole number is expected.
  • A text argument is longer than the method allows, or a list holds more items than it allows.
  • A value is not one of the ones the method accepts. The message lists the allowed values.
  • A value deeper inside an argument does not match what the method expects. The message gives its path, such as items[0].key.
  • The Idempotency-Key header is not 1 to 255 visible characters.
  • The address contains an access token. Revoke that token. See Authentication.

A method can also answer 400 for a value it cannot use, such as a name that is already taken or a date in the wrong format. Its page describes those cases.

401: the token

Message What it means
"An access token is required. Send it in the Authorization header as Bearer followed by the token!" No token arrived, or the header was empty
"This access token is invalid, revoked or expired!" The value does not match a live token

Both carry a WWW-Authenticate header. A 401 never succeeds on a retry: fix the header or create a new token.

402: no credits

Work that spends AI credits is refused when the workspace has none left, for example send_message with an empty balance. Nothing ran and nothing was charged. See Credits.

403: not allowed here

A 403 has several causes, and the message says which:

  • A missing scope. The message names the scope the token needs. Edit the token on the Tokens page to add it, and the change reaches every client already using it.
  • A workspace the token cannot reach. Either the token was narrowed to other workspaces, or the site or workspace you pointed at is not one of yours. list_workspaces shows where the token can work.
  • Your role. Your role in that workspace does not hold the API access permission. A workspace owner can grant it. See Members and roles.
  • A plan or site limit. Some methods refuse when the workspace is over a limit, and say why in data. For example create_site answers with data.reason set to site-limit-reached with the current count and limit, or credits-limit-reached.
  • A locked site. A site over the plan's site limit cannot be changed until the workspace upgrades or frees a slot.

404: not found

The method name is not one of the methods, or an id you sent does not match anything you can reach. For an unknown method the message reads, for example, There is no tool called "list_site". GET /v1/tools lists the tools this token can use!. Method names are lowercase with underscores, exactly as on their pages.

409: already running

The same work is in flight and cannot start twice:

  • A call with the same Idempotency-Key is still running. Wait, then send it again to get its answer. See Idempotency and retries.
  • The method found the site busy, for example run_site_cron on a scheduled job that is already running.

422: refused as it stands

  • The Idempotency-Key was already used with a different method or a different body. Use a new key for a new request.
  • The method understood the request but will not carry it out, for example trigger_deploy_hook when the publish it would start is refused. The message gives the reason.

429: slow down

Two different limits answer 429:

  • The token's per-minute budget. Every token may make 240 method calls a minute, shared with any MCP client using it. The answer carries Retry-After with the seconds until the minute ends. Wait that long.
  • A quota on the work itself. For example a site's chat queue holds at most 20 waiting messages, and the analytics methods share 1,200 lookups per site per hour. The message names the quota. Waiting for the queue to drain or the hour to pass is the fix, not retrying.

See Rate limits.

500: something broke

The call failed on Modulify's side. A read is safe to repeat after a short pause. A write may or may not have happened, so repeat it with the same Idempotency-Key you sent the first time, or read the current state before sending it again. If it keeps failing, contact support with the X-Request-Id of the call.

Details in data

A refusal can carry more than a message. When a method has something to add, it is in data:

Method What data carries on a refusal
create_site reason, plus sitesCount and siteLimit when the plan is full
send_message code, a site chat error code

How to retry

Code Retry?
400, 401, 403, 404, 405, 422 No. Change the request first
402 After adding credits
409 After the running work finishes
429 After Retry-After, or after the quota frees up
500 Yes, after a pause, with the same Idempotency-Key for writes

Next