ARMANOS

For agencies

For agencies

You run other people's accounts with other people's money. This page is about the parts that decide who touches what: seats, roles, folders, a profile that opens in one place, and a log that answers the question afterwards.
5
Roles, from operator to owner
$3 / mo
One extra team seat
3
Seats in Business, the owner among them
58
Named event kinds in the log

An agency loses accounts on people, not on fingerprints

Twelve clients, four people, one spreadsheet of logins. That is the state of most agencies, and it holds until someone opens the wrong account from the wrong machine. The spreadsheet has no way to stop them.

ARMANOS puts the agency into one workspace. One account owns the subscription. Everyone else joins by invitation, and every request they make is resolved against that owner: the profile quota, the device seats, the proxy pool, the groups, the log. One file does that resolution, and every other module asks it who the owner is.

A person belongs to one workspace at a time. The membership row is unique per user, so a contractor cannot sit in two agencies at once. To join yours, they leave the other one first, and leaving has consequences that are spelled out further down this page.

  • Profile quota

    Counted across the owner and every member together. The owner's own profiles take the quota first, then members by seniority.

  • Device seats

    One pool of machines for the whole team, counted at registration and again at every heartbeat.

  • Proxy pool

    One library per workspace. Passwords are handed out by role, not to anyone who can name a record id.

  • Groups

    The same set of folders for everyone, and the unit you use to narrow what a member sees.

  • Creative library

    Up to 500 items. They belong to the workspace, so they stay when the person who uploaded them leaves.

  • Automation scripts and schedules

    Shared across the workspace, edited by manager and above.

  • Audit log

    Every member's actions in one place, read by admin and owner.

A seat is a person, and the owner already holds one

Seats are counted per person, not per machine. Business includes three: you and two colleagues. Professional includes one, which is yours, so a team there starts with bought seats. An extra seat is $3 a month, and the checkout lets you take up to fifty.

The person you invite must already have an account. The server refuses an invitation to an address nobody has registered, because ownership of an address is never proven anywhere. So the order is: they sign up, then you invite them. The invitation is issued to that account, lives seven days, and can be revoked while it is unused.

Seats are counted three times, and that is deliberate. At the invitation, so a full team refuses you and not your colleague. At the accept, under a write lock on your subscription row, so two people cannot take the last seat at once. And at every profile start, so a plan that lapses does not keep five people working.

When the plan drops, nothing is deleted. The live seats stay with the oldest members, and the rest get a clear refusal when they try to open a profile. Restore the plan and they carry on where they stopped.

Business, 200 profiles
$42 / month
Two seats over the three included
+$6 / month
Monthly total
$48
Same order paid yearly
$38 / month, $456 / year

The browser only asks. The price is recomputed on the server at checkout: packages/shared/src/index.js, priceForPlan.

The Members screen in the app: a seat counter reading 1 of 3 seats on Business, an Invite member button, and the owner listed as the only member.
Members, in the app. The seat count comes from the subscription, not from the screen.

Five roles, and the server answers each of them differently

The roles are owner, admin, manager, operator and member. They are ranks, so a higher one satisfies a lower requirement. Operator and member sit at the same rank: two names exist so you can label who does what.

The gate is one guard on the route, and it resolves your role in your workspace before the handler runs. Manager was once a word in a list with no code behind it. Today it separates: shared working resources, groups, the proxy pool, scripts and schedules, belong to manager and above. Money, people and the log belong to admin and owner.

Editing a profile is not a role question at all. Only the account that created a profile can rename it, change its proxy or delete it. A colleague the profile was opened to can launch it and work inside it. To everyone else the server answers not found, so guessing ids tells nobody what exists.

API keys are personal, up to twenty per person, and each carries its own scopes. A key is never stronger than its holder: the same role guard runs on the key's request, so a member's key with logs:read still cannot read the log.

Can doMember, operatorManagerAdminOwner
Open a profile shared with themOoOoOoOo
Create profiles inside the workspace quotaOoOoOoOo
Rename or delete a profile they createdOoOoOoOo
Groups: create, rename, deleteOoOoOo
Proxy pool: add, edit, delete, pull with passwordsOoOoOo
Buy proxies in the storeOoOoOo
Automation scripts and schedulesOoOoOo
Read one pool proxy passwordonly with a profile opened to themOoOoOo
Invite, change roles, open foldersOoOo
Plan, seats, extra profiles, paymentsOoOo
Read the workspace logOoOo
Unlink another person's machineOoOo
Cannot be removed or demotedOo

