Aller au contenu

Cette page n’existe pas encore dans votre langue. Vous lisez le texte anglais.

Automation

Local API, keys and webhooks

The interface for your own programs lives on your computer and is switched on from the For developers screen: a port on 127.0.0.1, its own token and 26 routes. On our server there are separate keys with rights, and subscriptions that call your server when something happens.
50325
Default port on 127.0.0.1
26
Routes in the local API
8
Scopes a server key can carry
13
Events a webhook can carry

Where the API runs

The local API is a small web server inside the desktop app. Your own programs on the same machine call it over loopback and get an answer.

Everything it works with is on your disk: profiles, cookies, the engine and the proxy bridge. With the network down your scripts keep calling, and the app works offline for 24 hours.

  • Drive profiles from your own code

    List, create, start, stop and delete them without touching the window.

  • Attach Puppeteer, Playwright or Selenium

    You get back the debugging endpoint for that exact profile.

  • Run saved flows from outside

    Your own scheduler or build server can start a flow over named profiles.

  • Let an AI client act

    Through the bundled MCP server an AI client takes these same routes, and the API has to be on.

The switch and the token

The API is off until you turn it on, because enabling it opens a port. On first run the app writes itself a random token, 24 bytes shown as 48 characters, into a file only your account can read.

You can send the token three ways: as a parameter in the address, as a header, or as a bearer credential. Regenerate it and every script carrying the old one stops, so the app asks you to confirm.

  1. 1

    Open the For developers screen

    It shows the switch, the address, the token and the list of routes.

  2. 2

    Click Enable local API

    You should see Running, and if the usual port was busy the panel names the one it took.

  3. 3

    Copy the address and the token

    The panel offers a ready command line with your own token already in it.

  4. 4

    Point your script at it

    Every call you make except the status route carries the token, and a wrong one gets you 401.

The For developers screen in ARMANOS: the enable switch, the local address, the access token and the list of routes.
The app interface is in English. The same screen carries the config block for an AI client.

Why a page cannot call it

Binding to loopback sounds like a boundary. It is not one: the pages you visit run on this same computer, so they can reach that address as well.

So a page in your browser cannot reach it: the app recognises a call like that and refuses. A domain name pointed at loopback does not help either: it arrives under its own name and is turned away.

Even the status route sits behind that check

The status route needs no token, because your script has to be able to ask whether the app is up. It answers with the product and its exact version, and for an antidetect browser that fact is worth hiding. From a page it does not answer either, so a site learns nothing.

Routes and one envelope

An answer carries three fields: a code, the payload and a message. The code is 0 on success, and on a refusal you get the reason. The one exception is the call asking whether the API is up: it answers in a short form of its own, without the payload and message fields.

Branch on the code in the envelope rather than on the HTTP status: the status carries refusals at the door, while a refusal on the merits comes back as 200 with a non zero code. A body over a megabyte is not trimmed: it gets 413 with payload_too_large, and loading cookies, a one-time profile and import take up to 16 MB.

Call
curl -H x-api-token:YOUR_TOKEN http://127.0.0.1:50325/api/v1/browser/list
Envelope
{ code: 0, msg: success, data: { list: [ ... ] } }
One profile
profileId, name, scenario, group, fingerprintTemplate, tags, notes, status, lastUsedAt, launches, runTimeMs, running
Its proxy field
protocol, host, port. Never the login, never the password
Wrong token
HTTP 401, { code: -401, msg: unauthorized }
Called from a page
HTTP 403, { code: -403, msg: forbidden }

On a path it does not know you get 404. You can also send the token as a query parameter or as a bearer credential.

