Skip to main content

Overview

Teams in Inbox organize your account links, prospects, and conversations. This guide covers retrieving team information and managing team members via the API.

Get team information

Retrieve your team details:
const { data: team } = await client.get("/team");

console.log("Team:", team.name);
console.log("Currency:", team.currency);
console.log("Created:", team.createdAt);
Response:
{
  "id": "hzcai5t59nn9vsck3rbuepyg",
  "name": "Acme Corp",
  "slug": "acme-corp",
  "createdAt": "2024-01-15T10:30:00.000Z",
  "updatedAt": null,
  "currency": "USD",
  "allowSupportAccess": false
}
FieldDescription
idInbox team ID
nameTeam display name
slugURL-friendly team identifier
currencyCurrency used for prospect valuations (e.g., "USD")
allowSupportAccessWhether the Inbox support team can access your workspace

List team members

Get all members of your team:
const { data: members } = await client.get("/members");

console.log(`Team has ${members.length} members`);
members.forEach((member) => {
  console.log(`${member.name} (${member.email}) - ${member.role}`);
});
Response:
[
  {
    "id": "r3km7xj9wq5p2bvnhfdteoly",
    "userId": "usr4hn8xj2wq5p1bvnhfdteo",
    "name": "Jane Smith",
    "email": "jane@acmecorp.com",
    "image": "https://lh3.googleusercontent.com/...",
    "role": "owner",
    "createdAt": "2024-01-15T10:30:00.000Z",
    "updatedAt": null
  },
  {
    "id": "s4ln8yk0xr6q3cw1behsifup",
    "userId": "usr5io9yk3xr6q2cw1behsifu",
    "name": "John Doe",
    "email": "john@acmecorp.com",
    "image": "https://lh3.googleusercontent.com/...",
    "role": "admin",
    "createdAt": "2024-02-01T09:00:00.000Z",
    "updatedAt": null
  },
  {
    "id": "t5mo9zl1ys7r4dx2cfitjgvqw",
    "userId": "usr6jp0zl4ys7r3dx2cfitjgv",
    "name": "Alice Johnson",
    "email": "alice@acmecorp.com",
    "image": null,
    "role": "user",
    "createdAt": "2024-02-15T14:00:00.000Z",
    "updatedAt": null
  }
]
GET /members returns a flat array, not a wrapped object. The same applies to GET /account-links, GET /tags, and GET /statuses.

Get specific member

Retrieve details for a specific member:
const { data: member } = await client.get(`/members/${memberId}`);
console.log("Member:", member.name);

Member roles

RolePermissions
ownerFull access, billing management, team deletion
adminFull access except billing and team deletion
userAccess to assigned threads and features

Thread assignment

Assign threads to team members for workload distribution:
// Assign a thread to a member
await client.patch(`/threads/${threadId}`, {
  assigneeId: "r3km7xj9wq5p2bvnhfdteoly",
});

// Unassign a thread
await client.patch(`/threads/${threadId}`, {
  assigneeId: null,
});

Filter by assignee

Get threads assigned to specific members:
// Get threads assigned to a specific member
const { data } = await client.get("/threads", {
  params: {
    "filters[assignees][selectedIds][0]": "r3km7xj9wq5p2bvnhfdteoly",
  },
});

// Get unassigned threads
const { data: unassigned } = await client.get("/threads", {
  params: {
    "filters[assignees][noAssignee]": true,
  },
});

Common patterns

Round-robin assignment

Distribute new threads evenly across team members:
async function getTeamMembers(): Promise<string[]> {
  const { data: members } = await client.get("/members");
  return members.filter((m: any) => m.role !== "owner").map((m: any) => m.id);
}

class RoundRobinAssigner {
  private members: string[] = [];
  private currentIndex = 0;

  async initialize() {
    this.members = await getTeamMembers();
  }

  next(): string {
    const memberId = this.members[this.currentIndex];
    this.currentIndex = (this.currentIndex + 1) % this.members.length;
    return memberId;
  }
}

// Usage
const assigner = new RoundRobinAssigner();
await assigner.initialize();

async function assignNewThread(threadId: string) {
  const memberId = assigner.next();
  await client.patch(`/threads/${threadId}`, {
    assigneeId: memberId,
  });
  console.log(`Assigned thread to ${memberId}`);
}

Workload-based assignment

Assign to the team member with the fewest open threads. Since the API doesn’t return a total count, you need to paginate to get real numbers:
async function countThreadsForMember(memberId: string): Promise<number> {
  let count = 0;
  let cursorId: string | undefined;
  let cursorTimestamp: string | undefined;

  do {
    const { data } = await client.get("/threads", {
      params: {
        "filters[assignees][selectedIds][0]": memberId,
        inbox: "default",
        limit: 100,
        ...(cursorId && { cursorId, cursorTimestamp }),
      },
    });

    count += data.threads.length;
    cursorId = data.nextCursor?.id;
    cursorTimestamp = data.nextCursor?.timestamp;
  } while (cursorId);

  return count;
}

async function assignToLeastBusy(threadId: string) {
  const { data: members } = await client.get("/members");

  let minMember = "";
  let minCount = Infinity;

  for (const member of members) {
    if (member.role === "owner") continue;

    const count = await countThreadsForMember(member.id);
    if (count < minCount) {
      minCount = count;
      minMember = member.id;
    }
  }

  if (minMember) {
    await client.patch(`/threads/${threadId}`, {
      assigneeId: minMember,
    });
    console.log(`Assigned to ${minMember} (${minCount} open threads)`);
  }
}
This makes multiple API calls per member. For teams with many members or threads, consider caching workload counts and refreshing periodically rather than computing on every assignment.

Role-based routing

Route threads based on message content to appropriate team members:
interface RoutingConfig {
  memberId: string;
  keywords: string[];
}

const routingRules: RoutingConfig[] = [
  {
    memberId: "s4ln8yk0xr6q3cw1behsifup",
    keywords: ["pricing", "demo", "quote", "buy", "purchase"],
  },
  {
    memberId: "t5mo9zl1ys7r4dx2cfitjgvqw",
    keywords: ["help", "issue", "problem", "bug", "error", "not working"],
  },
];

async function routeByContent(threadId: string, messageText: string) {
  const text = messageText.toLowerCase();

  for (const rule of routingRules) {
    if (rule.keywords.some((k) => text.includes(k))) {
      await client.patch(`/threads/${threadId}`, {
        assigneeId: rule.memberId,
      });
      console.log(`Routed to ${rule.memberId} based on keywords`);
      return rule.memberId;
    }
  }

  return null;
}

Best practices

Use workload-based or round-robin assignment to prevent bottlenecks.
Each thread should have a clear owner. Avoid leaving threads unassigned for too long.

Next steps