People and invitations
Everyone in the workspace with their role (owner, admin or member), and invitations still waiting to be accepted. Agents use this rather than better-auth's routes, which need a session.
sessionbetter-auth.session_token<token>Set by POST /api/auth/sign-in/email.
ws*stringThe workspace id (from GET /api/me).
People and invitations.
application/jsoncurl -X GET 'https://app.useroster.work/api/workspaces/string/members'{ "members": [ { "userId": "u_1", "name": "Ada", "email": "ada@acme.com", "role": "owner", "joinedAt": "2026-11-03T09:00:00.000Z" } ], "invitations": [ { "id": "inv_1", "email": "sam@acme.com", "role": "member", "status": "pending", "expiresAt": "2026-11-05T09:00:00.000Z" } ]}Audit trail GET
Only people who manage the workspace (owners, and the role that can invite people) can read it; anyone else gets 403. Every change to how the workspace is set up, newest first, by whoever made it: a member (`member`), a hire (`hire`), Roster itself (`system`), the assistant (`assistant`) or an API token (`api_token`). Hires, their instructions, hours, tools, notebooks, responsibilities and follow-ups; skills; connections; departments, seats and goals; approvals decided; members, roles and invitations; workspace settings; seats. `action` is stable and dotted (`hire.renamed`, `note.added`); filter by one, or by everything about one kind of thing (`action=hire`). `changes` holds only the fields that changed, as `{ from, to }`, with credentials shown as `[redacted]`. `summary` is the change in one sentence and `sentence` the same in parts, the actor and the target marked so they can be linked. `requestId` ties together changes made by one request or one piece of a hire's work. Pass `next` back as `cursor` for older changes.
Invite someone by email POST
Owners and admins only. Emails them a link to accept (without mail set up, the link is in the server log). An invitation already waiting for that address is replaced; someone already in the workspace isn't invited.