Skip to main content

Members + invites

Every user on AfriAnnotate belongs to zero or more organisations. Within each org they hold one role (Owner, Admin, Manager, Reviewer, Annotator, Guest) that gates what they can see and do. For the full role matrix, see Roles + permissions.

This page covers the operations: adding members, inviting people, changing roles, removing members.

Find members​

Open Organization → Members from the sidebar. The page shows every member of the current org with their role, status, and date joined. You can filter by role or status, and search by name / email / username.

Every action on the Members page (invite, add, change role, remove, suspend, export CSV) is available to Owners and Admins (plus platform staff). Managers can open the page and read the list, but cannot change it; they manage per-project membership from Project → Settings → Members, where they can still invite people by email or add existing users unless the organisation enforces the invites restricted to owners and admins policy. Reviewers, annotators and guests cannot see the member list at all, in the app or through the API. Nobody can grant the Owner role here — it moves only by ownership transfer (see Organisation overview).

For onboarding many annotators at once:

  1. Open Organization → Members → Add Members. Three ways to add people: share an invite link, invite by email, or add existing users from the other organisations you manage (pick their role as you add them).
  2. Copy the invite URL — the link contains a token unique to this org.
  3. Share the link (Slack, email, etc.).
  4. Recipients click it, create their account (or sign in if they already have one), and land in your organisation. New users join as Annotators by default; their role can be changed later from this page.

To rotate the link, click Reset link. The previous token stops working immediately. Existing accounts stay; only future joiners with the old token are rejected.

Add people by email​

