ReferenceReference by module

Shop API

Every Shop action (74) and data model (33): endpoints, scopes, input, preconditions, events and examples.

Sales channels, stock, shipping and orders — from basket to doorstep.

Module code retail · 74 actions · 33 data models · 56 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: retail (everything), retail:read (read only) or retail:<capability>.

Resources

ResourceTableList and readPOSTPATCHDELETE
allocationsallocation/api/v1/allocations
checkout_linescheckout_line/api/v1/checkout_lines
checkoutscheckout/api/v1/checkoutsretail.create_checkout
collection_itemsitem_collection_item/api/v1/collection_items
collectionsitem_collection/api/v1/collectionsretail.save_collectionretail.delete_collection
fulfilment_linesfulfilment_line/api/v1/fulfilment_lines
fulfilmentsfulfilment/api/v1/fulfilments
item_collection_channel_listingsitem_collection_channel_listing/api/v1/item_collection_channel_listings
order_discountssales_order_discount/api/v1/order_discounts
order_gift_cardssales_order_gift_card/api/v1/order_gift_cards
order_granted_refund_linesorder_granted_refund_line/api/v1/order_granted_refund_lines
order_granted_refundsorder_granted_refund/api/v1/order_granted_refunds
order_linessales_order_line/api/v1/order_lines
order_return_linesorder_return_line/api/v1/order_return_lines
order_returnsorder_return/api/v1/order_returns
orderssales_order/api/v1/ordersretail.create_draft_orderretail.update_orderretail.delete_draft_order
preorder_allocationspreorder_allocation/api/v1/preorder_allocations
product_listingsitem_channel_listing/api/v1/product_listings
sales_channel_warehouseschannel_warehouse/api/v1/sales_channel_warehouses
sales_channelschannel/api/v1/sales_channelsretail.save_channelretail.delete_channel
shipping_method_channel_listingsshipping_method_channel_listing/api/v1/shipping_method_channel_listings
shipping_method_excluded_itemsshipping_method_excluded_item/api/v1/shipping_method_excluded_items
shipping_method_postal_code_rulesshipping_method_postal_code_rule/api/v1/shipping_method_postal_code_rules
shipping_methodsshipping_method/api/v1/shipping_methodsretail.save_shipping_methodretail.delete_shipping_method
shipping_zone_channelsshipping_zone_channel/api/v1/shipping_zone_channels
shipping_zonesshipping_zone/api/v1/shipping_zonesretail.save_shipping_zoneretail.delete_shipping_zone
stock_movementsstock_movement/api/v1/stock_movements
stock_reservationsstock_reservation/api/v1/stock_reservations
stocksstock/api/v1/stocks
variant_listingsitem_variant_channel_listing/api/v1/variant_listings
variant_preordersvariant_preorder/api/v1/variant_preorders
warehouse_shipping_zoneswarehouse_shipping_zone/api/v1/warehouse_shipping_zones
warehouseswarehouse/api/v1/warehousesretail.create_warehouseretail.update_warehouseretail.delete_warehouse

Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.

Actions

ActionNeedsWhat it does
retail.adjust_stockretail:writeAdjust stock
retail.approve_fulfilmentretail:approveApprove a despatch
retail.attach_gift_cardretail:writePay with a gift card
retail.bulk_update_pricesretail:writeReprice in bulk
retail.cancel_fulfilmentretail:handleCancel a despatch
retail.cancel_orderretail:manageCancel an order
retail.close_returnretail:handleClose a return
retail.complete_checkoutretail:writePlace the order
retail.complete_draft_orderretail:writePlace a draft order
retail.confirm_gift_cardretail:writeConfirm a gift card redemption
retail.confirm_orderretail:approveConfirm an order
retail.create_checkoutretail:writeOpen a basket
retail.create_draft_orderretail:writeStart a draft order
retail.create_warehouseretail:manageOpen a warehouse
retail.delete_channelretail:deleteDelete a channel
retail.delete_collectionretail:deleteDelete a collection
retail.delete_draft_orderretail:deleteDiscard a draft order
retail.delete_draft_ordersretail:deleteDiscard drafts
retail.delete_shipping_methodretail:deleteDelete a delivery rate
retail.delete_shipping_zoneretail:deleteDelete a shipping zone
retail.delete_warehouseretail:deleteClose a warehouse
retail.detach_gift_cardretail:writeTake a gift card off
retail.duplicate_orderretail:writeOrder again
retail.end_preorderretail:manageEnd a preorder
retail.expire_orderretail:handleExpire an unconfirmed order
retail.expire_stock_reservationsretail:handleRelease expired checkout stock
retail.fulfil_orderretail:handleDespatch an order
retail.grant_refundretail:manageGrant a refund
retail.import_channel_orderretail:handleImport a marketplace order
retail.inspect_returnretail:handleInspect a return
retail.open_shopretail:manageOpen the shop
retail.raise_abandoned_checkoutsretail:handleFlag abandoned baskets
retail.receive_returnretail:handleReceive a return
retail.refresh_collectionretail:writeRefresh a smart collection
retail.reject_returnretail:handleRefuse a return
retail.remove_order_discountretail:writeRemove the staff discount
retail.renew_checkout_reservationretail:writeHold checkout stock
retail.request_returnretail:handleOpen a return
retail.return_productsretail:handleRecord a return
retail.save_channelretail:manageSave a sales channel
retail.save_collectionretail:writeSave a collection
retail.save_shipping_methodretail:manageSave a delivery rate
retail.save_shipping_zoneretail:manageSave a shipping zone
retail.set_channel_activeretail:manageOpen or close a channel
retail.set_channel_warehousesretail:manageChoose a channel’s warehouses
retail.set_checkout_deliveryretail:writeChoose delivery
retail.set_checkout_linesretail:writeChange a basket
retail.set_collection_itemsretail:writeChoose what a collection holds
retail.set_collection_ruleretail:writeFill a collection from a rule
retail.set_item_listingretail:writeList something in a channel
retail.set_order_discountretail:writeGive a staff discount
retail.set_order_linesretail:writeChange an order’s lines
retail.set_order_voucherretail:writeApply a coupon
retail.set_postal_code_rulesretail:manageSet postal-code rules
retail.set_preorderretail:manageSell on preorder
retail.set_shipping_excluded_itemsretail:manageExclude products from a delivery rate
retail.set_shipping_priceretail:managePrice a delivery rate in a channel
retail.set_stockretail:writeCount stock
retail.set_stock_policyretail:manageHold back safety stock
retail.set_trackingretail:handleSet a tracking number
retail.set_variant_priceretail:writePrice a variant in a channel
retail.set_warehouse_zonesretail:manageChoose which zones a warehouse serves
retail.site_cart_addretail:writeAdd to basket (site)
retail.site_cart_claimretail:writeKeep my basket after signing in
retail.site_cart_setretail:writeChange a basket line (site)
retail.site_checkout_deliveryretail:writeChoose delivery (site)
retail.site_checkout_detailsretail:writeGive checkout details (site)
retail.site_checkout_voucherretail:writeUse a coupon (site)
retail.site_place_orderretail:writePlace an order (site)
retail.sync_charge_statusretail:writeUpdate what an order has been paid
retail.transfer_stockretail:writeMove stock between warehouses
retail.update_orderretail:writeEdit an order
retail.update_order_metadataretail:writeEdit order metadata
retail.update_warehouseretail:manageEdit a warehouse

retail.adjust_stock

Adjust stock — Goods in or out of one warehouse by an amount, with a reason for the ledger.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/stocks/actions/adjust_stock
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.adjust_stock

Input

FieldTypeRequiredNotes
warehouseIduuidyesWarehouse · id of warehouse
itemVariantIduuidyesVariant · id of item_variant
deltanumberyesChange · Positive in, negative out.
reasonstring (enum)yesReason · Allowed values: count, received, damaged, correction
notestringNote · max 500

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
no_changeThe change must be a whole number other than zero.
warehouse_not_foundThe warehouse must exist.
variant_not_foundThe variant must exist.
below_allocatedThe shelf may not drop below what orders are holding.

Events it publishes: retail.stock_changed, retail.stock_low

What it writes: stock (upsert) — Moves the count by the amount, in the statement; stock_movement (insert) — Records the movement and its reason

curl -X POST https://app.getera.io/api/v1/stocks/actions/adjust_stock \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"warehouseId":"WAREHOUSE_ID","itemVariantId":"ITEM_VARIANT_ID","delta":1,"reason":"count"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.stock_changed",
    "retail.stock_low"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.stocks.adjustStock({
  warehouseId: "WAREHOUSE_ID",
  itemVariantId: "ITEM_VARIANT_ID",
  delta: 1,
  reason: "count"
})
era stocks adjust_stock \
  --warehouse-id "WAREHOUSE_ID" \
  --item-variant-id "ITEM_VARIANT_ID" \
  --delta 1 \
  --reason "count"
