What a workspace owns
A workspace id starts withts_tm_, and each of these belongs to exactly one of them:
- Connected LinkedIn accounts, their browsers, conversations, searches, mass actions, auto scrapes.
- API keys, login sessions and OAuth grants. A key is workspace-wide: it reaches every account in that workspace, and no key can be scoped to one account.
- The plan, the account-slot cap and the billing history.
- The member list, including invitations nobody has accepted yet.
owner_user_sid), the only structural role on the platform.
Everything else is a permission list, which is why the app shows an Access column rather than a
role column. Two workspace fields are editable: name (1 to 255 characters) and config.timezone
(an IANA zone such as Europe/Berlin); status, plan, limits and the owner are
derived, and the API drops them silently if you send them.
Membership does not share accounts: being a member of workspace A and B does not let you drive A’s
LinkedIn account from B. Moving an account across workspaces is a share or a transfer, both in
account sharing and handover.
Create and switch workspaces
Click the workspace chip under the logo in the sidebar to switch: the current one carries a check icon, and the list holds every workspace you own plus every one where you are an active member. Create workspace sits at the bottom of that dropdown, and confirming the name switches you into the new workspace immediately, as its owner.Your first workspace starts on Sandbox, the forever free plan: one
connected-account slot, no card, no time limit. Sandbox is one workspace per account, so a further
workspace you create comes up without capacity until you buy a plan for it. Plans are per
workspace: a paid plan on one workspace grants nothing to another.
POST /auth/switch-team, gets a new access and refresh token, blacklists
the old pair, and reloads. Your other devices, API keys and OAuth tokens are untouched.
Which workspace opens when you load the app is the first valid candidate, in order, of: the
?team=ts_tm_... query parameter, which makes any app URL a shareable deep link; the workspace open
in this tab; the one last used in this browser; config.latest_team_sid on your user; your working
team (default_team_sid, Working team in the UI, assigned when you join your first workspace,
and where accounts shared with you land); then the first workspace you have. An invalid candidate is
dropped and the next one is tried.
Over the API there is no switching, because a token is already scoped. The Team-SID header is read
before the token’s own claim, but it has to name the workspace the token was minted for: anything
else answers 403 forbidden, reason wrong_team. See authentication.
How member access is expressed
There is no role column in the data. Access is a flat list of permission tokens shapedcan_{verb}_{noun}, plus an optional account slice. The catalog holds 49 tokens (24
platform-level, 25 channel-level), and the wildcard * means all of them.
The
account_sids field is the slice: null is every account in the workspace (rendered All), a
list of ln_ac_ sids is only those ( of ), an empty list is none.
Invite a teammate
Open Settings, then Teammates under the Workspace group in the left rail. The panel is titled Members and invites, and its path is in the URL, so the page is linkable. Click Invite, enter the email (max 255 characters) and send: a row appears immediately with status Invited, carrying a permission chip that pops the member’s full token list. The invitee receives an email with subject “You are invited to{workspace name}” and an Accept
invitation button carrying a single-use code. Accepting requires a signed-in session, because a
membership binds to the authenticated user and never to an address in a request body, so somebody
without an account signs up first. On acceptance the row flips from invited to active, the code
is cleared, and if the person had no working team yet this workspace becomes it.
An invitation link is valid for 7 days, after which a daily job clears the stored code and the
old link stops working. The row stays on the list: press Resend to re-roll the code and give
another 7 days, which only works on rows in status invited. Inviting an email already on the list
is not an error and sends no second email, so use Resend to genuinely re-send; inviting an
address you removed earlier creates a fresh row.
The panel loads the first 100 members sorted by join date and has no pagination control. A
workspace with more members than that is read over the API, which pages with a cursor.
Remove, hand over, delete
Removing a member and cancelling an invitation are the same row action, both safe for the data:- Cancelling a pending invitation kills the code. The link stops working immediately.
- Removing an active member revokes their login sessions and agent tokens in this workspace only. Their sessions elsewhere survive, and so does the durable OAuth grant behind any connected app. Accounts, browsers, conversations and history stay where they are. If this workspace was their working team, that pointer moves to another membership of theirs, or clears.
already_deleted: true. The owner’s membership cannot be removed at all, and that
button is disabled with the tooltip Transfer ownership first.
To hand the workspace over, open Settings -> General, find the Owner row and click
Transfer. Only the current owner can do this, not an admin holding can_manage_teams. The picker
lists active members only, the target is re-checked as active at commit time, transferring to
yourself answers changed: false, and the previous owner stays a member with the same permissions.
The free plan is single-user
Because the gate runs on acceptance as well as on the invite, a workspace that was paid, invited people, and then fell to the free plan keeps its pending invitations frozen rather than losing them: the invitee gets the 402, and the same link works again once a plan is applied. Paid and partner plans are multi-user: see billing and plans.Over the API
Members live in the ID service. Invite withPOST /api/team-members, list members and pending
invitations with POST /api/team-members/search (there is no GET /api/team-members/{sid}, member
lists are small), narrow one with PATCH /api/team-members/{sid}, remove or cancel with DELETE on
that path, re-roll a code with POST /api/team-members/{sid}/resend-invitation, and accept with
POST /api/team-members/accept-invitation, which needs a signed-in user token rather than a key.
{"user_sid": {"is_null": true}} for pending invitations only. Field names and
the full request shape are in the API reference.