A member sees only the folders you opened to them

Until you say otherwise, a member sees every profile shared with them. Give them a list of groups and the view narrows to those groups. Clearing the list again is a deliberate act: an empty list means the person sees everything, so removing the last folder never locks someone out by accident.

The limit is enforced in two places, because a list is not protection. The profile list filters by the allowed groups, and a direct start by id checks the same rows. A profile with no group at all stays hidden while a limit is set, so nobody dodges it by leaving a profile out of a folder.

The access rows are written against your workspace, not against the person. Your restriction does not travel with a contractor to their next client, and it is deleted the moment they leave you. Only owner and admin hand it out, and the owner cannot be restricted at all.

  1. 1

    Make a folder per client

    The Groups screen, manager and above. Name it the way the client is named in your invoices.

  2. 2

    Put that client's profiles into it

    A profile carries one group. Profiles outside a folder are invisible to a limited member.

  3. 3

    Invite the contractor as operator

    They register first, you invite the address, they accept within seven days.

  4. 4

    Open that one folder to them

    The Members screen, folders. One group selected means one client visible.

  5. 5

    Share the profiles they will actually open

    Visibility and access are separate. A folder narrows what they see, a share is what lets them launch.

The Groups screen in the app with folders named Marketplaces, Social media, Ad accounts and Clients, above a line saying groups are shared across the workspace.
Groups, in the app. They belong to the workspace, and they are the unit of visibility.

One profile opens in one place

Two people opening one account from two machines is the pattern that gets accounts locked. A product built for agencies must not create it by accident, so every profile carries a lock.

Start claims the lock for your machine for three minutes, and the app renews it every sixty seconds while the window is open. A second machine gets a 409 that names the holder and the moment they took it, instead of a silent failure or a silent pass.

Takeover is explicit and conditional. It wins only while the lock is still held by the machine you were shown, so two simultaneous takeovers cannot both succeed. The previous holder finds out within a minute: the renewal is refused, the app closes those windows and says what happened.

Closing a profile releases the lock of that machine only, so your window never frees a colleague's. A machine that is switched off releases nothing, and the profile comes free on its own three minutes later.

Response
409 Conflict
error
profile_busy
busy.name
Anna, MacBook Pro
busy.since
2026-09-10T09:14:02Z
busy.sameUser
false

What the second machine receives: apps/server/src/profiles/profiles.service.ts, start().

The lock lives on the server

When the app is offline, or the server cannot be reached, the launch is not blocked. Taking work away from a person over a broken connection would be worse than the risk it prevents. Two machines that are both offline can open one profile.

The log answers who did it, and it outlives the person

The vocabulary is 58 named event kinds in one file, shared by everything that writes and everything that reads. Registration, logins and the lockout after guessed passwords, profile create, start, stop, edit and delete, the life of a proxy, machines registered and unlinked, invitations, roles, folder grants, plan changes, keys issued and revoked.

Every row is stamped with the workspace owner at the moment it is written. That single decision means removing a member does not erase their history: the log used to be read through the current member list, and an ex-employee's actions disappeared along with them. Rows also resolve to the actor's email and to the profile name, so you read words instead of ids.

When an action came through an API key, the key id goes into the row. One person may hold several keys, and without the id a leak would force you to revoke all of them and break your own automation.

There are three surfaces: every action, browser open and close, and logins with machine registrations carrying IP and country. A page holds up to a hundred rows. Reading is admin and owner only, and an API key does not lift that.

On top of the same rows sits a suspicion panel with three rules. A login from a country this person has not used in the last thirty days. Four or more profiles sitting on one proxy. Five starts inside one minute, with our own batch launcher excluded, because it spaces starts by three to fourteen seconds.

  • Who

    The member's email, resolved from the user id when the page is built.

  • What

    One of 58 names, for example profile.start, team.role, proxy.secret.read.

  • Which profile

    The profile name and its scenario, lifted out of the stored details.

  • From where

    IP, country and machine name on logins and machine registrations.

  • By what

    The API key id, when the action came from a key rather than from a person at a keyboard.

  • Whose workspace

    Written into the row itself, so the history survives the member being removed.

When someone leaves, one transaction takes the access back

Machines are seats too. They are counted at registration and at every heartbeat, and unlinking one in the dashboard frees the seat at once. The machine remembers that it was unlinked, so it cannot quietly take the seat back on the next heartbeat.

An unlinked machine cannot start a profile or renew a lock. The refusal lives on the server, not in the app, so a rewritten client does not walk around it. Anyone may unlink their own machine, and only admin and owner may unlink someone else's.