Members → Add members → By email takes one or many addresses (type, paste a comma-separated list, or press Enter after each). While you type, people you already work with but who are not in this organisation yet are suggested; pick one with the arrow keys or a click instead of retyping. Each address becomes a row with its own role dropdown (pre-filled with the organisation's default role), so one batch can mix reviewers and annotators. The Existing users tab works the same way: tick people and set a role beside each name. Addresses without an account are created and receive a setup-link email.

Suggestions and the Existing users list only ever show members of the other organisations where you are an owner, admin or manager. The platform's full list of accounts is never shown to an organisation. To add someone outside those organisations, type their email: if they already have an account they are added to this organisation, and if not one is created for them.

Add a specific person (pre-create)​

For named people who'll get a specific role:

  1. Open Platform → Users → + Create User (staff-only).
  2. Fill in name, email, and starting role.
  3. Choose Invite mode — the platform sends a setup-link email so the user sets their own password.

Use Set password now if you'll hand them credentials in person. The user can change the password later from their profile.

Upload a member list (CSV or JSON)​

For a cohort — a training class, a field team, a spreadsheet of volunteers — invite everyone at once: Members → Add members → Upload file.

  1. Drop a .csv or .json file on the upper card (or Choose file); the download icon next to it gives a CSV template. Or paste CSV / JSON into the lower card and click Use this text.
  2. Map the columns: Email is required; Full name (or First name + Last name) and Role are optional. Column names are guessed (email, name, role, …) and can be changed.
  3. Check the preview: invalid emails and duplicates are struck through and skipped; unknown role values fall back to the default role you pick in the panel. Roles accept labels or codes in any case (annotator/AN, reviewer/RE, manager/MA, admin/AD, owner/OW, guest/GU).
  4. Invite N members. Existing accounts are added to the organisation with their row's role; new accounts are created with the row's name, receive the set-password email, and join with that role. The summary lists invited, created, already-member and error rows.

The same rules as single invites apply — the email-domain allowlist, the member quota and the default role — and every invite lands in the activity log. API: POST /api/organizations/<id>/invite-email with {"members": [{"email": "…", "role": "reviewer", "name": "…"}], "role": "AN"}.

Change a member's role​

From Organization → Members, change the role in the member's row (or select several rows and Set role in bulk). Owners and Admins can set Admin, Manager, Reviewer, Annotator or Guest. The Owner role is not granted this way — use ownership transfer (Organization → Settings → Danger Zone), which also demotes the previous Owner to Admin.

The affected member gets a notification. In the platform audit log the action is member.role_change (previous + new role).

Remove a member​

From the member row, click Remove. You choose what happens to their annotations in this org — leave them as they are, anonymize them (detach the author), or delete them — and can add an optional reason that is included in the notification they receive. The user's OrganizationMember row is soft-deleted (deleted_at is set, the row is retained) — the user no longer appears in the members list and their organisation-scoped queries return empty.

The user's account is not deleted; they can still sign in. If they had no other organisations, they'll see the "You were removed from X" empty-state page (the X names the most recently removed org). They keep access to their profile and password but see no projects or organisation pages.

If you need to fully delete the user's account, go to Platform → Users → click user → Delete. That's a hard-delete (cascades across annotations and uploads) and requires the superuser flag — staff alone can't do it.

Per-project roles​

A user's organisation-level role is their default within projects. Projects can override it on a per-project basis:

  1. Open a project, then Settings → Members.
  2. Open Add Members, switch to existing users, and pick the user.
  3. Choose their per-project role.

A user added to a project as Annotator can label tasks in that project even if their org-level role is something else. A user not added to the project doesn't see it at all unless their org role is Owner / Admin (which sees everything).

Workspaces​

You can group projects into workspaces for campaigns, languages, or whatever your team's natural unit is. Workspace membership cascades to projects inside the workspace — add someone to the workspace and they automatically see all its projects.

Audit log​

Member events use these audit actions in Platform → Audit log:

  • member.add — who, by whom, role
  • member.remove — who, by whom
  • member.role_change — who, by whom, old role → new role
  • member.suspend / member.unsuspend — who, by whom, reason (automatic suspensions log as member.suspend.auto)

Staff-only. Searchable by user, action type, or date.

Common gotchas​

A user says they were invited but can't sign in. Two possible causes: their email never arrived (see [FAQ → Email

  • sign-in](../faq#email--sign-in)), or they verified their email on the cloud's HTML signup page but the token-flow was interrupted and they have no org membership. Re-invite them.

Member status shows as "Pending invitation" — never activates. A pre-created user (via Platform → Users → + Create User with Invite mode) who never clicked their setup link shows this state. It's a status, not a role. The link is one-shot but you can re-send it from the user's row.

Removed someone by mistake. Add them again (Add Members → existing users) or re-invite them by email; the platform reuses the existing account and restores the soft-deleted membership row (their previous role is replaced by the one you pick).

Suspending a member (without removing)​

Sometimes you want to pause a member's access without ripping them out of the org. Use suspension instead of removal:

  1. Organization → Members → click the member's row
  2. Suspend button → reason (optional but recommended)
  3. Save

Effect:

  • The member stops receiving tasks from this org — they are left out of assignment and project-member role resolution. Their account and sign-in are untouched; they get a notification with the reason.
  • Their existing annotations stay; their audit trail is preserved
  • Their org membership row stays (suspended_at is set)

To unsuspend, open the member row → Unsuspend. Both actions are audit-logged (member.suspend / member.unsuspend).

Suspension is distinct from removal — removal soft-deletes the membership row and lets you dispose of the member's annotations; suspension keeps everything intact and is reversible in one click.

Useful when:

  • Audit / legal hold — pause a contractor during an investigation
  • HR action — pause without committing to removal
  • Quality issues — pause while a manager reviews recent work (pairs with Auto-suspend rules for automated triggers)

Default role on invite​

By default, invite links land new members at Annotator. Org admins can change this:

  1. Organization → Settings → Access → Default role for new members
  2. Pick the role (Annotator by default)
  3. Save

Individual invites (by email, or adding existing users) can pick a role at send time.

Email-domain allowlist​

Gate joins by company domain (e.g. only @your-org.com emails):

  1. Organization → Settings → Access → Allowed email domains
  2. Comma-separated list: example.org, partner-org.com
  3. Save

Effect:

  • Invites by email to an off-list domain are rejected with Email domain @x is not allowed for this organization.
  • The check runs only on the invite-by-email path — the shared invite link and adding existing users are not domain-checked, so keep the link private if the allowlist matters
  • Existing members with off-list domains aren't affected (grandfathered)
  • Empty list = allow any domain (default)

Useful for SAML-less enterprise where domain matching is the cheap proof-of-affiliation. For real SSO, see the Security model.

What's next​

Mobile

Invite links always carry the public cloud address, so a link copied from the mobile app works for the invitee. Exports (members CSV) open the device's share sheet in the apps.