# See Who Did What on Your Team with the xCloud Public API and MCP

> Find out who deleted a site or what your team did this week with GET /api/v1/activity or the activity_list MCP tool: filters, access and limits.

Team activity tells you who did what in your xCloud team over the last 30 days, newest first. Use it to answer "who deleted example.com?" or "what did my team do this week?" from a script or an AI agent. Call `GET /api/v1/activity`, or ask an agent to run the `activity_list` MCP tool. It only reads data, and it changes nothing on your servers.

The dashboard already shows the same history on the **All Events** page. Open it with **View All Events** in the events menu at the top of the dashboard. For one server or site, see [How to View Logs and Events for Your Server and Site](/docs/view-logs-and-events-of-your-server-and-site/).

## Prerequisites

- **Your role:** the team owner, or a **Team Admin** with the server logs and events permission. In the member's permissions, this is the one that reads "Allows members to handle and manage server related events or triggers and server logs for troubleshooting or analysis". Server Admins and Site Admins cannot read team activity.
- **Your token:** an xCloud API token with **both** `read:servers` and `read:sites`. A read-only token is enough. See [How to Access the xCloud API](/docs/how-to-access-the-xcloud-api/) to create one.
- **For MCP:** the token or connection must also allow MCP (`mcp:invoke`). An OAuth connection from an MCP client works too. See [How to Connect xCloud MCP to Your AI Agent](/docs/how-to-connect-xcloud-mcp-to-ai-agent/).

## What each entry holds

| Field | What it holds |
|---|---|
| `uuid`, `name` | The entry's ID and its name, such as `Backup Site: example.com` |
| `type`, `status` | The kind of action, and `queued`, `running`, `finished`, `failed`, `timeout` or `killed` |
| `created_at`, `finished_at` | When it started and ended. `finished_at` is `null` while it is queued or running |
| `server` | The server's `uuid` and `name`, and `deleted: true` if the server has since been archived. `null` when the entry has no server, or the server was permanently deleted |
| `site` | The site's `uuid` and `name`. `null` when the entry names no site or the site is gone |
| `site_deleted` | `true` only when the entry recorded a site that no longer exists |
| `initiated_by` | The `uuid` and `name` of the person who started it. `null` when xCloud started it itself, or the person's account was deleted |

Emails, command output and scripts are never included.

## Step 1: List your team's recent activity

Send a `GET` request with your token. Store the token in an environment variable instead of pasting it into the command.

```bash
export XCLOUD_TOKEN='xc_live_xxxxxxxxxxxx'

curl 'https://app.xcloud.host/api/v1/activity?per_page=25' \
  --header "Authorization: Bearer $XCLOUD_TOKEN" \
  --header 'Accept: application/json'
```

**Expected result:** a `200` response with the newest entries first and a `pagination` block. `per_page` is 10 by default and 100 at most. Increase `page` to read further back.

```json
{
  "success": true,
  "message": "Success",
  "data": {
    "items": [
      {
        "uuid": "9b1f2a3d-4e5f-4a7b-8c9d-0e1f2a3b4c5d",
        "name": "Backup Site: example.com",
        "type": "system",
        "status": "finished",
        "created_at": "2026-11-03T09:30:00+00:00",
        "finished_at": "2026-11-03T09:31:00+00:00",
        "server": {
          "uuid": "9a1f0c2e-4b7d-4e8a-9c3f-1d2e3f4a5b6c",
          "name": "docs-demo",
          "deleted": false
        },
        "site": {
          "uuid": "3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f",
          "name": "example.com"
        },
        "site_deleted": false,
        "initiated_by": {
          "uuid": "7e8f9a0b-1c2d-4e3f-8a4b-5c6d7e8f9a0b",
          "name": "Jane Doe"
        }
      }
    ],
    "pagination": { "total": 1, "per_page": 25, "current_page": 1, "last_page": 1 }
  }
}
```

To read another team you have access to, add the `X-Team-Id` header with that team's UUID from `GET /api/v1/teams`. See [Multi-Team API Tokens and MCP Access](/docs/multi-team-api-tokens-and-mcp-access/).

