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,
nullor 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-Keyheader 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_workspacesshows 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 examplecreate_siteanswers withdata.reasonset tosite-limit-reachedwith the current count and limit, orcredits-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-Keyis 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_cronon a scheduled job that is already running.
422: refused as it stands
- The
Idempotency-Keywas 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_hookwhen 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-Afterwith 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
- Rate limits for the budget and the headers that report it.
- Idempotency and retries for repeating writes safely.