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

Easel

← API Documentation

Sites API

Manage the storefront sites in your store. A site has a name, a copyright name,
a slug, a status, a currency, a language, the set of countries you ship to,
whether it sends wishlist sale alerts, and the
handling time its product pages and checkout estimate delivery dates from.
What it charges to ship is set by its
shipping rates.

A site's language is its main language, used for its storefront and for the
email it sends buyers, such as order confirmations, so it should match the
language your products are written in. A site can also be offered in other
languages, each under its own path prefix such as
/fr/. Buyers see the storefront in the language of the URL they visit,
whatever their browser asks for.

Related resources:

Endpoints


List Sites

Retrieve the sites for your store. This endpoint is not paginated. The list
does not include allowed shipping countries, so allowed_shipping_countries is empty.
Fetch a single site to see them.

Endpoint: GET /api/v1/sites/

Scope Required: sites:read

Request

curl -X GET "https://studio.easel.engineering/api/v1/sites/" \
  -H "Authorization: Bearer your_api_key_here"

Response

Status: 200 OK

{
  "data": [
    {
      "id": "sit_d0b6fmv28q6vn14peun0",
      "name": "My Store",
      "copyright_name": "My Store",
      "slug": "my-store",
      "status": "active",
      "currency": "USD",
      "language": "en",
      "languages": [],
      "domain_host": null,
      "allowed_shipping_countries": [],
      "cancel_window_minutes": 15,
      "gift_notes_enabled": true,
      "gift_note_max_length": 200,
      "created_at": "2023-01-01T10:00:00Z",
      "updated_at": "2023-01-01T10:00:00Z",
      "wishlist_sale_alerts": true,
      "delivery_times": {
        "handling_days": 1
      }
    }
  ]
}

Create Site

Create a new storefront site.

Endpoint: POST /api/v1/sites/

Scope Required: sites:write

Request Body

{
  "name": "My Store",
  "copyright_name": "My Store",
  "allowed_shipping_countries": ["CA", "US"],
  "language": "en"
}
Field Type Required Description
name string Yes Site name
copyright_name string Yes Name shown in the footer copyright notice
allowed_shipping_countries array No ISO 3166-1 alpha-2 codes of the countries you ship to, such as ["CA", "US"]. See Country Codes
language string No Language code such as en or de. Defaults to en
all_products boolean No Show every product the store has on the new site (default false). A store's first site always does. See Product Sites

A store's first site shows all of its products. Any later site starts with
none unless you send "all_products": true; add products to it with
Add Product Site.

A new site starts with wishlist sale alerts on. Use
Update Site to turn them off. It also starts with one free
"Standard" shipping rate per zone, which you can
price or replace.

Request

curl -X POST "https://studio.easel.engineering/api/v1/sites/" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-12345" \
  -d '{
    "name": "My Store",
    "copyright_name": "My Store",
    "allowed_shipping_countries": ["CA", "US"],
    "language": "en",
    "languages": [],
    "wishlist_sale_alerts": false
  }'

Response

Status: 201 Created

{
  "id": "sit_d0b6fmv28q6vn14peun0"
}

Error Responses

Missing required field

Status: 400 Bad Request

{
  "error": "Name is required",
  "code": "MISSING_FIELD"
}

Unknown country

A code in allowed_shipping_countries names no country Easel knows.

Status: 400 Bad Request

{
  "error": "Countries must be ISO 3166-1 alpha-2 codes, such as \"US\"",
  "code": "INVALID_FIELD"
}

Get Site

Retrieve a single site, including its allowed shipping countries.

Endpoint: GET /api/v1/sites/{site_id}/

Scope Required: sites:read

Request

curl -X GET "https://studio.easel.engineering/api/v1/sites/sit_d0b6fmv28q6vn14peun0/" \
  -H "Authorization: Bearer your_api_key_here"

Response

Status: 200 OK

{
  "id": "sit_d0b6fmv28q6vn14peun0",
  "name": "My Store",
  "copyright_name": "My Store",
  "slug": "my-store",
  "status": "active",
  "currency": "USD",
  "language": "en",
  "languages": [],
  "domain_host": "shop.example.com",
  "allowed_shipping_countries": ["CA", "US"],
  "reviews_enabled": true,
  "cancel_window_minutes": 15,
  "gift_notes_enabled": true,
  "gift_note_max_length": 200,
  "created_at": "2023-01-01T10:00:00Z",
  "updated_at": "2023-01-01T10:00:00Z",
  "wishlist_sale_alerts": true,
  "delivery_times": {
    "handling_days": 1
  }
}

