> ## Documentation Index
> Fetch the complete documentation index at: https://kb.aampe.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Audit Log

> Read the history of configuration changes in your Aampe account: who made each change, when, and what changed.

The audit log records configuration changes in your Aampe account (who made each one, when, and for most kinds of item the values before and after), and you can read it with three endpoints on the public API.

## Authentication

Send your Aampe API key in the `X-API-KEY` header on every request (see [Authentication](/api-guide/composer-api/authentication)). All endpoints are read-only `GET` requests under `https://composer.api.aampe.com/api`, and the key's user needs read access to the account.

```bash theme={null}
curl https://composer.api.aampe.com/api/activity-logs/account \
  -H "X-API-KEY: <your API key>"
```

Each request only ever returns your own account's history. Times are UTC, in ISO 8601 format.

***

## What's Recorded

Each change is one entry: who made it, when, what changed and, for most kinds of item, the values before and after. Entries are never edited or removed after they're written.

| What changed | `object_type` | Filed under (`target_type`) |
| - | - | - |
| Labels and label weights | `Label` | `Label` itself, for a label's creation |
| A label's component type | `LabelVariantType` | `Label` |
| Audiences and their filters | `Audience` | — |
| Triggers and their rules | `CompoundTrigger` | — |
| Frequency caps | `FrequencyLimit` | `CompoundTrigger`, when the cap belongs to a trigger |
| Default frequency caps, for the account or for one trigger | `DefaultFrequencyLimits` | `CompoundTrigger`, when the default belongs to a trigger |
| Reward functions, their target events and weight overrides | `RewardFunction` | — |
| A message created, or its settings or status changed | `Formula` | `Formula` itself |
| A label added to or removed from a message | `FormulaLabel` | `Formula` |
| A message's audience set | `FormulaAudience` | `Formula` |
| An alternate added to or removed from a message | `Variant` | `Formula` |

<Note>
  Some changes are recorded without values for now: their `data` is `null`, so an entry says who changed which item and when, but not what changed. This covers every `Formula`, `FormulaLabel`, `FormulaAudience`, `Variant` and `LabelVariantType` entry, and a label's creation. Tag changes and edits to an alternate's text aren't recorded yet.
</Note>

In every entry:

