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

Easel

← API Documentation

Orders API

Manage orders in your store. An order is a customer purchase, moving
through a few statuses from pending to fulfilled.

Related resources:

Endpoints


List Orders

Retrieve a paginated list of orders for your store, oldest first.

Endpoint: GET /api/v1/orders/

Scope Required: orders:read

Query Parameters

Parameter Type Description
after string Cursor for pagination. Order public ID to return orders after
before string Cursor for pagination. Order public ID to return orders before, for paging back
limit integer Number of orders to return (default 10, max 100)
status string Filter by order status (pending, paid, fulfilled)
refund_status string Filter by refund status (none, partially_refunded, refunded)

Every page comes oldest first, whether you page forward with after or back
with before. The response reports has_more, which is true when another
page lies beyond this one in the direction you're paging.
after and before cannot be used together. An invalid limit returns
INVALID_REQUEST_ERROR.

Request

curl -X GET "https://studio.easel.engineering/api/v1/orders/?status=paid" \
  -H "Authorization: Bearer your_api_key_here"

Response

Status: 200 OK

{
  "data": [
    {
      "id": "ord_d0b6fmv28q6vn14peun0",
      "number": 1001,
      "customer_id": "cus_d0b6fmv28q6vn14peun0",
      "location_id": null,
      "status": "paid",
      "refund_status": "none",
      "shipping": 599,
      "total": 2598,
      "discount": 0,
      "discount_reason": null,
      "billing_zip": "12345",
      "phone": "+13105551234",
      "shipping_needed": true,
      "gift_option": null,
      "gift_note": null,
      "shipping_rate": {"name": "Ground", "transit": {"min": 3, "max": 5}},
      "tax": 0,
      "prices_include_tax": false,
      "taxes": [],
      "gift_card": null,
      "amount_charged": 2598,
      "items": [],
      "downloads": [],
      "created_at": "2023-01-01T10:00:00Z",
      "updated_at": "2023-01-01T10:15:00Z",
      "canceled_at": null,
      "canceled_by": null
    }
  ],
  "has_more": true
}

The list response does not load line items or downloads, so items and
downloads are empty. Fetch a single order to see them.

Error Responses

Invalid query parameter

Status: 400 Bad Request

A malformed after or before, both at once, or an invalid limit returns
INVALID_REQUEST_ERROR, with the offending parameter named in the error
message:

{
  "error": "Invalid 'limit' parameter: cannot exceed 100",
  "code": "INVALID_REQUEST_ERROR"
}

Failed to list orders

Status: 500 Internal Server Error

{
  "error": "Internal server error",
  "code": "INTERNAL_ERROR"
}

Get Order

Retrieve a single order by its public ID. This response includes the order's
line items and its downloads for digital items.

Endpoint: GET /api/v1/orders/{order_id}/

Scope Required: orders:read

Path Parameters

Parameter Type Description
order_id string Order public ID (e.g., ord_d0b6fmv28q6vn14peun0)

Request

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

Response

Status: 200 OK

{
  "id": "ord_d0b6fmv28q6vn14peun0",
  "number": 1001,
  "customer_id": "cus_d0b6fmv28q6vn14peun0",
  "location_id": null,
  "status": "paid",
  "refund_status": "none",
  "shipping": 599,
  "total": 3323,
  "discount": 0,
  "discount_reason": null,
  "billing_zip": "12345",
  "phone": "+13105551234",
  "shipping_needed": true,
  "gift_option": {
    "name": "Gift wrap",
    "description": "Kraft paper with a cotton ribbon.",
    "price": 500
  },
  "gift_note": "Happy birthday, Sam!",
  "shipping_rate": {"name": "Ground", "transit": {"min": 3, "max": 5}},
  "tax": 225,
  "prices_include_tax": false,
  "taxes": [
    {
      "country": "US",
      "region": "CA",
      "name": "Sales tax",
      "rate": "7.25",
      "taxable": 3098,
      "tax": 225,
      "tax_id": null
    }
  ],
  "gift_card": {
    "last4": "QX4P",
    "amount": 1000
  },
  "amount_charged": 2323,
  "items": [
    {
      "order_variant_id": "orv_d0b6fmv28q6vn14peun0",
      "product_id": "pro_d0b6fmv28q6vn14peun0",
      "product_name": "Premium T-Shirt",
      "variant_name": "Small Red",
      "quantity": 1,
      "price": 1999
    }
  ],
  "downloads": [
    {
      "id": "ovd_d0b6fmv28q6vn14peun0",
      "product_name": "Ebook",
      "variant_name": "PDF",
      "download_url": "https://shop.easel.engineering/downloads/...",
      "download_count": 1,
      "downloads_remaining": 4,
      "status": "active",
      "expires_at": "2023-02-01T10:00:00Z",
      "created_at": "2023-01-01T10:00:00Z"
    }
  ],
  "created_at": "2023-01-01T10:00:00Z",
  "updated_at": "2023-01-01T10:15:00Z",
  "canceled_at": null,
  "canceled_by": null
}