Error Responses

Site not found

Status: 404 Not Found

{
  "error": "Resource not found",
  "code": "NOT_FOUND"
}

Update Site

Update a site's name, copyright name, status, domain, allowed countries, language, reviews setting, wishlist sale alerts, cancel window,
and delivery times. All fields except language, reviews_enabled,
wishlist_sale_alerts, cancel_window_minutes, and delivery_times are
required. An empty domain_host clears the custom domain. The site logo is
preserved.

Endpoint: PUT /api/v1/sites/{site_id}/

Scope Required: sites:write

Request Body

{
  "name": "My Store",
  "copyright_name": "My Store",
  "status": "active",
  "domain_host": "shop.example.com",
  "allowed_shipping_countries": ["CA", "US"],
  "language": "en",
  "reviews_enabled": true,
  "wishlist_sale_alerts": false,
  "cancel_window_minutes": 15,
  "gift_notes_enabled": true,
  "gift_note_max_length": 200
}
Field Type Required Description
name string Yes Site name
copyright_name string Yes Name shown in the footer copyright notice
status string Yes active or draft
domain_host string Yes Custom domain host, or an empty string
allowed_shipping_countries array Yes ISO 3166-1 alpha-2 codes of the countries you ship to
language string No Language code such as en or de. Omit it to keep the current language
wishlist_sale_alerts boolean No Whether the site emails opted-in customers when wishlist items go on sale. Omit it to keep the current setting. See Wishlist Sale Alerts
reviews_enabled boolean No Turn product reviews on or off for the site. Omit it to keep the current setting
cancel_window_minutes integer No Minutes after paying that a buyer with an account may cancel their own order for a full refund, from 0 (off) to 1440. Omit it to keep the current setting
delivery_times object No Replaces the site's delivery times. Omit it to keep the current ones
gift_notes_enabled boolean No Whether buyers can write a gift note at checkout. Omit it to keep the current setting
gift_note_max_length integer No Longest gift note, in characters, from 1 to 1000. Omit it to keep the current limit

Request

curl -X PUT "https://studio.easel.engineering/api/v1/sites/sit_d0b6fmv28q6vn14peun0/" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-67890" \
  -d '{
    "name": "My Store",
    "copyright_name": "My Store",
    "status": "active",
    "domain_host": "shop.example.com",
    "allowed_shipping_countries": ["CA", "US"],
    "language": "en",
    "languages": [],
    "wishlist_sale_alerts": false,
    "cancel_window_minutes": 15
  }'

Response

Status: 204 No Content

Error Responses

Invalid status

Status: 400 Bad Request

{
  "error": "Status must be 'active' or 'draft'",
  "code": "INVALID_FIELD"
}

Unknown country

A code in allowed_shipping_countries names no country Easel knows.

Status: 400 Bad Request

{
  "error": "Countries must be ISO 3166-1 alpha-2 codes, such as \"US\"",
  "code": "INVALID_FIELD"
}

Invalid language

Status: 400 Bad Request

{
  "error": "language must be a language code such as en or de",
  "code": "INVALID_FIELD"
}

Invalid cancel window

Status: 400 Bad Request

{
  "error": "cancel_window_minutes must be from 0 to 1440",
  "code": "INVALID_FIELD"
}

Invalid delivery times

Status: 400 Bad Request

{
  "error": "Days must be between 0 and 60",
  "code": "INVALID_FIELD"
}

Site Object

Fields

