---
title: "Create team"
method: POST
path: "/team"
tags: ["Teams"]
---

# Create team

`POST /team`

## Request

- Base URL: `https://api.elaichi.ai`
- URL: `https://api.elaichi.ai/team`
- Auth: HTTP bearer

Creates a team. Requires `team:create` (every Member holds it) or `team:manage`. Team names are unique within the organization. The caller becomes this team's administrator immediately — the same auto-ownership every other created resource gets — whether or not their own id also appears in `member_ids`. `member_ids` optionally adds other existing organization members (`GET /member`) as ordinary members in the same call; an id that is not already an org member fails the whole call before anything is created. To promote one of them to administrator too, follow up with `PATCH /team/{id}/members/{userId}`. There is no way to create a team you do not administer: to stand one up for somebody else, create it and appoint them; a team administrator cannot remove another administrator, themselves included, so taking yourself off afterwards needs a `team:manage` holder.

## Headers

- `X-Organization-Id` string

## Request body

- object
  - `name` string, required
  - `description` string, nullable
  - `member_ids` string[]: User ids (`usr_…`) of existing organization members to add alongside the caller. Optional.

## Response `201`

Created

- Team
  - `id` string: Team id (`team_…`).
  - `name` string: Unique within the organization.
  - `description` string, nullable
  - `member_count` integer: How many people are in the team. The row carries no roster array; `GET /team/{id}/member` is the roster.
  - `admin_count` integer: How many of them administer the team.
  - `admin_preview` object[]: The first few administrators, with display names already resolved, so a client can name them without a lookup per row. At most 5 — a preview for a hover, never the set; `admin_count` is the size. `name` and `email` are both null for someone who has left the organization.
    - `user_id` string
    - `name` string, nullable
    - `email` string, nullable
    - `avatar_url` string, nullable: The person's picture: their stored profile picture, else a Gravatar URL (`d=404`, 96px) derived from their email (the address itself is not sent), else null. Draw initials when it is null or the image fails to load.
    - `is_admin` boolean: Always true here.
  - `member_preview` object[]: The same, for the first few members (administrators included, flagged by `is_admin`). `member_count` is the size; `GET /team/{id}/member` is the full, paginated roster.
    - `user_id` string
    - `name` string, nullable
    - `email` string, nullable
    - `avatar_url` string, nullable: The person's picture: their stored profile picture, else a Gravatar URL (`d=404`, 96px) derived from their email (the address itself is not sent), else null. Draw initials when it is null or the image fails to load.
    - `is_admin` boolean
  - `created_at` string, date-time
  - `updated_at` string, date-time

## Other responses

- `400`: Bad request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `429`: Rate limited

---

[API](https://skmtc.dev/elaichi/apis/elaichi-api.md) · [All operations](https://skmtc.dev/elaichi/apis/elaichi-api/llms.txt) · [OpenAPI document](https://skmtc.dev/elaichi/apis/elaichi-api/revisions/b22cfb7b6d15?raw)
