Developer documentation

Inbound API

REST endpoints your plugin calls into a merchant store — orders, products, customers, inventory.

Base URL & versioning

All requests target https://api.aeonzap.com/v1. The version is part of the path, never a header. Breaking changes ship as v2; v1 is supported for at least 24 months after that.

Authentication

Plugins receive a per-installation project token via ctx.token. The token is scoped to the merchant store that installed your plugin and inherits exactly the scopes your manifest declared. Send it in the Authorization header.

curl https://api.aeonzap.com/v1/orders?limit=20 \
  -H "Authorization: Bearer $AEONZAP_TOKEN" \
  -H "X-Aeonzap-Store: store_4f2a"

Orders

MethodPathScopeDescription
GET/v1/ordersorders.readList orders, paginated by cursor
GET/v1/orders/{id}orders.readFetch one order with line items
POST/v1/ordersorders.writeCreate a draft or live order
PATCH/v1/orders/{id}orders.writeUpdate tags, notes, custom fields
POST/v1/orders/{id}/fulfillmentsorders.writeMark items shipped
POST/v1/orders/{id}/refundsorders.writeRefund money or items

Products

MethodPathScopeDescription
GET/v1/productsproducts.readList products with variants
POST/v1/productsproducts.writeCreate a product
PATCH/v1/products/{id}products.writeUpdate fields
POST/v1/products/{id}/variantsproducts.writeAdd a variant
POST/v1/inventory/adjustproducts.writeIncrement or set stock

Customers

MethodPathScopeDescription
GET/v1/customerscustomers.readList customers
GET/v1/customers/{id}customers.readSingle customer + addresses
POST/v1/customerscustomers.writeCreate a customer
PATCH/v1/customers/{id}customers.writeUpdate profile

Pagination

List endpoints return a cursor-based page. Pass ?cursor= to continue. Cursors are opaque; do not parse them.

{
  "data": [ /* items */ ],
  "page": {
    "next_cursor": "eyJpZCI6Im9yZF84ODIxIn0",
    "has_more": true
  }
}

Rate limits

Default budget is 60 requests per second per store, 600 per minute, with bursts up to 120/s. The headers X-RateLimit-Remaining and X-RateLimit-Reset come on every response. A 429 includes Retry-After in seconds.

Error format

{
  "error": {
    "code": "validation_failed",
    "message": "price must be a positive integer",
    "field": "variants[0].price",
    "request_id": "req_01HM6XB42Z"
  }
}