Field Type Description
id string Site public ID
name string Site name
copyright_name string Name shown in the footer copyright notice
slug string Storefront slug, made from the name when the site is created. Renaming the site keeps it, so its address on Easel's domain never moves
status string active or draft
currency string The store's currency code, such as USD, which all its sites price in
language string Main language code of the storefront and buyer email, such as en
languages array Other languages the storefront is offered in, sorted, such as ["de", "fr"]. Set them with Set Site Languages
domain_host string|null Custom domain host
allowed_shipping_countries array ISO 3166-1 alpha-2 codes of the countries you ship to, in order of their English names
reviews_enabled boolean Whether the storefront shows product reviews and takes new ones
cancel_window_minutes integer Minutes after paying that a buyer with an account may cancel their own order for a full refund, as long as nothing has shipped or been downloaded. 0 turns it off; new sites start at 15
gift_notes_enabled boolean Whether buyers can write a gift note at checkout
gift_note_max_length integer Longest gift note, in characters. A new site takes 200
created_at string ISO 8601 timestamp
updated_at string ISO 8601 timestamp
wishlist_sale_alerts boolean Whether the site emails opted-in customers when items on their wishlist go on sale. New sites start with it on. See Wishlist Sale Alerts
delivery_times object The handling time product pages and checkout estimate delivery dates from. See Delivery Times Object
price_mode string added when checkout adds tax on top of prices, as in the US; included when prices already include it, as in the EU, UK, and Australia, whose law requires it. Read-only: it follows the site's home country, set in the dashboard's Tax settings, and is added only for the US and Canada

Reviews

Product reviews are on for a new site. With reviews_enabled set to
false, the storefront shows no reviews, ratings, or review structured
data, offers no review form, and hides customers' review pages. No review is
deleted: the dashboard and the Reviews API still list and
moderate them, and setting it back to true shows them again. A server run
with EASEL_REVIEWS=false has no reviews whatever this setting says.


Wishlist Sale Alerts

A site can email customers when items on their account wishlist go on sale.
wishlist_sale_alerts turns this on or off for the whole site. It starts on,
because only customers who opted in ever get an alert: a customer opts in
themselves, at registration or on their email preferences page, and neither the
store nor the API can opt anyone in. Turning it off stops every alert from the
site, including ones already waiting to be sent. Guests, whose wishlist lives
only in a browser cookie, never get alerts.

  • What triggers one. Saving a variant so it is on sale for less than its
    regular price, from the dashboard or with
    Update Product Variant,
    starts a sale. Each opted-in customer with that variant on their account
    wishlist is queued an alert. Changing the price of a running sale, even
    lowering it, is not a new sale and alerts no one again. Ending a sale and
    starting another is a new sale.
  • One a day. Alerts go out hourly. Everything waiting for a customer is
    grouped into one email, and a customer gets at most one alert email a day;
    anything that goes on sale in between waits for the next one.
  • Checked at send time. If the customer withdrew consent, was banned, or was
    erased, or the item left their wishlist, the product is no longer active, or
    the sale ended, the alert is dropped instead of sent.
  • Postal address required. Marketing email must show the sender's physical
    postal address (CAN-SPAM in the US, and similar rules elsewhere), so alerts
    pause until the store has one. A merchant sets it under Postal Address in the
    dashboard; it is shown, with the site's name, in the footer of every alert.
    While it is missing, alerts stay queued rather than being dropped, and the
    site edit page and the dashboard say so. Once it is added, sending resumes
    on the next hourly run, after the checks above drop anything that went
    stale. The API can't read or set the address.
  • Unsubscribe. Every alert has a one-click unsubscribe link that works
    without logging in, and List-Unsubscribe headers so mail clients can offer
    their own unsubscribe button. Unsubscribing withdraws the customer's
    marketing consent.

The email is in the site's language and shows each product's regular and sale
price in the store's currency. Merchants can't send alerts by hand; a
customer's page in the dashboard shows when they were last sent one.


Delivery Times Object

A physical product's page shows an estimated delivery date range, such as
"Thu, Oct 23 – Tue, Oct 28", and checkout shows one beside each shipping
rate. The shop ships handling_days business days after the order, or a
product's own handling_days when it sets one (see
Products), and the carrier delivers
within the shipping rate's transit range after
that. A product page estimates by the cheapest rate to the buyer's zone and
names a faster one when there is one, as in "or faster with 2-day air".

Business days skip weekends and the nationwide public holidays of the US,
Canada, the UK, Ireland, Australia, Germany, Austria, France, Belgium, the
Netherlands, Spain, Italy, Portugal, Poland, Denmark, Sweden, and Finland.
Handling counts on the calendar of the site's default country and transit on
the buyer's. Other countries close only on weekends.

Buyers see the estimate for the site's default country until they pick
another country the site ships to, which they do from the estimate itself.
Only countries whose zone has a rate are offered.

Field Type Description
handling_days integer Business days the shop takes to ship an order, from 0 to 60. New sites start at 1
{
  "handling_days": 1
}