An order placed for no one, such as a sale in the shop to someone who gave
no name or email, has customer_id set to null. A guest who checks out
with an email is a customer, so their orders have one.

Error Responses

Order not found

Status: 404 Not Found

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

Failed to get order

Status: 500 Internal Server Error

{
  "error": "Internal server error",
  "code": "INTERNAL_ERROR"
}

Update Order

Update an existing order's status.

Endpoint: PUT /api/v1/orders/{order_id}/

Scope Required: orders:write

Path Parameters

Parameter Type Description
order_id string Order public ID (e.g., ord_d0b6fmv28q6vn14peun0)

Request Body

{
  "status": "fulfilled"
}

Fields

Field Type Required Description
status string Yes Order status: pending, paid, or fulfilled

Discounts and billing details are not editable through this endpoint.

Request

curl -X PUT "https://studio.easel.engineering/api/v1/orders/ord_d0b6fmv28q6vn14peun0/" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-12345" \
  -d '{
    "status": "fulfilled"
  }'

Optional Headers:

  • Idempotency-Key: Unique string to prevent duplicate order updates (see Idempotency)

Response

Returns the updated order.

Status: 200 OK

{
  "id": "ord_d0b6fmv28q6vn14peun0",
  "number": 1001,
  "customer_id": "cus_d0b6fmv28q6vn14peun0",
  "location_id": null,
  "status": "fulfilled",
  "refund_status": "none",
  "shipping": 599,
  "total": 2598,
  "discount": 0,
  "discount_reason": null,
  "billing_zip": "12345",
  "phone": "+13105551234",
  "shipping_needed": true,
  "gift_option": null,
  "gift_note": null,
  "shipping_rate": {"name": "Ground", "transit": {"min": 3, "max": 5}},
  "tax": 0,
  "prices_include_tax": false,
  "taxes": [],
  "gift_card": null,
  "amount_charged": 2598,
  "items": [
    {
      "order_variant_id": "orv_d0b6fmv28q6vn14peun0",
      "product_id": "pro_d0b6fmv28q6vn14peun0",
      "product_name": "Premium T-Shirt",
      "variant_name": "Small Red",
      "quantity": 1,
      "price": 1999
    }
  ],
  "downloads": [],
  "created_at": "2023-01-01T10:00:00Z",
  "updated_at": "2023-01-01T11:30:00Z",
  "canceled_at": null,
  "canceled_by": null
}

Error Responses

Invalid JSON body

Status: 400 Bad Request

{
  "error": "Invalid JSON body",
  "code": "INVALID_JSON"
}

Missing required field

Status: 400 Bad Request

{
  "error": "Order status is required",
  "code": "MISSING_FIELD"
}

Invalid status

Status: 400 Bad Request

{
  "error": "Status must be 'pending', 'paid', or 'fulfilled'",
  "code": "INVALID_FIELD"
}

Order not found

Status: 404 Not Found

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

Failed to update order

Status: 500 Internal Server Error

{
  "error": "Internal server error",
  "code": "INTERNAL_ERROR"
}

List Order Events

Retrieve an order's history, newest first: what happened to it, when, and
who did it. Events are read-only. Easel records each one in the same
transaction as the change it describes, such as a refund or a shipment, and
never edits or deletes them; a correction is a later event.

Endpoint: GET /api/v1/orders/{order_id}/events/

