9Login API: requests and errors#
How to call the 9Login API: the address, the key, the shape of every answer, the error codes and the limits. The endpoints are listed by group on the pages that follow.
Quick start#
Every endpoint lives under http://127.0.0.1:37286 and needs the key shown on the API & MCP screen of 9Login in an Authorization header: Authorization: Bearer <key>. Reads are GET with parameters in the query; writes are POST with a JSON body.
9Login must be open and signed in, on a paid plan. Calls run with the permissions of the account signed in to this app.
The examples use curl in a POSIX shell (macOS, Linux, Git Bash). In Windows PowerShell call curl.exe, and put the JSON body in a file passed with -d @body.json.
Key and safety#
The key is 32 hex characters, one key for the endpoints below, the events WebSocket and MCP.
Send it in the Authorization header of every request: Authorization: Bearer <key>. A key in the URL is refused, except on the WebSocket, where browsers cannot set headers: there ?key= works too. A missing or wrong key answers 401 badKey.
With Require Auth off, every request runs without a key. Requests sent from a web page are always refused, so a site you visit cannot call the API. With Local only on, only 127.0.0.1 and localhost are accepted as the Host as well; with it off (the default), any host or IP is accepted, so a firewall rule or port forward can expose the port to other machines, and the key is then the only lock: keep Require Auth on.
Anyone holding the key can create, start and (when allowed) delete profiles of this account on this machine. Do not paste it anywhere public; if it leaks, make a new key.
The settings and the key belong to the 9Login account that turned the API on. When another account signs in on this computer, the API turns off and the key is cleared; turning it on again makes a new key.
Responses and errors#
Success is { "ok": true, "data": ... } with HTTP 200. A refusal of the whole request is { "ok": false, "code", "message", "details"? } with the status below. code never changes meaning; message is for people.
Endpoints that work on many profiles answer 200 and list per-profile refusals in failed, each with id, code and message (second table).
A call that succeeded can also carry warnings: [{ code, message, ids }], present only when there is something to point out. scriptOnRestore (create and update): the profiles have a script and onStartup "restore", so the browser reopens the last session first and the script starts on a restored tab. Use "custom" with a url when the run depends on the script. earlierRunLogs (exec): an earlier run on the profile passed its timeoutSec and was still going, so logs may include lines it printed; a run that fails carries it in details.warnings. noSetResult (add-script, proxy update, test-script): the proxy script never calls SetResult, so every start that uses it fails once its time runs out.
| Code | HTTP | Meaning |
|---|---|---|
badKey |
401 | The key is missing or wrong. Send it as Authorization: Bearer <key>. |
badHost |
403 | Local only is on and the request was not sent to 127.0.0.1 or localhost. |
planRequired |
403 | The plan does not include the API (or a field asked for a feature the plan lacks). |
notSignedIn |
403 | 9Login is not signed in. |
permissionDenied |
403 | This sub-user may not do this. |
toolsetOff |
403 | A switch on the API & MCP screen is off (Allow changes, Allow deleting, Allow automation). |
invalidParams |
400 | A field is wrong; details lists each one with its path. |
invalidJson |
400 | The body is not valid JSON. |
unsupportedMediaType |
415 | A POST body was sent without Content-Type: application/json. |
notFound |
404 | No such endpoint, or nothing with this id (profile, proxy, extension, script, task, task run or job). |
methodNotAllowed |
405 | Wrong HTTP method for this endpoint. |
profileRunning |
409 | The profile is not fully stopped. |
fpBudget |
409 | Not enough new fingerprints left for the last 30 days; details has left and freesAt. |
quota |
409 | The plan has no room for more (profiles, proxies, extensions, scripts or tasks). |
conflict |
409 | The same data was changed elsewhere first. For a script, details.server has the account's version: get it again and retry, or pass overwrite true. For the proxy list and the task list, call again with onConflict "reload". |
notRunning |
409 | The profile has no running browser. |
noWindow |
409 | The browser has no visible window yet, or it runs hidden. |
inSync |
409 | The profile is in a Sync control session, which fixes its window size. |
busy |
429 | Too many requests or jobs at once, or the task already has a run going. |
unsupportedPlatform |
501 | This feature does not exist on this operating system. |
macroError |
422 | The macro failed in the browser: it threw, its tab closed, or it did not finish in time. message has the error, details.logs what it logged. |
browserError |
502 | The browser did not answer, or refused the request. The message says why. |
serverUnreachable |
502 | The 9Hits server could not be reached. |
serverError |
502 | The 9Hits server refused the write. |
internal |
500 | 9Login hit an error. |
Per-profile results#
Codes found in failed[] of the commands and jobs that work on many items: profiles, proxies, cookies, cloud data, extensions, scripts and windows. Each entry carries its id (or the install source) and a message that says more.
| Code | Meaning |
|---|---|
notFound |
Nothing with this id: profile, proxy, extension, script or install source. |
profileRunning |
The profile is not fully stopped. Stop it first. |
fpUnavailable |
The fingerprint of this profile could not be loaded from the server. Try again. |
lockedElsewhere |
The profile is open on another machine or by another member. |
permissionDenied |
This sub-user may not do this to this item. |
planExpired |
This sub-user account is suspended. |
planRequired |
The current plan does not include this. |
overLimit |
The profile is outside the number of profiles the plan can run. |
serverUnreachable |
The 9Hits server could not be reached. |
serverError |
The 9Hits server refused the request. |
updateNeeded |
This app needs an update before it can open profiles. |
notAuthorised |
The server did not authorise this launch. |
cloudNewer |
The cloud has newer browser data than this computer. Start: pass cloudNewer; upload: pass overwriteNewer. |
launchFailed |
The browser could not be launched. |
quota |
The plan has no room for more: profiles, list entries, or cloud storage. The message says which. |
fpBudget |
The limit of new fingerprints for the last 30 days is reached. |
conflict |
Another machine changed it first. Read it again and retry. |
identityChange |
This change gives the profile a new fingerprint and it already has browsing data. Pass confirmNewIdentity true to do it anyway. |
failed |
It could not be done. The message says why. |
refused |
This item was refused. The message says why. |
inUse |
It is still in use. The message says by what. |
duplicate |
Another entry already has the same endpoint and credentials. |
exists |
It is already installed. Pass replace true to install over it. |
notRunning |
The profile has no running browser. |
noWindow |
The browser has no visible window yet, or it runs hidden. |
tooBig |
It is larger than allowed. The message says which limit. |
noLocalData |
This profile has no browser data on this computer. |
noCloudData |
The cloud has no browser data for this profile. |
undecryptable |
The cloud copy could not be decrypted with this account's key. |
dataBusy |
An upload or download of this profile's data is already queued or running. |
localNewer |
This computer has browser data newer than the cloud copy. Pass overwriteLocalNewer true to replace it anyway. |
badSource |
The source is not a Chrome Web Store id or URL, nor an absolute local path. |
downloadFailed |
The download from the Chrome Web Store failed. |
noStoreBuild |
The Chrome Web Store has no build of this extension for this browser version. |
badPackage |
The file is not a valid Chrome extension package. |
writeFailed |
The extension could not be written to disk. |
Limits#
| What | Limit |
|---|---|
HTTP |
HTTP/1.1; a body needs a Content-Length header (chunked bodies are not supported) |
| Request body | 4 MB |
| Requests running at once | 64 (more answer busy) |
| Start jobs running at once | 5 (more answer busy; one start takes up to 500 ids) |
| Upload and download jobs running at once | 2 together (more answer busy) |
| Proxy check, proxy script test and extension install jobs | 1 of each at a time (more answer busy) |
| Proxy script | 16 KB (UTF-8); a start waits 120 seconds for it to call SetResult |
| Profile ids per call | 500 (download: 250) |
| Profiles per create, copies per duplicate | 100 |
| Proxy ids per call | 1000 |
| Script or extension ids per delete | 200 |
| wait on jobs | 100 seconds |
| Finished jobs kept | 30 minutes |
| WebSocket connections | 32 |
| MCP messages per request | 1 (a batch only from clients on 2025-03-26) |
| Macro run (exec) | timeoutSec 60 by default, at most 110; code up to 512 KB |
| Automation calls per profile | 1 at a time; a call that arrives meanwhile waits up to 15 seconds, then answers busy |
| Task runs at once | 3 on this computer (more wait their turn); 1 per task |
| Task run history | the last 50 runs of each task, on this computer only |
| Task list | stored in the account as one list, like proxies: 1000 tasks on a paid plan, up to 2000 hand-picked profiles per task, 512 KB compressed in all |