Public Alpha. Easel is in early development, so expect rough edges.

Easel

← API Documentation

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

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 connected
  • duplicated - The product was made as a copy of another, whose ID is in
    source_id and name in name
  • edited - The record changed; each changed field is in changes
  • deleted - The record was deleted. For a key, it was disconnected; for a
    store user, they were removed from the store
  • invited - A person was invited to join the store's dashboard; the
    role they'll join with is in changes as role
  • joined - The invited person accepted and joined the store; they are the
    event's actor
  • replaced - A payment or shipping key was replaced with a new one, or a
    variant's digital file with another (part is digital_file, and
    changes holds the old and new file names)
  • added and removed - A part of a record, named by part and name,
    was added or removed, such as a product's variant or a collection's tag
  • moved - The record, or the part part and name say, moved one place
    up or down its list, as direction says
  • hidden and unhidden - One of a product's reviews was hidden from
    shoppers or shown again (part is review)
  • signed_in - A store user logged in to the dashboard with the passkey
    name names (part is passkey); they are the event's actor, in the
    store their session opened
  • reset - Every passkey of a store user who lost theirs was removed at
    once (part is passkey), 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 it
  • redeemed - An Easel staff member used the store's support access code;
    they are the event's actor
  • revoked - The store's owner ended its support access, or made a new
    code in its place
  • voided - The support access code was guessed wrong too many times,
    so it no longer works; the actor is the staff member whose guess
    voided it
  • ended - 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 it
  • expired - The support access code lapsed unused, or the access ran
    out; the actor is system
  • taken_down and restored - 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, and part is review or
    image, with an image's ID in name; reason says why
  • billed - Easel's staff charged the store for its Easel plan on
    demand, rather than on its billing date; the actor is the staff member
  • suspended and unsuspended - Easel's staff suspended the store for its
    content, or lifted the suspension; reason says 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.