RouteMethodWhat it does
/statusGETSays the app is up and names its version. The only route with no token.
/api/v1/browser/listGETYour profiles, each with the state it is in now.
/api/v1/profile/listGET, POSTThe same set with filters, order and pages; POST takes a long list of ids in the body.
/api/v1/profile/quickPOSTCreates a one-time profile and opens it; it is deleted when it closes.
/api/v1/browser/startPOSTOpens a profile and answers with its debugging endpoint. A profile pinned to a kernel this computer does not have is not opened and answers kernel_missing, or kernel_builtin when the built-in engine is chosen or ARMANOS Browser did not start.
/api/v1/browser/stopPOSTCloses every window of a profile and says how many.
/api/v1/browser/activeGETThe ids of the profiles open at this moment.
/api/v1/profile/createPOSTCreates a profile through the same quota gate as the window. Without presetId the default template of this computer fills it, and what the body sends wins; presetId none makes it without a template. A template that cannot be used answers preset_not_found, preset_no_free_proxy or preset_password_needs_account.
/api/v1/profile/updatePOSTChanges only the fields you send, through the same checks as the window. Where this app version cannot change an account profile's hand-picked values or kernel, it answers fp_edit_paused.
/api/v1/profile/deletePOSTMoves a profile to the recycle bin.
/api/v1/profile/unlockPOSTOpens a profile closed with a password, for one launch or until ARMANOS closes.
/api/v1/profile/lockPOSTCloses a password-protected profile again at once.
/api/v1/profile/passwordPOSTSets or changes the password of a profile.
/api/v1/profile/password/removePOSTRemoves the password, given the current one.
/api/v1/profile/codeGETThe current one-time code for a profile with a 2FA key stored.
/api/v1/profile/cookiesGETCookies of one profile, as JSON or Netscape text.
/api/v1/profile/cookies/exportPOSTCookies of up to 100 profiles, with an answer for each.
/api/v1/profile/cookies/importPOSTLoads cookies into a profile, open or closed.
/api/v1/profile/exportPOSTSettings in the answer or full archives with the session, up to 100 profiles.
/api/v1/profile/importPOSTBrings profiles back from settings or archives, with an answer for each.
/api/v1/proxy/listGETHosts, ports and usernames from the saved library with the last check result, never the passwords.
/api/v1/preset/listGETTemplates of this computer: the id for presetId in profile/create and which one is the default.
/api/v1/flow/listGETSaved automation flows with the number of steps in each.
/api/v1/flow/runPOSTRuns a flow over the profile ids you name.
/api/v1/app/stateGETWhether the program is signed in and as whom, the engine, open profiles and the video card.
/api/v1/app/loginPOSTSigns the program in with a Dashboard code, email and password, or an account key.

Starting a profile from code

You can pass the profile id in the body or in the query string: both examples below use the query string, and neither has to be rewritten. Ask for a run without a window, or send nothing and the profile's own setting decides.

Three engines, three answers

What comes back depends on the engine. On the ARMANOS Browser each profile gets its own debugging endpoint, isolated from every other profile.

  • ARMANOS Browser engine

    A port and a socket address for this profile only. Attach your automation library straight to it.

  • Built-in engine

    One shared port for the whole app, named in the answer with a warning that it is shared.

  • Neither available

    You get an answer saying no endpoint is open and why, rather than an empty field.

The same gate as buttons

The API is not a side door. A profile you create by call goes through the same licence and quota check as one created by the button, and without a licence neither of them starts.

Run a flow and you get back the ids the app does not know, and if it takes no profile into work at all, that is a refusal rather than a success.

Deleting through the API is a soft delete

Deleting through a call puts the profile in the recycle bin and frees your quota slot. Nothing goes from your disk, and you restore the profile from the window.

Server keys and their scopes

The token above drives one installation on one computer. A server key is a different thing: it talks to our server from anywhere, and it never opens a browser window.

You see a key once, at creation, and we keep only enough of it to tell your keys apart. Keys belong to the paid plans, you may hold 20 live ones, and a change of plan reaches a key within a minute.

ScopeWhat it opens
profiles:readThe profile list, and searching it with filters, order and pages.
profiles:writeCreate, edit and delete a profile.
browser:runMark a profile open or closed on the server, without the right to edit it.
proxies:readThe saved proxy list, without passwords.
proxies:writeCreate, edit and delete a proxy, if the member's role allows it.
flows:readThe list of saved automation flows.
logs:readWhat the Actions, Profile sessions and IP log tabs show, and the suspicion rules.
app:signinSign the ARMANOS program in on a server, as a device that takes a seat. Not ticked by default; a sign-in with a key cannot issue keys, change the password or touch billing.

Webhooks to your own server

A webhook is our server calling yours when something happens in your workspace. Subscriptions are created by a person signed in with a password, never by a key, and a new one asks for the password again, and for the two-step code if it is on. You may keep up to ten.