## Step 2: Find who deleted a site

Search for the site's domain. A deleted site has no ID left to filter by, so `search` is the way to find it. It matches 3 to 100 characters against the entry's name.

```bash
curl 'https://app.xcloud.host/api/v1/activity?search=old.example.com' \
  --header "Authorization: Bearer $XCLOUD_TOKEN" \
  --header 'Accept: application/json'
```

**Expected result:** in most cases, the deletion entry is named `Deleting Site (<domain> on <server>)`, and `initiated_by` holds who deleted it:

```json
{
  "name": "Deleting Site (old.example.com on docs-demo)",
  "status": "finished",
  "created_at": "2026-11-03T08:56:00+00:00",
  "site": null,
  "site_deleted": false,
  "initiated_by": {
    "uuid": "7e8f9a0b-1c2d-4e3f-8a4b-5c6d7e8f9a0b",
    "name": "Jane Doe"
  }
}
```

The deletion entry reads `site: null` and `site_deleted: false`, because it does not record the site. So don't filter on `site_deleted` to find deletions. That field is `true` only on other entries, the ones that recorded the site before it was deleted.

If the search finds no such entry, the deletion may be one that team activity [leaves out](#what-team-activity-leaves-out).

## Step 3: Narrow the list

Combine any of these filters as query parameters:

| Filter | What it does |
|---|---|
| `server` | One server's UUID. Archived servers work too; a permanently deleted server returns an empty list |
| `site` | One live site's UUID |
| `initiated_by` | One person's UUID, taken from `initiated_by.uuid` in an earlier response |
| `type` | One kind of action, such as `deployment`, `custom`, `system`, `cleanup` or `security_patch`. A value that isn't allowed returns `422` with the full list |
| `status` | `queued`, `running`, `finished`, `failed`, `timeout` or `killed` |
| `since`, `until` | A time window. `since` can go back 30 days at most, and `until` cannot be in the future |
| `search` | 3 to 100 characters matched against the entry's name |

For example, this lists what failed for one person since 1 November:

```bash
curl -G 'https://app.xcloud.host/api/v1/activity' \
  --data-urlencode 'since=2026-11-01T00:00:00+06:00' \
  --data-urlencode 'status=failed' \
  --data-urlencode 'initiated_by=7e8f9a0b-1c2d-4e3f-8a4b-5c6d7e8f9a0b' \
  --header "Authorization: Bearer $XCLOUD_TOKEN" \
  --header 'Accept: application/json'
```

**Expected result:** only the entries that match every filter. Without `since`, the list starts 30 days ago.

`since` and `until` need a date, a time and an offset, such as `2026-11-01T00:00:00Z`. A bare date returns `422`. When you build the URL yourself, send the `+` in an offset as `%2B`, or use `Z`. `--data-urlencode` does this for you.

An unknown UUID in `server`, `site` or `initiated_by` returns an empty page with `200`, not a `404`. So an empty list can also mean the UUID is wrong, or that it belongs to a deleted site or a permanently deleted server.

## Step 4: Ask an AI agent

In an MCP client connected to xCloud, ask in plain language:

```text
Who deleted old.example.com in my xCloud team, and when?
```

```text
What did my team do on xCloud this week? List anything that failed.
```

The agent runs the `activity_list` tool, which returns the same data as the API. On the compact MCP profile, the agent finds the `activity.list` operation with search and runs it through `xcloud_execute_read`, which changes nothing.

**Expected result:** an answer that names the person, the action and the time. If you have more than one team, name the team in the prompt.

## See who started an event on one server

`GET /api/v1/servers/{uuid}/tasks` lists one server's events, and each one now has the same `initiated_by` field. It needs only `read:servers` and permission to see that server's logs and events, so people who can't read team activity may still be able to use it.

```bash
curl 'https://app.xcloud.host/api/v1/servers/SERVER_UUID/tasks?per_page=10' \
  --header "Authorization: Bearer $XCLOUD_TOKEN" \
  --header 'Accept: application/json'
```

**Expected result:** the server's events, newest first, with a short `output` preview and `initiated_by` as `{uuid, name}` or `null`. On a white-label team, `initiated_by` is also `null` when you don't hold the permission on the white label's owner team.

## What team activity leaves out

- **Some server deletions.** Archiving a server leaves no entry, and neither does removing it from xCloud only. Deleting it from its provider too, which always happens for xCloud and white-label servers, adds an entry named `DeleteServer` with `initiated_by`. That entry does not name the server once the server is gone.
- **The names of permanently deleted servers.** Entries stay for 30 days. `server.deleted` is `true` for an archived server. For a permanently deleted server, `server` is `null`.
- **Some site deletions.** If the site never started setting up, or its server had not finished setting up, there is no `Deleting Site` entry. Sites removed along with their server have none either.
- **Anything older than 30 days.** To keep a longer record, save the results on your side on a schedule.
- **Servers you cannot access.** If your access is limited to selected servers, the list covers only those, so entries for archived or permanently deleted servers may not appear.
- **Other teams.** Each request reads one team.

## Troubleshooting

| Response | Cause | Fix |
|---|---|---|
| `401` | No bearer token, or the token was revoked | Send `Authorization: Bearer <token>` with an active token |
| `403` "Invalid ability provided." | The token is missing `read:servers` or `read:sites` | Create a token with both. Tokens cannot be edited |
| `403` with both permissions | You are a Server Admin or Site Admin, or a Team Admin without the server logs and events permission | Ask the team owner to change your role or permission |
| `422` "The since format is invalid." | A bare date, or a `+` in the offset that wasn't encoded | Send a full date and time. Use `Z` or `%2B` |
| `422` "The since must not be older than 30 days." | The window starts too far back | Use a `since` within the last 30 days |
| `422` "The until must not be in the future." | `until` is more than 5 minutes ahead | Use the current time, or leave `until` out |
| `422` on `search` | The term is shorter than 3 or longer than 100 characters | Search for a longer part of the domain, or a shorter one |
| Empty list with `200` | Nothing matches, or a UUID is unknown or belongs to a deleted site or a permanently deleted server | Remove filters one at a time. For a deleted site or server, use `search` |
| `initiated_by` is `null` | xCloud started the action itself, or the person's account was deleted | No fix needed. The action is still listed |

## Frequently asked questions

### How do I find out who deleted a site in xCloud?

Call GET /api/v1/activity with search set to the site's domain, or ask an AI agent connected to xCloud MCP. The matching entry is named Deleting Site, followed by the domain and the server, and initiated_by holds the name of the person who deleted it. Entries stay for 30 days. Some deletions leave no such entry, such as when the site never started setting up or its server had not finished setting up.

### Why does GET /api/v1/activity return 403?

Either your token is missing read:servers or read:sites, or your role is not allowed. Only the team owner, or a Team Admin with the server logs and events permission, can read team activity. Server Admins and Site Admins receive 403.

### Why does my since filter return 422?

since and until need a full date and time with an offset, such as 2026-11-01T00:00:00Z. A bare date such as 2026-11-01 is rejected. since also cannot be more than 30 days ago, and a + in an offset must be sent as %2B in the URL.

### Can I see who deleted a server?

Sometimes. If the server is also deleted from its provider, which always happens for xCloud and white-label servers, the list has an entry named DeleteServer, and initiated_by holds the name of the person who deleted it. That entry does not name the server once the server is gone. Archiving a server leaves no entry, and neither does removing a server from xCloud only. Entries stay for 30 days. server.deleted is true for an archived server. For a permanently deleted server, server is null.

## Next steps

- Read every server and site in one call with [How to Get a Fleet Overview with the xCloud Public API and MCP](/docs/get-fleet-overview-with-xcloud-public-api-and-mcp/).
- Read the full request and response format in the [xCloud Public API reference](https://app.xcloud.host/api/v1/docs), and authentication and rate limits in the [xCloud API documentation overview](/docs/xcloud-api/).

If you run into any issues with team activity, feel free to reach out to our [support team](/docs/access-built-in-support-portal-in-xcloud/) for help.
