Skip to content

List a team's members

One team's memberships, a page at a time, with each person's team role, company role and other teams.

On this page

One team's members, a page at a time, with each person's role on the team, their company role, and the other teams they are on.

Get a team returns a team's whole membership in one response, including the invitation link for each pending member. This endpoint is the one to page, search and filter a team's people with, and it names their roles. It does not return invitation links.

GEThttps://api2.rundiffusion.com/api/v2/teams/{team_id}/members
AcceptsOAuth device flowCompany API Access Token

Who may read it

Whoever manages the company's teams, and the team's own members:

The callerResult
MANAGE_TEAMS on the team's companyAny team in the company
A member who has joined the teamThis team
Someone who has joined only other teams in the company403 PERMISSION_DENIED
Anyone else, including someone on no team in the company404 TEAM_NOT_FOUND

A Company API Access Token acts as the member it was made for, so it reads what that member would read with their own sign-in.

MANAGE_TEAMS comes from the caller's company role, which is a separate grant from their team role. See Two roles, two maps.

Request

Headers

AuthorizationstringRequired
Bearer token. This endpoint accepts an OAuth device flow token or a Company API Access Token. A Personal API Access Token is refused. See Authentication.Authorization: Bearer eyJhbGciOi…

Path parameters

team_idstringRequired
The team whose members to list, from List teams. It also names the company, so no separate selector is needed. A team in another company returns 404.https://api2.rundiffusion.com/api/v2/teams/2D8NEx…/members

Query

company_idstringoptional
Optional. The team already names its company. Send it to make sure the team belongs to the company you expect; a team in a different one returns 404.https://api2.rundiffusion.com/api/v2/teams/2D8NEx…/members?company_id=Cm4pQ7…
cursorstringoptional
Opaque pagination token. When a response has has_more true, pass its next_cursor here to get the following page. Do not construct or parse one.https://api2.rundiffusion.com/api/v2/teams/2D8NEx…/members?cursor=eyJ2IjoxL…
limitintegeroptionaldefault 24
Members per page, from 1 to 100.https://api2.rundiffusion.com/api/v2/teams/2D8NEx…/members?limit=100
sortstringoptionaldefault email
Result order. joined is when the person accepted, and pending invitations sort last in either direction because they have no joined instant. invited is when the invitation was created. Ties always break on the email address, so two pages never overlap.https://api2.rundiffusion.com/api/v2/teams/2D8NEx…/members?sort=joined&order=desc
orderstringoptionaldefault asc
Which direction sort runs in.https://api2.rundiffusion.com/api/v2/teams/2D8NEx…/members?sort=invited&order=desc
qstringoptional
Case-insensitive substring match on the email address, up to 200 characters. Percent and underscore match themselves rather than acting as wildcards.https://api2.rundiffusion.com/api/v2/teams/2D8NEx…/members?q=example.com
statusstringoptional
joined for members who have accepted, pending for invitations still outstanding. Omit it for both.https://api2.rundiffusion.com/api/v2/teams/2D8NEx…/members?status=pending
team_role_idstringoptional
Only members whose team_role is this role.https://api2.rundiffusion.com/api/v2/teams/2D8NEx…/members?team_role_id=Rk7Vq2…
curl "https://api2.rundiffusion.com/api/v2/teams/2D8NEx…/members?status=pending" \
  -H "Authorization: Bearer $RUNDIFFUSION_TOKEN"

The path team_id names the team to read. It is not the account selection a team_id query parameter performs on other endpoints.

Response

200 OK with one page of memberships, sorted by email address unless you asked otherwise.