tools/call
{
  "name": "era__retail__adjust_stock",
  "arguments": {
    "warehouseId": "WAREHOUSE_ID",
    "itemVariantId": "ITEM_VARIANT_ID",
    "delta": 1,
    "reason": "count"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 no_change, warehouse_not_found, variant_not_found, below_allocated · 429 slow down

retail.approve_fulfilment

Approve a despatch — Only needed when the shop does not approve despatches automatically.

Needs retail:approve · changes data

POSThttps://app.getera.io/api/v1/fulfilments/{id}/actions/approve_fulfilment
API key or OAuth token · retail:approve
  • Canonical address: POST /api/v1/actions/retail.approve_fulfilment

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Despatch · id of fulfilment

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe despatch must exist.
fulfilment_not_awaitingOnly a despatch waiting for approval can be approved.

Events it publishes: retail.fulfilment_approved

What it writes: fulfilment (update) — Marks it fulfilled

curl -X POST https://app.getera.io/api/v1/fulfilments/FULFILMENT_ID/actions/approve_fulfilment \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.fulfilment_approved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.fulfilments.approveFulfilment("FULFILMENT_ID")
era fulfilments approve_fulfilment FULFILMENT_ID
tools/call
{
  "name": "era__retail__approve_fulfilment",
  "arguments": {
    "id": "FULFILMENT_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:approve · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, fulfilment_not_awaiting · 429 slow down

retail.attach_gift_card

Pay with a gift card — One call: records the spend as pending and asks gift_cards to redeem it (a reaction); a refusal marks it failed and puts the amount back.

Needs retail:write · removes or cannot be undone

POSThttps://app.getera.io/api/v1/orders/{id}/actions/attach_gift_card
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.attach_gift_card

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order
codestringGift card code · max 64
giftCardIduuidGift card (already redeemed)
giftCardEventIduuidRedemption
codeTailstringLast four · max 16
amountnumber (money)yesAmount · min 1
idempotencyKeystringIdempotency key · max 512

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
order_not_editableOnly a draft or unconfirmed order takes a gift card.
gift_card_not_on_orderThe card is named, by its code or as an already-redeemed card.
gift_card_exceeds_dueA gift card never pays more than is still due.

Events it publishes: retail.gift_card_requested, retail.gift_card_applied

What it writes: sales_order_gift_card (insert) — Records the spend (pending until redeemed); sales_order_gift_card (delete) — A failed try of the same card gives way to the new one; sales_order (update) — Lowers the amount due

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/attach_gift_card \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"amount":1}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.gift_card_requested",
    "retail.gift_card_applied"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.attachGiftCard("ORDER_ID", {
  amount: 1
})
era orders attach_gift_card ORDER_ID \
  --amount 1
tools/call
{
  "name": "era__retail__attach_gift_card",
  "arguments": {
    "id": "ORDER_ID",
    "amount": 1
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, order_not_editable, gift_card_not_on_order, gift_card_exceeds_due · 429 slow down

retail.bulk_update_prices

Reprice in bulk — One rule — set, or up or down by an amount or a percent — over many variants in a channel.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/variant_listings/actions/bulk_update_prices
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.bulk_update_prices

Input

FieldTypeRequiredNotes
channelIduuidyesChannel · id of channel
itemVariantIdsobject / arrayyesVariants
modestring (enum)yesChange · Allowed values: set, increase_percent, decrease_percent, increase_amount, decrease_amount
valuenumberyesValue · min 0
fieldstring (enum)Which figure · Allowed values: price, cost

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
channel_not_foundThe channel must exist.
no_variantsAt least one variant must be chosen.
variant_not_foundEvery variant must exist.
negative_priceNo variant may end up below zero; one refusal stops the batch.

Events it publishes: retail.channel_price_changed

What it writes: item_variant_channel_listing (upsert) — Writes each new channel price or cost

curl -X POST https://app.getera.io/api/v1/variant_listings/actions/bulk_update_prices \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"channelId":"CHANNEL_ID","itemVariantIds":{},"mode":"set","value":1}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.channel_price_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.variantListings.bulkUpdatePrices({
  channelId: "CHANNEL_ID",
  itemVariantIds: {},
  mode: "set",
  value: 1
})
era variant_listings bulk_update_prices --data '{"channelId":"CHANNEL_ID","itemVariantIds":{},"mode":"set","value":1}'
tools/call
{
  "name": "era__retail__bulk_update_prices",
  "arguments": {
    "channelId": "CHANNEL_ID",
    "itemVariantIds": {},
    "mode": "set",
    "value": 1
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 channel_not_found, no_variants, variant_not_found, negative_price · 429 slow down

retail.cancel_fulfilment

Cancel a despatch — The goods go back to the shelf they left from.

Needs retail:handle · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/fulfilments/{id}/actions/cancel_fulfilment
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.cancel_fulfilment

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Despatch · id of fulfilment

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe despatch must exist.
fulfilment_not_cancellableA refunded or cancelled despatch cannot be cancelled again.

Events it publishes: retail.fulfilment_canceled

What it writes: fulfilment (update) — Marks it cancelled; stock (update) — Puts the goods back; sales_order_line (update) — Lowers quantity_fulfilled

curl -X POST https://app.getera.io/api/v1/fulfilments/FULFILMENT_ID/actions/cancel_fulfilment \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.fulfilment_canceled"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.fulfilments.cancelFulfilment("FULFILMENT_ID")
era fulfilments cancel_fulfilment FULFILMENT_ID
tools/call
{
  "name": "era__retail__cancel_fulfilment",
  "arguments": {
    "id": "FULFILMENT_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, fulfilment_not_cancellable · 429 slow down

retail.cancel_order

Cancel an order — Releases everything it was holding. The goods never left the shelf.

Needs retail:manage · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/orders/{id}/actions/cancel_order
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.cancel_order

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order
reasonstringReason · max 500

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
order_not_cancellableA finished, cancelled or expired order cannot be cancelled.
order_has_fulfilmentsLive despatches must be cancelled first.
gift_card_pendingA gift card still being redeemed is answered before the order cancels.

Events it publishes: retail.order_canceled, retail.gift_card_removed, retail.customer_notification_requested

What it writes: sales_order (update) — Marks it cancelled; allocation (delete) — Releases the stock it held; stock (update) — Lowers the allocated count; sales_order_gift_card (delete) — Gives every gift card back (gift_cards refunds it, a reaction)

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/cancel_order \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"reason":"Reason"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_canceled",
    "retail.gift_card_removed",
    "retail.customer_notification_requested"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.cancelOrder("ORDER_ID", {
  reason: "Reason"
})
era orders cancel_order ORDER_ID \
  --reason "Reason"
tools/call
{
  "name": "era__retail__cancel_order",
  "arguments": {
    "id": "ORDER_ID",
    "reason": "Reason"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, order_not_cancellable, order_has_fulfilments, gift_card_pending · 429 slow down

retail.close_return

Close a return — Nothing more will happen on it.

Needs retail:handle · changes data

POSThttps://app.getera.io/api/v1/order_returns/{id}/actions/close_return
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.close_return

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Return · id of order_return

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
return_not_foundThe return must exist.
return_not_openOnly a received or inspected return can be closed.

Events it publishes: retail.return_closed

What it writes: order_return (update) — Marks it closed

curl -X POST https://app.getera.io/api/v1/order_returns/ORDER_RETURN_ID/actions/close_return \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.return_closed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orderReturns.closeReturn("ORDER_RETURN_ID")
era order_returns close_return ORDER_RETURN_ID
tools/call
{
  "name": "era__retail__close_return",
  "arguments": {
    "id": "ORDER_RETURN_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 return_not_found, return_not_open · 429 slow down

retail.complete_checkout

Place the order — Turns a basket into an order, allocates stock and closes the basket — once.

Needs retail:write · removes or cannot be undone

POSThttps://app.getera.io/api/v1/orders/actions/complete_checkout
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.complete_checkout

Input

FieldTypeRequiredNotes
tokenuuidyesBasket

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe basket must exist.
checkout_completingThe double-submit lock: one basket becomes one order.
checkout_emptyAn empty basket is not an order.
prices_staleA quote worked out too long ago must be refreshed.
order_not_paidUnless the channel allows unpaid orders, it must be paid for.
shipping_address_missingSomething to be shipped needs somewhere to ship it.
insufficient_stockEvery tracked line must be coverable, or none of them is taken.
voucher_not_applicableA coupon on the basket must still apply to the placed lines.
voucher_usage_exceededA coupon on the basket must not be used up by the time the order is placed.

Events it publishes: retail.order_placed, retail.customer_notification_requested, retail.stock_low, retail.order_discounts_applied

What it writes: sales_order (insert) — Writes the order; sales_order_line (insert) — Writes its lines, frozen; allocation (insert) — Promises stock to the order; stock (update) — Raises the allocated count; stock_reservation (update) — Commits the basket hold into the order allocation; checkout (delete) — Closes the basket

curl -X POST https://app.getera.io/api/v1/orders/actions/complete_checkout \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"token":"TOKEN_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_placed",
    "retail.customer_notification_requested",
    "retail.stock_low",
    "retail.order_discounts_applied"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.completeCheckout({
  token: "TOKEN_ID"
})
era orders complete_checkout \
  --token "TOKEN_ID"
tools/call
{
  "name": "era__retail__complete_checkout",
  "arguments": {
    "token": "TOKEN_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, checkout_completing, checkout_empty, prices_stale, order_not_paid, shipping_address_missing, insufficient_stock, voucher_not_applicable, voucher_usage_exceeded · 429 slow down

retail.complete_draft_order

Place a draft order — Allocates stock and moves the draft into the order lifecycle.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/orders/{id}/actions/complete_draft_order
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.complete_draft_order

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
not_a_draftOnly a draft can be placed.
order_emptyA draft with no lines is not an order.
gift_card_pendingA gift card still being redeemed is answered before the draft is placed.
shipping_address_missingSomething to be shipped needs somewhere to ship it.
insufficient_stockEvery tracked line must be coverable, or none of them is taken.
voucher_not_foundA coupon on the draft must still exist.
voucher_not_applicableA coupon on the draft must still apply.
voucher_usage_exceededA coupon on the draft must not have been used up meanwhile.

Events it publishes: retail.order_placed, retail.order_discounts_applied, retail.customer_notification_requested, retail.stock_low

What it writes: sales_order (update) — Moves it out of draft; sales_order_line (update) — Freezes the discount snapshot; sales_order_discount (insert) — Records what was applied; allocation (insert) — Promises stock to the order; preorder_allocation (insert) — Promises preorders; stock (update) — Raises the allocated count

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/complete_draft_order \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_placed",
    "retail.order_discounts_applied",
    "retail.customer_notification_requested",
    "retail.stock_low"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.completeDraftOrder("ORDER_ID")
era orders complete_draft_order ORDER_ID
tools/call
{
  "name": "era__retail__complete_draft_order",
  "arguments": {
    "id": "ORDER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_a_draft, order_empty, gift_card_pending, shipping_address_missing, insufficient_stock, voucher_not_found, voucher_not_applicable, voucher_usage_exceeded · 429 slow down

retail.confirm_gift_card

Confirm a gift card redemption — Machine-only (finance-reactions.ts): gift_cards redeemed the card, so the pending row on the order is applied.

Needs retail:write · changes data

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/order_gift_cards/{id}/actions/confirm_gift_card
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.confirm_gift_card

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Gift card on the order · id of sales_order_gift_card
giftCardIduuidyesGift card
giftCardEventIduuidRedemption

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
gift_card_not_on_orderThe gift card must be on the order.

Events it publishes: retail.gift_card_applied

What it writes: sales_order_gift_card (update) — Applies the pending row

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 gift_card_not_on_order · 429 slow down

retail.confirm_order

Confirm an order — The step that exists only when the channel does not confirm automatically.

Needs retail:approve · changes data

POSThttps://app.getera.io/api/v1/orders/{id}/actions/confirm_order
API key or OAuth token · retail:approve
  • Canonical address: POST /api/v1/actions/retail.confirm_order

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
order_not_unconfirmedOnly an unconfirmed order can be confirmed.

Events it publishes: retail.order_confirmed

What it writes: sales_order (update) — Moves it to unfulfilled

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/confirm_order \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_confirmed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.confirmOrder("ORDER_ID")
era orders confirm_order ORDER_ID
tools/call
{
  "name": "era__retail__confirm_order",
  "arguments": {
    "id": "ORDER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:approve · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, order_not_unconfirmed · 429 slow down

retail.create_checkout

Open a basket — A basket in one channel, for a customer or a guest.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/checkouts/actions/create_checkout
API key or OAuth token · retail:write
  • REST alias: POST /api/v1/checkouts
  • Canonical address: POST /api/v1/actions/retail.create_checkout

Input

FieldTypeRequiredNotes
channelIduuidyesChannel · id of channel
customerIduuidCustomer · id of customer
emailemailEmail
linesobject / arrayLines

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
channel_not_foundThe channel must exist.
channel_closedA closed channel takes no baskets.
malformed_linesEvery line needs a variant and a quantity.
variant_not_foundEvery variant must exist.
variant_not_pricedA variant with no price in this channel cannot be sold here.
reservation_stock_unavailableEvery tracked line must be reservable for fifteen minutes.
gift_line_lockedA promotion’s gift line cannot be edited by hand.

Events it publishes: retail.checkout_created

What it writes: checkout (insert) — Opens the basket; checkout_line (upsert) — Writes its lines; stock_reservation (upsert) — Holds tracked stock for fifteen minutes

curl -X POST https://app.getera.io/api/v1/checkouts/actions/create_checkout \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"channelId":"CHANNEL_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.checkout_created"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.checkouts.create({
  channelId: "CHANNEL_ID"
})
era checkouts create \
  --channel-id "CHANNEL_ID"
tools/call
{
  "name": "era__retail__create_checkout",
  "arguments": {
    "channelId": "CHANNEL_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 channel_not_found, channel_closed, malformed_lines, variant_not_found, variant_not_priced, reservation_stock_unavailable, gift_line_locked · 429 slow down

retail.create_draft_order

Start a draft order — The shop assistant’s version of a basket: an order nobody has placed yet.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/orders/actions/create_draft_order
API key or OAuth token · retail:write
  • REST alias: POST /api/v1/orders
  • Canonical address: POST /api/v1/actions/retail.create_draft_order

Input

FieldTypeRequiredNotes
channelIduuidyesChannel · id of channel
customerIduuidCustomer · id of customer
emailemailEmail
customerNotestringNote · max 2000
billingAddressIduuidBilling address · id of address
shippingAddressIduuidDelivery address · id of address
fulfilmentMethodstring (enum)Delivery · Allowed values: shipping, pickup

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
channel_not_foundThe channel must exist.
channel_closedA closed channel takes no orders.

Events it publishes: retail.draft_order_created

What it writes: sales_order (insert) — Writes the draft

curl -X POST https://app.getera.io/api/v1/orders/actions/create_draft_order \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"channelId":"CHANNEL_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.draft_order_created"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.create({
  channelId: "CHANNEL_ID"
})
era orders create \
  --channel-id "CHANNEL_ID"
tools/call
{
  "name": "era__retail__create_draft_order",
  "arguments": {
    "channelId": "CHANNEL_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 channel_not_found, channel_closed · 429 slow down

retail.create_warehouse

Open a warehouse — A place stock is held and orders are despatched from.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/warehouses/actions/create_warehouse
API key or OAuth token · retail:manage
  • REST alias: POST /api/v1/warehouses
  • Canonical address: POST /api/v1/actions/retail.create_warehouse

Input

FieldTypeRequiredNotes
namestringyesName · max 250
slugstringAddress · max 255
addressIduuidExisting address · id of address
streetAddress1stringStreet · max 250
streetAddress2stringStreet (second line) · max 250
cityAreastringDistrict · max 120
citystringCity · max 120
countryAreastringRegion · max 120
postalCodestringPostal code · max 32
countrystringCountry · max 2
phonephonePhone
emailemailEmail
clickAndCollectOptionstring (enum)Collection · Allowed values: disabled, local, all
isPrivatebooleanHidden from customers

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_nameThe name must produce a usable address.
slug_takenThe address must be free in this workspace.
address_not_foundA warehouse cannot exist without an address.

Events it publishes: retail.warehouse_saved

What it writes: warehouse (insert) — Creates the warehouse

curl -X POST https://app.getera.io/api/v1/warehouses/actions/create_warehouse \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.warehouse_saved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.warehouses.create({
  name: "Name"
})
era warehouses create \
  --name "Name"
tools/call
{
  "name": "era__retail__create_warehouse",
  "arguments": {
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_name, slug_taken, address_not_found · 429 slow down

retail.delete_channel

Delete a channel — Only a channel that never took an order or a basket; one that has sold is closed instead.

Needs retail:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/sales_channels/{id}/actions/delete_channel
API key or OAuth token · retail:delete
  • REST alias: DELETE /api/v1/sales_channels/{id}
  • Canonical address: POST /api/v1/actions/retail.delete_channel

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Channel · id of channel

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
channel_not_foundThe channel must exist.
channel_in_useA channel with orders or baskets stays; close it instead.

Events it publishes: retail.channel_deleted

What it writes: channel (delete) — Removes the channel and its listings

curl -X POST https://app.getera.io/api/v1/sales_channels/SALES_CHANNEL_ID/actions/delete_channel \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.channel_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.salesChannels.deleteChannel("SALES_CHANNEL_ID")
era sales_channels delete_channel SALES_CHANNEL_ID
tools/call
{
  "name": "era__retail__delete_channel",
  "arguments": {
    "id": "SALES_CHANNEL_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 channel_not_found, channel_in_use · 429 slow down

retail.delete_collection

Delete a collection — The list goes; the items in it are the catalogue’s and stay.

Needs retail:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/collections/{id}/actions/delete_collection
API key or OAuth token · retail:delete
  • REST alias: DELETE /api/v1/collections/{id}
  • Canonical address: POST /api/v1/actions/retail.delete_collection

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Collection · id of item_collection

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe collection must exist.

Events it publishes: retail.collection_deleted

What it writes: item_collection (delete) — Removes the collection

curl -X POST https://app.getera.io/api/v1/collections/COLLECTION_ID/actions/delete_collection \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.collection_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.collections.deleteCollection("COLLECTION_ID")
era collections delete_collection COLLECTION_ID
tools/call
{
  "name": "era__retail__delete_collection",
  "arguments": {
    "id": "COLLECTION_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

retail.delete_draft_order

Discard a draft order — Removes an order shell only before it is placed.

Needs retail:delete · removes or cannot be undone

POSThttps://app.getera.io/api/v1/orders/{id}/actions/delete_draft_order
API key or OAuth token · retail:delete
  • REST alias: DELETE /api/v1/orders/{id}
  • Canonical address: POST /api/v1/actions/retail.delete_draft_order

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
not_a_draftPlaced orders are cancelled, never deleted.
draft_has_gift_cardsA gift card spent on the draft comes off first.

Events it publishes: retail.draft_order_deleted

What it writes: sales_order (delete) — Removes the draft and its lines

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/delete_draft_order \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.draft_order_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.deleteDraftOrder("ORDER_ID")
era orders delete_draft_order ORDER_ID
tools/call
{
  "name": "era__retail__delete_draft_order",
  "arguments": {
    "id": "ORDER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_a_draft, draft_has_gift_cards · 429 slow down

retail.delete_draft_orders

Discard drafts — Several drafts at once, from the orders list. All or none.

Needs retail:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/orders/actions/delete_draft_orders
API key or OAuth token · retail:delete
  • Canonical address: POST /api/v1/actions/retail.delete_draft_orders

Input

FieldTypeRequiredNotes
idsobject / arrayyesDrafts

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
no_ordersAt least one draft is chosen.
not_a_draftEvery one must be a draft.
draft_has_gift_cardsA draft a gift card paid towards keeps until the card is taken off.

Events it publishes: retail.draft_order_deleted

What it writes: sales_order (delete) — Removes the drafts

curl -X POST https://app.getera.io/api/v1/orders/actions/delete_draft_orders \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"ids":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.draft_order_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.deleteDraftOrders({
  ids: {}
})
era orders delete_draft_orders --data '{"ids":{}}'
tools/call
{
  "name": "era__retail__delete_draft_orders",
  "arguments": {
    "ids": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 no_orders, not_a_draft, draft_has_gift_cards · 429 slow down

retail.delete_shipping_method

Delete a delivery rate — Past orders keep the name they were sold with.

Needs retail:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/shipping_methods/{id}/actions/delete_shipping_method
API key or OAuth token · retail:delete
  • REST alias: DELETE /api/v1/shipping_methods/{id}
  • Canonical address: POST /api/v1/actions/retail.delete_shipping_method

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Rate · id of shipping_method

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe rate must exist.

Events it publishes: retail.shipping_method_deleted

What it writes: shipping_method (delete) — Removes the rate

curl -X POST https://app.getera.io/api/v1/shipping_methods/SHIPPING_METHOD_ID/actions/delete_shipping_method \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.shipping_method_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.shippingMethods.deleteShippingMethod("SHIPPING_METHOD_ID")
era shipping_methods delete_shipping_method SHIPPING_METHOD_ID
tools/call
{
  "name": "era__retail__delete_shipping_method",
  "arguments": {
    "id": "SHIPPING_METHOD_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

retail.delete_shipping_zone

Delete a shipping zone — Only an empty zone can go; its rates would leave orders without one.

Needs retail:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/shipping_zones/{id}/actions/delete_shipping_zone
API key or OAuth token · retail:delete
  • REST alias: DELETE /api/v1/shipping_zones/{id}
  • Canonical address: POST /api/v1/actions/retail.delete_shipping_zone

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Zone · id of shipping_zone

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe zone must exist.
zone_has_methodsA zone holding rates cannot be deleted.

Events it publishes: retail.shipping_zone_deleted

What it writes: shipping_zone (delete) — Removes the zone

curl -X POST https://app.getera.io/api/v1/shipping_zones/SHIPPING_ZONE_ID/actions/delete_shipping_zone \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.shipping_zone_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.shippingZones.deleteShippingZone("SHIPPING_ZONE_ID")
era shipping_zones delete_shipping_zone SHIPPING_ZONE_ID
tools/call
{
  "name": "era__retail__delete_shipping_zone",
  "arguments": {
    "id": "SHIPPING_ZONE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, zone_has_methods · 429 slow down

retail.delete_warehouse

Close a warehouse — The warehouse and its address go together, as they do in the source.

Needs retail:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/warehouses/{id}/actions/delete_warehouse
API key or OAuth token · retail:delete
  • REST alias: DELETE /api/v1/warehouses/{id}
  • Canonical address: POST /api/v1/actions/retail.delete_warehouse

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Warehouse · id of warehouse

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe warehouse must exist.
warehouse_has_allocationsStock promised to open orders must be settled first.

Events it publishes: retail.warehouse_deleted

What it writes: warehouse (delete) — Removes the warehouse and its stock rows

curl -X POST https://app.getera.io/api/v1/warehouses/WAREHOUSE_ID/actions/delete_warehouse \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.warehouse_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.warehouses.deleteWarehouse("WAREHOUSE_ID")
era warehouses delete_warehouse WAREHOUSE_ID
tools/call
{
  "name": "era__retail__delete_warehouse",
  "arguments": {
    "id": "WAREHOUSE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, warehouse_has_allocations · 429 slow down

retail.detach_gift_card

Take a gift card off — Removes a gift card from an order; gift_cards puts the money back onto the card (a reaction). With failure set, it is the compensation of a refused redemption.

Needs retail:write · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/order_gift_cards/{id}/actions/detach_gift_card
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.detach_gift_card

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Gift card on the order · id of sales_order_gift_card
failurestringWhy the card was refused (compensation) · max 500

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
gift_card_not_on_orderThe gift card must be on the order.
gift_card_pendingA card still being redeemed waits for its answer.
order_not_editableA placed order keeps its gift cards.

Events it publishes: retail.gift_card_removed

What it writes: sales_order_gift_card (delete) — Removes the spend; sales_order_gift_card (update) — Marks a refused redemption failed; sales_order (update) — Raises the amount due again

curl -X POST https://app.getera.io/api/v1/order_gift_cards/ORDER_GIFT_CARD_ID/actions/detach_gift_card \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"failure":"Why the card was refused (compensation)"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.gift_card_removed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orderGiftCards.detachGiftCard("ORDER_GIFT_CARD_ID", {
  failure: "Why the card was refused (compensation)"
})
era order_gift_cards detach_gift_card ORDER_GIFT_CARD_ID \
  --failure "Why the card was refused (compensation)"
tools/call
{
  "name": "era__retail__detach_gift_card",
  "arguments": {
    "id": "ORDER_GIFT_CARD_ID",
    "failure": "Why the card was refused (compensation)"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 gift_card_not_on_order, gift_card_pending, order_not_editable · 429 slow down

retail.duplicate_order

Order again — A new draft with the same customer, addresses and lines, at today’s channel prices.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/orders/{id}/actions/duplicate_order
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.duplicate_order

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
channel_closedIts channel must still be open.

Events it publishes: retail.draft_order_created, retail.order_lines_changed, retail.order_discounts_applied

What it writes: sales_order (insert) — Writes the new draft; sales_order_line (insert) — Copies the lines at today’s prices; sales_order_discount (insert) — Records what applies to the new draft

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/duplicate_order \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.draft_order_created",
    "retail.order_lines_changed",
    "retail.order_discounts_applied"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.duplicateOrder("ORDER_ID")
era orders duplicate_order ORDER_ID
tools/call
{
  "name": "era__retail__duplicate_order",
  "arguments": {
    "id": "ORDER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, channel_closed · 429 slow down

retail.end_preorder

End a preorder — The goods arrived: every preorder becomes a real allocation on a shelf — all of them, or none.

Needs retail:manage · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/allocations/actions/end_preorder
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.end_preorder

Input

FieldTypeRequiredNotes
itemVariantIduuidyesVariant · id of item_variant

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
variant_not_foundThe variant must exist.
not_preorderThe variant must be on preorder.
insufficient_stockThe shelves must hold what the preorders promised.

Events it publishes: retail.preorder_ended, retail.stock_low

What it writes: preorder_allocation (delete) — Releases the preorders; variant_preorder (delete) — Ends the preorder; allocation (insert) — Promises the shelf instead; stock (update) — Raises the allocated count

curl -X POST https://app.getera.io/api/v1/allocations/actions/end_preorder \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"itemVariantId":"ITEM_VARIANT_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.preorder_ended",
    "retail.stock_low"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.allocations.endPreorder({
  itemVariantId: "ITEM_VARIANT_ID"
})
era allocations end_preorder \
  --item-variant-id "ITEM_VARIANT_ID"
tools/call
{
  "name": "era__retail__end_preorder",
  "arguments": {
    "itemVariantId": "ITEM_VARIANT_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 variant_not_found, not_preorder, insufficient_stock · 429 slow down

retail.expire_order

Expire an unconfirmed order — Machine: the shop sweep lets an order nobody confirmed in time go, with its stock and its coupon.

Needs retail:handle · removes or cannot be undone

POSThttps://app.getera.io/api/v1/orders/{id}/actions/expire_order
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.expire_order

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
order_not_expirableOnly an unconfirmed order past the expiry setting expires.

Events it publishes: retail.order_expired

What it writes: sales_order (update) — Marks it expired; allocation (delete) — Releases the stock it held; stock (update) — Lowers the allocated count

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/expire_order \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_expired"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.expireOrder("ORDER_ID")
era orders expire_order ORDER_ID
tools/call
{
  "name": "era__retail__expire_order",
  "arguments": {
    "id": "ORDER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, order_not_expirable · 429 slow down

retail.expire_stock_reservations

Release expired checkout stock — Machine action: releases checkout claims older than fifteen minutes.

Needs retail:handle · changes data

POSThttps://app.getera.io/api/v1/stock_reservations/actions/expire_stock_reservations
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.expire_stock_reservations

Input

This action takes no input.

Events it publishes: retail.stock_reservations_expired

What it writes: stock_reservation (update) — Marks expired claims released

curl -X POST https://app.getera.io/api/v1/stock_reservations/actions/expire_stock_reservations \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.stock_reservations_expired"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.stockReservations.expireStockReservations()
era stock_reservations expire_stock_reservations
tools/call
{
  "name": "era__retail__expire_stock_reservations",
  "arguments": {}
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down

retail.fulfil_order

Despatch an order — Goods leave a named shelf. This is where the count actually drops.

Needs retail:handle · changes data

POSThttps://app.getera.io/api/v1/orders/{id}/actions/fulfil_order
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.fulfil_order

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order
linesobject / arrayyesLines
trackingNumberstringTracking number · max 255
carrierstringCarrier · max 120
trackingUrlstringTracking link · max 1000
notifyCustomerbooleanTell the customer

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
order_not_fulfillableOnly an open order can be despatched from.
preorder_not_fulfillableA line on preorder waits for the preorder to end.
malformed_linesEvery despatch line needs an order line and a quantity.
line_not_foundEvery line must be on this order.
over_fulfilmentMore cannot go out than was ordered.
insufficient_stockThe named warehouse must actually hold the goods.

Events it publishes: retail.fulfilment_created, retail.customer_notification_requested, retail.stock_low

What it writes: fulfilment (insert) — Records the despatch; fulfilment_line (insert) — Records which shelf each line left from; stock (update) — Lowers the count and the allocation; sales_order_line (update) — Raises quantity_fulfilled; sales_order (update) — Settles the order status

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/fulfil_order \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"lines":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.fulfilment_created",
    "retail.customer_notification_requested",
    "retail.stock_low"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.fulfilOrder("ORDER_ID", {
  lines: {}
})
era orders fulfil_order ORDER_ID --data '{"lines":{}}'
tools/call
{
  "name": "era__retail__fulfil_order",
  "arguments": {
    "id": "ORDER_ID",
    "lines": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, order_not_fulfillable, preorder_not_fulfillable, malformed_lines, line_not_found, over_fulfilment, insufficient_stock · 429 slow down

retail.grant_refund

Grant a refund — The shop agrees to give an amount back — Saleor’s granted refund. The money moves in Finance.

Needs retail:manage · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/order_granted_refunds/actions/grant_refund
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.grant_refund

Input

FieldTypeRequiredNotes
iduuidyesOrder · id of sales_order
amountnumber (money)Amount · Leave empty to work it out from the lines. · min 0
linesobject / arrayLines
includeShippingbooleanInclude delivery
reasonstringReason · max 500
returnIduuidReturn · id of order_return

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
line_not_foundEvery line must be on this order.
no_refund_amountA grant has an amount.
refund_exceeds_orderGrants never exceed what the order was sold for.
return_not_foundA named return must exist.

Events it publishes: retail.refund_granted, retail.customer_notification_requested

What it writes: order_granted_refund (insert) — Records the grant; order_granted_refund_line (insert) — Records the lines it is for

curl -X POST https://app.getera.io/api/v1/order_granted_refunds/actions/grant_refund \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"id":"SALES_ORDER_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.refund_granted",
    "retail.customer_notification_requested"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orderGrantedRefunds.grantRefund({
  id: "SALES_ORDER_ID"
})
era order_granted_refunds grant_refund \
  --id "SALES_ORDER_ID"
tools/call
{
  "name": "era__retail__grant_refund",
  "arguments": {
    "id": "SALES_ORDER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, line_not_found, no_refund_amount, refund_exceeds_order, return_not_found · 429 slow down

retail.import_channel_order

Import a marketplace order — Writes (or moves) one order that came from a marketplace or another shop: lines, frozen addresses, the stock it holds.

Needs retail:handle · changes data

POSThttps://app.getera.io/api/v1/orders/actions/import_channel_order
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.import_channel_order

Input

FieldTypeRequiredNotes
channelIduuidyesChannel · id of channel
accountIduuidIntegration account
providerstringyesProvider · max 41
warehouseIduuidWarehouse · id of warehouse
customerIduuidCustomer · id of customer
orderobject / arrayyesOrder

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
malformed_orderThe order needs an id, a known status, a currency and lines.
channel_not_foundThe channel must exist in this workspace.
unknown_orderA status-only update cannot create an order Era does not have.

Events it publishes: retail.channel_order_imported, retail.channel_order_updated, retail.stock_low

What it writes: sales_order (upsert) — The order, keyed on (channel, external reference); sales_order_line (insert) — Its lines, each tied to a variant where one matched; allocation (upsert) — Holds the stock (may oversell; returned as a shortage); stock (update) — Allocated, released or taken off the shelf by a despatch; stock_movement (insert) — The despatch in the stock ledger; fulfilment (insert) — The despatch when the marketplace shipped it; fulfilment_line (insert) — What left, from which shelf

curl -X POST https://app.getera.io/api/v1/orders/actions/import_channel_order \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"channelId":"CHANNEL_ID","provider":"Provider","order":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.channel_order_imported",
    "retail.channel_order_updated",
    "retail.stock_low"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.importChannelOrder({
  channelId: "CHANNEL_ID",
  provider: "Provider",
  order: {}
})
era orders import_channel_order --data '{"channelId":"CHANNEL_ID","provider":"Provider","order":{}}'
tools/call
{
  "name": "era__retail__import_channel_order",
  "arguments": {
    "channelId": "CHANNEL_ID",
    "provider": "Provider",
    "order": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 malformed_order, channel_not_found, unknown_order · 429 slow down

retail.inspect_return

Inspect a return — What can be sold again goes back on a named shelf, with a ledger row; what is damaged does not.

Needs retail:handle · changes data

POSThttps://app.getera.io/api/v1/order_returns/{id}/actions/inspect_return
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.inspect_return

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Return · id of order_return
linesobject / arrayyesLines

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
return_not_foundThe return must exist.
return_not_openOnly a received return can be inspected.
line_not_foundEvery line must be on this return.
over_restockMore cannot go back on the shelf than came back.
warehouse_not_foundA restock names the shelf it goes back on.

Events it publishes: retail.return_inspected, retail.stock_changed, retail.stock_low

What it writes: order_return_line (update) — Records the condition and the restock; order_return (update) — Marks it inspected; stock (upsert) — Puts resellable goods back; stock_movement (insert) — Explains the restock

curl -X POST https://app.getera.io/api/v1/order_returns/ORDER_RETURN_ID/actions/inspect_return \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"lines":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.return_inspected",
    "retail.stock_changed",
    "retail.stock_low"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orderReturns.inspectReturn("ORDER_RETURN_ID", {
  lines: {}
})
era order_returns inspect_return ORDER_RETURN_ID --data '{"lines":{}}'
tools/call
{
  "name": "era__retail__inspect_return",
  "arguments": {
    "id": "ORDER_RETURN_ID",
    "lines": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 return_not_found, return_not_open, line_not_found, over_restock, warehouse_not_found · 429 slow down

retail.open_shop

Open the shop — One call: an open sales channel named after the workspace, in TRY and Türkiye unless told otherwise. Answers with the existing shop when there is one. Era calls it after "Mağazan yok — açayım mı?" is answered yes.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/sales_channels/actions/open_shop
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.open_shop

Input

FieldTypeRequiredNotes
namestringName · Empty = the workspace name. · max 250
currencyCodestringCurrency · ISO-4217. Empty = TRY. · max 3
defaultCountrystringDefault country · Empty = TR. · max 2

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_currencyThe currency must be an ISO-4217 code.

Events it publishes: retail.channel_saved

What it writes: channel (upsert) — Creates (or opens) the shop channel

curl -X POST https://app.getera.io/api/v1/sales_channels/actions/open_shop \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.channel_saved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.salesChannels.openShop({
  name: "Name"
})
era sales_channels open_shop \
  --name "Name"
tools/call
{
  "name": "era__retail__open_shop",
  "arguments": {
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_currency · 429 slow down

retail.raise_abandoned_checkouts

Flag abandoned baskets — Machine-only (the shop sweep): every basket with an address on it that went quiet for the window is told about once.

Needs retail:handle · changes data

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/checkouts/actions/raise_abandoned_checkouts
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.raise_abandoned_checkouts

Input

This action takes no input.

Events it publishes: retail.checkout_abandoned

What it writes: checkout (update) — Records that the basket was flagged as abandoned

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down

retail.receive_return

Receive a return — The parcel arrived. The order moves to returned or partially returned; the shelf waits for the inspection.

Needs retail:handle · changes data

POSThttps://app.getera.io/api/v1/order_returns/{id}/actions/receive_return
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.receive_return

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Return · id of order_return
linesobject / arrayLines

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
return_not_foundThe return must exist.
return_not_openOnly a requested return can be received.
over_receiptMore cannot arrive than was asked back.

Events it publishes: retail.return_received, retail.order_returned

What it writes: order_return_line (update) — Records what arrived; order_return (update) — Marks it received; sales_order (update) — Moves it to returned or partially returned

curl -X POST https://app.getera.io/api/v1/order_returns/ORDER_RETURN_ID/actions/receive_return \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"lines":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.return_received",
    "retail.order_returned"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orderReturns.receiveReturn("ORDER_RETURN_ID", {
  lines: {}
})
era order_returns receive_return ORDER_RETURN_ID --data '{"lines":{}}'
tools/call
{
  "name": "era__retail__receive_return",
  "arguments": {
    "id": "ORDER_RETURN_ID",
    "lines": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 return_not_found, return_not_open, over_receipt · 429 slow down

retail.refresh_collection

Refresh a smart collection — Runs the rule again, for items added or changed since.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/collection_items/actions/refresh_collection
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.refresh_collection

Input

FieldTypeRequiredNotes
iduuidyesCollection · id of item_collection

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe collection must exist.
collection_not_smartOnly a rule collection can be refreshed.

Events it publishes: retail.collection_items_changed

What it writes: item_collection_item (upsert) — Replaces the membership

curl -X POST https://app.getera.io/api/v1/collection_items/actions/refresh_collection \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"id":"ITEM_COLLECTION_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.collection_items_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.collectionItems.refreshCollection({
  id: "ITEM_COLLECTION_ID"
})
era collection_items refresh_collection \
  --id "ITEM_COLLECTION_ID"
tools/call
{
  "name": "era__retail__refresh_collection",
  "arguments": {
    "id": "ITEM_COLLECTION_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, collection_not_smart · 429 slow down

retail.reject_return

Refuse a return — The return is not accepted — outside the window, or not what was sold.

Needs retail:handle · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/order_returns/{id}/actions/reject_return
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.reject_return

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Return · id of order_return
reasonstringReason · max 500

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
return_not_foundThe return must exist.
return_not_openOnly a requested return can be refused.

Events it publishes: retail.return_rejected

What it writes: order_return (update) — Marks it rejected

curl -X POST https://app.getera.io/api/v1/order_returns/ORDER_RETURN_ID/actions/reject_return \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"reason":"Reason"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.return_rejected"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orderReturns.rejectReturn("ORDER_RETURN_ID", {
  reason: "Reason"
})
era order_returns reject_return ORDER_RETURN_ID \
  --reason "Reason"
tools/call
{
  "name": "era__retail__reject_return",
  "arguments": {
    "id": "ORDER_RETURN_ID",
    "reason": "Reason"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 return_not_found, return_not_open · 429 slow down

retail.remove_order_discount

Remove the staff discount — Saleor’s orderDiscountDelete. The coupon and promotions apply again.

Needs retail:write · removes or cannot be undone

POSThttps://app.getera.io/api/v1/orders/{id}/actions/remove_order_discount
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.remove_order_discount

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
order_not_editableOnly a draft or unconfirmed order changes its discount.

Events it publishes: retail.order_discounts_applied

What it writes: sales_order (update) — Clears the discount and recomputes the totals; sales_order_line (update) — Rewrites the per-line snapshot; sales_order_discount (insert) — Records what applies now

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/remove_order_discount \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_discounts_applied"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.removeOrderDiscount("ORDER_ID")
era orders remove_order_discount ORDER_ID
tools/call
{
  "name": "era__retail__remove_order_discount",
  "arguments": {
    "id": "ORDER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, order_not_editable · 429 slow down

retail.renew_checkout_reservation

Hold checkout stock — Renews the basket stock claim for fifteen minutes.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/stock_reservations/actions/renew_checkout_reservation
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.renew_checkout_reservation

Input

FieldTypeRequiredNotes
tokenuuidyesBasket

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe basket must exist.
checkout_completingA basket being completed cannot renew its hold.
reservation_stock_unavailableEvery tracked line must be reservable.

Events it publishes: retail.stock_reserved

What it writes: stock_reservation (upsert) — Replaces the fifteen-minute stock hold

curl -X POST https://app.getera.io/api/v1/stock_reservations/actions/renew_checkout_reservation \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"token":"TOKEN_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.stock_reserved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.stockReservations.renewCheckoutReservation({
  token: "TOKEN_ID"
})
era stock_reservations renew_checkout_reservation \
  --token "TOKEN_ID"
tools/call
{
  "name": "era__retail__renew_checkout_reservation",
  "arguments": {
    "token": "TOKEN_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, checkout_completing, reservation_stock_unavailable · 429 slow down

retail.request_return

Open a return — The customer is sending something back. Nothing moves until it arrives.

Needs retail:handle · changes data

POSThttps://app.getera.io/api/v1/order_returns/actions/request_return
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.request_return

Input

FieldTypeRequiredNotes
iduuidyesOrder · id of sales_order
linesobject / arrayyesLines
reasonstringReason · max 500
notestringNote · max 2000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
order_not_returnableNothing can come back that never went out.
malformed_linesSay which lines are coming back, and how many.
line_not_foundEvery line must be on this order.
over_returnMore cannot come back than went out and is not already on its way.

Events it publishes: retail.return_requested

What it writes: order_return (insert) — Opens the return; order_return_line (insert) — Lists what is coming back

curl -X POST https://app.getera.io/api/v1/order_returns/actions/request_return \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"id":"SALES_ORDER_ID","lines":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.return_requested"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orderReturns.requestReturn({
  id: "SALES_ORDER_ID",
  lines: {}
})
era order_returns request_return --data '{"id":"SALES_ORDER_ID","lines":{}}'
tools/call
{
  "name": "era__retail__request_return",
  "arguments": {
    "id": "SALES_ORDER_ID",
    "lines": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, order_not_returnable, malformed_lines, line_not_found, over_return · 429 slow down

retail.return_products

Record a return — The status moves; the shelf does not. A returned item may be damaged.

Needs retail:handle · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/orders/{id}/actions/return_products
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.return_products

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order
linesobject / arrayyesLines

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
order_not_returnableNothing can come back that never went out.
malformed_linesSay which lines are coming back, and how many.
line_not_foundEvery line must be on this order.
over_returnMore cannot come back than went out.

Events it publishes: retail.order_returned

What it writes: sales_order (update) — Moves it to returned or partially returned

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/return_products \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"lines":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_returned"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.returnProducts("ORDER_ID", {
  lines: {}
})
era orders return_products ORDER_ID --data '{"lines":{}}'
tools/call
{
  "name": "era__retail__return_products",
  "arguments": {
    "id": "ORDER_ID",
    "lines": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, order_not_returnable, malformed_lines, line_not_found, over_return · 429 slow down

retail.save_channel

Save a sales channel — A place things are sold: its name, address, currency and country.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/sales_channels/{id}/actions/save_channel
API key or OAuth token · retail:manage
  • REST alias: PATCH /api/v1/sales_channels/{id}
  • Canonical address: POST /api/v1/actions/retail.save_channel

Input

FieldTypeRequiredNotes
iduuidFilled from the path {id} · Channel · id of channel
namestringyesName · max 250
slugstringAddress · max 255
currencyCodestringCurrency · ISO-4217, three letters. · max 3
defaultCountrystringDefault country · max 2

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_nameThe name must produce a usable address.
slug_takenThe address must be free in this workspace.
invalid_currencyThe currency must be an ISO-4217 code.
channel_not_foundThe channel must exist.
channel_currency_lockedA channel with prices in it cannot change currency.

Events it publishes: retail.channel_saved

What it writes: channel (upsert) — Creates or edits the channel

curl -X POST https://app.getera.io/api/v1/sales_channels/SALES_CHANNEL_ID/actions/save_channel \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.channel_saved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.salesChannels.saveChannel("SALES_CHANNEL_ID", {
  name: "Name"
})
era sales_channels save_channel SALES_CHANNEL_ID \
  --name "Name"
tools/call
{
  "name": "era__retail__save_channel",
  "arguments": {
    "id": "SALES_CHANNEL_ID",
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_name, slug_taken, invalid_currency, channel_not_found, channel_currency_locked · 429 slow down

retail.save_collection

Save a collection — A hand-ordered merchandising list — “Summer”, “Staff picks”.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/collections/{id}/actions/save_collection
API key or OAuth token · retail:write
  • REST alias: PATCH /api/v1/collections/{id}
  • Canonical address: POST /api/v1/actions/retail.save_collection

Input

FieldTypeRequiredNotes
iduuidFilled from the path {id} · Collection · id of item_collection
namestringyesName · max 250
slugstringAddress · max 255
descriptionstringDescription · max 4000
seoTitlestringSEO title · max 200
seoDescriptionstringSEO description · max 500
backgroundFileIduuidBanner image · id of file
backgroundAltstringBanner description · max 250

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_nameThe name must produce a usable address.
slug_takenThe address must be free in this workspace.
not_foundThe collection must exist when one is named.

Events it publishes: retail.collection_saved

What it writes: item_collection (upsert) — Creates or edits the collection

curl -X POST https://app.getera.io/api/v1/collections/COLLECTION_ID/actions/save_collection \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.collection_saved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.collections.saveCollection("COLLECTION_ID", {
  name: "Name"
})
era collections save_collection COLLECTION_ID \
  --name "Name"
tools/call
{
  "name": "era__retail__save_collection",
  "arguments": {
    "id": "COLLECTION_ID",
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_name, slug_taken, not_found · 429 slow down

retail.save_shipping_method

Save a delivery rate — A way of delivering, priced by order value or by weight.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/shipping_methods/{id}/actions/save_shipping_method
API key or OAuth token · retail:manage
  • REST alias: PATCH /api/v1/shipping_methods/{id}
  • Canonical address: POST /api/v1/actions/retail.save_shipping_method

Input

FieldTypeRequiredNotes
iduuidFilled from the path {id} · Rate · id of shipping_method
shippingZoneIduuidyesZone · id of shipping_zone
namestringyesName · max 100
typestring (enum)Priced by · Allowed values: price, weight
descriptionstringDescription · max 2000
minimumOrderWeightGramsnumberFrom (grams) · min 0
maximumOrderWeightGramsnumberTo (grams) · min 0
minimumDeliveryDaysnumberFastest (days) · min 0
maximumDeliveryDaysnumberSlowest (days) · min 0
taxClassIduuidTax class · Empty: the country’s default rate. · id of tax_class

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
zone_not_foundThe zone must exist.
tax_class_not_foundThe tax class must exist and not be archived.
not_foundThe rate must exist when one is named.
weight_on_price_methodA price-based rate carries no weight band.
range_invertedThe smaller end of a range must not exceed the larger.

Events it publishes: retail.shipping_method_saved

What it writes: shipping_method (upsert) — Creates or edits the rate

curl -X POST https://app.getera.io/api/v1/shipping_methods/SHIPPING_METHOD_ID/actions/save_shipping_method \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"shippingZoneId":"SHIPPING_ZONE_ID","name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.shipping_method_saved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.shippingMethods.saveShippingMethod("SHIPPING_METHOD_ID", {
  shippingZoneId: "SHIPPING_ZONE_ID",
  name: "Name"
})
era shipping_methods save_shipping_method SHIPPING_METHOD_ID \
  --shipping-zone-id "SHIPPING_ZONE_ID" \
  --name "Name"
tools/call
{
  "name": "era__retail__save_shipping_method",
  "arguments": {
    "id": "SHIPPING_METHOD_ID",
    "shippingZoneId": "SHIPPING_ZONE_ID",
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 zone_not_found, tax_class_not_found, not_found, weight_on_price_method, range_inverted · 429 slow down

retail.save_shipping_zone

Save a shipping zone — A group of countries that share delivery rates.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/shipping_zones/{id}/actions/save_shipping_zone
API key or OAuth token · retail:manage
  • REST alias: PATCH /api/v1/shipping_zones/{id}
  • Canonical address: POST /api/v1/actions/retail.save_shipping_zone

Input

FieldTypeRequiredNotes
iduuidFilled from the path {id} · Zone · id of shipping_zone
namestringyesName · max 100
descriptionstringDescription · max 2000
countriesobject / arrayCountries
isDefaultbooleanEverywhere else
channelIdsobject / arrayChannels

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_countryEvery country must be a two-letter code.
not_foundThe zone must exist when one is named.
channel_not_foundEvery channel must exist.

Events it publishes: retail.shipping_zone_saved

What it writes: shipping_zone (upsert) — Creates or edits the zone

curl -X POST https://app.getera.io/api/v1/shipping_zones/SHIPPING_ZONE_ID/actions/save_shipping_zone \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.shipping_zone_saved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.shippingZones.saveShippingZone("SHIPPING_ZONE_ID", {
  name: "Name"
})
era shipping_zones save_shipping_zone SHIPPING_ZONE_ID \
  --name "Name"
tools/call
{
  "name": "era__retail__save_shipping_zone",
  "arguments": {
    "id": "SHIPPING_ZONE_ID",
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_country, not_found, channel_not_found · 429 slow down

retail.set_channel_active

Open or close a channel — A closed channel takes no baskets and no orders.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/sales_channels/{id}/actions/set_channel_active
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.set_channel_active

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Channel · id of channel
isActivebooleanyesOpen

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
channel_not_foundThe channel must exist.
channel_has_open_workA channel with open baskets or orders cannot be closed.

Events it publishes: retail.channel_saved

What it writes: channel (update) — Opens or closes the channel

curl -X POST https://app.getera.io/api/v1/sales_channels/SALES_CHANNEL_ID/actions/set_channel_active \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"isActive":true}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.channel_saved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.salesChannels.setChannelActive("SALES_CHANNEL_ID", {
  isActive: true
})
era sales_channels set_channel_active SALES_CHANNEL_ID \
  --is-active true
tools/call
{
  "name": "era__retail__set_channel_active",
  "arguments": {
    "id": "SALES_CHANNEL_ID",
    "isActive": true
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 channel_not_found, channel_has_open_work · 429 slow down

retail.set_channel_warehouses

Choose a channel’s warehouses — Which warehouses a channel draws stock from, in the order stock is taken.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/sales_channel_warehouses/actions/set_channel_warehouses
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.set_channel_warehouses

Input

FieldTypeRequiredNotes
channelIduuidyesChannel · id of channel
warehouseIdsobject / arrayyesWarehouses

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
channel_not_foundThe channel must exist.
warehouse_not_foundEvery warehouse must exist.

Events it publishes: retail.channel_warehouses_changed

What it writes: channel_warehouse (upsert) — Replaces the channel’s warehouse order

curl -X POST https://app.getera.io/api/v1/sales_channel_warehouses/actions/set_channel_warehouses \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"channelId":"CHANNEL_ID","warehouseIds":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.channel_warehouses_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.salesChannelWarehouses.setChannelWarehouses({
  channelId: "CHANNEL_ID",
  warehouseIds: {}
})
era sales_channel_warehouses set_channel_warehouses --data '{"channelId":"CHANNEL_ID","warehouseIds":{}}'
tools/call
{
  "name": "era__retail__set_channel_warehouses",
  "arguments": {
    "channelId": "CHANNEL_ID",
    "warehouseIds": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 channel_not_found, warehouse_not_found · 429 slow down

retail.set_checkout_delivery

Choose delivery — The address, the rate and, where offered, the collection point.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/checkouts/actions/set_checkout_delivery
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.set_checkout_delivery

Input

FieldTypeRequiredNotes
tokenuuidyesBasket
shippingAddressIduuidDelivery address · id of address
billingAddressIduuidBilling address · id of address
shippingMethodIduuidDelivery rate · id of shipping_method
collectionPointIduuidCollect from · id of warehouse

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe basket must exist.
shipping_method_not_availableThe rate must serve this address at this order value.
collection_point_unavailableThat location must offer collection.

Events it publishes: retail.checkout_updated

What it writes: checkout (update) — Writes the delivery choice

curl -X POST https://app.getera.io/api/v1/checkouts/actions/set_checkout_delivery \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"token":"TOKEN_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.checkout_updated"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.checkouts.setCheckoutDelivery({
  token: "TOKEN_ID"
})
era checkouts set_checkout_delivery \
  --token "TOKEN_ID"
tools/call
{
  "name": "era__retail__set_checkout_delivery",
  "arguments": {
    "token": "TOKEN_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, shipping_method_not_available, collection_point_unavailable · 429 slow down

retail.set_checkout_lines

Change a basket — Add, change or remove lines. A quantity of zero removes the line.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/checkout_lines/actions/set_checkout_lines
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.set_checkout_lines

Input

FieldTypeRequiredNotes
tokenuuidyesBasket
linesobject / arrayyesLines

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe basket must exist.
checkout_completingA basket being turned into an order cannot be edited.
malformed_linesEvery line needs a variant and a quantity.
variant_not_pricedA variant with no price in this channel cannot be sold here.
variant_not_foundEvery variant must exist.
reservation_stock_unavailableEvery tracked line must be reservable for fifteen minutes.
gift_line_lockedA promotion’s gift line cannot be edited by hand.

Events it publishes: retail.checkout_updated

What it writes: checkout_line (upsert) — Writes the basket lines; stock_reservation (upsert) — Replaces the basket stock hold

curl -X POST https://app.getera.io/api/v1/checkout_lines/actions/set_checkout_lines \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"token":"TOKEN_ID","lines":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.checkout_updated"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.checkoutLines.setCheckoutLines({
  token: "TOKEN_ID",
  lines: {}
})
era checkout_lines set_checkout_lines --data '{"token":"TOKEN_ID","lines":{}}'
tools/call
{
  "name": "era__retail__set_checkout_lines",
  "arguments": {
    "token": "TOKEN_ID",
    "lines": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, checkout_completing, malformed_lines, variant_not_priced, variant_not_found, reservation_stock_unavailable, gift_line_locked · 429 slow down

retail.set_collection_items

Choose what a collection holds — The whole membership, in the order the storefront draws it.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/collection_items/actions/set_collection_items
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.set_collection_items

Input

FieldTypeRequiredNotes
iduuidyesCollection · id of item_collection
itemIdsobject / arrayyesItems

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe collection must exist.
item_not_foundEvery catalogue entry must exist.
collection_is_smartA rule collection is not picked by hand.

Events it publishes: retail.collection_items_changed

What it writes: item_collection_item (upsert) — Replaces the membership

curl -X POST https://app.getera.io/api/v1/collection_items/actions/set_collection_items \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"id":"ITEM_COLLECTION_ID","itemIds":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.collection_items_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.collectionItems.setCollectionItems({
  id: "ITEM_COLLECTION_ID",
  itemIds: {}
})
era collection_items set_collection_items --data '{"id":"ITEM_COLLECTION_ID","itemIds":{}}'
tools/call
{
  "name": "era__retail__set_collection_items",
  "arguments": {
    "id": "ITEM_COLLECTION_ID",
    "itemIds": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, item_not_found, collection_is_smart · 429 slow down

retail.set_collection_rule

Fill a collection from a rule — A smart collection: its members are whatever matches — a category, a brand, a price range, a name.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/collections/{id}/actions/set_collection_rule
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.set_collection_rule

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Collection · id of item_collection
ruleobject / arrayRule

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe collection must exist.
invalid_ruleA rule has at least one condition and a sane price range.

Events it publishes: retail.collection_items_changed

What it writes: item_collection (update) — Writes the rule; item_collection_item (upsert) — Replaces the membership

curl -X POST https://app.getera.io/api/v1/collections/COLLECTION_ID/actions/set_collection_rule \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"rule":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.collection_items_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.collections.setCollectionRule("COLLECTION_ID", {
  rule: {}
})
era collections set_collection_rule COLLECTION_ID --data '{"rule":{}}'
tools/call
{
  "name": "era__retail__set_collection_rule",
  "arguments": {
    "id": "COLLECTION_ID",
    "rule": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, invalid_rule · 429 slow down

retail.set_item_listing

List something in a channel — Whether a catalogue entry is published, visible and on sale in one channel.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/product_listings/actions/set_item_listing
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.set_item_listing

Input

FieldTypeRequiredNotes
itemIduuidyesItem · id of item
channelIduuidChannel · Empty = the shop. · id of channel
isPublishedbooleanPublished
visibleInListingsbooleanShow in listings
availableForPurchaseAtdate-timeOn sale from

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
channel_not_foundThe channel must exist.
item_not_foundThe catalogue entry must exist.
store_missingWith no channel given, the workspace must have an open shop (retail.open_shop).

Events it publishes: retail.listing_changed

What it writes: item_channel_listing (upsert) — Writes the channel listing

curl -X POST https://app.getera.io/api/v1/product_listings/actions/set_item_listing \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"itemId":"ITEM_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.listing_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.productListings.setItemListing({
  itemId: "ITEM_ID"
})
era product_listings set_item_listing \
  --item-id "ITEM_ID"
tools/call
{
  "name": "era__retail__set_item_listing",
  "arguments": {
    "itemId": "ITEM_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 channel_not_found, item_not_found, store_missing · 429 slow down

retail.set_order_discount

Give a staff discount — Saleor’s orderDiscountAdd/Update: one percentage or amount off a draft or unconfirmed order, with a reason. The order-level coupon and order promotions step aside while it is on.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/orders/{id}/actions/set_order_discount
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.set_order_discount

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order
valueTypestring (enum)yesOff by · Allowed values: percentage, fixed
valuenumberyesValue (percent, or minor units) · min 0
reasonstringReason · max 500

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
order_not_editableOnly a draft or unconfirmed order is discounted.
invalid_discount_valueAbove zero; a percentage at most 100, an amount at most the undiscounted total.

Events it publishes: retail.order_discounts_applied

What it writes: sales_order (update) — Writes the discount and the new totals; sales_order_line (update) — Spreads the discount over the lines; sales_order_discount (insert) — Records what was applied

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/set_order_discount \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"valueType":"percentage","value":1}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_discounts_applied"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.setOrderDiscount("ORDER_ID", {
  valueType: "percentage",
  value: 1
})
era orders set_order_discount ORDER_ID \
  --value-type "percentage" \
  --value 1
tools/call
{
  "name": "era__retail__set_order_discount",
  "arguments": {
    "id": "ORDER_ID",
    "valueType": "percentage",
    "value": 1
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, order_not_editable, invalid_discount_value · 429 slow down

retail.set_order_lines

Change an order’s lines — Only while it is a draft or unconfirmed — the source’s ORDER_EDITABLE_STATUS.

Needs retail:write · removes or cannot be undone

POSThttps://app.getera.io/api/v1/orders/{id}/actions/set_order_lines
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.set_order_lines

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order
linesobject / arrayyesLines

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
order_not_editableOnly drafts and unconfirmed orders may change lines.
malformed_linesEvery line needs a variant and a quantity.
variant_not_foundEvery variant must exist.
variant_not_pricedA variant with no price needs one typed.

Events it publishes: retail.order_lines_changed, retail.order_discounts_applied

What it writes: sales_order_line (upsert) — Replaces the lines, with promotions and the coupon applied; allocation (delete) — Releases what the old lines held; sales_order (update) — Recomputes the totals; sales_order_discount (insert) — Records what was applied

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/set_order_lines \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"lines":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_lines_changed",
    "retail.order_discounts_applied"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.setOrderLines("ORDER_ID", {
  lines: {}
})
era orders set_order_lines ORDER_ID --data '{"lines":{}}'
tools/call
{
  "name": "era__retail__set_order_lines",
  "arguments": {
    "id": "ORDER_ID",
    "lines": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, order_not_editable, malformed_lines, variant_not_found, variant_not_priced · 429 slow down

retail.set_order_voucher

Apply a coupon — Puts a voucher code on a draft or unconfirmed order, or takes it off. Order promotions step aside for a coupon.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/orders/{id}/actions/set_order_voucher
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.set_order_voucher

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order
codestringCoupon code · max 255

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
order_not_editableOnly a draft or unconfirmed order changes its coupon.
voucher_not_foundThe code must name a voucher.
voucher_not_applicableThe voucher must be running, priced in the channel and its conditions met.
voucher_usage_exceededThe code must not be used up.

Events it publishes: retail.order_discounts_applied

What it writes: sales_order (update) — Writes the code and the new totals; sales_order_line (update) — Writes the per-line discount snapshot; sales_order_discount (insert) — Records what was applied

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/set_order_voucher \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"code":"Coupon code"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_discounts_applied"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.setOrderVoucher("ORDER_ID", {
  code: "Coupon code"
})
era orders set_order_voucher ORDER_ID \
  --code "Coupon code"
tools/call
{
  "name": "era__retail__set_order_voucher",
  "arguments": {
    "id": "ORDER_ID",
    "code": "Coupon code"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, order_not_editable, voucher_not_found, voucher_not_applicable, voucher_usage_exceeded · 429 slow down

retail.set_postal_code_rules

Set postal-code rules — Absence is permission; adding a rule restricts where a rate applies.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/shipping_method_postal_code_rules/actions/set_postal_code_rules
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.set_postal_code_rules

Input

FieldTypeRequiredNotes
shippingMethodIduuidyesRate · id of shipping_method
rulesobject / arrayyesRules

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe rate must exist.
malformed_rulesEvery rule needs a starting code.
duplicate_ruleThe same range may not appear twice.

Events it publishes: retail.shipping_rules_changed

What it writes: shipping_method_postal_code_rule (upsert) — Replaces the rate’s postal-code rules

curl -X POST https://app.getera.io/api/v1/shipping_method_postal_code_rules/actions/set_postal_code_rules \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"shippingMethodId":"SHIPPING_METHOD_ID","rules":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.shipping_rules_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.shippingMethodPostalCodeRules.setPostalCodeRules({
  shippingMethodId: "SHIPPING_METHOD_ID",
  rules: {}
})
era shipping_method_postal_code_rules set_postal_code_rules --data '{"shippingMethodId":"SHIPPING_METHOD_ID","rules":{}}'
tools/call
{
  "name": "era__retail__set_postal_code_rules",
  "arguments": {
    "shippingMethodId": "SHIPPING_METHOD_ID",
    "rules": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, malformed_rules, duplicate_rule · 429 slow down

retail.set_preorder

Sell on preorder — Take orders before the goods are on a shelf, up to a limit per channel and overall.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/variant_preorders/actions/set_preorder
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.set_preorder

Input

FieldTypeRequiredNotes
itemVariantIduuidyesVariant · id of item_variant
enabledbooleanyesOn preorder
endDatedate-timeEnds
globalThresholdnumberLimit, all channels · min 0
channelThresholdsobject / arrayLimits per channel

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
variant_not_foundThe variant must exist.
invalid_preorderA preorder ends in the future.
preorder_has_ordersOrders holding preorders are moved by ending it, not by switching it off.
channel_not_foundEvery channel must exist.

Events it publishes: retail.preorder_changed

What it writes: variant_preorder (upsert) — Writes the preorder; item_variant_channel_listing (upsert) — Writes the per-channel limit

curl -X POST https://app.getera.io/api/v1/variant_preorders/actions/set_preorder \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"itemVariantId":"ITEM_VARIANT_ID","enabled":true}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.preorder_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.variantPreorders.setPreorder({
  itemVariantId: "ITEM_VARIANT_ID",
  enabled: true
})
era variant_preorders set_preorder \
  --item-variant-id "ITEM_VARIANT_ID" \
  --enabled true
tools/call
{
  "name": "era__retail__set_preorder",
  "arguments": {
    "itemVariantId": "ITEM_VARIANT_ID",
    "enabled": true
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 variant_not_found, invalid_preorder, preorder_has_orders, channel_not_found · 429 slow down

retail.set_shipping_excluded_items

Exclude products from a delivery rate — Saleor’s excluded products: an order holding any of them is not offered the rate.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/shipping_method_excluded_items/actions/set_shipping_excluded_items
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.set_shipping_excluded_items

Input

FieldTypeRequiredNotes
shippingMethodIduuidyesRate · id of shipping_method
itemIdsobject / arrayyesProducts

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe rate must exist.
item_not_foundEvery product must exist.

Events it publishes: retail.shipping_exclusions_changed

What it writes: shipping_method_excluded_item (upsert) — Replaces the rate’s exclusions

curl -X POST https://app.getera.io/api/v1/shipping_method_excluded_items/actions/set_shipping_excluded_items \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"shippingMethodId":"SHIPPING_METHOD_ID","itemIds":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.shipping_exclusions_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.shippingMethodExcludedItems.setShippingExcludedItems({
  shippingMethodId: "SHIPPING_METHOD_ID",
  itemIds: {}
})
era shipping_method_excluded_items set_shipping_excluded_items --data '{"shippingMethodId":"SHIPPING_METHOD_ID","itemIds":{}}'
tools/call
{
  "name": "era__retail__set_shipping_excluded_items",
  "arguments": {
    "shippingMethodId": "SHIPPING_METHOD_ID",
    "itemIds": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, item_not_found · 429 slow down

retail.set_shipping_price

Price a delivery rate in a channel — What delivery costs, and between which order values it applies.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/shipping_method_channel_listings/actions/set_shipping_price
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.set_shipping_price

Input

FieldTypeRequiredNotes
shippingMethodIduuidyesRate · id of shipping_method
channelIduuidyesChannel · id of channel
priceAmountnumber (money)yesPrice (minor units) · min 0
minimumOrderPriceAmountnumber (money)From order value · min 0
maximumOrderPriceAmountnumber (money)To order value · min 0

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
channel_not_foundThe channel must exist.
not_foundThe rate must exist.
range_invertedThe smallest order value must not exceed the largest.

Events it publishes: retail.shipping_price_changed

What it writes: shipping_method_channel_listing (upsert) — Writes the channel price

curl -X POST https://app.getera.io/api/v1/shipping_method_channel_listings/actions/set_shipping_price \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"shippingMethodId":"SHIPPING_METHOD_ID","channelId":"CHANNEL_ID","priceAmount":1}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.shipping_price_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.shippingMethodChannelListings.setShippingPrice({
  shippingMethodId: "SHIPPING_METHOD_ID",
  channelId: "CHANNEL_ID",
  priceAmount: 1
})
era shipping_method_channel_listings set_shipping_price \
  --shipping-method-id "SHIPPING_METHOD_ID" \
  --channel-id "CHANNEL_ID" \
  --price-amount 1
tools/call
{
  "name": "era__retail__set_shipping_price",
  "arguments": {
    "shippingMethodId": "SHIPPING_METHOD_ID",
    "channelId": "CHANNEL_ID",
    "priceAmount": 1
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 channel_not_found, not_found, range_inverted · 429 slow down

retail.set_stock

Count stock — The number on a shelf, in one warehouse, for one variant.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/stocks/actions/set_stock
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.set_stock

Input

FieldTypeRequiredNotes
warehouseIduuidyesWarehouse · id of warehouse
itemVariantIduuidyesVariant · id of item_variant
quantitynumberyesQuantity
notestringNote · max 500

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
warehouse_not_foundThe warehouse must exist.
variant_not_foundThe variant must exist.
below_allocatedThe count may not drop below what is already promised.

Events it publishes: retail.stock_changed, retail.stock_low

What it writes: stock (upsert) — Writes the count; stock_movement (insert) — Records the stocktake difference in the ledger

curl -X POST https://app.getera.io/api/v1/stocks/actions/set_stock \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"warehouseId":"WAREHOUSE_ID","itemVariantId":"ITEM_VARIANT_ID","quantity":1}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.stock_changed",
    "retail.stock_low"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.stocks.setStock({
  warehouseId: "WAREHOUSE_ID",
  itemVariantId: "ITEM_VARIANT_ID",
  quantity: 1
})
era stocks set_stock \
  --warehouse-id "WAREHOUSE_ID" \
  --item-variant-id "ITEM_VARIANT_ID" \
  --quantity 1
tools/call
{
  "name": "era__retail__set_stock",
  "arguments": {
    "warehouseId": "WAREHOUSE_ID",
    "itemVariantId": "ITEM_VARIANT_ID",
    "quantity": 1
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 warehouse_not_found, variant_not_found, below_allocated · 429 slow down

retail.set_stock_policy

Hold back safety stock — How many on this shelf are never promised to an order.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/stocks/actions/set_stock_policy
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.set_stock_policy

Input

FieldTypeRequiredNotes
warehouseIduuidyesWarehouse · id of warehouse
itemVariantIduuidyesVariant · id of item_variant
safetyStocknumberyesSafety stock · min 0

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
stock_not_foundThe warehouse must keep the variant.

Events it publishes: retail.stock_policy_changed, retail.stock_low

What it writes: stock (update) — Writes the safety stock

curl -X POST https://app.getera.io/api/v1/stocks/actions/set_stock_policy \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"warehouseId":"WAREHOUSE_ID","itemVariantId":"ITEM_VARIANT_ID","safetyStock":1}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.stock_policy_changed",
    "retail.stock_low"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.stocks.setStockPolicy({
  warehouseId: "WAREHOUSE_ID",
  itemVariantId: "ITEM_VARIANT_ID",
  safetyStock: 1
})
era stocks set_stock_policy \
  --warehouse-id "WAREHOUSE_ID" \
  --item-variant-id "ITEM_VARIANT_ID" \
  --safety-stock 1
tools/call
{
  "name": "era__retail__set_stock_policy",
  "arguments": {
    "warehouseId": "WAREHOUSE_ID",
    "itemVariantId": "ITEM_VARIANT_ID",
    "safetyStock": 1
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 stock_not_found · 429 slow down

retail.set_tracking

Set a tracking number — What the customer follows the parcel with.

Needs retail:handle · changes data

POSThttps://app.getera.io/api/v1/fulfilments/{id}/actions/set_tracking
API key or OAuth token · retail:handle
  • Canonical address: POST /api/v1/actions/retail.set_tracking

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Despatch · id of fulfilment
trackingNumberstringyesTracking number · max 255
carrierstringCarrier · max 120
trackingUrlstringTracking link · max 1000
notifyCustomerbooleanTell the customer

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe despatch must exist.

Events it publishes: retail.fulfilment_tracking_updated, retail.customer_notification_requested

What it writes: fulfilment (update) — Writes the carrier, tracking number and link

curl -X POST https://app.getera.io/api/v1/fulfilments/FULFILMENT_ID/actions/set_tracking \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"trackingNumber":"Tracking number"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.fulfilment_tracking_updated",
    "retail.customer_notification_requested"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.fulfilments.setTracking("FULFILMENT_ID", {
  trackingNumber: "Tracking number"
})
era fulfilments set_tracking FULFILMENT_ID \
  --tracking-number "Tracking number"
tools/call
{
  "name": "era__retail__set_tracking",
  "arguments": {
    "id": "FULFILMENT_ID",
    "trackingNumber": "Tracking number"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

retail.set_variant_price

Price a variant in a channel — The channel override. Without one, the catalogue list price applies.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/variant_listings/actions/set_variant_price
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.set_variant_price

Input

FieldTypeRequiredNotes
itemVariantIduuidyesVariant · id of item_variant
channelIduuidyesChannel · id of channel
priceAmountnumber (money)Price (minor units) · min 0
costPriceAmountnumber (money)Cost (minor units) · min 0
priorPriceAmountnumber (money)Was (minor units) · min 0

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
channel_not_foundThe channel must exist.
variant_not_foundThe variant must exist.

Events it publishes: retail.channel_price_changed

What it writes: item_variant_channel_listing (upsert) — Writes the price override

curl -X POST https://app.getera.io/api/v1/variant_listings/actions/set_variant_price \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"itemVariantId":"ITEM_VARIANT_ID","channelId":"CHANNEL_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.channel_price_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.variantListings.setVariantPrice({
  itemVariantId: "ITEM_VARIANT_ID",
  channelId: "CHANNEL_ID"
})
era variant_listings set_variant_price \
  --item-variant-id "ITEM_VARIANT_ID" \
  --channel-id "CHANNEL_ID"
tools/call
{
  "name": "era__retail__set_variant_price",
  "arguments": {
    "itemVariantId": "ITEM_VARIANT_ID",
    "channelId": "CHANNEL_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 channel_not_found, variant_not_found · 429 slow down

retail.set_warehouse_zones

Choose which zones a warehouse serves — A warehouse only ships to the countries its zones cover.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/warehouse_shipping_zones/actions/set_warehouse_zones
API key or OAuth token · retail:manage
  • Canonical address: POST /api/v1/actions/retail.set_warehouse_zones

Input

FieldTypeRequiredNotes
warehouseIduuidyesWarehouse · id of warehouse
shippingZoneIdsobject / arrayyesShipping zones

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe warehouse must exist.
zone_not_foundEvery shipping zone must exist.

Events it publishes: retail.warehouse_zones_changed

What it writes: warehouse_shipping_zone (upsert) — Replaces the zone assignment

curl -X POST https://app.getera.io/api/v1/warehouse_shipping_zones/actions/set_warehouse_zones \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"warehouseId":"WAREHOUSE_ID","shippingZoneIds":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.warehouse_zones_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.warehouseShippingZones.setWarehouseZones({
  warehouseId: "WAREHOUSE_ID",
  shippingZoneIds: {}
})
era warehouse_shipping_zones set_warehouse_zones --data '{"warehouseId":"WAREHOUSE_ID","shippingZoneIds":{}}'
tools/call
{
  "name": "era__retail__set_warehouse_zones",
  "arguments": {
    "warehouseId": "WAREHOUSE_ID",
    "shippingZoneIds": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, zone_not_found · 429 slow down

retail.site_cart_add

Add to basket (site) — A visitor puts a product in their basket; the basket opens in the site’s channel if they have none.

Needs retail:write · changes data · Also callable from a published site (visitor)

A website action: your site calls it through the site API (/api/site/v1/{siteId}, e.g. with @getera/storefront). With an API key or a token it is refused (403 site_only).
POSThttps://app.getera.io/api/v1/checkouts/actions/site_cart_add
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.site_cart_add

Input

FieldTypeRequiredNotes
tokenuuidBasket
itemVariantIduuidyesVariant · id of item_variant
quantitynumberQuantity

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
shop_closedThe site’s workspace has an open sales channel.
not_for_saleOnly a public product listed in the site’s channel can be bought.
bad_quantityA quantity is a whole number from 0 to 99.

Events it publishes: retail.checkout_created, retail.checkout_updated

What it writes: checkout (insert) — Opens the basket when there is none; checkout_line (upsert) — Adds the quantity to the line; stock_reservation (upsert) — Holds tracked stock for fifteen minutes

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 shop_closed, not_for_sale, bad_quantity · 429 slow down

retail.site_cart_claim

Keep my basket after signing in — The guest basket becomes the signed-in customer’s, with the lines of any basket they left before.

Needs retail:write · removes or cannot be undone · Also callable from a published site (customer)

A website action: your site calls it through the site API (/api/site/v1/{siteId}, e.g. with @getera/storefront). With an API key or a token it is refused (403 site_only).
POSThttps://app.getera.io/api/v1/checkout_lines/actions/site_cart_claim
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.site_cart_claim

Input

FieldTypeRequiredNotes
tokenuuidyesBasket

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
basket_not_foundThe basket must exist and not be someone else’s.

Events it publishes: retail.checkout_updated

What it writes: checkout (update) — Puts the customer on the basket; checkout_line (upsert) — Folds in the older basket’s lines; checkout (delete) — Removes the older basket

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 basket_not_found · 429 slow down

retail.site_cart_set

Change a basket line (site) — A visitor changes the quantity of a line in their basket; 0 removes it.

Needs retail:write · changes data · Also callable from a published site (visitor)

A website action: your site calls it through the site API (/api/site/v1/{siteId}, e.g. with @getera/storefront). With an API key or a token it is refused (403 site_only).
POSThttps://app.getera.io/api/v1/checkout_lines/actions/site_cart_set
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.site_cart_set

Input

FieldTypeRequiredNotes
tokenuuidyesBasket
itemVariantIduuidyesVariant · id of item_variant
quantitynumberyesQuantity

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
basket_not_foundThe basket must exist and be the caller’s.
checkout_completingA basket being turned into an order does not change.
bad_quantityA quantity is a whole number from 0 to 99.
not_for_saleOnly a public product listed in the site’s channel can be bought.

Events it publishes: retail.checkout_updated

What it writes: checkout_line (upsert) — Sets or removes the line; stock_reservation (upsert) — Re-holds the basket’s stock

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 basket_not_found, checkout_completing, bad_quantity, not_for_sale · 429 slow down

retail.site_checkout_delivery

Choose delivery (site) — A site basket picks a delivery rate that serves its address, or a pickup point of the channel.

Needs retail:write · changes data · Also callable from a published site (visitor)

A website action: your site calls it through the site API (/api/site/v1/{siteId}, e.g. with @getera/storefront). With an API key or a token it is refused (403 site_only).
POSThttps://app.getera.io/api/v1/checkouts/actions/site_checkout_delivery
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.site_checkout_delivery

Input

FieldTypeRequiredNotes
tokenuuidyesBasket
shippingMethodIduuidDelivery rate · id of shipping_method
pickupPointIduuidCollect from · id of warehouse

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
basket_not_foundThe basket must exist and be the caller’s.
checkout_completingA basket being turned into an order does not change.
delivery_missingA rate or a pickup point is chosen.
collection_point_unavailableThe pickup point collects for the site’s channel.

Events it publishes: retail.checkout_updated

What it writes: checkout (update) — Writes the delivery and its charge

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 basket_not_found, checkout_completing, delivery_missing, collection_point_unavailable · 429 slow down

retail.site_checkout_details

Give checkout details (site) — The email, the customer and the delivery address of a site basket; answers the delivery rates and pickup points that apply.

Needs retail:write · changes data · Also callable from a published site (visitor)

A website action: your site calls it through the site API (/api/site/v1/{siteId}, e.g. with @getera/storefront). With an API key or a token it is refused (403 site_only).
POSThttps://app.getera.io/api/v1/checkouts/actions/site_checkout_details
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.site_checkout_details

Input

FieldTypeRequiredNotes
tokenuuidyesBasket
emailstringyesEmail · max 320
customerIduuidyesCustomer · id of customer
addressIduuidDelivery address · id of address
notestringNote · max 1000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
basket_not_foundThe basket must exist and be the caller’s.
checkout_completingA basket being turned into an order does not change.
invalid_emailThe email must be usable.
customer_mismatchA guest is the record of the email they typed; a customer is themself.
address_not_foundThe address is the snapshot the checkout just wrote.

Events it publishes: retail.checkout_updated

What it writes: checkout (update) — Writes the email, the customer and the address

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 basket_not_found, checkout_completing, invalid_email, customer_mismatch, address_not_found · 429 slow down

retail.site_checkout_voucher

Use a coupon (site) — A site basket takes a coupon code — judged by the discounts rules on its lines — or drops it; the basket shows what comes off and the order carries it.

Needs retail:write · changes data · Also callable from a published site (visitor)

A website action: your site calls it through the site API (/api/site/v1/{siteId}, e.g. with @getera/storefront). With an API key or a token it is refused (403 site_only).
POSThttps://app.getera.io/api/v1/checkouts/actions/site_checkout_voucher
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.site_checkout_voucher

Input

FieldTypeRequiredNotes
tokenuuidyesBasket
codestringCoupon code · max 255

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
basket_not_foundThe basket must exist and be the caller’s.
checkout_completingA basket being turned into an order does not change.
voucher_not_foundThe code must name a voucher.
voucher_not_applicableThe voucher must be running, priced in the channel and its conditions met by the basket.
voucher_usage_exceededThe code must not be used up.

Events it publishes: retail.checkout_updated

What it writes: checkout (update) — Writes the code, the discount and the new total

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 basket_not_found, checkout_completing, voucher_not_found, voucher_not_applicable, voucher_usage_exceeded · 429 slow down

retail.site_place_order

Place an order (site) — A site basket becomes an order awaiting payment by the chosen method; stock is allocated and the confirmation email is asked for.

Needs retail:write · removes or cannot be undone · Also callable from a published site (visitor)

A website action: your site calls it through the site API (/api/site/v1/{siteId}, e.g. with @getera/storefront). With an API key or a token it is refused (403 site_only).
POSThttps://app.getera.io/api/v1/orders/actions/site_place_order
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.site_place_order

Input

FieldTypeRequiredNotes
tokenuuidyesBasket
paymentMethodstringPayment method · Empty when a gift card on the basket pays it all. · max 40

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
basket_not_foundThe basket must exist and be the caller’s.
checkout_completingA basket is turned into an order once.
payment_method_unavailableThe method is a connected payment app, or the test method outside production.
details_missingThe basket has an email and a customer.
voucher_usage_exceededA coupon on the basket must still be usable when the order is placed.

Events it publishes: retail.order_placed, retail.customer_notification_requested, retail.stock_low, retail.order_discounts_applied

What it writes: sales_order (insert) — The order; sales_order_line (insert) — Its lines, frozen; allocation (insert) — The stock it holds; checkout (delete) — The basket is gone

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 basket_not_found, checkout_completing, payment_method_unavailable, details_missing, voucher_usage_exceeded · 429 slow down

retail.sync_charge_status

Update what an order has been paid — Machine-only (finance-reactions.ts): money moved on the order, so its payment status follows.

Needs retail:write · changes data

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/orders/{id}/actions/sync_charge_status
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.sync_charge_status

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.

Events it publishes: retail.order_charge_status_changed

What it writes: sales_order (update) — Writes the payment status and the total charged

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

retail.transfer_stock

Move stock between warehouses — Two ledger rows, one move. What orders are holding stays where it is.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/stocks/actions/transfer_stock
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.transfer_stock

Input

FieldTypeRequiredNotes
fromWarehouseIduuidyesFrom · id of warehouse
toWarehouseIduuidyesTo · id of warehouse
itemVariantIduuidyesVariant · id of item_variant
quantitynumberyesQuantity · min 1
notestringNote · max 500

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
no_changeA transfer moves at least one.
same_warehouseThe two warehouses must differ.
warehouse_not_foundBoth warehouses must exist.
variant_not_foundThe variant must exist.
insufficient_stockThe source must have that many free.

Events it publishes: retail.stock_transferred, retail.stock_low

What it writes: stock (upsert) — Moves the count; stock_movement (insert) — Writes both sides of the move

curl -X POST https://app.getera.io/api/v1/stocks/actions/transfer_stock \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"fromWarehouseId":"WAREHOUSE_ID","toWarehouseId":"WAREHOUSE_ID","itemVariantId":"ITEM_VARIANT_ID","quantity":1}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.stock_transferred",
    "retail.stock_low"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.stocks.transferStock({
  fromWarehouseId: "WAREHOUSE_ID",
  toWarehouseId: "WAREHOUSE_ID",
  itemVariantId: "ITEM_VARIANT_ID",
  quantity: 1
})
era stocks transfer_stock \
  --from-warehouse-id "WAREHOUSE_ID" \
  --to-warehouse-id "WAREHOUSE_ID" \
  --item-variant-id "ITEM_VARIANT_ID" \
  --quantity 1
tools/call
{
  "name": "era__retail__transfer_stock",
  "arguments": {
    "fromWarehouseId": "WAREHOUSE_ID",
    "toWarehouseId": "WAREHOUSE_ID",
    "itemVariantId": "ITEM_VARIANT_ID",
    "quantity": 1
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 no_change, same_warehouse, warehouse_not_found, variant_not_found, insufficient_stock · 429 slow down

retail.update_order

Edit an order — Its note, email, addresses and — while still editable — its delivery rate.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/orders/{id}/actions/update_order
API key or OAuth token · retail:write
  • REST alias: PATCH /api/v1/orders/{id}
  • Canonical address: POST /api/v1/actions/retail.update_order

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order
customerIduuidCustomer · id of customer
customerNotestringNote · max 2000
emailemailEmail
billingAddressIduuidBilling address · id of address
shippingAddressIduuidDelivery address · id of address
shippingMethodIduuidDelivery rate · id of shipping_method
fulfilmentMethodstring (enum)Delivery · Allowed values: shipping, pickup

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.
customer_not_foundThe customer must exist and be active.
order_not_editableA despatched order cannot change its delivery method.
shipping_method_not_availableThe rate must be priced in this order’s channel.

Events it publishes: retail.order_updated, retail.order_discounts_applied

What it writes: sales_order (update) — Edits the order; sales_order_line (update) — Re-applies discounts while editable; sales_order_discount (insert) — Records what was applied

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/update_order \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"customerId":"CUSTOMER_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_updated",
    "retail.order_discounts_applied"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.updateOrder("ORDER_ID", {
  customerId: "CUSTOMER_ID"
})
era orders update_order ORDER_ID \
  --customer-id "CUSTOMER_ID"
tools/call
{
  "name": "era__retail__update_order",
  "arguments": {
    "id": "ORDER_ID",
    "customerId": "CUSTOMER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, customer_not_found, order_not_editable, shipping_method_not_available · 429 slow down

retail.update_order_metadata

Edit order metadata — Replaces the order’s key → value metadata, public or private.

Needs retail:write · changes data

POSThttps://app.getera.io/api/v1/orders/{id}/actions/update_order_metadata
API key or OAuth token · retail:write
  • Canonical address: POST /api/v1/actions/retail.update_order_metadata

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Order · id of sales_order
metadataobject / arrayMetadata
privateMetadataobject / arrayPrivate metadata

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe order must exist.

Events it publishes: retail.order_updated

What it writes: sales_order (update) — Writes the metadata

curl -X POST https://app.getera.io/api/v1/orders/ORDER_ID/actions/update_order_metadata \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"metadata":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.order_updated"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.orders.updateOrderMetadata("ORDER_ID", {
  metadata: {}
})
era orders update_order_metadata ORDER_ID --data '{"metadata":{}}'
tools/call
{
  "name": "era__retail__update_order_metadata",
  "arguments": {
    "id": "ORDER_ID",
    "metadata": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

retail.update_warehouse

Edit a warehouse — Its name, address, contact and whether customers may collect there.

Needs retail:manage · changes data

POSThttps://app.getera.io/api/v1/warehouses/{id}/actions/update_warehouse
API key or OAuth token · retail:manage
  • REST alias: PATCH /api/v1/warehouses/{id}
  • Canonical address: POST /api/v1/actions/retail.update_warehouse

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Warehouse · id of warehouse
namestringName · max 250
addressIduuidAddress · id of address
streetAddress1stringStreet · max 250
streetAddress2stringStreet (second line) · max 250
cityAreastringDistrict · max 120
citystringCity · max 120
countryAreastringRegion · max 120
postalCodestringPostal code · max 32
countrystringCountry · max 2
phonephonePhone
emailemailEmail
clickAndCollectOptionstring (enum)Collection · Allowed values: disabled, local, all
isPrivatebooleanHidden from customers

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe warehouse must exist.
address_not_foundThe address must exist.

Events it publishes: retail.warehouse_saved

What it writes: warehouse (update) — Edits the warehouse

curl -X POST https://app.getera.io/api/v1/warehouses/WAREHOUSE_ID/actions/update_warehouse \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "retail.warehouse_saved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.warehouses.updateWarehouse("WAREHOUSE_ID", {
  name: "Name"
})
era warehouses update_warehouse WAREHOUSE_ID \
  --name "Name"
tools/call
{
  "name": "era__retail__update_warehouse",
  "arguments": {
    "id": "WAREHOUSE_ID",
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold retail:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, address_not_found · 429 slow down

Data models

Allocation

Table allocation · Resource allocations

  • GET /api/v1/allocations
  • GET /api/v1/allocations/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
order_line_idstring (uuid) · uuidsales_order_line
stock_idstring (uuid) · uuidstock
quantity_allocatedinteger · int4
created_atstring (date-time) · timestamptz

Primary key: id

Unique: order_line_id, stock_id

Checks:

  • CHECK ((quantity_allocated >= 0))

CheckoutLine

Table checkout_line · Resource checkout_lines

  • GET /api/v1/checkout_lines
  • GET /api/v1/checkout_lines/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
item_variant_idstring (uuid) · uuiditem_variant
quantityinteger · int4
is_giftboolean · bool
price_overridestring (int64) · int8yes
currencystring · bpcharmax 3
undiscounted_unit_amountstring (int64) · int8
total_amountstring (int64) · int8
metadataobject · jsonb
created_atstring (date-time) · timestamptz

Primary key: id

Unique: checkout_token, item_variant_id

Checks:

  • CHECK ((currency ~ '^[A-Z]{3}$'::text))
  • CHECK (((price_override IS NULL) OR (price_override >= 0)))
  • CHECK ((quantity >= 1))
  • CHECK ((total_amount >= 0))
  • CHECK ((undiscounted_unit_amount >= 0))

Checkout

Table checkout · Resource checkouts

ColumnTypeNullableAllowed valuesReferences
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
channel_idstring (uuid) · uuidchannel
currencystring · bpcharmax 3
countrystring · bpcharyesmax 2
language_codestring · textyes
customer_idstring (uuid) · uuidyescustomer
emailstring · textyes
notestring · text
billing_address_idstring (uuid) · uuidyesaddress
shipping_address_idstring (uuid) · uuidyesaddress
save_billing_addressboolean · bool
save_shipping_addressboolean · bool
shipping_method_idstring (uuid) · uuidyesshipping_method
shipping_method_namestring · textyes
collection_point_idstring (uuid) · uuidyeswarehouse
delivery_methods_stale_atstring (date-time) · timestamptzyes
subtotal_amountstring (int64) · int8
shipping_amountstring (int64) · int8
discount_amountstring (int64) · int8
total_amountstring (int64) · int8
discount_namestring · textyes
authorize_statusstring · textnone, partial, full
charge_statusstring · textnone, partial, full, overcharged
automatically_refundableboolean · bool
voucher_codestring · textyes
is_voucher_usage_increasedboolean · bool
price_expirationstring (date-time) · timestamptz
discount_expirationstring (date-time) · timestamptz
completing_started_atstring (date-time) · timestamptzyes
redirect_urlstring · textyes
tracking_codestring · textyes
metadataobject · jsonb
created_atstring (date-time) · timestamptz
last_changestring (date-time) · timestamptz
abandoned_notice_atstring (date-time) · timestamptzyes

Primary key: token

Checks:

  • CHECK ((currency ~ '^[A-Z]{3}$'::text))
  • CHECK ((discount_amount >= 0))
  • CHECK ((shipping_amount >= 0))
  • CHECK ((subtotal_amount >= 0))
  • CHECK ((total_amount >= 0))

ItemCollectionItem

Table item_collection_item · Resource collection_items

  • GET /api/v1/collection_items
  • GET /api/v1/collection_items/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
collection_idstring (uuid) · uuiditem_collection
item_idstring (uuid) · uuiditem
sort_orderinteger · int4
created_atstring (date-time) · timestamptz

Primary key: id

Unique: collection_id, item_id

ItemCollection

Table item_collection · Resource collections

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
namestring · text
slugstring · text
descriptionstring · textyes
background_file_idstring (uuid) · uuidyesfile
background_altstring · textyes
seo_titlestring · textyes
seo_descriptionstring · textyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
ruleobject · jsonbyes

Primary key: id

FulfilmentLine

Table fulfilment_line · Resource fulfilment_lines

  • GET /api/v1/fulfilment_lines
  • GET /api/v1/fulfilment_lines/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
fulfilment_idstring (uuid) · uuidfulfilment
order_line_idstring (uuid) · uuidsales_order_line
quantityinteger · int4
stock_idstring (uuid) · uuidyesstock
created_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK ((quantity >= 1))

Fulfilment

Table fulfilment · Resource fulfilments

  • GET /api/v1/fulfilments
  • GET /api/v1/fulfilments/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
order_idstring (uuid) · uuidsales_order
sequenceinteger · int4
statusstring · textfulfilled, refunded, returned, replaced, refunded_and_returned, canceled, waiting_for_approval
tracking_numberstring · text
currencystring · bpcharyesmax 3
shipping_refund_amountstring (int64) · int8yes
total_refund_amountstring (int64) · int8yes
metadataobject · jsonb
created_by_user_idstring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
carrierstring · textyes
tracking_urlstring · textyes
customer_notified_atstring (date-time) · timestamptzyes

Primary key: id

Unique: order_id, sequence

Checks:

  • CHECK (((currency IS NULL) OR (currency ~ '^[A-Z]{3}$'::text)))
  • CHECK ((sequence >= 1))
  • CHECK (((shipping_refund_amount IS NULL) OR (shipping_refund_amount >= 0)))
  • CHECK (((total_refund_amount IS NULL) OR (total_refund_amount >= 0)))

ItemCollectionChannelListing

Table item_collection_channel_listing · Resource item_collection_channel_listings

  • GET /api/v1/item_collection_channel_listings
  • GET /api/v1/item_collection_channel_listings/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
collection_idstring (uuid) · uuiditem_collection
channel_idstring (uuid) · uuidchannel
is_publishedboolean · bool
published_atstring (date-time) · timestamptzyes

Primary key: id

Unique: collection_id, channel_id

SalesOrderDiscount

Table sales_order_discount · Resource order_discounts

  • GET /api/v1/order_discounts
  • GET /api/v1/order_discounts/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
order_idstring (uuid) · uuidsales_order
order_line_idstring (uuid) · uuidyessales_order_line
typestring · textpromotion, order_promotion, voucher, manual
scopestring · textorder, line, shipping
value_typestring · textfixed, percentage
valuestring (decimal) · numeric
amountstring (int64) · int8
currencystring · bpcharmax 3
namestring · textyes
reasonstring · textyes
promotion_rule_idstring (uuid) · uuidyes
voucher_idstring (uuid) · uuidyes
voucher_codestring · textyes
created_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK ((amount >= 0))
  • CHECK (((scope = 'line'::text) = (order_line_id IS NOT NULL)))
  • CHECK ((currency ~ '^[A-Z]{3}$'::text))
  • CHECK ((value >= (0)::numeric))

SalesOrderGiftCard

Table sales_order_gift_card · Resource order_gift_cards

  • GET /api/v1/order_gift_cards
  • GET /api/v1/order_gift_cards/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
order_idstring (uuid) · uuidsales_order
gift_card_idstring (uuid) · uuidyes
gift_card_event_idstring (uuid) · uuidyes
code_tailstring · text
amountstring (int64) · int8
currencystring · bpcharmax 3
idempotency_keystring · text
created_atstring (date-time) · timestamptz
statusstring · textpending, applied, failed
pending_codestring · textyes
failure_reasonstring · textyes
resolved_atstring (date-time) · timestamptzyes

Primary key: id

Unique: workspace_id, idempotency_key

Checks:

  • CHECK ((amount > 0))
  • CHECK (((status <> 'applied'::text) OR (gift_card_id IS NOT NULL)))
  • CHECK ((currency ~ '^[A-Z]{3}$'::text))
  • CHECK (((status <> 'pending'::text) OR (pending_code IS NOT NULL)))

OrderGrantedRefundLine

Table order_granted_refund_line · Resource order_granted_refund_lines

  • GET /api/v1/order_granted_refund_lines
  • GET /api/v1/order_granted_refund_lines/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
granted_refund_idstring (uuid) · uuidorder_granted_refund
order_line_idstring (uuid) · uuidsales_order_line
quantityinteger · int4
reasonstring · textyes

Primary key: id

Unique: granted_refund_id, order_line_id

Checks:

  • CHECK ((quantity > 0))

OrderGrantedRefund

Table order_granted_refund · Resource order_granted_refunds

  • GET /api/v1/order_granted_refunds
  • GET /api/v1/order_granted_refunds/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
order_idstring (uuid) · uuidsales_order
return_idstring (uuid) · uuidyesorder_return
amountstring (int64) · int8
currencystring · bpcharmax 3
reasonstring · textyes
shipping_costs_includedboolean · bool
created_by_user_idstring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK ((amount > 0))
  • CHECK ((currency ~ '^[A-Z]{3}$'::text))

SalesOrderLine

Table sales_order_line · Resource order_lines

  • GET /api/v1/order_lines
  • GET /api/v1/order_lines/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
order_idstring (uuid) · uuidsales_order
item_idstring (uuid) · uuidyesitem
item_variant_idstring (uuid) · uuidyesitem_variant
item_namestring · text
variant_namestring · text
skustring · textyes
is_shipping_requiredboolean · bool
quantityinteger · int4
quantity_fulfilledinteger · int4
is_giftboolean · bool
currencystring · bpcharmax 3
unit_amountstring (int64) · int8
total_amountstring (int64) · int8
undiscounted_unit_amountstring (int64) · int8
undiscounted_total_amountstring (int64) · int8
unit_discount_amountstring (int64) · int8
unit_discount_typestring · textyesfixed, percentage
unit_discount_reasonstring · textyes
is_price_overriddenboolean · boolyes
voucher_codestring · textyes
draft_base_price_expire_atstring (date-time) · timestamptzyes
display_orderinteger · int4
metadataobject · jsonb
created_atstring (date-time) · timestamptz
tax_class_idstring (uuid) · uuidyes
tax_class_namestring · textyes
tax_ratestring (decimal) · numericyes
tax_amountstring (int64) · int8
tax_includedboolean · bool
order_discount_amountstring (int64) · int8

Primary key: id

Checks:

  • CHECK ((quantity_fulfilled <= quantity))
  • CHECK ((currency ~ '^[A-Z]{3}$'::text))
  • CHECK ((order_discount_amount >= 0))
  • CHECK ((quantity >= 1))
  • CHECK ((quantity_fulfilled >= 0))
  • CHECK ((tax_amount >= 0))
  • CHECK ((total_amount >= 0))
  • CHECK ((undiscounted_total_amount >= 0))
  • CHECK ((undiscounted_unit_amount >= 0))
  • CHECK ((unit_amount >= 0))
  • CHECK ((unit_discount_amount >= 0))

OrderReturnLine

Table order_return_line · Resource order_return_lines

  • GET /api/v1/order_return_lines
  • GET /api/v1/order_return_lines/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
return_idstring (uuid) · uuidorder_return
order_line_idstring (uuid) · uuidsales_order_line
quantityinteger · int4
quantity_receivedinteger · int4
quantity_restockedinteger · int4
conditionstring · textyesresellable, damaged
warehouse_idstring (uuid) · uuidyeswarehouse
notestring · textyes

Primary key: id

Unique: return_id, order_line_id

Checks:

  • CHECK ((quantity_received <= quantity))
  • CHECK ((quantity_restocked <= quantity_received))
  • CHECK ((quantity > 0))
  • CHECK ((quantity_received >= 0))
  • CHECK ((quantity_restocked >= 0))

OrderReturn

Table order_return · Resource order_returns

  • GET /api/v1/order_returns
  • GET /api/v1/order_returns/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
order_idstring (uuid) · uuidsales_order
sequenceinteger · int4
statusstring · textrequested, received, inspected, closed, rejected
reasonstring · textyes
notestring · textyes
created_by_user_idstring (uuid) · uuidyesapp_user
received_atstring (date-time) · timestamptzyes
inspected_atstring (date-time) · timestamptzyes
closed_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Unique: order_id, sequence

Checks:

  • CHECK ((sequence >= 1))

SalesOrder

Table sales_order · Resource orders

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
numberstring (int64) · int8
statusstring · textdraft, unconfirmed, unfulfilled, partially fulfilled, partially_returned, returned, fulfilled, canceled, expired
originstring · textcheckout, draft, reissue, bulk_create, marketplace
authorize_statusstring · textnone, partial, full
charge_statusstring · textnone, partial, full, overcharged
channel_idstring (uuid) · uuidchannel
currencystring · bpcharmax 3
language_codestring · textyes
customer_idstring (uuid) · uuidyescustomer
user_emailstring · textyes
customer_notestring · text
tracking_client_idstring · textyes
billing_address_idstring (uuid) · uuidyesaddress
shipping_address_idstring (uuid) · uuidyesaddress
shipping_method_idstring (uuid) · uuidyesshipping_method
shipping_method_namestring · textyes
collection_point_idstring (uuid) · uuidyeswarehouse
collection_point_namestring · textyes
subtotal_amountstring (int64) · int8
shipping_amountstring (int64) · int8
undiscounted_shipping_amountstring (int64) · int8
discount_total_amountstring (int64) · int8
tax_total_amountstring (int64) · int8
total_amountstring (int64) · int8
undiscounted_total_amountstring (int64) · int8
total_charged_amountstring (int64) · int8
total_authorized_amountstring (int64) · int8
voucher_codestring · textyes
original_order_idstring (uuid) · uuidyessales_order
lines_countinteger · int4
redirect_urlstring · textyes
external_referencestring · textyes
metadataobject · jsonb
created_by_user_idstring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
expired_atstring (date-time) · timestamptzyes
gift_card_amountstring (int64) · int8
manual_discount_typestring · textyesfixed, percentage
manual_discount_percentagestring (decimal) · numericyes
manual_discount_fixed_amountstring (int64) · int8yes
manual_discount_reasonstring · textyes
shipping_tax_ratestring (decimal) · numeric
shipping_tax_includedboolean · bool
shipping_tax_class_idstring (uuid) · uuidyes
shipping_tax_class_namestring · textyes
shipping_tax_amountstring (int64) · int8
fulfilment_methodstring · textshipping, pickup
private_metadataobject · jsonb

Primary key: id

Unique: workspace_id, number

Checks:

  • CHECK ((currency ~ '^[A-Z]{3}$'::text))
  • CHECK ((discount_total_amount >= 0))
  • CHECK ((gift_card_amount >= 0))
  • CHECK ((lines_count >= 0))
  • CHECK (((manual_discount_fixed_amount IS NULL) OR (manual_discount_fixed_amount > 0)))
  • CHECK (((manual_discount_percentage IS NULL) OR ((manual_discount_percentage > (0)::numeric) AND (manual_discount_percentage <= (100)::numeric))))
  • CHECK ((((manual_discount_type IS NULL) AND (manual_discount_percentage IS NULL) AND (manual_discount_fixed_amount IS NULL)) OR ((manual_discount_type = 'percentage'::text) AND (manual_discount_percentage IS NOT NULL) AND (manual_discount_fixed_amount IS NULL)) OR ((manual_discount_type = 'fixed'::text) AND (manual_discount_fixed_amount IS NOT NULL) AND (manual_discount_percentage IS NULL))))
  • CHECK ((shipping_amount >= 0))
  • CHECK ((subtotal_amount >= 0))
  • CHECK ((tax_total_amount >= 0))
  • CHECK ((total_amount >= 0))
  • CHECK ((undiscounted_shipping_amount >= 0))
  • CHECK ((undiscounted_total_amount >= 0))

PreorderAllocation

Table preorder_allocation · Resource preorder_allocations

  • GET /api/v1/preorder_allocations
  • GET /api/v1/preorder_allocations/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
order_line_idstring (uuid) · uuidsales_order_line
item_variant_idstring (uuid) · uuiditem_variant
channel_idstring (uuid) · uuidchannel
quantityinteger · int4
created_atstring (date-time) · timestamptz

Primary key: id

Unique: order_line_id

Checks:

  • CHECK ((quantity > 0))

ItemChannelListing

Table item_channel_listing · Resource product_listings

  • GET /api/v1/product_listings
  • GET /api/v1/product_listings/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
item_idstring (uuid) · uuiditem
channel_idstring (uuid) · uuidchannel
is_publishedboolean · bool
published_atstring (date-time) · timestamptzyes
visible_in_listingsboolean · bool
available_for_purchase_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Unique: item_id, channel_id

ChannelWarehouse

Table channel_warehouse · Resource sales_channel_warehouses

  • GET /api/v1/sales_channel_warehouses
  • GET /api/v1/sales_channel_warehouses/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
channel_idstring (uuid) · uuidchannel
warehouse_idstring (uuid) · uuidwarehouse
sort_orderinteger · int4

Primary key: id

Unique: channel_id, warehouse_id

Channel

Table channel · Resource sales_channels

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
namestring · text
slugstring · text
is_activeboolean · bool
currency_codestring · bpcharmax 3
default_countrystring · bpcharyesmax 2
metadataobject · jsonb
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK ((currency_code ~ '^[A-Z]{3}$'::text))

ShippingMethodChannelListing

Table shipping_method_channel_listing · Resource shipping_method_channel_listings

  • GET /api/v1/shipping_method_channel_listings
  • GET /api/v1/shipping_method_channel_listings/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
shipping_method_idstring (uuid) · uuidshipping_method
channel_idstring (uuid) · uuidchannel
currencystring · bpcharmax 3
price_amountstring (int64) · int8
minimum_order_price_amountstring (int64) · int8yes
maximum_order_price_amountstring (int64) · int8yes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Unique: shipping_method_id, channel_id

Checks:

  • CHECK (((maximum_order_price_amount IS NULL) OR (maximum_order_price_amount >= 0)))
  • CHECK (((minimum_order_price_amount IS NULL) OR (minimum_order_price_amount >= 0)))
  • CHECK (((minimum_order_price_amount IS NULL) OR (maximum_order_price_amount IS NULL) OR (minimum_order_price_amount <= maximum_order_price_amount)))
  • CHECK ((currency ~ '^[A-Z]{3}$'::text))
  • CHECK ((price_amount >= 0))

ShippingMethodExcludedItem

Table shipping_method_excluded_item · Resource shipping_method_excluded_items

  • GET /api/v1/shipping_method_excluded_items
  • GET /api/v1/shipping_method_excluded_items/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
shipping_method_idstring (uuid) · uuidshipping_method
item_idstring (uuid) · uuiditem

Primary key: id

Unique: shipping_method_id, item_id

ShippingMethodPostalCodeRule

Table shipping_method_postal_code_rule · Resource shipping_method_postal_code_rules

  • GET /api/v1/shipping_method_postal_code_rules
  • GET /api/v1/shipping_method_postal_code_rules/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
shipping_method_idstring (uuid) · uuidshipping_method
start_codestring · text
end_codestring · textyes
inclusion_typestring · textinclude, exclude

Primary key: id

ShippingMethod

Table shipping_method · Resource shipping_methods

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
shipping_zone_idstring (uuid) · uuidshipping_zone
namestring · text
descriptionstring · textyes
typestring · textprice, weight
minimum_order_weight_gramsstring (int64) · int8yes
maximum_order_weight_gramsstring (int64) · int8yes
minimum_delivery_daysinteger · int4yes
maximum_delivery_daysinteger · int4yes
metadataobject · jsonb
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
tax_class_idstring (uuid) · uuidyestax_class

Primary key: id

Checks:

  • CHECK (((minimum_order_weight_grams IS NULL) OR (maximum_order_weight_grams IS NULL) OR (minimum_order_weight_grams <= maximum_order_weight_grams)))
  • CHECK (((minimum_delivery_days IS NULL) OR (maximum_delivery_days IS NULL) OR (minimum_delivery_days <= maximum_delivery_days)))
  • CHECK (((type <> 'price'::text) OR ((minimum_order_weight_grams IS NULL) AND (maximum_order_weight_grams IS NULL))))
  • CHECK (((maximum_delivery_days IS NULL) OR (maximum_delivery_days >= 0)))
  • CHECK (((maximum_order_weight_grams IS NULL) OR (maximum_order_weight_grams >= 0)))
  • CHECK (((minimum_delivery_days IS NULL) OR (minimum_delivery_days >= 0)))
  • CHECK (((minimum_order_weight_grams IS NULL) OR (minimum_order_weight_grams >= 0)))

ShippingZoneChannel

Table shipping_zone_channel · Resource shipping_zone_channels

  • GET /api/v1/shipping_zone_channels
  • GET /api/v1/shipping_zone_channels/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
shipping_zone_idstring (uuid) · uuidshipping_zone
channel_idstring (uuid) · uuidchannel

Primary key: id

Unique: shipping_zone_id, channel_id

ShippingZone

Table shipping_zone · Resource shipping_zones

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
namestring · text
descriptionstring · textyes
countriesstring[] · bpchar[]
is_defaultboolean · bool
metadataobject · jsonb
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

StockMovement

Table stock_movement · Resource stock_movements

  • GET /api/v1/stock_movements
  • GET /api/v1/stock_movements/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
stock_idstring (uuid) · uuidstock
warehouse_idstring (uuid) · uuidwarehouse
item_variant_idstring (uuid) · uuiditem_variant
quantity_deltainteger · int4
quantity_afterinteger · int4
reasonstring · textcount, received, damaged, correction, fulfilment, fulfilment_canceled, returned, transfer_out, transfer_in
notestring · textyes
order_idstring (uuid) · uuidyessales_order
fulfilment_idstring (uuid) · uuidyesfulfilment
created_by_user_idstring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
transfer_idstring (uuid) · uuidyes
return_idstring (uuid) · uuidyes

Primary key: id

Checks:

  • CHECK ((quantity_delta <> 0))

StockReservation

Table stock_reservation · Resource stock_reservations

  • GET /api/v1/stock_reservations
  • GET /api/v1/stock_reservations/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
checkout_line_idstring (uuid) · uuidcheckout_line
stock_idstring (uuid) · uuidstock
quantityinteger · int4
expires_atstring (date-time) · timestamptz
committed_atstring (date-time) · timestamptzyes
released_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz

Primary key: id

Unique: checkout_line_id, stock_id

Checks:

  • CHECK ((NOT ((committed_at IS NOT NULL) AND (released_at IS NOT NULL))))
  • CHECK ((quantity > 0))

Stock

Table stock · Resource stocks

  • GET /api/v1/stocks
  • GET /api/v1/stocks/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
warehouse_idstring (uuid) · uuidwarehouse
item_variant_idstring (uuid) · uuiditem_variant
quantityinteger · int4
quantity_allocatedinteger · int4
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
safety_stockinteger · int4

Primary key: id

Unique: warehouse_id, item_variant_id

Checks:

  • CHECK ((quantity_allocated >= 0))
  • CHECK ((safety_stock >= 0))

ItemVariantChannelListing

Table item_variant_channel_listing · Resource variant_listings

  • GET /api/v1/variant_listings
  • GET /api/v1/variant_listings/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
item_variant_idstring (uuid) · uuiditem_variant
channel_idstring (uuid) · uuidchannel
currencystring · bpcharmax 3
price_amountstring (int64) · int8yes
cost_price_amountstring (int64) · int8yes
prior_price_amountstring (int64) · int8yes
discounted_price_amountstring (int64) · int8yes
discounted_price_dirtyboolean · bool
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
preorder_quantity_thresholdinteger · int4yes

Primary key: id

Unique: item_variant_id, channel_id

Checks:

  • CHECK (((cost_price_amount IS NULL) OR (cost_price_amount >= 0)))
  • CHECK ((currency ~ '^[A-Z]{3}$'::text))
  • CHECK (((discounted_price_amount IS NULL) OR (discounted_price_amount >= 0)))
  • CHECK (((preorder_quantity_threshold IS NULL) OR (preorder_quantity_threshold >= 0)))
  • CHECK (((price_amount IS NULL) OR (price_amount >= 0)))
  • CHECK (((prior_price_amount IS NULL) OR (prior_price_amount >= 0)))

VariantPreorder

Table variant_preorder · Resource variant_preorders

  • GET /api/v1/variant_preorders
  • GET /api/v1/variant_preorders/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
item_variant_idstring (uuid) · uuiditem_variant
end_datestring (date-time) · timestamptzyes
global_thresholdinteger · int4yes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Unique: item_variant_id

Checks:

  • CHECK (((global_threshold IS NULL) OR (global_threshold >= 0)))

WarehouseShippingZone

Table warehouse_shipping_zone · Resource warehouse_shipping_zones

  • GET /api/v1/warehouse_shipping_zones
  • GET /api/v1/warehouse_shipping_zones/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
warehouse_idstring (uuid) · uuidwarehouse
shipping_zone_idstring (uuid) · uuidshipping_zone

Primary key: id

Unique: warehouse_id, shipping_zone_id

Warehouse

Table warehouse · Resource warehouses

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
namestring · text
slugstring · text
address_idstring (uuid) · uuidaddress
emailstring · textyes
click_and_collect_optionstring · textdisabled, local, all
is_privateboolean · bool
external_referencestring · textyes
metadataobject · jsonb
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Events

Workflows and webhooks react to these events.

EventWhat happensPayload
retail.channel_deletedA channel that never sold was deleted.id, slug
retail.channel_order_importedAn order from a marketplace or another shop arrived.id, number, channelId, provider, externalId, customerId, currency, totalAmount, status, lines
retail.channel_order_updatedA marketplace order changed status at its marketplace.id, number, channelId, provider, externalId, from, to, remoteStatus
retail.channel_price_changedA per-channel price changed.itemVariantId, channelId, amount, currency
retail.channel_savedA sales channel was created or edited.id, slug
retail.channel_warehouses_changedA channel’s warehouse order changed.channelId, count
retail.checkout_abandonedA basket with an email on it was left untouched.token, customerId, customerName, email, channelId, currency, totalAmount, totalText, lineCount, idleMinutes
retail.checkout_createdA basket was opened.token, channelId
retail.checkout_updatedA basket changed.token
retail.collection_deletedA collection was removed.id
retail.collection_items_changedA collection’s membership changed.id, count
retail.collection_savedA collection was created or edited.id, slug
retail.customer_notification_requestedAn order confirmation, despatch or tracking change the customer should hear about; notifications emails it (a reaction).kind, orderId, number, fulfilmentId, sequence, email, customerName, carrier, trackingNumber, trackingUrl, totalAmount, currency
retail.draft_order_createdA draft order was started.id, number
retail.draft_order_deletedA staff-created draft was discarded.id, number
retail.fulfilment_approvedA despatch was signed off.id, orderId
retail.fulfilment_canceledA despatch was cancelled.id, orderId
retail.fulfilment_createdA despatch was created.id, orderId, status, customerId, number, sequence, carrier, trackingNumber
retail.fulfilment_tracking_updatedA tracking number was set.id, orderId
retail.gift_card_appliedA gift card paid towards an order.id, orderId, giftCardId, amount, currency
retail.gift_card_removedA gift card came off an order.id, orderId, orderNumber, giftCardId, amount, currency
retail.gift_card_requestedA gift card was put on an order; gift_cards redeems it (a reaction).id, orderId, amount, currency, idempotencyKey
retail.listing_changedSomething was listed or delisted in a channel.itemId, channelId, isPublished
retail.order_canceledAn order was cancelled.id, number, releasedQuantity, reason, giftCardsReleased
retail.order_charge_status_changedWhat an order has been paid changed (none, partial, full, overcharged).id, from, to, collectedAmount
retail.order_confirmedAn order was confirmed.id, number
retail.order_discounts_appliedPromotions and a coupon were (re)applied to an order.id, currency, voucherCode, total, discounts
retail.order_expiredAn unconfirmed order expired.id, number, releasedQuantity
retail.order_lines_changedAn order’s lines changed.id, count
retail.order_placedAn order was placed.id, number, channelId, customerId, customerOrderCount, currency, totalAmount, origin, fulfilmentMethod, lines, shippingAmount, undiscountedShippingAmount, giftCardAmount, taxOnTopAmount, voucherCode, discountTotal, discounts, shippingTaxAmount, shippingTaxRate, shippingTaxIncluded, shippingTaxClassId
retail.order_returnedGoods came back.id, quantity, complete
retail.order_updatedAn order was edited.id
retail.preorder_changedA variant went on or off preorder.itemVariantId, enabled, endDate
retail.preorder_endedA preorder ended and its orders moved onto a shelf.itemVariantId, orders
retail.refund_grantedThe shop granted a refund; finance moves the money.id, orderId, amount, currency, reason, idempotencyKey
retail.return_closedA return was closed.id, orderId
retail.return_inspectedA return was inspected and restocked.id, orderId, restocked
retail.return_receivedA returned parcel arrived.id, orderId, quantity
retail.return_rejectedA return was refused.id, orderId, reason
retail.return_requestedA return was opened.id, orderId, sequence, quantity, reason
retail.shipping_exclusions_changedThe products a delivery rate refuses changed.shippingMethodId, count
retail.shipping_method_deletedA delivery rate was removed.id
retail.shipping_method_savedA delivery rate was created or edited.id, type
retail.shipping_price_changedA delivery rate was priced in a channel.shippingMethodId, channelId, amount, currency
retail.shipping_rules_changedA rate’s postal-code rules changed.shippingMethodId, count
retail.shipping_zone_deletedA shipping zone was removed.id
retail.shipping_zone_savedA shipping zone was created or edited.id, countries
retail.stock_changedA shelf was counted.warehouseId, itemVariantId, quantity
retail.stock_lowA shelf’s free stock fell to or below the low-stock threshold.stockId, warehouseId, itemVariantId, quantity, free, threshold
retail.stock_policy_changedA shelf’s safety stock changed.stockId, safetyStock
retail.stock_reservations_expiredExpired basket stock claims were released.count
retail.stock_reservedA basket holds tracked stock for fifteen minutes.token, quantity, expiresInMinutes
retail.stock_transferredStock moved between two warehouses.transferId, fromWarehouseId, toWarehouseId, itemVariantId, quantity
retail.warehouse_deletedA warehouse was closed.id
retail.warehouse_savedA warehouse was created or edited.id, slug
retail.warehouse_zones_changedA warehouse’s shipping zones changed.warehouseId, count