Activity Log API
Read your store's activity log: who changed what, how, and when, whether in
the dashboard or through the API. Every change a person or API key makes is
logged; only automatic changes, such as stock a checkout takes, stock a
refund puts back, and Easel's background jobs, are not. It is the same log
the dashboard shows under Settings › Activity and as the History on each
record's page.
Events are read-only. Easel records each one in the same transaction as the
change it describes and keeps it until the store is deleted; a correction is
a later event. Orders keep their own history, read with List Order
Events, and gift cards theirs in their
transactions, so an order's shipments and refunds and a gift card's
balance aren't repeated here.
Endpoints
- List Audit Events -
GET /api/v1/audit-events/
List Audit Events
Retrieve a page of the store's activity log, newest first.
Endpoint: GET /api/v1/audit-events/
Scope Required: audit_events:read
Query Parameters
| Parameter | Type | Description |
|---|---|---|
after |
string | Cursor for pagination. Event ID to return older events after |
before |
string | Cursor for pagination. Event ID to return the newer events before, for paging back |
limit |
integer | Number of events to return (default 10, max 100) |
entity_type |
string | Only changes to this kind of record (see Entity Types) |
entity_id |
string | Only changes to this one record, such as a product's public ID. Requires entity_type |
actor |
string | Only changes made by this dashboard user or API key, named by the actor.id of one of its events. Easel's staff can't be filtered by |
Events come newest first either way. The response reports has_more, which
is true when more events follow in the direction of travel: older ones, or
newer ones with before.
To read one product's history, pass its ID with its type:
GET /api/v1/audit-events/?entity_type=product&entity_id=pro_d0b6db728q6vrspbvbqg
Request
curl -X GET "https://studio.easel.engineering/api/v1/audit-events/?entity_type=product&limit=3" \
-H "Authorization: Bearer your_api_key_here"
Response
Status: 200 OK
{
"data": [
{
"id": "aud_d0b6db728q6vrsaud006",
"entity": {
"type": "product",
"id": "pro_d0b6db728q6vrspbvbqg",
"name": "Cozy Blanket"
},
"action": "edited",
"actor": {
"type": "api_key",
"id": "api_devseedkey0000000001",
"name": "Inventory sync"
},
"details": {
"changes": [{ "field": "description" }]
},
"created_at": "2025-05-03T19:06:40Z"
},
{
"id": "aud_d0b6db728q6vrsaud005",
"entity": {
"type": "product",
"id": "pro_d0b6db728q6vrspbvbqg",
"name": "Cozy Blanket"
},
"action": "edited",
"actor": {
"type": "user",
"id": "usr_d0b6cu728q6vrspbvbag",
"name": "Ada"
},
"details": {
"changes": [{ "field": "stock", "from": "30", "to": "42" }],
"variant": "Green, Small",
"source": "inventory"
},
"created_at": "2025-05-03T19:05:00Z"
},
{
"id": "aud_d0b6db728q6vrsaud004",
"entity": {
"type": "product",
"id": "pro_d0b6db728q6vrspbvbqg",
"name": "Cozy Blanket"
},
"action": "edited",
"actor": { "type": "user", "id": null, "name": null },
"details": {
"changes": [{ "field": "price", "from": "2499", "to": "2999" }],
"variant": "Green, Small"
},
"created_at": "2025-05-03T18:55:52Z"
}
],
"has_more": true
}
The last event was made by a dashboard user who has since been removed, so
its actor has no id or name.
Error Responses
Invalid parameter
Status: 400 Bad Request
A malformed after or before, both at once, an invalid limit, an
unknown entity_type, an entity_id without entity_type, or an actor
that isn't one of the store's users or API keys returns
INVALID_REQUEST_ERROR, with the offending parameter named in the error
message:
{
"error": "Invalid 'entity_type' parameter: must be a kind of record the log holds",
"code": "INVALID_REQUEST_ERROR"
}
Unknown cursor
Status: 404 Not Found
An after or before that names no event of the store:
{
"error": "Resource not found",
"code": "NOT_FOUND"
}
Audit Event Object
| Field | Type | Description |
|---|---|---|
id |
string | Event public ID |
entity |
object | The record the change was made to (see below) |
action |
string | What happened to it (see Actions) |
actor |
object | Who made the change (see below) |
details |
object | Fields that depend on action and the record; fields that don't apply are left out (see Details) |
created_at |
string | ISO 8601 timestamp |
Entity Object
| Field | Type | Description |
|---|---|---|
type |
string | The kind of record (see Entity Types) |
id |
string | The record's ID, the value entity_id filters by |
name |
string | The record's name when the change was made, so the log still reads well after it's renamed or deleted |
Actor Object
| Field | Type | Description |
|---|---|---|
type |
string | user (a dashboard user), api_key, system (Easel itself), or platform (Easel's staff, from its operator console or in your dashboard with support access) |
id |
string|null | The user's, API key's, or Easel staff member's public ID; for a user or key, the value actor filters by. null for Easel itself, for a platform change no staff member is named for, or once that user or key is deleted |
name |
string|null | The user's, API key's, or Easel staff member's name; null whenever id is |
Entity Types
| Type | Record | entity.id |
Actions |
|---|---|---|---|
product |
A product, its variants, options and their choices, images, digital files, tags, sites, and reviews | Product ID | created, duplicated, edited, added, removed, replaced, moved, hidden, unhidden, taken_down, restored |
tag |
A tag | Tag ID | created, edited, deleted |
collection |
A collection and its tags | Collection ID | created, edited, deleted, added, removed, taken_down, restored |
store_filter |
A site's storefront filter, named by the option name it filters by | Store filter ID | created, edited, moved, deleted |
page |
A site's home page or information page, such as its returns policy | Site ID and page type, such as sit_d0b6fmv28q6vn14peun1/returns, or /home for the home page |
created, edited, deleted, taken_down, restored |
gift_option |
A site's gift option | Gift option ID | created, edited, moved, deleted |
discount_code |
A discount code | Discount code ID | created, edited, deleted |
gift_card |
A gift card's expiry and note, named by the last four characters of its code | Gift card ID | edited |
customer |
A customer and their addresses, with no name (see Personal Data) | Customer ID | created, edited, deleted, added, removed |
shipping_rate |
A shipping rate | Shipping rate ID | created, edited, moved, deleted |
tax_registration |
A tax registration, named by its place, such as US-CA |
Tax registration ID | created, edited, deleted |
location |
A location, named by its name | Location ID | created, edited, deleted |
site |
A site's settings, including its languages, translations, gift notes, tax, and review settings | Site ID | created, edited |
payment_key |
The store's Stripe keys | stripe |
created, replaced, deleted |
shipping_key |
The store's ShipStation key | shipstation |
created, replaced, deleted |
store_user |
A person on the store's dashboard team, and their passkeys | User ID | invited, joined, edited, deleted, added, removed, signed_in, reset |
store |
The store's own settings, such as requiring passkeys, and its Easel plan, and Easel's moderation of the store and of its reviews and images | Store ID | edited, billed, suspended, unsuspended, taken_down, restored |
api_key |
An API key | API key ID | created, deleted |
staff_access |
Support access the store granted Easel's staff, named by how long it lasts once used: 2h, 24h, 1w, or 1m |
Support access ID | created, redeemed, revoked, voided, ended, expired |
export |
A request for a copy of the store's data, which holds its customers' personal data | Export ID | created |
New entity types may be added, so ignore types you don't recognize.
Actions
created- The record was made. For a payment or shipping key, the key
was connectedduplicated- The product was made as a copy of another, whose ID is in
source_idand name innameedited- The record changed; each changed field is inchangesdeleted- The record was deleted. For a key, it was disconnected; for a
store user, they were removed from the storeinvited- A person was invited to join the store's dashboard; the
role they'll join with is inchangesasrolejoined- The invited person accepted and joined the store; they are the
event's actorreplaced- A payment or shipping key was replaced with a new one, or a
variant's digital file with another (partisdigital_file, and
changesholds the old and new file names)addedandremoved- A part of a record, named bypartandname,
was added or removed, such as a product's variant or a collection's tagmoved- The record, or the partpartandnamesay, moved one place
up or down its list, asdirectionsayshiddenandunhidden- One of a product's reviews was hidden from
shoppers or shown again (partisreview)signed_in- A store user logged in to the dashboard with the passkey
namenames (partispasskey); they are the event's actor, in the
store their session openedreset- Every passkey of a store user who lost theirs was removed at
once (partispasskey), and they were logged out, by a teammate or
by Easel's support. Passkeys belong to the person rather than a store,
so each store they're on logs itredeemed- An Easel staff member used the store's support access code;
they are the event's actorrevoked- The store's owner ended its support access, or made a new
code in its placevoided- The support access code was guessed wrong too many times,
so it no longer works; the actor is the staff member whose guess
voided itended- The Easel staff member ended their support access, done
helping, or Easel's operator ended it as they removed the staff member's
sign-in; the actor is whoever ended itexpired- The support access code lapsed unused, or the access ran
out; the actor issystemtaken_downandrestored- Easel's staff removed content as illegal
or against Easel's terms, or put it back (see Moderation).
For a review or image, the entity is the store, andpartisreviewor
image, with an image's ID inname;reasonsays whybilled- Easel's staff charged the store for its Easel plan on
demand, rather than on its billing date; the actor is the staff membersuspendedandunsuspended- Easel's staff suspended the store for its
content, or lifted the suspension;reasonsays why it was suspended
New actions may be added, so ignore actions you don't recognize.
Details
| Field | Description |
|---|---|
changes |
For edited, each field that changed, as field, from, and to (see below); for a store user invited, the role they'll join with, in to |
part |
What kind of part an event is about: variant, option, option_value, image, digital_file, tag, site, review, address, or passkey |
name |
The part's name, such as the variant Large, a choice as Size: Large, or a digital file's file name, or the name a store user gave a passkey; for duplicated, the product copied. Reviews and addresses are never named |
variant |
The variant a change is for, such as to its price, stock, image, or digital file; left out for a product without options |
direction |
For moved, up or down |
source |
Where stock was changed: variant (the variant's own page) or inventory (the inventory page); left out for the product's page or the API |
source_id |
For duplicated, the ID of the product copied |
previous |
For a page edited or deleted, its text before the change, when it was no longer than 8,000 bytes; for the home page, its main text |
reason |
For taken_down or suspended, why: illegal, csam (child sexual abuse material), ip (intellectual property), fraud, hate (hate or violence), terms (against Easel's terms), or other |
Each change's field names what changed, and from and to are its old
and new values as strings. Either is left out when the field was unset, and
both are left out for a field logged without its values, such as a product's
description, a site's logo, its postal address, or any of a customer's
fields. Values longer than 200 characters are cut short with …. Prices are
in the store's smallest currency unit, weights in grams, dates as
YYYY-MM-DD, images by their public IDs, and true or false settings are
true or false.
| Record | Fields |
|---|---|
| Product | name, slug, description, status, made_to_order, handling_days, weight, price, sale_price, stock, sku, barcode, option (an option's name), option_value and swatch (a choice's name and its color as hex, with the choice in name), image (a variant's image), alt_text (an image's description), digital_file (a file name) |
| Tag | name |
| Collection | name, description |
| Store filter | name, position |
| Home page | hero_content (its main text, logged as changed), image, social_image (the image shown when it's shared), seo_title, seo_description |
| Gift option | name, description, price, offered (offered at checkout), image, position |
| Gift card | expires, note |
| Customer | name, email |
| Discount code | code, percentage, active |
| Shipping rate | name, base_price, transit, surcharge_percent, free_over |
| Tax registration | tax_rate (a percent, left out for the built-in rate), tax_id |
| Location | name, place (its country and region, such as US-IL), sites (the names of the sites offering it) |
| Site | name, copyright_name, site_status, language, languages (its other languages' codes), translations (the code of a language whose translations were saved, in to), domain, logo, favicon, shipping_countries (the ISO 3166-1 alpha-2 codes of the countries it ships to, such as CA, US), sale_alerts, reviews, cancel_window, handling_days, postal_address, gift_notes, gift_note_length, home_country (its country's ISO 3166-1 alpha-2 code), price_mode (only in older events; it now follows home_country) |
| Store user | name, email, role (owner or manager) |
| Store | require_passkeys (every dashboard user logs in with a passkey after their password), subscription_tier (the store's Easel plan, by name, which Easel's staff change) |
New fields may be added, so ignore fields you don't recognize.
Moderation
Easel hosts what your store publishes, so under the EU Digital Services Act
its staff review it and may remove content that's illegal or against
Easel's terms, or suspend the store. Each such decision is logged with the
platform actor naming the staff member, and the store's owners are
emailed a statement of the reasons; the dashboard lists them under
Settings › Activity › Easel decisions. Content Easel took down has its
taken_down_at set, the time it was taken down, and can't be published
or shown again through the API either; see each resource's errors.
Support Access
Easel's staff have no standing access to your dashboard. To let them in
to help, the store's owner makes an 8-digit code under Settings › Support
access and reads it to them. A staff member redeems it in Easel's
operator console, for your store only, within the hour, and may then use
your dashboard for the time the owner chose, until the owner revokes it.
They can't manage your team, API keys, payouts, billing, or exports.
Each change they make is logged with actor.type platform, naming the
staff member in actor.id and actor.name, and the access itself is
logged as a staff_access record from the code's creation to its end.
Personal Data
The log is kept as long as the store, past a customer's erasure, so it
holds no customer's personal data. A customer is named only by their ID,
their fields are logged as changed without their values, their addresses
are never described, and a review hidden or shown again isn't quoted.
Secrets
The log never holds a secret. A payment or shipping key's events say only
that it was connected (created), replaced, or disconnected (deleted),
and an API key's events never carry the key itself.