# List CRM changes

Source: https://help.ruuster.com/api/crm-changes-list

```http
GET https://api.ruuster.com/v1/crm/changes
```

The audit record of changes made to your CRM through Ruuster, newest first. Every request (in the person's words), who asked and from where, what it did, when it was confirmed and completed, and how many people were changed, skipped or failed, including previews that were never confirmed.

- Authentication: `x-api-key` and `x-email` headers of an owner or admin
- Rate limit: 120 requests per minute per key

Everything asked of your CRM through Ruuster stays on record and can't be deleted: every preview (confirmed or not), who asked for it (the Ruuster login and whether it came through an AI assistant), the request in the person's words, the action and its values, when it was confirmed, cancelled or completed, and the counts. Filter by status, by day, or to the changes that touched one CRM person. For one change's people with their before and after values, and its full history, use [Get a CRM change](https://help.ruuster.com/api/crm-change-get). No CRM key is needed.

## Query parameters

| Name | Type | Default | Description |
|---|---|---|---|
| `status` | `open` \| `proposed` \| `applying` \| `completed` \| `completed_with_errors` \| `cancelled` | | Only changes in this state; `open` is `proposed` or `applying`. An unconfirmed preview past its window shows as `expired` |
| `from` | date | | Changes created on or after this day, `YYYY-MM-DD` in America/Chicago |
| `to` | date | | Changes created before this day, `YYYY-MM-DD`, excluded |
| `personId` | string | | Only changes that included this CRM person id |
| `cursor` | string | | `meta.nextCursor` from the previous page |
| `limit` | integer | `25` | Changes per page, 1 to 100 |

## Response

`data.changes[]`, newest first: `changeId`, `status` (`proposed`, `expired`, `applying`, `completed`, `completed_with_errors`, `cancelled`), `action`, `summary`, `request`, `params`, `source`, `undoOf`, `vendor`, `crmAccount`, `crmUser` (the CRM user the key belongs to), `requestedBy` (`email`, `role`, `client`: `mcp` or `direct`), `counts` (`requested`, `willChange`, `skipped`, `done`, `failed`), `warnings`, `createdAt`, `expiresAt`, `confirmedAt`, `completedAt`, `cancelledAt`, `lastError`.

## Example request

cURL:

```bash
curl -s "https://api.ruuster.com/v1/crm/changes?status=completed&limit=1" \
  -H "x-api-key: $RUUSTER_API_KEY" \
  -H "x-email: $RUUSTER_EMAIL"
```

Node.js:

```javascript
const res = await fetch("https://api.ruuster.com/v1/crm/changes?status=completed&limit=1", {
  headers: {
    "x-api-key": process.env.RUUSTER_API_KEY,
    "x-email": process.env.RUUSTER_EMAIL,
  },
});
const body = await res.json();
if (!body.ok) throw new Error(`${body.error.code}: ${body.error.message} (${body.requestId})`);
console.log(body.data);
```

Python:

```python
import os
import requests

res = requests.get(
    "https://api.ruuster.com/v1/crm/changes?status=completed&limit=1",
    headers={"x-api-key": os.environ["RUUSTER_API_KEY"], "x-email": os.environ["RUUSTER_EMAIL"]},
    timeout=30,
)
body = res.json()
if not body["ok"]:
    raise RuntimeError(f'{body["error"]["code"]}: {body["error"]["message"]} ({body.get("requestId")})')
print(body["data"])
```

## Example response

```json
{
  "ok": true,
  "data": {
    "changes": [
      {
        "changeId": "crmchg_7Qm2VbX9kLp4RtYz",
        "status": "completed",
        "action": "add_tags",
        "summary": "Add the tag \"xyz\" to 2 people in Follow Up Boss.",
        "request": "Tag my leads who viewed homes in the last 7 days but haven't been called with xyz",
        "params": { "tags": ["xyz"] },
        "source": { "tool": "leads_follow_up", "criteria": { "from": "2026-10-15", "engagement": "viewed", "quietDays": 30 } },
        "undoOf": null,
        "vendor": "fub",
        "crmAccount": "examplerealty",
        "crmUser": "alex@examplerealty.com",
        "requestedBy": { "email": "alex@examplerealty.com", "role": "owner", "client": "mcp" },
        "counts": { "requested": 2, "willChange": 2, "skipped": 0, "done": 2, "failed": 0 },
        "warnings": ["Tags can start Follow Up Boss automations or action plans that are set to run on them."],
        "createdAt": "2026-10-22T19:00:00.000Z",
        "expiresAt": "2026-10-22T19:15:00.000Z",
        "confirmedAt": "2026-10-22T19:00:41.000Z",
        "completedAt": "2026-10-22T19:00:43.000Z",
        "cancelledAt": null,
        "lastError": null
      }
    ]
  },
  "meta": { "brokerageId": "41c73a1a-1dde-42e9-a9c9-0da74502b50e", "nextCursor": null }
}
```