Each call is signed, and fields whose names look like a credential never reach your receiver. An invite code or a password reset link never leaves for a third party server.

  • Profiles

    profile.create, profile.update, profile.delete, profile.start, profile.stop, profile.transfer.accept

  • Proxies

    proxy.create, proxy.update, proxy.delete

  • Keys

    apikey.create, apikey.revoke

  • Team

    team.invite, team.remove

  • Money

    plan.change

What a delivery looks like

Delivery is honest about failure: three attempts, retried on a server error, on a too many requests refusal and when no answer came at all, and you see the last status on the subscription itself. After fifteen failures in a row the subscription switches itself off.

Method
POST, Content-Type application/json
X-Armanos-Event
profile.start
X-Armanos-Timestamp
Unix seconds, also part of the signature
X-Armanos-Signature
sha256=... HMAC of timestamp and body
Body
{ id, event, createdAt, data }
Delivery
At least once. Keep the id and drop repeats

Redirects are not followed, because an answer pointing back at loopback would undo the address check. A test send carries a test flag, so your system does not create a phantom profile.

The address is re-checked before every send

We resolve your address again and refuse private ranges, including the cloud address that hands out credentials for a whole account.

What this does not do

  • The local API reaches only the copy of ARMANOS on that one computer. There is no cloud route that opens a browser window for you, and a server key starts nothing: it only marks a profile busy and writes the log.
  • The local token is one token for the whole API. It has no scopes, no expiry and no per-route rights, and regenerating it stops every script you have at once.
  • The local API has no rate limit of its own. It trusts the machine it runs on, so against an unwanted call you are covered there by the page check and the token alone.
  • Server keys cannot create keys or webhooks, and any route with no declared scope is closed to them. The recycle bin, the fingerprint preview, proxy rotation and checks, and flow editing are all password only.
  • Webhook delivery is at least once, and a call carries only the fields left after redaction. Your receiver has to drop repeats by id and fetch the object itself when it needs more than the event.

How to check

Every claim on this page comes from a file you can open, and most are held by a stand that runs.

The local API refuses browser-shaped requests, and /status sits behind that check too
apps/desktop/src/lib/local-api.js · apps/desktop/test/local-api-gate.js
The unprotected app-level debug port is opened only for the built-in engine
apps/desktop/src/main/main.js · apps/desktop/test/cdp-port-only-when-needed.js
The token is random per installation and the API starts out disabled
apps/desktop/src/lib/api-config.js · apps/desktop/src/main/main.js
Server keys are a paid tool, and every scope guards a real route
apps/server/src/api-keys/api-keys.service.ts · apps/server/test/ключи-платные.js · apps/server/test/права-ключей-живые.js
Webhooks are signed, cannot be aimed inside our network, and record their failures
apps/server/src/webhooks/webhook-dispatch.service.ts · apps/server/test/webhooks.js · apps/web/test/webhooks-web.js

Questions

What happens if the default port is already taken?
The server takes a free port instead and the panel names it. Your scripts still point at the old address, so read the panel after a restart rather than assuming 50325. The MCP server looks up the new port by itself.
Which answer means the key expired rather than the rights?
402 means the paid time ran out, 401 means the key is bad or revoked, and 403 means a missing scope. Three different codes, so a program can act instead of guessing.
Can a key create another key?
No. Keys and webhook subscriptions are created only by a person signed in with a password, so one leaked key cannot mint more of itself. A new key or subscription also asks for the person's own password again, and for the two-step code if it is on. Blocking an account kills its keys on the next call.
What do the two packages for developers give me?
One for Node and a single file for Python that imports nothing outside the standard library. Both read the key and the address from the environment, give up after 30 seconds, and return typed errors rather than a message that may be translated.
How do I check a webhook signature on my side?
Both packages ship that check: it compares in constant time and refuses anything older than 300 seconds. Without it, anyone who learns your address can send you an invented event.
Does the log show that a script did it rather than a person?
Yes. When a call arrives through a key, you see the key id in the log row as well, so one leaked key does not mean revoking all of them.

Turn it on and call it today

The For developers screen is in every build. Switch the local API on in the app and point your script at 127.0.0.1.