---
title: "Teams API: members, runs and triggers"
description: "Halo HTTP API for teams of Digital Humans: create and dissolve teams, manage members, start and stop runs, set triggers, and read boards and outputs."
type: "reference"
audience: ["developer"]
lang: "en"
canonical: "https://hello-halo.cc/docs/en/developers/api/team.html"
last_updated: "2026-10-19T00:11:17+08:00"
source: "Halo 3.0.4 docs"
---
# API: Teams

Halo HTTP API for teams of Digital Humans: create and dissolve teams, manage members, start and stop runs, set triggers, and read boards and outputs.

A team is a group of Digital Humans working toward one goal. Use these operations to create and dissolve teams, manage members and how they work together, start and stop runs, set triggers, and read boards, conversations and the files a run produced.

Paths are relative to your Halo base URL, and every request carries the access password. Set `$HALO_URL` and `$HALO_TOKEN` as in the [quickstart](https://hello-halo.cc/docs/en/developers/quickstart.html); base URL, authentication and error conventions are in the [HTTP API overview](https://hello-halo.cc/docs/en/developers/api/).

| Operation | Endpoint |
| --- | --- |
| [List teams, optionally only those owned by one space](#get-api-teams) | `GET /api/teams` |
| [Create a persistent team, with a lead provisioned for it](#post-api-teams) | `POST /api/teams` |
| [Get one team's own record](#get-api-teams-teamid) | `GET /api/teams/:teamId` |
| [Edit a team's name, goal, mode, escalation routing or lead](#patch-api-teams-teamid) | `PATCH /api/teams/:teamId` |
| [Dissolve a team](#delete-api-teams-teamid)  (Irreversible) | `DELETE /api/teams/:teamId` |
| [List files each member produced in the current or latest run](#get-api-teams-teamid-artifacts) | `GET /api/teams/:teamId/artifacts` |
| [Read one member's transcript within a team](#get-api-teams-teamid-chat-messages) | `GET /api/teams/:teamId/chat-messages` |
| [Stop one periodic check a member set inside a team](#delete-api-teams-teamid-checks-checkid)  (Irreversible) | `DELETE /api/teams/:teamId/checks/:checkId` |
| [List a team's open conversations, newest first](#get-api-teams-teamid-conversations) | `GET /api/teams/:teamId/conversations` |
| [Open a new team conversation](#post-api-teams-teamid-conversations) | `POST /api/teams/:teamId/conversations` |
| [Rename a team conversation](#patch-api-teams-teamid-conversations-epochid) | `PATCH /api/teams/:teamId/conversations/:epochId` |
| [Archive (close) a team conversation](#delete-api-teams-teamid-conversations-epochid)  (Irreversible) | `DELETE /api/teams/:teamId/conversations/:epochId` |
| [Get a team with members, edges, roster status, board and decisions](#get-api-teams-teamid-detail) | `GET /api/teams/:teamId/detail` |
| [Replace who hands work to whom in a structured team](#put-api-teams-teamid-edges) | `PUT /api/teams/:teamId/edges` |
| [List a team's runs and conversations (history), newest first](#get-api-teams-teamid-epochs) | `GET /api/teams/:teamId/epochs` |
| [List files produced during one run](#get-api-teams-teamid-epochs-epochid-artifacts) | `GET /api/teams/:teamId/epochs/:epochId/artifacts` |
| [Get the tasks, findings and members of one run](#get-api-teams-teamid-epochs-epochid-board) | `GET /api/teams/:teamId/epochs/:epochId/board` |
| [See which computers of a shared team are online](#get-api-teams-teamid-federation-presence) | `GET /api/teams/:teamId/federation/presence` |
| [Leave a team hosted on someone else's computer](#post-api-teams-teamid-leave)  (Irreversible) | `POST /api/teams/:teamId/leave` |
| [Add an existing digital human to a team](#post-api-teams-teamid-members) | `POST /api/teams/:teamId/members` |
| [Rewrite what a member is responsible for in this team](#patch-api-teams-teamid-members-appid) | `PATCH /api/teams/:teamId/members/:appId` |
| [Remove a member from a team](#delete-api-teams-teamid-members-appid)  (Irreversible) | `DELETE /api/teams/:teamId/members/:appId` |
| [Send a message to one team member and wait for its reply](#post-api-teams-teamid-members-appid-send) | `POST /api/teams/:teamId/members/:appId/send` |
| [Stop the turn one team member is running](#post-api-teams-teamid-members-appid-stop) | `POST /api/teams/:teamId/members/:appId/stop` |
| [Stop the team's current run](#post-api-teams-teamid-pause) | `POST /api/teams/:teamId/pause` |
| [Start a team run on its goal](#post-api-teams-teamid-run) | `POST /api/teams/:teamId/run` |
| [Keep a temporary collaboration as a persistent team](#post-api-teams-teamid-save-collab) | `POST /api/teams/:teamId/save-collab` |
| [List a team's schedules and other triggers](#get-api-teams-teamid-triggers) | `GET /api/teams/:teamId/triggers` |
| [Add a schedule, file or WeCom trigger to a team, or change one](#post-api-teams-teamid-triggers) | `POST /api/teams/:teamId/triggers` |
| [Remove a schedule or other trigger from a team](#delete-api-teams-teamid-triggers-triggerid)  (Irreversible) | `DELETE /api/teams/:teamId/triggers/:triggerId` |
| [Get the temporary collaboration started from one conversation](#get-api-teams-collab-for-conversation-conversationid) | `GET /api/teams/collab-for-conversation/:conversationId` |
| [Draft AI member roles for a team goal (creates nothing)](#post-api-teams-propose-members) | `POST /api/teams/propose-members` |

## List teams, optionally only those owned by one space {#get-api-teams}

`GET /api/teams`  (Assistant)

- Optional query parameter `spaceId` narrows the list to teams owned by one workspace; without it the list covers every workspace, as the Halo app shows it.
- `ephemeral: true` marks a temporary collaboration started from a conversation. It stays off the Teams page until it is kept with [`POST /api/teams/:teamId/save-collab`](#post-api-teams-teamid-save-collab).
- `hostNodeId` set means the team is hosted on someone else's computer and was joined from here: you can read it and message its members, but not edit or run it.

**Query parameters**: `spaceId`

**Response**

```ts
{success:true,data:[{id,name,status:"idle"|"running"|"waiting_user"|"error",memberCount,hasWaitingUser,waitingCount?,leadAppId,localMembers:[{appId,memberName,isLead}],hostNodeId?,ephemeral?,updatedAt}]}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Create a persistent team, with a lead provisioned for it {#post-api-teams}

`POST /api/teams`  (Reversible)  (Assistant)

- memberSourcing "manual": members are existing digital humans (appId from [`GET /api/apps`](https://hello-halo.cc/docs/en/developers/api/digital-human.html#get-api-apps)). memberSourcing "ai": omit members and send "confirmedProposal": [{memberName, role, responsibility}] (up to 5) beside "input" — [`POST /api/teams/propose-members`](#post-api-teams-propose-members) drafts one; Halo creates a new digital human for each.
- collabMode: "free" (members contact anyone) or "structured" (edges are generated from the lead; edit them with [`PUT /api/teams/:teamId/edges`](#put-api-teams-teamid-edges)). escalationRouting: "user" (questions go to the user) or "lead".
- Creates digital humans (the lead, and AI-sourced members) as a side effect; on any failure the whole team is rolled back.
- Create a persistent team only when the user asked for one. Members' delegated permissions are set in the Halo app — see this page's withheld list.

**Request body**

```json
{
  "input": {
    "name": "Weekly market brief",
    "goal": "Every Monday, summarise competitor moves into brief.md",
    "owningSpaceId": "<spaceId — a uuid from GET /api/spaces>",
    "memberSourcing": "manual",
    "collabMode": "free",
    "escalationRouting": "user",
    "members": [
      {
        "appId": "<appId — a digital human from GET /api/apps>",
        "memberName": "Researcher",
        "role": "Research",
        "duty": "Collects competitor news"
      }
    ]
  }
}
```

**Response**

```ts
{success:true,data:{id,name,owningSpaceId,goal,leadAppId,memberSourcing,collabMode,escalationRouting,status,currentEpochId,createdAt,updatedAt}}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/teams" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"input":{"name":"Weekly market brief","goal":"Every Monday, summarise competitor moves into brief.md","owningSpaceId":"<spaceId — a uuid from GET /api/spaces>","memberSourcing":"manual","collabMode":"free","escalationRouting":"user","members":[{"appId":"<appId — a digital human from GET /api/apps>","memberName":"Researcher","role":"Research","duty":"Collects competitor news"}]}}'
```

## Get one team's own record {#get-api-teams-teamid}

`GET /api/teams/:teamId`  (Assistant)

- For members, edges, live board and waiting decisions use [`GET /api/teams/:teamId/detail`](#get-api-teams-teamid-detail).

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Response**

```ts
{success:true,data:{id,name,owningSpaceId,goal,leadAppId,memberSourcing,collabMode,escalationRouting,status,currentEpochId,hostNodeId,ephemeral?,createdAt,updatedAt} | null}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams/<teamId>" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Edit a team's name, goal, mode, escalation routing or lead {#patch-api-teams-teamid}

`PATCH /api/teams/:teamId`  (Reversible)  (Assistant)

- Only the fields sent change. Also accepts "collabMode": "free"|"structured", "escalationRouting": "user"|"lead", "leadAppId".

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Request body**

```json
{
  "name": "New name",
  "goal": "New goal"
}
```

**Response**

```ts
{success:true,data:{id,name,goal,collabMode,escalationRouting,leadAppId,...}}
```

**Example**

```bash
curl -sX PATCH "$HALO_URL/api/teams/<teamId>" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"New name","goal":"New goal"}'
```

## Dissolve a team {#delete-api-teams-teamid}

`DELETE /api/teams/:teamId`  (Irreversible)  (Assistant)

::: danger Irreversible
This cannot be undone, and nothing goes to a trash folder. Make sure it is what the user wants before you call it.
If you only need something narrower, use [`DELETE /api/teams/:teamId/members/:appId`](#delete-api-teams-teamid-members-appid)
:::

- Also deletes the Digital Humans Halo created for this team (its lead and the members Halo added) and their workspaces. Digital Humans the user added stay. The run history goes with the team.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Response**

```ts
{success:true}
```

**Example**

```bash
curl -sX DELETE "$HALO_URL/api/teams/<teamId>" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## List files each member produced in the current or latest run {#get-api-teams-teamid-artifacts}

`GET /api/teams/:teamId/artifacts`  (Assistant)

- Covers the current or latest run. For an earlier run use [`GET /api/teams/:teamId/epochs/:epochId/artifacts`](#get-api-teams-teamid-epochs-epochid-artifacts). Read a file's content with [`GET /api/artifacts/content`](https://hello-halo.cc/docs/en/developers/api/workspace.html#get-api-artifacts-content) and its `path`.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Response**

```ts
{success:true,data:[{appId,memberName,spaceId,epochId,artifacts:[{name,type:"file"|"folder",path,relativePath,size?,createdAt}]}]}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams/<teamId>/artifacts" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Read one member's transcript within a team {#get-api-teams-teamid-chat-messages}

`GET /api/teams/:teamId/chat-messages`  (Assistant)

- Optional query: &amp;epochId= (a run or conversation id from [`GET /api/teams/:teamId/epochs`](#get-api-teams-teamid-epochs); default: the open run, else the member's own chat, else the latest), &amp;sinceSeq= for incremental reads.
- A member on another computer is fetched from its owner; stale:true means a cached copy because the owner is offline, and a 502 means it is unavailable right now.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Query parameters**: `appId` (required), `epochId`, `sinceSeq`

**Response**

```ts
{success:true,data:[messages],stale?:true}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams/<teamId>/chat-messages?appId=<appId — a member appId from GET /api/teams/:teamId/detail>" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Stop one periodic check a member set inside a team {#delete-api-teams-teamid-checks-checkid}

`DELETE /api/teams/:teamId/checks/:checkId`  (Irreversible)  (Assistant)

::: danger Irreversible
This cannot be undone, and nothing goes to a trash folder. Make sure it is what the user wants before you call it.
:::

- checkId comes from checks[] in [`GET /api/teams/:teamId/detail`](#get-api-teams-teamid-detail).

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |
| `checkId` | Id of a periodic check a team member set. |

**Response**

```ts
{success:true}
```

**Example**

```bash
curl -sX DELETE "$HALO_URL/api/teams/<teamId>/checks/<checkId>" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## List a team's open conversations, newest first {#get-api-teams-teamid-conversations}

`GET /api/teams/:teamId/conversations`  (Assistant)

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Response**

```ts
{success:true,data:[{epochId,teamId,kind:"native"|"im"|"member"|"run"|"collab",label,readonly,memberAppId?,channel?,startedAt,lastActivityAt,active?,waitingUser?}]}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams/<teamId>/conversations" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Open a new team conversation {#post-api-teams-teamid-conversations}

`POST /api/teams/:teamId/conversations`  (Reversible)  (Assistant)

- Optional body: "memberAppId" to open it as a one-to-one thread with that member.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Request body**

```json
{
  "title": "optional title"
}
```

**Response**

```ts
{success:true,data:{epochId}}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/teams/<teamId>/conversations" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"optional title"}'
```

## Rename a team conversation {#patch-api-teams-teamid-conversations-epochid}

`PATCH /api/teams/:teamId/conversations/:epochId`  (Reversible)  (Assistant)

- Send "title": null to go back to the derived label.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |
| `epochId` | Id of one team run or conversation, from [`GET /api/teams/:teamId/epochs`](#get-api-teams-teamid-epochs). |

**Request body**

```json
{
  "title": "New title"
}
```

**Response**

```ts
{success:true}
```

**Example**

```bash
curl -sX PATCH "$HALO_URL/api/teams/<teamId>/conversations/<epochId>" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"New title"}'
```

## Archive (close) a team conversation {#delete-api-teams-teamid-conversations-epochid}

`DELETE /api/teams/:teamId/conversations/:epochId`  (Irreversible)  (Assistant)

::: danger Irreversible
This cannot be undone, and nothing goes to a trash folder. Make sure it is what the user wants before you call it.
:::

- The conversation stays in run history ([`GET /api/teams/:teamId/epochs`](#get-api-teams-teamid-epochs)) but can no longer take messages.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |
| `epochId` | Id of one team run or conversation, from [`GET /api/teams/:teamId/epochs`](#get-api-teams-teamid-epochs). |

**Response**

```ts
{success:true}
```

**Example**

```bash
curl -sX DELETE "$HALO_URL/api/teams/<teamId>/conversations/<epochId>" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Get a team with members, edges, roster status, board and decisions {#get-api-teams-teamid-detail}

`GET /api/teams/:teamId/detail`  (Assistant)

- The richest single read of a team; start here when the user asks how a team is doing. A pending escalation is answered by the user in Halo, not over this API.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Response**

```ts
{success:true,data:{team,members:[{appId,memberName,role,duty,isLead,origin,ownerDisplayName,...}],edges:[{fromAppId,toAppId,sync}],roster:[{appId,memberName,role,status:"working"|"idle"|"error"|"waiting_user",currentTaskTitle?}],tasks:[{id,title,assigneeAppId,status,resultRef,note}],findings:[...],activities?,pendingEscalations?:[{appId,memberName,entryId,question}],checks?:[{id,targetMemberName,instruction,schedule,runCount}],boardEpochId,crossesMachines?} | null}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams/<teamId>/detail" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Replace who hands work to whom in a structured team {#put-api-teams-teamid-edges}

`PUT /api/teams/:teamId/edges`  (Reversible)  (Assistant)

- Replaces the whole list. Read the current edges from [`GET /api/teams/:teamId/detail`](#get-api-teams-teamid-detail), change them and send the full list back. Only meaningful when the team's `collabMode` is `structured`; member ids come from the same response.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Request body**

```json
{
  "edges": [
    {
      "fromAppId": "<appId>",
      "toAppId": "<appId>",
      "sync": false
    }
  ]
}
```

**Response**

```ts
{success:true}
```

**Example**

```bash
curl -sX PUT "$HALO_URL/api/teams/<teamId>/edges" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"edges":[{"fromAppId":"<appId>","toAppId":"<appId>","sync":false}]}'
```

## List a team's runs and conversations (history), newest first {#get-api-teams-teamid-epochs}

`GET /api/teams/:teamId/epochs`  (Assistant)

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Response**

```ts
{success:true,data:[{id,startedAt,lastActivityAt,endedAt,endReason,summary,taskCount,doneCount,lifecycle:"run"|"conversation",label?,outcome?:"output"|"no_action"|"escalation"|"failed",triggerType?,artifactCount?}]}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams/<teamId>/epochs" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## List files produced during one run {#get-api-teams-teamid-epochs-epochid-artifacts}

`GET /api/teams/:teamId/epochs/:epochId/artifacts`  (Assistant)

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |
| `epochId` | Id of one team run or conversation, from [`GET /api/teams/:teamId/epochs`](#get-api-teams-teamid-epochs). |

**Response**

```ts
{success:true,data:[{appId,memberName,spaceId,epochId,artifacts:[...]}]}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams/<teamId>/epochs/<epochId>/artifacts" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Get the tasks, findings and members of one run {#get-api-teams-teamid-epochs-epochid-board}

`GET /api/teams/:teamId/epochs/:epochId/board`  (Assistant)

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |
| `epochId` | Id of one team run or conversation, from [`GET /api/teams/:teamId/epochs`](#get-api-teams-teamid-epochs). |

**Response**

```ts
{success:true,data:{epoch,tasks:[...],findings:[...],members:[...],activities?} | null}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams/<teamId>/epochs/<epochId>/board" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## See which computers of a shared team are online {#get-api-teams-teamid-federation-presence}

`GET /api/teams/:teamId/federation/presence`  (Assistant)

- null means the team is not shared with other computers.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Response**

```ts
{success:true,data:{officeId,role:"host"|"joined",nodes:[{nodeId,displayName,status,lastSeen}],authority} | null}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams/<teamId>/federation/presence" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Leave a team hosted on someone else's computer {#post-api-teams-teamid-leave}

`POST /api/teams/:teamId/leave`  (Irreversible)  (Assistant)

::: danger Irreversible
This cannot be undone, and nothing goes to a trash folder. Make sure it is what the user wants before you call it.
:::

- Only for a team joined from another computer (`hostNodeId` set in [`GET /api/teams`](#get-api-teams)). The members this computer brought leave with it; joining again needs a new invite from the host.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Request body**

```json
{}
```

**Response**

```ts
{success:true} | {success:false,error}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/teams/<teamId>/leave" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Add an existing digital human to a team {#post-api-teams-teamid-members}

`POST /api/teams/:teamId/members`  (Reversible)  (Assistant)

- To have Halo create a new digital human for a role, create one first (digital-human group) and add it here. Delegated permissions are set in the Halo app — see this page's withheld list.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Request body**

```json
{
  "appId": "<appId — a digital human from GET /api/apps>",
  "memberName": "Reviewer",
  "role": "Review",
  "duty": "Checks every draft before it is filed"
}
```

**Response**

```ts
{success:true,data:{teamId,appId,memberName,role,duty,isLead,addedAt,...}}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/teams/<teamId>/members" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"appId":"<appId — a digital human from GET /api/apps>","memberName":"Reviewer","role":"Review","duty":"Checks every draft before it is filed"}'
```

## Rewrite what a member is responsible for in this team {#patch-api-teams-teamid-members-appid}

`PATCH /api/teams/:teamId/members/:appId`  (Reversible)  (Assistant)

- Only members that run on this computer can be changed; a member someone else brought is refused. Delegated permissions are set in the Halo app — see this page's withheld list.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |
| `appId` | Digital Human id, from [`GET /api/apps`](https://hello-halo.cc/docs/en/developers/api/digital-human.html#get-api-apps). |

**Request body**

```json
{
  "duty": "Owns the pricing section"
}
```

**Response**

```ts
{success:true,data:{teamId,appId,memberName,role,duty,...}}
```

**Example**

```bash
curl -sX PATCH "$HALO_URL/api/teams/<teamId>/members/<appId>" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"duty":"Owns the pricing section"}'
```

## Remove a member from a team {#delete-api-teams-teamid-members-appid}

`DELETE /api/teams/:teamId/members/:appId`  (Irreversible)  (Assistant)

::: danger Irreversible
This cannot be undone, and nothing goes to a trash folder. Make sure it is what the user wants before you call it.
:::

- The digital human itself stays installed unless Halo created it only for this team.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |
| `appId` | Digital Human id, from [`GET /api/apps`](https://hello-halo.cc/docs/en/developers/api/digital-human.html#get-api-apps). |

**Response**

```ts
{success:true}
```

**Example**

```bash
curl -sX DELETE "$HALO_URL/api/teams/<teamId>/members/<appId>" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Send a message to one team member and wait for its reply {#post-api-teams-teamid-members-appid-send}

`POST /api/teams/:teamId/members/:appId/send`  (Reversible)  (Assistant)

- Blocks until the member finishes its turn (can take minutes) and returns its final message. delivery "queued"/"mid_turn" means the member was busy: the message was accepted but no reply exists yet — read it later with [`GET /api/teams/:teamId/chat-messages`](#get-api-teams-teamid-chat-messages).
- Optional body: "epochId" to address a specific run or conversation. Works for members on other computers too.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |
| `appId` | Digital Human id, from [`GET /api/apps`](https://hello-halo.cc/docs/en/developers/api/digital-human.html#get-api-apps). |

**Request body**

```json
{
  "message": "Please re-check the pricing section"
}
```

**Response**

```ts
{success:true,data:{ok,finalMessage,reason?,delivery?:"queued"|"mid_turn"}}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/teams/<teamId>/members/<appId>/send" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message":"Please re-check the pricing section"}'
```

## Stop the turn one team member is running {#post-api-teams-teamid-members-appid-stop}

`POST /api/teams/:teamId/members/:appId/stop`  (Reversible)  (Assistant)

- Optional body: "epochId". To stop the whole team run instead, [`POST /api/teams/:teamId/pause`](#post-api-teams-teamid-pause).

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |
| `appId` | Digital Human id, from [`GET /api/apps`](https://hello-halo.cc/docs/en/developers/api/digital-human.html#get-api-apps). |

**Request body**

```json
{}
```

**Response**

```ts
{success:true,data:{ok,stopped,reason?}}  — stopped:false means nothing was running
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/teams/<teamId>/members/<appId>/stop" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Stop the team's current run {#post-api-teams-teamid-pause}

`POST /api/teams/:teamId/pause`  (Reversible)  (Assistant)

- Seals the run as stopped; members mid-turn are stopped with it. Start again with [`POST /api/teams/:teamId/run`](#post-api-teams-teamid-run).

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Request body**

```json
{}
```

**Response**

```ts
{success:true}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/teams/<teamId>/pause" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Start a team run on its goal {#post-api-teams-teamid-run}

`POST /api/teams/:teamId/run`  (Reversible)  (Assistant)

- Starts a run on the team's goal and returns once it has started; the run continues in the background. The lead works from the team goal, as this call carries no brief.
- Fails for a temporary collaboration (keep it first) and for a team hosted on another computer. Follow progress with [`GET /api/teams/:teamId/detail`](#get-api-teams-teamid-detail) or over the WebSocket.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Request body**

```json
{}
```

**Response**

```ts
{success:true}  — returns once the run has started; it continues in the background
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/teams/<teamId>/run" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Keep a temporary collaboration as a persistent team {#post-api-teams-teamid-save-collab}

`POST /api/teams/:teamId/save-collab`  (Reversible)  (Assistant)

- Keeps a temporary collaboration as a team, optionally under a new `name`. Keep one when the user asked for it.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Request body**

```json
{
  "name": "Market research team"
}
```

**Response**

```ts
{success:true,data:{id,name,owningSpaceId,goal,leadAppId,status,...}}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/teams/<teamId>/save-collab" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Market research team"}'
```

## List a team's schedules and other triggers {#get-api-teams-teamid-triggers}

`GET /api/teams/:teamId/triggers`  (Assistant)

- `config` is returned as stored, including any secret it holds. Treat the response like a secret.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Response**

```ts
{success:true,data:[{id,teamId,sourceType:"schedule"|"webhook"|"file"|"wecom",config,enabled,createdAt}]}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams/<teamId>/triggers" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Add a schedule, file or WeCom trigger to a team, or change one {#post-api-teams-teamid-triggers}

`POST /api/teams/:teamId/triggers`  (Reversible)  (Assistant)

- `config` by `sourceType`: `schedule` takes `{"every": "30m"}` or `{"cron": "0 9 * * 1"}`; `file` takes `{"pattern": "*.csv", "path": "&lt;part of the folder path&gt;"}`; `wecom` takes `{"chatId": "&lt;optional&gt;"}`.
- To change an existing trigger, send `triggerId` next to `trigger`; its `sourceType` must stay the same.

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |

**Request body**

```json
{
  "trigger": {
    "sourceType": "schedule",
    "config": {
      "cron": "0 9 * * 1"
    },
    "enabled": true
  }
}
```

**Response**

```ts
{success:true,data:{id,teamId,sourceType,config,enabled,createdAt}}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/teams/<teamId>/triggers" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"trigger":{"sourceType":"schedule","config":{"cron":"0 9 * * 1"},"enabled":true}}'
```

## Remove a schedule or other trigger from a team {#delete-api-teams-teamid-triggers-triggerid}

`DELETE /api/teams/:teamId/triggers/:triggerId`  (Irreversible)  (Assistant)

::: danger Irreversible
This cannot be undone, and nothing goes to a trash folder. Make sure it is what the user wants before you call it.
If you only need something narrower, use [`POST /api/teams/:teamId/triggers`](#post-api-teams-teamid-triggers)
:::

- To pause one without losing it, [`POST /api/teams/:teamId/triggers`](#post-api-teams-teamid-triggers) with its triggerId and "enabled": false (not a webhook trigger — see this page's withheld list).

**Path parameters**

| Name | Description |
| --- | --- |
| `teamId` | Team id, from [`GET /api/teams`](#get-api-teams). |
| `triggerId` | Trigger id, from [`GET /api/teams/:teamId/triggers`](#get-api-teams-teamid-triggers). |

**Response**

```ts
{success:true}
```

**Example**

```bash
curl -sX DELETE "$HALO_URL/api/teams/<teamId>/triggers/<triggerId>" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Get the temporary collaboration started from one conversation {#get-api-teams-collab-for-conversation-conversationid}

`GET /api/teams/collab-for-conversation/:conversationId`  (Assistant)

- conversationId is a space conversation id ([`GET /api/spaces/:spaceId/conversations`](https://hello-halo.cc/docs/en/developers/api/conversation.html#get-api-spaces-spaceid-conversations)). null means that conversation never started a collaboration.

**Path parameters**

| Name | Description |
| --- | --- |
| `conversationId` | Conversation id, from [`GET /api/spaces/:spaceId/conversations`](https://hello-halo.cc/docs/en/developers/api/conversation.html#get-api-spaces-spaceid-conversations). |

**Response**

```ts
{success:true,data:{teamId,name,goal,epochId,active,saved,members:[...]} | null}
```

**Example**

```bash
curl -s "$HALO_URL/api/teams/collab-for-conversation/<conversationId>" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Draft AI member roles for a team goal (creates nothing) {#post-api-teams-propose-members}

`POST /api/teams/propose-members`  (Assistant)

- Runs a model call, so it takes a few seconds. Show the draft to the user, then pass it as confirmedProposal to [`POST /api/teams`](#post-api-teams) with memberSourcing "ai".

**Request body**

```json
{
  "goal": "Every Monday, summarise competitor moves into brief.md",
  "owningSpaceId": "<spaceId — a uuid from GET /api/spaces>"
}
```

**Response**

```ts
{success:true,data:[{memberName,role,responsibility}]}  — at most 5
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/teams/propose-members" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"goal":"Every Monday, summarise competitor moves into brief.md","owningSpaceId":"<spaceId — a uuid from GET /api/spaces>"}'
```
