Orders
Send your shop’s orders to credit revenue to emails and build purchase profiles.
Create or update an order
Send an order from your shop’s backend. The order is keyed by its id in your shop: send the same id again and the stored order is updated instead. Requires an API key with the full or events scope. With an events key, the response holds only object, id and external_id.
When an order is stored for the first time, Emailit:
- credits it to the campaign or automation email the buyer last clicked within the click window before
placed_at, or, without a click, last opened within the open window. The windows are in the commerce settings. See How orders are credited to emails. - links it to the buyer’s contact, and creates the contact if needed (see
create_contact). - marks the cart named in
cart_idas converted, and also the buyer’s other open carts that were last updated before the order. - marks matching coupon codes as redeemed.
- updates the contact’s purchase metrics.
- emits
order.placed, which webhooks and automations receive.
Sending an order that’s already stored updates it and emits order.updated, with previous_status when the status changed. The attribution doesn’t change. Only the fields you send change: status, placed_at, currency, the amounts, coupon_codes, cart_id and items keep their stored values when you leave them out, metadata is merged into the stored object, and total isn’t required. Sending items replaces all items. To change only the status or a refund, you can also use Update an order.
To import past orders without crediting emails or starting automations, use Import orders in bulk.
/ordersRequest Body
idstring | numberRequiredThe order ID in your shop, up to 255 characters. Numbers are stored as strings. Stored as external_id. You can also send it as external_id or order_id.
emailstringThe buyer’s email address. Stored in lowercase. Emailit uses it to find the contact and to credit the order to an email sent to that address. customer.email is also accepted.
contact_idstringThe buyer’s contact (con_...). If no contact has this ID, Emailit looks the contact up by email.
first_namestringThe buyer’s first name, up to 191 characters. Used when Emailit creates the contact. customer.first_name is also accepted.
last_namestringThe buyer’s last name, up to 191 characters. Used when Emailit creates the contact. customer.last_name is also accepted.
statusstringplaced (default), paid, fulfilled, canceled or refunded. The first time an order has paid, fulfilled, canceled or refunded, Emailit sets the matching paid_at, fulfilled_at, canceled_at or refunded_at to the current time. Canceled orders don’t count toward revenue.
currencystringThree-letter ISO 4217 code. Defaults to the workspace currency in the commerce settings. Amounts are never converted: reports group revenue by currency.
totalnumber | stringOrder total. Required for a new order without items. Without it, Emailit computes the sum of the item totals, minus discount, plus shipping and tax, and never below 0.
Amounts are numbers or numeric strings, can’t be negative, and are stored with up to 4 decimal places.
subtotalnumber | stringAmount before discount, shipping and tax. Defaults to the sum of the item totals when the order has items.
discountnumber | stringDiscount amount, as a positive number.
shippingnumber | stringShipping amount.
taxnumber | stringTax amount.
refunded_amountnumber | stringAmount refunded. Defaults to 0, or to total when status is refunded. Revenue is total minus refunded_amount.
coupon_codesstring[]Up to 20 coupon or discount codes used in the order. A code that matches a coupon code in the workspace, ignoring case, is marked redeemed by this order. coupon_code and discount_codes are also accepted.
cart_idstringThe cart or checkout ID in your shop that the order came from. The cart with this ID becomes converted.
placed_atstring | numberWhen the order was placed: an ISO 8601 date-time or a Unix timestamp in seconds (milliseconds also work). Defaults to the current time. Can’t be more than 24 hours in the future. created_at is also accepted.
itemsobject[]Up to 250 line items. line_items is also accepted. Each item has:
-
product_id(string or number): the product ID in your shop. Items without atitle,url,image_urlorcategoriestake them from the catalog.idis also accepted. -
variant_id,sku(string): up to 255 characters. -
title(string): up to 500 characters. Required when the item has noproduct_idorsku.nameis also accepted. -
quantity(integer): 1 or more. Defaults to 1. -
price(number or string): the unit price. Defaults to 0.unit_priceis also accepted. -
total(number or string): the line total. Defaults topricetimesquantity. -
categories(string[]): up to 50 category names. -
url,image_url(string):httporhttpsURLs.
metadataobjectYour own key-value data, up to 16 KB as JSON. On updates, the keys you send are merged into the stored object.
create_contactbooleanDefault true: when no contact matches contact_id or email, Emailit creates one from email, first_name and last_name and emits contact.created. The new contact isn’t subscribed to any audience, so campaigns don’t reach it. Set to false to never create a contact: the order is then linked only to a contact that already exists.
accepts_marketingbooleanSet to true together with audience_id when the buyer agreed to receive marketing. Emailit then subscribes the contact to that audience, unless the contact is already in it. Default false.
audience_idstringThe audience (aud_...) to subscribe the buyer to when accepts_marketing is true. If the audience doesn’t exist or your plan’s subscriber limit is reached, the order is still stored and the contact isn’t subscribed.
email_idstringThe campaign email (eml_...) the buyer came from, if your shop tracks it. Only used for new orders, and only IDs that start with eml_ are read. The order is credited to this email when it’s a campaign email of the workspace and either has a click within the click window before the order or was sent within that window. Otherwise Emailit credits the order as usual. attribution.email_id is also accepted.
Returns
201 Created with the order object when the order is new, or 200 OK when an existing order was updated. Returns 422 when a field is invalid.
{
"object": "order",
"id": "ord_3aMEK4No62Zw8S1fcHNznAnnbfp",
"external_id": "1042",
"contact_id": "con_3EwrXnu9OaQWlfI1AyPUUEoYjQs",
"email": "ada@example.com",
"status": "paid",
"currency": "USD",
"subtotal": 107,
"discount": 10.7,
"shipping": 5,
"tax": 0,
"total": 101.3,
"refunded_amount": 0,
"coupon_codes": [
"WELCOME-7KQ2M9XA"
],
"cart_id": "c-58f1a2",
"source": "api",
"placed_at": "2026-10-08T14:32:10.000Z",
"paid_at": "2026-10-08T14:32:11.204Z",
"fulfilled_at": null,
"canceled_at": null,
"refunded_at": null,
"attribution": {
"email_id": "eml_3TSvDAUQi7vqxvAQ1UEVN7k4igq",
"campaign_id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
"campaign_name": "October newsletter",
"variant_id": null,
"automation_id": null,
"automation_name": null,
"type": "click",
"touched_at": "2026-10-08T09:41:52.000Z"
},
"items": [
{
"product_id": "8123456789",
"variant_id": "42-blue",
"sku": "TRS-BLU-42",
"title": "Trail running shoe",
"quantity": 1,
"unit_price": 89,
"total": 89,
"categories": [
"Shoes",
"Running"
],
"url": "https://shop.example.com/products/trail-running-shoe",
"image_url": "https://shop.example.com/images/trail-running-shoe.jpg"
},
{
"product_id": "8123456790",
"variant_id": null,
"sku": null,
"title": "Merino running socks",
"quantity": 2,
"unit_price": 9,
"total": 18,
"categories": [
"Accessories"
],
"url": "https://shop.example.com/products/merino-running-socks",
"image_url": "https://shop.example.com/images/merino-running-socks.jpg"
}
],
"metadata": {
"channel": "web"
},
"created_at": "2026-10-08T14:32:11.204Z",
"updated_at": "2026-10-08T14:32:11.204Z"
}{
"message": "Validation failed. items.1.quantity: must be a positive integer",
"errors": {
"items.1.quantity": [
"must be a positive integer"
]
}
}Retrieve an order
Retrieve an order by its Emailit ID or by the order ID in your shop, with its items and its attribution. Requires an API key with the full scope.
/orders/{id}Path Parameters
idstringRequiredThe order ID (ord_...) or the order ID in your shop (external_id). URL-encode shop IDs that contain special characters.
The order object
objectstringAlways order.
idstringEmailit order ID (ord_...).
external_idstringThe order ID in your shop: the id you sent.
contact_idstring | nullThe buyer’s contact (con_...), or null when the order isn’t linked to a contact.
emailstring | nullThe buyer’s email address, in lowercase.
statusstringplaced, paid, fulfilled, canceled or refunded.
currencystringThree-letter ISO 4217 code of the amounts.
subtotalnumber | nullSum of the items before discount, shipping and tax.
discountnumber | nullDiscount amount.
shippingnumber | nullShipping amount.
taxnumber | nullTax amount.
totalnumberOrder total. Revenue in reports is total minus refunded_amount, and canceled orders don’t count.
refunded_amountnumberAmount refunded so far. 0 when nothing was refunded.
coupon_codesstring[]Coupon or discount codes used in the order.
cart_idstring | nullThe cart or checkout ID in your shop that the order came from.
sourcestringHow the order reached Emailit: api, js (the tracking script) or import (bulk import).
placed_atstringWhen the order was placed, in ISO 8601 UTC.
paid_at, fulfilled_at, canceled_at, refunded_atstring | nullWhen Emailit first stored the order with that status. Set once and not cleared when the status changes again.
attributionobject | nullThe email the order is credited to, or null. Set once, when the order is first stored. See How orders are credited to emails.
-
email_id(string): the credited email. -
campaign_id,campaign_name(string or null): its campaign. -
variant_id(string or null): the A/B test variant (cvr_...) the buyer received. -
automation_id,automation_name(string or null): its automation. -
type(string):clickoropen. -
touched_at(string or null): when the click or open happened.
itemsobject[]Line items. Each has product_id (the product ID in your shop), variant_id, sku, title, quantity, unit_price, total, categories, url and image_url.
metadataobjectYour own key-value data.
created_at, updated_atstringWhen Emailit stored the order and when it last changed, in ISO 8601 UTC.
{
"object": "order",
"id": "ord_3aMEK4No62Zw8S1fcHNznAnnbfp",
"external_id": "1042",
"contact_id": "con_3EwrXnu9OaQWlfI1AyPUUEoYjQs",
"email": "ada@example.com",
"status": "paid",
"currency": "USD",
"subtotal": 107,
"discount": 10.7,
"shipping": 5,
"tax": 0,
"total": 101.3,
"refunded_amount": 0,
"coupon_codes": [
"WELCOME-7KQ2M9XA"
],
"cart_id": "c-58f1a2",
"source": "api",
"placed_at": "2026-10-08T14:32:10.000Z",
"paid_at": "2026-10-08T14:32:11.204Z",
"fulfilled_at": null,
"canceled_at": null,
"refunded_at": null,
"attribution": {
"email_id": "eml_3TSvDAUQi7vqxvAQ1UEVN7k4igq",
"campaign_id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
"campaign_name": "October newsletter",
"variant_id": null,
"automation_id": null,
"automation_name": null,
"type": "click",
"touched_at": "2026-10-08T09:41:52.000Z"
},
"items": [
{
"product_id": "8123456789",
"variant_id": "42-blue",
"sku": "TRS-BLU-42",
"title": "Trail running shoe",
"quantity": 1,
"unit_price": 89,
"total": 89,
"categories": [
"Shoes",
"Running"
],
"url": "https://shop.example.com/products/trail-running-shoe",
"image_url": "https://shop.example.com/images/trail-running-shoe.jpg"
},
{
"product_id": "8123456790",
"variant_id": null,
"sku": null,
"title": "Merino running socks",
"quantity": 2,
"unit_price": 9,
"total": 18,
"categories": [
"Accessories"
],
"url": "https://shop.example.com/products/merino-running-socks",
"image_url": "https://shop.example.com/images/merino-running-socks.jpg"
}
],
"metadata": {
"channel": "web"
},
"created_at": "2026-10-08T14:32:11.204Z",
"updated_at": "2026-10-08T14:32:11.204Z"
}{
"error": "Order not found",
"message": "Order not found."
}Update an order
Change the status of a stored order, record a refund, or add metadata. Everything else stays as it is, including the items and the attribution. The buyer’s purchase metrics are recalculated, and Emailit emits order.updated, with the order’s previous_status when the status changed. Requires an API key with the full or events scope. With an events key, the response holds only object, id and external_id.
/orders/{id}Path Parameters
idstringRequiredThe order ID (ord_...) or the order ID in your shop.
Request Body
Send at least one of these fields.
statusstringplaced, paid, fulfilled, canceled or refunded. The first time the order gets paid, fulfilled, canceled or refunded, the matching paid_at, fulfilled_at, canceled_at or refunded_at is set to the current time. Canceled orders don’t count toward revenue.
refunded_amountnumber | stringTotal amount refunded so far, not the amount of this refund. Can’t be negative. Revenue is total minus refunded_amount. If you set status to refunded without refunded_amount and nothing was refunded before, the whole total counts as refunded.
metadataobjectKeys to merge into the order’s metadata. Up to 16 KB as JSON.
Returns
200 OK with the updated order object. Returns 404 if no order matches id and 422 when the body is empty or a field is invalid.
{
"object": "order",
"id": "ord_3aMEK4No62Zw8S1fcHNznAnnbfp",
"external_id": "1042",
"contact_id": "con_3EwrXnu9OaQWlfI1AyPUUEoYjQs",
"email": "ada@example.com",
"status": "paid",
"currency": "USD",
"subtotal": 107,
"discount": 10.7,
"shipping": 5,
"tax": 0,
"total": 101.3,
"refunded_amount": 18,
"coupon_codes": [
"WELCOME-7KQ2M9XA"
],
"cart_id": "c-58f1a2",
"source": "api",
"placed_at": "2026-10-08T14:32:10.000Z",
"paid_at": "2026-10-08T14:32:11.204Z",
"fulfilled_at": null,
"canceled_at": null,
"refunded_at": null,
"attribution": {
"email_id": "eml_3TSvDAUQi7vqxvAQ1UEVN7k4igq",
"campaign_id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
"campaign_name": "October newsletter",
"variant_id": null,
"automation_id": null,
"automation_name": null,
"type": "click",
"touched_at": "2026-10-08T09:41:52.000Z"
},
"items": [
{
"product_id": "8123456789",
"variant_id": "42-blue",
"sku": "TRS-BLU-42",
"title": "Trail running shoe",
"quantity": 1,
"unit_price": 89,
"total": 89,
"categories": [
"Shoes",
"Running"
],
"url": "https://shop.example.com/products/trail-running-shoe",
"image_url": "https://shop.example.com/images/trail-running-shoe.jpg"
},
{
"product_id": "8123456790",
"variant_id": null,
"sku": null,
"title": "Merino running socks",
"quantity": 2,
"unit_price": 9,
"total": 18,
"categories": [
"Accessories"
],
"url": "https://shop.example.com/products/merino-running-socks",
"image_url": "https://shop.example.com/images/merino-running-socks.jpg"
}
],
"metadata": {
"channel": "web"
},
"created_at": "2026-10-08T14:32:11.204Z",
"updated_at": "2026-10-10T08:05:39.871Z"
}{
"error": "Order not found",
"message": "Order not found."
}{
"message": "Validation failed. status: is required",
"errors": {
"status": [
"is required"
]
}
}List orders
List orders with their items, the most recently placed first. Requires an API key with the full scope.
/ordersQuery Parameters
pageintegerPage number for pagination (minimum: 1, default: 1).
limitintegerNumber of orders to return (minimum: 1, maximum: 100, default: 25).
searchstringCase-insensitive match on the order ID in your shop or the buyer’s email address.
contact_idstringOnly orders of this contact (con_...).
emailstringOnly orders with this buyer email address, ignoring case.
statusstringOnly orders with this status: placed, paid, fulfilled, canceled or refunded.
campaign_idstringOnly orders credited to this campaign (cmp_...).
automation_idstringOnly orders credited to this automation (aut_...).
attributedbooleantrue for orders credited to an email, false for orders that aren’t.
fromstringOnly orders placed at or after this time. An ISO 8601 date or date-time; anything else returns 422.
tostringOnly orders placed at or before this time. An ISO 8601 date or date-time; anything else returns 422.
matchstringall (default) requires every key.condition filter to match. or matches any of them. See Filtering.
sortstringSort key: placed_at (default), total or created_at.
orderstringSort direction: asc or desc (default).
Filters
List filters are one layer of key.condition=value query parameters. See Filtering for match, order, direction and the condition list per type.
Filter keys
| Key | Type | Conditions | Notes |
|---|---|---|---|
external_id | string | exact, not_exact, contains, not_contains, starts_with, ends_with, empty, not_empty | |
email | string | exact, not_exact, contains, not_contains, starts_with, ends_with, empty, not_empty | |
status | enum | exact, not_exact | Values: placed, paid, fulfilled, canceled, refunded |
currency | string | exact, not_exact, contains, not_contains, starts_with, ends_with, empty, not_empty | |
total | number | exact, not_exact, gt, gte, lt, lte, empty, not_empty | |
source | enum | exact, not_exact | Values: api, js, import, dashboard |
attribution_type | enum | exact, not_exact | Values: click, open |
placed_at | date | exact, before, after, empty, not_empty | |
created_at | date | exact, before, after, empty, not_empty |
Sort keys
This endpoint sorts with sort set to one of these keys and order set to asc or desc (order=<key> returns 400 here): placed_at, total, created_at
On this endpoint, order only accepts asc or desc. Pass the sort key in sort, for example sort=total&order=desc.
Returns
A page of order objects in data, with total_records, next_page_url and previous_page_url. The page URLs carry only page and limit, so add your search and filters again when you follow them.
{
"data": [
{
"object": "order",
"id": "ord_3aMEK4No62Zw8S1fcHNznAnnbfp",
"external_id": "1042",
"contact_id": "con_3EwrXnu9OaQWlfI1AyPUUEoYjQs",
"email": "ada@example.com",
"status": "paid",
"currency": "USD",
"subtotal": 89,
"discount": null,
"shipping": 5,
"tax": 0,
"total": 94,
"refunded_amount": 0,
"coupon_codes": [],
"cart_id": null,
"source": "api",
"placed_at": "2026-10-08T14:32:10.000Z",
"paid_at": "2026-10-08T14:32:11.204Z",
"fulfilled_at": null,
"canceled_at": null,
"refunded_at": null,
"attribution": {
"email_id": "eml_3TSvDAUQi7vqxvAQ1UEVN7k4igq",
"campaign_id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
"campaign_name": "October newsletter",
"variant_id": null,
"automation_id": null,
"automation_name": null,
"type": "click",
"touched_at": "2026-10-08T09:41:52.000Z"
},
"items": [
{
"product_id": "8123456789",
"variant_id": null,
"sku": "TRS-BLU-42",
"title": "Trail running shoe",
"quantity": 1,
"unit_price": 89,
"total": 89,
"categories": [
"Shoes",
"Running"
],
"url": "https://shop.example.com/products/trail-running-shoe",
"image_url": "https://shop.example.com/images/trail-running-shoe.jpg"
}
],
"metadata": {},
"created_at": "2026-10-08T14:32:11.204Z",
"updated_at": "2026-10-08T14:32:11.204Z"
}
],
"total_records": 1,
"next_page_url": null,
"previous_page_url": null
}Import orders in bulk
Send up to 1,000 orders in one request. Use it to import your order history, so purchase metrics, segments and product recommendations have data from day one. Each order follows the rules of Create or update an order: it’s created or updated by its id, contacts are created unless create_contact is false, carts are converted, coupon codes are redeemed and purchase metrics are updated. Requires an API key with the full or events scope. With an events key, the response holds only object, id and external_id.
By default the orders are historical: they aren’t credited to any email, and Emailit doesn’t emit order.placed or order.updated, so they don’t start automations or reach webhooks. New contacts still emit contact.created. Orders sent with this endpoint have source set to import, with or without historical.
Invalid orders are skipped and listed in rejected; the others are stored. The request still returns 200.
/orders/batchRequest Body
ordersobject[]Required1 to 1,000 orders, each with the fields of Create or update an order.
historicalbooleanDefault true: no attribution and no order events. Set to false to treat the orders like orders sent one by one: new orders are credited to emails and emit order.placed, updated orders emit order.updated.
Returns
createdintegerNumber of new orders.
updatedintegerNumber of orders that were already stored and were updated.
rejectedobject[]Orders that weren’t stored. Each item has the index of the order in your orders array and errors, keyed by field path such as orders.4.currency. An order that passed validation but couldn’t be saved has the error could not be stored under orders.<index>.
Returns 422 if orders is empty or has more than 1,000 items.
{
"created": 1,
"updated": 0,
"rejected": [
{
"index": 1,
"errors": {
"orders.1.currency": [
"must be a three-letter ISO 4217 code, e.g. USD"
]
}
}
]
}{
"message": "Validation failed. orders: Send 1 to 1000 orders.",
"errors": {
"orders": [
"Send 1 to 1000 orders."
]
}
}Delete an order
Delete an order and its items. The buyer’s purchase metrics are recalculated without it, and its revenue no longer counts in reports. Coupon codes it redeemed stay redeemed and converted carts stay converted. No event is emitted. To keep the order but stop counting its revenue, set its status to canceled with Update an order instead. Requires an API key with the full scope.
/orders/{id}Path Parameters
idstringRequiredThe order ID (ord_...) or the order ID in your shop.
{
"object": "order",
"id": "ord_3aMEK4No62Zw8S1fcHNznAnnbfp",
"deleted": true
}{
"error": "Order not found",
"message": "Order not found."
}