json
{
  "data": [
    {
      "key": "sam@example.com",
      "email": "sam@example.com",
      "user_id": "k3PqV9…",
      "invited": "2026-03-14T09:03:40+00:00",
      "joined": "2026-03-14T09:04:52+00:00",
      "is_pending": false,
      "company_role_invite_only": false,
      "team_role": { "id": "Rk7Vq2…", "name": "Editor" },
      "company_role": { "id": "Hn2Lw8…", "name": "Admin" },
      "teams": [
        { "id": "2D8NEx…", "name": "Design Studio", "pending": false, "is_active": true },
        { "id": "7QmWb2…", "name": "Archive 2025", "pending": false, "is_active": false }
      ]
    },
    {
      "key": "new_hire@example.com",
      "email": "new_hire@example.com",
      "user_id": null,
      "invited": "2026-05-02T11:20:07+00:00",
      "joined": null,
      "is_pending": true,
      "company_role_invite_only": false,
      "team_role": { "id": "Pz4Tc1…", "name": "Viewer" },
      "company_role": null,
      "teams": [
        { "id": "2D8NEx…", "name": "Design Studio", "pending": true, "is_active": true }
      ]
    }
  ],
  "next_cursor": null,
  "has_more": false
}
dataarray
The memberships on this page, one row each. Empty when nobody matches, which is not an error.
next_cursorstring | null
Pass this back as cursor to fetch the next page. Null on the last page.
has_moreboolean
Whether more pages exist beyond this one. This is the flag to branch on when paging.

Member object

keystring
The row's identity, which is the email address. It is also the id of the membership record. Use it to key a list, not user_id, which a pending member does not have yet.
emailstring
The email address the membership belongs to.
user_idstring | null
The member's user ID. Always null while is_pending is true, since there is no user until someone accepts.
invitedstring (ISO 8601) | null
When the invitation was created, in UTC. Present whether or not it has been accepted.
joinedstring (ISO 8601) | null
When the person joined this team, in UTC, or null while the invitation is pending.
is_pendingboolean
Whether the invitation is still outstanding. Derived from the joined instant rather than a separate flag, so the two cannot disagree.
company_role_invite_onlyboolean
True when this invitation was created to carry a company role to an address with no account yet, rather than to put the person on this team. Cancelling the company role withdraws it.
team_roleobject | null
The person's role on this team, with id and name. See Roles.
company_roleobject | null
The person's company role, with id and name. See Roles.
teamsarray
Every team in the company this person is on, this one included, each with id, name, pending and is_active. Only the teams you can see.

Roles

Both roles are objects with an id and a name, or null for none.

  • team_role is the role the person holds on this team once they have joined. While the invitation is pending, it is the role the invitation will grant when they accept.
  • company_role is the person's company role once they have an account. For someone who has not accepted yet, it is the company role their invitation will grant.

A role whose definition has been deleted reads as null. The two are separate grants: a team role decides what a member may do inside this team, a company role what they may do to the organization. See Two roles, two maps.

Other teams

teams lists every team in the company the person is on, this one included. Like everything here it stays inside what you can see: a holder of MANAGE_TEAMS gets all of them, and a member gets the teams they share with the person.

Freshness

This listing is read from a copy of the data that trails live changes by up to about 20 seconds, so someone invited a moment ago may not appear yet. Get a team reads live.

Paging

Cursor paginated, the same way as every other listing. Read has_more, and when it is true send next_cursor back as cursor.

A cursor belongs to the listing it was issued for: the team, the sort, the order and every filter. Change any of them partway through a walk and the cursor returns 400 INVALID_CURSOR. limit may change between pages.

Errors

Status codes

400INVALID_REQUEST
A query parameter failed validation, such as a limit above 100 or a sort this endpoint does not offer. details names the field.
400INVALID_CURSOR
The cursor no longer matches this listing, which happens if you change the sort, the order or a filter partway through a walk. Restart the walk without a cursor.
401TOKEN_INVALID
Missing or unrecognized token, or a Personal API Access Token, which this endpoint refuses because it is not scoped to a company.
401TOKEN_EXPIRED
The OAuth token has expired. Refresh it and retry.
403PERMISSION_DENIED
The caller has joined another team in the company, but not this one, and does not hold MANAGE_TEAMS. Someone on no team in the company gets 404 instead.
404TEAM_NOT_FOUND
No such team, it belongs to another company, or the caller is on no team in its company and does not hold MANAGE_TEAMS there. The cases are deliberately indistinguishable.
429RATE_LIMITED
Too many requests. See Rate limits.

A team in another company, or in one where you are on no team, returns 404, not 403, so the response does not confirm that a team you have no part in exists.

View as Markdown