Orders API
Manage orders in your store. An order is a customer purchase, moving through a few statuses from pending to fulfilled.
Related resources:
- Order Downloads for digital delivery
- Shipments for shipping and tracking
- Refunds for refunds against an order
- Order Documents for the invoices and credit notes issued for an order
- Webhooks to be told when an order is created or canceled
Endpoints
- List Orders -
GET /api/v1/orders/ - Get Order -
GET /api/v1/orders/{order_id}/ - Update Order -
PUT /api/v1/orders/{order_id}/ - List Order Events -
GET /api/v1/orders/{order_id}/events/
List Orders
Retrieve a paginated list of orders for your store, oldest first. Each order
is as whole as Get Order returns it, with its line items, taxes,
downloads, and documents, so a tool catching up on orders needn’t fetch each
one again. A tool’s first sync can start from a date with created_after.
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) |
created_after |
string | Only orders created at or after this RFC 3339 time, such as 2026-01-01T00:00:00Z |
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. The filters combine with each
other and with the cursors. An invalid limit, status, refund_status,
or created_after 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",
"currency": "USD",
"shipping": 599,
"total": 2598,
"discount": 0,
"discount_reason": null,
"discount_code": null,
"billing_country": "US",
"billing_zip": "97204",
"billing": {
"name": "Sam Rivera",
"email": "sam@example.com",
"address": {
"line1": "1120 SW 5th Ave",
"line2": null,
"city": "Portland",
"region": "OR",
"postal_code": "97204",
"country": "US"
}
},
"shipping_address": {
"name": "Sam Rivera",
"address": {
"line1": "1120 SW 5th Ave",
"line2": null,
"city": "Portland",
"region": "OR",
"postal_code": "97204",
"country": "US"
}
},
"phone": "+15035551234",
"shipping_needed": true,
"items": [
{
"order_variant_id": "orv_d0b6fmv28q6vn14peun0",
"product_id": "pro_d0b6fmv28q6vn14peun0",
"product_name": "Premium T-Shirt",
"variant_name": "Small Red",
"sku": "TS-S-RED",
"quantity": 1,
"price": 1999,
"line_total": 1999,
"delivery": "physical"
}
],
"downloads": [],
"documents": [],
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T10:15:00Z",
"canceled_at": null,
"canceled_by": null,
"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,
"buyer": {
"company": null,
"tax_id": null,
"tax_id_status": null,
"vies": null
},
"reverse_charge": null,
"non_eu_reverse_charge": null
}
],
"has_more": true
}
Error Responses
Invalid query parameter
Status: 400 Bad Request
A malformed after or before, both at once, an invalid limit, a
status or refund_status that isn’t one of its values, or a
created_after that isn’t an RFC 3339 time returns INVALID_REQUEST_ERROR,
with the offending parameter named in the error message:
{
"error": "Invalid 'created_after' parameter: must be an RFC 3339 time, such as 2026-01-01T00:00:00Z",
"code": "INVALID_REQUEST_ERROR"
}
Cursor not found
An after or before that names no order of the store.
Status: 404 Not Found
{
"error": "Resource not found",
"code": "NOT_FOUND"
}
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, with its line items, taxes, downloads for digital items, and documents.
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",
"currency": "USD",
"shipping": 599,
"total": 5040,
"discount": 400,
"discount_reason": "10% off",
"discount_code": "WELCOME10",
"billing_country": "US",
"billing_zip": "90012",
"billing": {
"name": "Sam Rivera",
"email": "sam@example.com",
"address": {
"line1": "200 N Spring St",
"line2": "Apt 4",
"city": "Los Angeles",
"region": "CA",
"postal_code": "90012",
"country": "US"
}
},
"shipping_address": {
"name": "Sam Rivera",
"address": {
"line1": "1600 Sunset Blvd",
"line2": null,
"city": "Los Angeles",
"region": "CA",
"postal_code": "90026",
"country": "US"
}
},
"phone": "+13105551234",
"shipping_needed": true,
"items": [
{
"order_variant_id": "orv_d0b6fmv28q6vn14peun0",
"product_id": "pro_d0b6fmv28q6vn14peun0",
"product_name": "Premium T-Shirt",
"variant_name": "Small Red",
"sku": "TS-S-RED",
"quantity": 1,
"price": 1999,
"line_total": 1999,
"delivery": "physical"
},
{
"order_variant_id": "orv_d0b6fmv28q6vn14peun1",
"product_id": "pro_d0b6fmv28q6vn14peun1",
"product_name": "Ebook",
"variant_name": "PDF",
"sku": "",
"quantity": 1,
"price": 2001,
"line_total": 2001,
"delivery": "digital"
}
],
"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"
}
],
"documents": [
{
"id": "odc_d0b6fmv28q6vn14peun0",
"kind": "invoice",
"number": "INV-1001",
"authority_code": null,
"url": "https://invoices.example.com/d/8f2a1c/INV-1001.pdf",
"issued_at": "2023-01-01T10:05:00Z",
"refund_id": null,
"external_source": "invoicing",
"external_id": "48211",
"created_at": "2023-01-01T10:05:03Z",
"updated_at": "2023-01-01T10:05:03Z"
}
],
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T10:15:00Z",
"canceled_at": null,
"canceled_by": null,
"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": 341,
"prices_include_tax": false,
"taxes": [
{
"country": "US",
"region": "CA",
"name": "Sales tax",
"rate": "7.25",
"taxable": 4699,
"tax": 341,
"tax_id": null
}
],
"gift_card": {
"last4": "QX4P",
"amount": 1000
},
"amount_charged": 4040,
"buyer": {
"company": null,
"tax_id": null,
"tax_id_status": null,
"vies": null
},
"reverse_charge": null,
"non_eu_reverse_charge": 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.
billing and shipping_address are personal data, so they are null
unless the API key also has customers:read. See Billing
Object and Shipping Address
Object.
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",
"currency": "USD",
"shipping": 599,
"total": 2598,
"discount": 0,
"discount_reason": null,
"discount_code": null,
"billing_country": "US",
"billing_zip": "97204",
"billing": null,
"shipping_address": null,
"phone": "+15035551234",
"shipping_needed": true,
"items": [
{
"order_variant_id": "orv_d0b6fmv28q6vn14peun0",
"product_id": "pro_d0b6fmv28q6vn14peun0",
"product_name": "Premium T-Shirt",
"variant_name": "Small Red",
"sku": "TS-S-RED",
"quantity": 1,
"price": 1999,
"line_total": 1999,
"delivery": "physical"
}
],
"downloads": [],
"documents": [],
"created_at": "2023-01-01T10:00:00Z",
"updated_at": "2023-01-01T11:30:00Z",
"canceled_at": null,
"canceled_by": null,
"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,
"buyer": {
"company": null,
"tax_id": null,
"tax_id_status": null,
"vies": null
},
"reverse_charge": null,
"non_eu_reverse_charge": null
}
This example’s key lacks customers:read, so billing and
shipping_address are 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 (on a hosted platform, a staff member using the access an owner gave them), or system (Easel itself) |
name |
string|null | The user’s, API key’s, or platform 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 |
document_attached |
document_id, document_kind, and document_number of the document attached, and refund_id for a credit note that documents a refund |
document_updated |
The same as document_attached, as the document is after the change |
document_removed |
The same as document_attached, as the document was; the document itself stays where it was issued |
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 |
currency |
string | The store’s ISO 4217 currency code, such as USD, which every amount on the order is in |
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 | What a discount took off the items, in the store’s smallest currency unit |
discount_reason |
string|null | The discount as the buyer saw it worded, or null |
discount_code |
string|null | The discount code the buyer entered, as it was when they applied it, or null. Renaming or deleting the code later doesn’t change it |
billing_country |
string | ISO 3166-1 alpha-2 code of the country the order is billed to, which its tax follows |
billing_zip |
string|null | The postal code the card was charged with, or null |
billing |
object|null | Who the order is billed to. It is personal data, so it is null unless the API key has customers:read. See Billing Object |
shipping_address |
object|null | Where the order’s goods go. It is personal data, so it is null unless the API key has customers:read, and null for an order that doesn’t ship or has no recorded address. See Shipping Address Object |
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 |
items |
array | Order line items. See Order Item Object |
downloads |
array | Download records for digital items |
documents |
array | The documents attached to the order, such as its invoice and credit notes, in the order they were attached; empty when there are none |
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 |
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; 0 for a reverse-charged order or one from a non-EU seller to an EU business |
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. 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 |
buyer |
object | The company and tax number the buyer gave for their invoice. Always an object, whose fields are null when the buyer gave none. See Buyer Object |
reverse_charge |
object|null | Set when a store established in the EU charged no VAT because the buyer, a business in another EU country, accounts for it: an intra-EU supply, reported on the EC sales list. Otherwise null. See Reverse Charge |
non_eu_reverse_charge |
object|null | Set when a store established outside the EU charged an EU business no VAT; otherwise null. Never set together with reverse_charge. See Non-EU Sellers |
Billing Object
Who the order is billed to, shown only to an API key with customers:read.
| Field | Type | Description |
|---|---|---|
name |
string|null | The name on the billing address, else the customer’s name, or null |
email |
string|null | The customer’s email, or null for an order placed for no one |
address |
object|null | The billing address checkout recorded, or null for an order without one, such as one sold in person or one that asked for only a country and postal code |
The address object:
| Field | Type | Description |
|---|---|---|
line1 |
string | First address line |
line2 |
string|null | Second address line, or null |
city |
string | City |
region |
string | Subdivision code, such as CA, possibly empty |
postal_code |
string|null | Postal code, or null |
country |
string | ISO 3166-1 alpha-2 country code |
Shipping Address Object
Where the order’s goods go, shown only to an API key with customers:read.
Use it, not billing_country, for the goods’ destination, which decides,
for example, whether a sale is an export.
| Field | Type | Description |
|---|---|---|
name |
string|null | The recipient’s name on the address, or null |
address |
object | The shipping address checkout recorded, with the same fields as the billing address |
Buyer Object
The company and tax number the buyer gave at checkout, for their invoice,
and how the tax number was checked. Checkout asks for them only when the
store has an EU VAT registration: its home, its primary site’s default
country, is in the EU, or it has a tax registration
in an EU country. For any other store every field is always null.
| Field | Type | Description |
|---|---|---|
company |
string|null | The buyer’s company name, or null |
tax_id |
string|null | The buyer’s tax number, or null. An EU VAT number is normalized with its VIES prefix, such as "DE123456789" or "EL123456789" for Greece; another tax number is kept as typed |
tax_id_status |
string|null | How the tax number was checked: verified by VIES; unverified when VIES couldn’t answer, so VAT was charged; or recorded when it needed no check, such as a buyer in the store’s own country or outside the EU. null without a tax number |
vies |
object|null | What VIES, the EU’s VAT number check, answered, kept as the evidence that the number was verified, or null without a check |
The vies object:
| Field | Type | Description |
|---|---|---|
consultation_number |
string|null | The number VIES gave the check, or null. VIES gives one only when the check named the store’s own VAT number: from its home tax registration, or for a store established outside the EU, a registration directly in an EU country. A non-Union One-Stop Shop number (EU…) can’t be named, so a store with only that gets null, and checked_at is the evidence |
name |
string|null | The trader’s name as their country registered it, or null when it doesn’t share it |
address |
string|null | The trader’s address, the same way |
checked_at |
string | ISO 8601 timestamp of when VIES answered |
Reverse Charge
A sale from an EU business to a business in another EU country is reverse charged: the seller charges no VAT, and the buyer accounts for it in their own country. Checkout reverse charges an order only when all of these hold:
- The store is VAT registered in the EU country it’s established in, its home, which is its primary site’s default country, with a whole-country tax registration there
- The buyer gave an EU VAT number and VIES verified it. When VIES can’t answer, VAT is charged as usual
- The VAT number is from the buyer’s billing country, and that country isn’t the store’s home. A buyer in the store’s own country pays VAT like anyone there
- Goods ship to the VAT number’s country. Digital products, which EU VAT treats as electronically supplied services, are supplied where the buyer is established, so the sale’s tax destination must be the VAT number’s country
- A Northern Ireland (
XI) VAT number covers goods only, shipped to Northern Ireland itself, aBTpostcode; goods to Great Britain are an export - An order of goods and digital products is reverse charged only when both parts would be. An order of only gift cards supplies nothing yet, so it isn’t
The legal basis is the VAT Directive: Article 138 for goods, and Article 196
for services. The invoice for a reverse-charged order must say “Reverse
charge”, cite the exemption for its supply_kind, and show the store’s VAT
number, seller_tax_id.
A reverse-charged order has tax 0, an empty taxes, and a total of
the net the buyer paid. When prices include tax, the VAT in them comes off
instead, as deduction, so the buyer pays the net price and the merchant
receives what they would from a consumer.
| Field | Type | Description |
|---|---|---|
supply_kind |
string | goods, services (digital products), or mixed |
deduction |
integer | The VAT taken off prices that included it, which the buyer didn’t pay; 0 when prices were before tax |
goods |
integer | The order’s net value for goods, as an EC sales list reports it. Shipping and the gift option count as goods |
services |
integer | The order’s net value for services. The gift option counts here when the order has no goods |
seller_tax_id |
string|null | The store’s VAT number at home when the order was placed, which a reverse-charged invoice must show (VAT Directive Art. 226(3)); null when that registration had no VAT number |
goods and services split the discount between them by value, so
together they add up to what the buyer paid for everything but gift cards.
These are the fields of a reverse-charged order from a store in Portugal to a German business, with prices that include VAT:
{
"currency": "EUR",
"total": 10500,
"billing_country": "DE",
"tax": 0,
"prices_include_tax": true,
"taxes": [],
"buyer": {
"company": "Beispiel GmbH",
"tax_id": "DE123456789",
"tax_id_status": "verified",
"vies": {
"consultation_number": "WAPIAAAAZ3x5Fv9B",
"name": "Beispiel GmbH",
"address": "Hauptstr. 1, 10115 Berlin",
"checked_at": "2026-10-01T09:00:00Z"
}
},
"reverse_charge": {
"supply_kind": "goods",
"deduction": 2415,
"goods": 10500,
"services": 0,
"seller_tax_id": "PT512345678"
}
}
Non-EU Sellers
A store established outside the EU, its home being outside the EU, may
still be registered for EU VAT, through the non-Union One-Stop Shop or
directly in an EU country, and charges EU consumers VAT. It charges an EU
business no VAT, and sets non_eu_reverse_charge, only when all of these
hold:
- The store has a tax registration in an EU country
- The buyer gave an EU VAT number of their billing country, and VIES verified it. When VIES can’t answer, VAT is charged as usual
- A Northern Ireland (
XI) number never qualifies - Digital products, which EU VAT treats as electronically supplied services, are taxed where the buyer is (VAT Directive Art. 44) and the buyer accounts for the VAT (Art. 196). The sale’s tax destination must be the VAT number’s country, and the store must have no location there: a location there may take part in the sale, which would make the store established there for it (Art. 192a), so VAT is charged
- Goods must ship to the VAT number’s country from outside the EU, with duties and import VAT unpaid, so that the buyer imports them and pays the import VAT (Art. 201); the One-Stop Shop for imports covers only sales to consumers. A store that clears customs itself (duties paid) sells the goods inside the EU and must not rely on this. A store with any location in an EU country charges VAT on goods, since they could ship from inside the EU
- An order of goods and digital products qualifies only when both parts would
non_eu_reverse_charge has the same fields as reverse_charge, but
supply_kind says why no VAT was charged, which the invoice must say too:
supply_kind |
Meaning |
|---|---|
services |
Reverse charge: the buyer accounts for the VAT (Art. 196) |
goods |
Not a reverse charge: the buyer imported the goods and pays the import VAT |
mixed |
Both, each for its part |
seller_tax_id is the store’s VAT number from a registration directly in an
EU country, preferring the buyer’s, or null for a store registered only
through the non-Union One-Stop Shop, whose number is for that scheme’s
returns alone.
The EC sales list includes these orders’ services, which a store identified for VAT in an EU country must report (Art. 262(1)©), when the store is registered directly in an EU country. Their goods, being imports, never appear, and a store registered only through the non-Union One-Stop Shop has no EC sales list to file.
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 paidamountof the ordergift_card_issued- The order bought a gift card worthamount, emailed to the address intogift_card_refunded- A refund putamountback on the gift card, withrefund_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 paidpaid- Payment receivedfulfilled- 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|null | Product public ID, or null when the product no longer exists |
product_name |
string | Product name when it was sold |
variant_name |
string | Variant name when it was sold |
sku |
string | Variant SKU when it was sold, possibly empty |
quantity |
integer | Quantity ordered |
price |
integer | Unit price paid, before any discount on the order, in the store’s smallest currency unit |
line_total |
integer | price times quantity |
delivery |
string | physical, digital, or gift_card |
product_name, variant_name, sku, and delivery are kept from
checkout, so renaming or changing the product later doesn’t change them. A
line sold before Easel kept them shows what the product is now instead, and
a delivery of physical if the product is gone. A gift_card line is a
multi-purpose voucher, which isn’t taxed when it’s sold.
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
reverse-charged order has none.
| 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.