Identity & Teams
Look up the authenticated caller and their team memberships.
The identity and teams endpoints expose the caller's own details, verified capabilities, and the teams they belong to. Use these to:
- Bootstrap an integration with one call —
GET /api/v1/auth/mereturns the caller, their primary team, and any other teams they belong to or have been invited to. - Render team directories and member pickers.
- Check whether the authenticated user is an admin of a given team before invoking admin-only operations.
Quick Reference
| Feature | Details |
|---|---|
GET /auth/me |
The caller's identity, capabilities, primary team, and any other teams they belong to or are invited to. |
GET /teams/{id} |
A single team. Includes an inline member list (up to 50) when the caller is an active member. |
GET /teams/{id}/members |
Paginated, role-filterable list of active members. Stable keyset ordering for cursor pagination. |
| Access levels | Active members get the full member list; callers with a pending invite see the team's details only. |
| Inline cap | members[] is capped at 50 entries. hasMoreMembers: true with a memberCount signals truncation. |
| IDs | All identifiers are opaque strings. Treat them as such; do not assume any format. |
| Not found | 404 not-found — never 403 — when the caller has no visibility into the target team. |
Endpoints
GET /api/v1/auth/me
Returns the authenticated caller. No query parameters — always a single object.
curl "https://app.propstreet.com/api/v1/auth/me" \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"id": "a3f8...",
"email": "jane@acme.com",
"firstName": "Jane",
"lastName": "Smith",
"capabilities": ["broker"],
"culture": "en-US",
"uiCulture": "en-US",
"region": "US",
"timeZone": "America/New_York",
"isBot": false,
"primaryTeam": {
"id": "...",
"name": "Acme Capital",
"categories": ["private_equity"],
"plan": "professional",
"membership": { "role": "admin", "status": "active", "joinedUtc": "2024-02-01T10:00:00Z" },
"members": [ /* up to 50 active members */ ],
"memberCount": 7,
"hasMoreMembers": false
},
"secondaryTeams": [ /* other teams — may include pending invitations */ ]
}
Notes:
capabilitieslists the caller's verified, non-revoked claims. Onlybrokerandinvestorappear on the wire.firstNameandlastNameare exposed as discrete fields. Compose display names client-side (e.g.`${firstName} ${lastName}`.trim()); fall back toemailwhen both name fields are missing.- Callers with no active team (pre-onboarding, service accounts, etc.) return
primaryTeam: nullandsecondaryTeams: []. Handle this gracefully — it's a valid runtime state. membership.statusinside each team tells you whether the caller is an active member or has a pending invite. Prefer this over inferring from position in thesecondaryTeams[]array.
GET /api/v1/teams/{id}
Returns a single team by its opaque id. The caller must have visibility — active membership or a pending invite — into the team; 404 otherwise.
curl "https://app.propstreet.com/api/v1/teams/TEAM_ID" \
-H "Authorization: Bearer YOUR_TOKEN"
The members[], memberCount, and hasMoreMembers fields are only populated when the caller is an active member of the team. Callers with a pending invite see the team's details but not the member list.
hasMoreMembers: true is a truncation signal, not continuation metadata. The inline member slice is capped at 50 entries and cannot be resumed — there is no cursor on the inline slice, and its ordering differs from the paginated /teams/{id}/members response. Clients that need the full roster should call /teams/{id}/members from page 1, not try to "append" pages onto the inline slice.
GET /api/v1/teams/{id}/members
Paginated list of a team's active members. The caller must be an active member; callers with a pending invite receive 404.
| Query parameter | Type | Description |
|---|---|---|
role |
string | Filter: admin or member. Omit for all roles. |
page_size |
int | Page size, 1–100. Default 50. Values above the cap are clamped. |
cursor |
string | Opaque cursor from a previous response's page.nextCursor. |
Snake_case query parameter names match the rest of the Public API.
curl "https://app.propstreet.com/api/v1/teams/TEAM_ID/members?role=admin&page_size=10" \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"data": [
{
"id": "...",
"role": "admin",
"status": "active",
"user": {
"id": "a3f8...",
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@acme.com"
}
}
],
"page": { "pageSize": 10, "hasMore": false }
}
Access levels
Team endpoints distinguish two levels of access based on the caller's relationship to the team:
- Pending invite — the caller has been invited but has not accepted. They see the team's details (
name,plan,country,contactPerson, etc.) so they can recognise the invitation, but not the member list. - Active member — the caller has accepted. In addition to the details above, they see
members[],memberCount,hasMoreMembers, and can callGET /teams/{id}/members.
membership.status on each team is the authoritative signal — use it rather than inferring from which fields are present.
Member ordering
The inline members[] slice on a team response is ordered for display:
- Admins first.
- Then by the composed first/last name, falling back to email when both are missing.
- Then by member
idas a stable tiebreaker.
The paginated /teams/{id}/members endpoint uses a different, keyset-stable ordering so cursors remain valid across pages:
joinedUtcascending.- Then by member
idas a stable tiebreaker.
These orderings differ by design. The inline slice is for display in a team card; the paginated endpoint is for walking the full roster with cursors. Because the orderings differ, the inline slice is not a prefix of the paginated listing — a client that wants the full roster must restart from page 1 of /teams/{id}/members.
Related
- Multi-Tenant — how teams isolate data between tenants.
- MCP Server — the same identity data is available to AI agents via the
get_metool.