Scope Required: orders: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)

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. A malformed after or before, both at once, or an
invalid limit returns INVALID_REQUEST_ERROR.

Request

curl -X GET "https://studio.easel.engineering/api/v1/orders/ord_d0b6fmv28q6vn14peun0/events/?limit=3" \
  -H "Authorization: Bearer your_api_key_here"

Response

Status: 200 OK

{
  "data": [
    {
      "id": "oev_d0b6fmv28q6vn14pev05",
      "type": "status_changed",
      "actor": { "type": "user", "name": "Ada" },
      "details": { "from": "paid", "to": "fulfilled" },
      "created_at": "2023-01-02T09:00:00Z"
    },
    {
      "id": "oev_d0b6fmv28q6vn14pev04",
      "type": "shipment_created",
      "actor": { "type": "user", "name": "Ada" },
      "details": {
        "shipment_id": "shp_d0b6fr728q6vn14peuu0",
        "shipment_number": 1,
        "items": [
          { "order_variant_id": "orv_d0b6fmv28q6vn14peuog", "quantity": 1 }
        ]
      },
      "created_at": "2023-01-02T09:00:00Z"
    },
    {
      "id": "oev_d0b6fmv28q6vn14pev02",
      "type": "paid",
      "actor": { "type": "customer", "name": null },
      "details": { "amount": 2598 },
      "created_at": "2023-01-01T10:00:00Z"
    }
  ],
  "has_more": true
}

Error Responses

Order not found

Status: 404 Not Found

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

Order Event Object

Field Type Description
id string Event public ID
type string What happened (see below)
actor object Who did it (see below)
details object Fields that depend on type; fields that don't apply are left out
created_at string ISO 8601 timestamp

Actor Object

Field Type Description
type string user (a dashboard user), api_key, customer, stripe (a webhook, or a change made in the Stripe dashboard), platform (an Easel staff member using the access an owner gave them), or system (Easel itself)
name string|null The user's, API key's, or Easel staff member's name; null for other actors, or once that user or key is deleted

Event Types

Type Details
created total
paid amount
status_changed from and to, each an order status
refunded amount, refund_id, and reason when one was given
restocked items put back in stock
canceled reason when one was given
shipment_created shipment_id, shipment_number, items, and tracking when it has a tracking number
shipment_updated shipment_id, shipment_number, items, tracking; a changed tracking number also sets from and to
shipment_reverted shipment_id, shipment_number, and the cleared tracking number in from
shipment_canceled shipment_id, shipment_number, and reason when one was given
address_edited from and to, each the address on one line
gift_options_changed from and to
note_added note
email_sent email: order_confirmation or shipment (with shipment_id and shipment_number)
dispute_opened amount and reason, as Stripe reports them, and dispute_id, Stripe's ID for the dispute
dispute_closed amount, dispute_id, and reason: Stripe's outcome, such as won, lost, or warning_closed
gift_card_redeemed amount the gift card paid, and gift_card_id and gift_card_last4 naming the card
gift_card_issued amount the card is worth, to, the email it was sent to, and gift_card_id and gift_card_last4
gift_card_refunded amount of a refund put back on the card that paid, refund_id, and gift_card_id and gift_card_last4
download_revoked download_id, the order_variant_id it's for, and file_name when the item has a file
download_regenerated download_id, order_variant_id, and file_name as for download_revoked; the old link no longer works

Amounts are in the store's smallest currency unit. Each item in items has
an order_variant_id and a quantity. New event types may be added, so
ignore types you don't recognize.


Order Object

Fields