Removing a person and a person leaving on their own run the same path, and the log records honestly which of the two it was. It is one transaction, in this order.

  1. 1

    Shares are cancelled in both directions

    What you opened to them, and what they opened from the profiles that leave with them.

  2. 2

    Their lock is released

    A profile they were holding does not stay busy after they are gone.

  3. 3

    Profiles made after they joined move to you

    The number of profiles moved is written into the log entry.

  4. 4

    Pool links are cleared from the profiles that leave

    A profile they brought with them keeps its own proxy and goes with them.

  5. 5

    Snapshots that match your pool are wiped

    Address, port and login are compared. Your working proxy does not leave inside someone's profile.

  6. 6

    Their machines are deleted

    The device seats come back to the workspace.

  7. 7

    Unaccepted invitations to that address are burned

    A second code, issued when the first email did not arrive, is not a way back in.

  8. 8

    The membership row goes

    Your plan, quota and seats stop resolving for that person.

  9. 9

    Folder access rows go

    Your restriction does not follow the person to their next client.

Profiles made before they joined stay theirs

The boundary is the moment the invitation was accepted. Profiles created earlier were paid for by that person and leave with them, and any link to your proxy pool is cut off them first.

What an agency gets on each plan

Free is one seat, which is yours, so there is no team on it. Professional includes one seat as well: it is a plan for one person with several machines, and a team there starts with bought seats. Business is the plan built for the work this page describes: three seats, five machines, 200 to 1000 profiles.

Enterprise is not sold by a button. The checkout refuses to invent a price for it and sends you to a conversation, because taking money for terms nobody agreed is worse than a slow sale.

The quota is shared, and it is asked again at every launch rather than once at purchase. Profiles are counted across the owner and members together, and the owner's own profiles enter the quota first. Drop a tier and the extra profiles freeze instead of vanishing: they stay in the list, they can be moved or deleted, but they do not open. An active subscription gets three days past its renewal date, and the app keeps working for twenty four hours without a connection.

FreeProfessionalBusinessEnterprise
Profiles210 to 100200 to 10005000 and up
Price, per month$0$6 to $25$42 to $139agreed with us
Team seats included, owner among them11320
Extra seat, per monthnot sold$3$3agreed with us
Extra profile, per monthnot sold$2$2agreed with us
Machines12520
API keysOoOoOo

What this does not do

  • Roles, folders and the lock decide who touches what inside your team. They say nothing about how a site judges a profile, and they are not a promise about bans.
  • A share has no levels. There is no read-only access to a profile: the person you open it to works with everything inside it, cookies and logins included.
  • Cookies do not travel with a share. The session lives in the profile folder on the machine that opened it, and the server keeps settings, not cookies. Moving a live session needs the sync folder, and the profile has to be closed.
  • The lock is a server rule. Offline, or with the server unreachable, the app still opens the profile, so two disconnected machines can open one account.
  • There is no single sign-on and no company domain. Each person registers themselves, then you invite the address, and an unused invitation dies after seven days.
  • One person, one workspace. A freelancer working for two agencies cannot hold both memberships, and joining you means leaving the other.

How to check

Each line names the file that does the work and the stand that keeps it honest.

Seats are counted at the invitation, at the accept under a row lock, and at every profile start
apps/server/src/team/team.service.ts · apps/server/src/common/workspace/workspace.service.ts · apps/server/test/team-money-seats.js
A member sees only the folders you opened, in the list and on a direct start by id
apps/server/src/profiles/profiles.service.ts · apps/server/src/team/team.service.ts · apps/server/test/group-access.js
Two machines cannot hold one profile: 409 with the holder, conditional takeover, expiry after three minutes
apps/server/src/profiles/profiles.service.ts (LOCK_TTL_MS) · apps/server/test/profile-lock.js
Leaving takes back shares, the lock, machines, unused invitations and folder access in one transaction
apps/server/src/team/team.service.ts (detach) · apps/server/test/team-money-seats.js
The log has 58 named kinds, and a row carries the actor's email, the workspace and the API key id
apps/server/src/common/audit/audit.service.ts · apps/server/test/audit-filters.js
A pool proxy password goes to manager and above, or with the profile it is attached to
apps/server/src/proxies/proxies.service.ts · apps/server/test/proxy-secret.js

Put the whole agency on one subscription

Business includes three seats and five machines. Extra seats are three dollars a month each, and the checkout counts them for you.