| Field | Meaning |
| - | - |
| `id` | The entry's id |
| `verb` | `CREATE`, `UPDATE`, `DELETE` or `ARCHIVE` |
| `object_type`, `object_id`, `object_name` | The item that changed, and its current name if it has one |
| `target_type`, `target_id`, `target_name` | The item it's filed under, if any |
| `user_id`, `user_name` | Who made the change |
| `created_at` | When (UTC) |
| `data` | `before`, `after` and `changed_fields`: the item's values before and after, and which fields differ |
| `transaction_id` | The save the change was part of. Changes made in one save share it. |
| `save_count`, `first_activity_id`, `first_created_at` | See [Combined saves](#combined-saves) |

`before` is `null` for a creation. Use `verb` to tell a deletion or archive apart: most items are kept when deleted or archived, so `after` holds the item with `deleted_at` or `archived_at` set, and `after` is `null` only when the item is removed outright. Ids of events and of audience-filter attributes and operators come with their names alongside, for example `event_id` with `event_name` and `event_code`. Snapshots in the examples on this page are excerpts. Older entries, from before the audit log launched, can have a simpler `data` shape without `before` and `after`.

***

## Account Log

```
GET /activity-logs/account
```

Returns every change in your account, newest first, one page at a time. All parameters are optional and combine with AND.

| Parameter | Type | Meaning |
| - | - | - |
| `start` | ISO 8601 datetime | Only changes at or after this time. Without a timezone, UTC is assumed. |
| `end` | ISO 8601 datetime | Only changes before this time. Must not be earlier than `start`. |
| `scope` | type, e.g. `Formula` | One kind of item and everything filed under it. `scope=Formula` covers messages with the labels, audiences and alternates filed under them; `scope=CompoundTrigger` covers triggers with their frequency caps. |
| `object_type` | type | Only this kind of item, matched exactly. |
| `user_id` | integer | Only changes by this person. [Who made changes](#who-made-changes) lists the ids. |
| `target_model` + `target_id` | type + id | One item's history: changes to it and to everything filed under it. Give both or neither. |
| `surface_id` | UUID | Every message on one surface. |
| `ungrouped` | boolean, default `false` | One entry per recorded change instead of [combined saves](#combined-saves). |
| `page` | integer, default `1` | Page number, from 1. |
| `per_page` | integer, default `10` | Entries per page. `0` returns only the count. |

For example, the changes Ana made in September:

```bash theme={null}
curl "https://composer.api.aampe.com/api/activity-logs/account?user_id=42&start=2026-09-01T00:00:00Z&end=2026-10-01T00:00:00Z&per_page=50" \
  -H "X-API-KEY: <your API key>"
```

The response wraps the entries with paging details:

```json theme={null}
{
  "items": [
    {
      "id": 9182,
      "verb": "UPDATE",
      "object_type": "FrequencyLimit",
      "object_id": "6f1c2a0e-8d3b-4c55-9a51-2b7e0c4d9f10",
      "object_name": null,
      "target_type": null,
      "target_id": null,
      "target_name": null,
      "user_id": 42,
      "user_name": "Ana Lopez",
      "created_at": "2026-09-14T10:02:11",
      "transaction_id": 55410,
      "save_count": 1,
      "first_activity_id": 9182,
      "first_created_at": "2026-09-14T10:02:11",
      "data": {
        "before": {"max_messages": 3, "time_frame": "daily_limit", "aggregation_type": "channel", "aggregation_value": "email"},
        "after": {"max_messages": 5, "time_frame": "daily_limit", "aggregation_type": "channel", "aggregation_value": "email"},
        "changed_fields": ["max_messages"]
      }
    }
  ],
  "total_count": 128,
  "page": 1,
  "per_page": 50,
  "total_pages": 3,
  "has_prev": false,
  "has_next": true,
  "prev_page": null,
  "next_page": 2
}
```

***

## Combined Saves

Settings are often saved several times in quick succession, so the log combines a person's back-to-back saves of the same item into one entry. Saves are combined when they are by the same person, on the same item, and each within 10 minutes of the one before. Another person's save in between starts a new entry.

A combined entry shows the net change:

* `data.before` is the item before the first save, `data.after` is the item after the last.
* `changed_fields` lists only fields that end up different. A field edited and then put back isn't listed, so an entry can show `[]`: no net change.
* `save_count` is how many saves it combines; `first_activity_id` and `first_created_at` are the first save's. `id` and `created_at` are the last save's.
* A single save has `save_count` 1, and its `first_*` fields equal its own.

Only changes to existing items combine. A creation, deletion or archive is always its own entry, and message changes aren't combined yet. Combining never crosses the edges of a `start`/`end` range, and never changes what's stored: add `ungrouped=true` to see every save on its own.

***

## One Item's History

```
GET /activity-logs
```

Returns every change to one item and to everything filed under it, oldest first, as a plain list with no paging. It uses the same entries and [combined saves](#combined-saves) as the account log.

| Parameter | Required | Meaning |
| - | - | - |
| `target_model` | Yes | The item's type, e.g. `Formula`. An unknown type returns an empty list. |
| `target_id` | Yes | The item's id |
| `ungrouped` | No | `true` for one entry per save |

```bash theme={null}
curl "https://composer.api.aampe.com/api/activity-logs?target_model=Formula&target_id=1204" \
  -H "X-API-KEY: <your API key>"
```

<Tip>
  For large histories, prefer the account log with `target_model` and `target_id`, which pages and can be filtered by date and person.
</Tip>

***

## Who Made Changes

```
GET /activity-logs/account/users
```

Lists everyone who has changed your account, for filtering the log by `user_id`. It includes people who have since left or been deactivated, and Aampe staff who changed your configuration on your behalf.

| Parameter | Meaning |
| - | - |
| `start`, `end` | Only people with changes in this range, as on the account log |
| `scope` | Only people who changed this kind of item, as on the account log |

```json theme={null}
[
  {"user_id": 42, "user_name": "Ana Lopez", "email": "ana@example.com"},
  {"user_id": 57, "user_name": "Sam Chen", "email": null}
]
```

`user_name` is the name on the person's latest change, or their current name if that change has none. `email` is `null` when their user account no longer exists. The list is sorted by name.

***

## Errors

| Status | When |
| - | - |
| `401` | The API key is missing or invalid |
| `403` | The key's user can't read this account |
| `422` | A parameter is invalid: an unknown type, `start` after `end`, or only one of `target_model`/`target_id`. On [one item's history](#one-items-history), an unknown `target_model` returns an empty list instead. |

Errors return a JSON body with a `detail` message.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.