Field Type Description
id string Order public ID
number integer Human-readable order number
customer_id string|null Customer public ID, or null for an order placed for no one
location_id string|null Public ID of the location it was sold at in person, or null for an order bought online or shipped
status string Order status: pending, paid, fulfilled
refund_status string none, partially_refunded, or refunded
shipping integer Shipping cost in the store's smallest currency unit
total integer Total order amount in the store's smallest currency unit
discount integer Discount amount in the store's smallest currency unit
discount_reason string|null Reason for the discount
billing_zip string|null Billing ZIP code
phone string|null The phone number the buyer gave with the shipping address for the carrier to call about delivery, in E.164 form such as "+13105551234", or null when they gave none or the order doesn't ship. It is personal data: show it only to the people who fulfill the order
shipping_needed boolean Whether the order contains physical items
gift_option object|null The gift option the buyer chose, such as gift wrapping, or null. See Gift Option Object
gift_note string|null The note the buyer asked to send with the gift, or null
shipping_rate object|null The shipping rate the buyer chose, whose price is shipping, or null for an order that doesn't ship. See Order Shipping Rate Object
tax integer Tax the order collected, already part of total
prices_include_tax boolean true when the prices already included the tax, as in the EU; false when checkout added it on top
taxes array Tax by jurisdiction (single order only). See Order Tax Object
gift_card object|null The gift card that paid part of total: last4 and amount, or null
amount_charged integer What the buyer's card paid: total less the gift card's amount
items array Order line items (single order only)
downloads array Download records for digital items (single order only)
created_at string ISO 8601 timestamp
updated_at string ISO 8601 timestamp
canceled_at string|null ISO 8601 timestamp of when the order was canceled, or null
canceled_by string|null Who canceled the order: customer, or null

Order Shipping Rate Object

The shipping rate as the buyer chose it. It is copied onto the order at
purchase, so renaming, repricing, or deleting the site's rate later never
changes it. Its price at purchase is the order's shipping.

Field Type Description
name string Rate name, such as Ground
transit object Business days the carrier was to take, as min and max

Gift Option Object

The gift option as the buyer bought it. It is copied onto the order at
purchase, so editing or deleting the site's gift option
later never changes it.

Field Type Description
name string Gift option name
description string Gift option description, possibly empty
price integer What the buyer paid for it, in the store's smallest currency unit

The gift option's price is part of total, charged on its own apart from the
items and shipping. A discount code never reduces it, and a refund can cover
it like any other part of the total.

Gift Cards

When a gift card paid part or all of an order, gift_card names it by the
last four characters of its code and says how much it paid, and
amount_charged is what was charged to the buyer's card. An order a gift
card paid in full has an amount_charged of 0. See
Gift Cards.

Order History Events

An order's history (GET /api/v1/orders/{order_id}/events/) records gift
cards with these event types. Their details carry gift_card_id and
gift_card_last4, never the code:

  • gift_card_redeemed - A gift card paid amount of the order
  • gift_card_issued - The order bought a gift card worth amount, emailed
    to the address in to
  • gift_card_refunded - A refund put amount back on the gift card, with
    refund_id

An order a gift card paid in full has no paid event, since nothing was
charged.

Order Status Values

  • pending - Order created but not yet paid
  • paid - Payment received
  • fulfilled - Every item has shipped, or the order had nothing to ship

Canceled Orders

A buyer with a storefront account can cancel their own order for a short
time after paying, set per site by cancel_window_minutes (see
Sites), as long as no shipment exists and no download link
has been used. Canceling refunds the order in full through Stripe, puts
its shipped items back on stock, and revokes its download links.

A canceled order keeps its status, has refund_status refunded, and
sets canceled_at and canceled_by. It can't take a shipment: creating
one returns 409 Conflict with the code ORDER_CANCELED.

Order Item Object

The items array lists the line items on an order. The order_variant_id is
the value you pass to the Shipments endpoints when you
ship all or part of an order.

Field Type Description
order_variant_id string Ordered line item public ID, used in shipments
product_id string Product public ID
product_name string Product name
variant_name string Variant name
quantity integer Quantity ordered
price integer Unit price in the store's smallest currency unit

Order Tax Object

The taxes array breaks an order's tax down by the jurisdictions that
charged it, as they were when the order was placed. They never change
afterward, even if the store's registrations or rates do. A list of orders
returns taxes empty, like items; retrieve one order to see them.

Field Type Description
country string ISO 3166-1 alpha-2 country code
region string|null Subdivision code, such as CA for California, or null for a whole country
name string Name of the tax, such as VAT, GST, or Sales tax
rate string Rate as a percentage, such as "7.25"
taxable integer Amount taxed, before tax, in the store's smallest currency unit
tax integer Tax charged in the store's smallest currency unit
tax_id string|null The store's tax ID there, such as a VAT number

Download Object

See Order Downloads for the full download object.