Scale Plan Feature

EcomLinx API Reference

Programmatic access to your orders, inventory and listings. Base URL:

https://app.ecomlinx.com/api/v1

Introduction

The EcomLinx REST API lets your ERP, warehouse system or scripts read the orders EcomLinx collects from every channel, read your listings, and read and set stock allocations. It is available on the Scale plan.

All requests go over HTTPS to https://app.ecomlinx.com/api/v1. Responses are JSON with snake_case fields. Dates are ISO 8601 in UTC; a missing value is null, never an empty string.

Get your API key - the account owner creates one in Settings → API Keys. It is shown once; store it as a secret. Anyone holding it can read your orders and change stock allocations.

Authentication

Authenticate using your API key as a Bearer token in the Authorization header.

Authentication header
Authorization: Bearer elk_live_Xq3v9KpL2mN8rT5wY1zA4bC7dE0fG6hJ

A missing, wrong or revoked key returns 401. A key stops working on the very next request after it is revoked, the account leaves the Scale plan, or the account is suspended. Call the API from your server - never put the key in a browser or mobile app.

Rate limits

Each API key may make 120 requests per minute. Keys are counted separately, so a second integration gets its own key and its own allowance. Every response says where you stand; going over returns 429 rate_limited with a Retry-After header in seconds.

Response headers
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 42

Errors

All errors return a JSON body with error.code and error.message.

Error response
{
  "error": {
    "code": "insufficient_stock",
    "message": "Cannot allocate 120 units - only 100 in stock"
  }
}
400bad_requestA parameter or the body is invalid - the message says which
401unauthorizedMissing, invalid or revoked API key
403plan_requiredThe account is not on the Scale plan
403account_suspendedThe account is suspended
404not_foundNo such record in your account
409ambiguous_skuSeveral SKUs share that code - address it by id
409insufficient_stockAllocations would exceed physical stock
429rate_limitedOver the per-key limit - wait Retry-After seconds
500internal_errorOur fault - retry with backoff

Pagination & polling

List endpoints return records oldest change first, with has_more and next_cursor. Pass the cursor back to get the next page. A record that changes while you are paging moves to the end of the stream, so you see it again rather than missing it.

To keep a system in sync, remember the updated_at of the last record you processed and send it as updated_since next time. It is inclusive, so de-duplicate by id.

node - sync new and changed orders
const since = loadCheckpoint();          // e.g. '2026-10-01T00:00:00Z'
let latest = since;
let cursor = null;
while (true) {
  const url = new URL('https://app.ecomlinx.com/api/v1/orders');
  url.searchParams.set('updated_since', since);
  if (cursor) url.searchParams.set('cursor', cursor);
  const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.ECOMLINX_API_KEY}` } });
  if (res.status === 429) { await sleep(Number(res.headers.get('Retry-After')) * 1000); continue; }
  if (!res.ok) throw new Error((await res.json()).error.message);
  const page = await res.json();
  for (const order of page.data) { await upsert(order); latest = order.updated_at; }
  if (!page.next_cursor) break;
  cursor = page.next_cursor;
}
saveCheckpoint(latest);

Account

GET/me

Check your key

Returns the account and key a request is authenticated as. Make this your first call: a 200 means the key works.

Example request
curl
curl "https://app.ecomlinx.com/api/v1/me" \
  -H "Authorization: Bearer $ECOMLINX_API_KEY"
Response
json
{
  "account": {
    "id": "sel_8KQ2",
    "business_name": "Artisan Craft Co.",
    "plan": "scale",
    "region": "IN",
    "currency": "INR"
  },
  "key": { "name": "ERP sync" },
  "rate_limit": { "requests_per_minute": 120 }
}

Orders

GET/orders

List orders

Orders from every connected channel, oldest change first. Poll with updated_since to pick up new orders and status changes.

Query parameters
status
stringNew | Processing | Ready | Shipped | Delivered | Cancelled | Return
channel
stringChannel name as shown on the order, e.g. Shopify (not case-sensitive).
updated_since
stringISO 8601 date or timestamp. Only records changed at or after it.
limit
integer1 to 100 (default 50).
cursor
stringnext_cursor from the previous page.
Example request
curl
curl "https://app.ecomlinx.com/api/v1/orders?status=New&limit=50" \
  -H "Authorization: Bearer $ECOMLINX_API_KEY"
Response
json
{
  "data": [
    {
      "id": "sel_8KQ2:#1001",
      "marketplace_order_id": "#1001",
      "channel": "Shopify",
      "status": "Ready",
      "customer": { "name": "Kiran Das", "city": "Bengaluru" },
      "shipping_address": {
        "name": "Kiran Das", "phone": "9876543210", "email": null,
        "line1": "12 MG Road", "line2": null, "city": "Bengaluru",
        "state": "Karnataka", "pincode": "560001", "country": "India"
      },
      "items": [
        { "sku": "MUG-1", "name": "Ceramic mug", "quantity": 2, "unit_price": 299 }
      ],
      "amount": 598,
      "payment_mode": "cod",
      "cod_amount": 598,
      "awb": "141500123",
      "courier": "Delhivery Surface",
      "shipment": {
        "courier": "Delhivery Surface", "awb": "141500123", "status": "booked",
        "label_url": "https://...", "pickup_scheduled_at": "2026-10-21T04:30:00.000Z"
      },
      "ordered_on": "2026-10-20",
      "ordered_at_time": "10:00",
      "created_at": "2026-10-20T04:30:12.000Z",
      "updated_at": "2026-10-20T06:02:40.000Z"
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMC0yMFQwNjowMjo0MC4wMDBafHNrdV8wMUhYNA"
}
GET/orders/{id}

Retrieve an order

By EcomLinx id, or by the marketplace's own order id when no EcomLinx id matches. URL-encode it: ids can contain ":" and "#".

Example request
curl
curl "https://app.ecomlinx.com/api/v1/orders/%231001" \
  -H "Authorization: Bearer $ECOMLINX_API_KEY"
Response
json
{
  "data": {
    "id": "sel_8KQ2:#1001",
    "marketplace_order_id": "#1001",
    "channel": "Shopify",
    "status": "Ready",
    "customer": { "name": "Kiran Das", "city": "Bengaluru" },
    "shipping_address": {
      "name": "Kiran Das", "phone": "9876543210", "email": null,
      "line1": "12 MG Road", "line2": null, "city": "Bengaluru",
      "state": "Karnataka", "pincode": "560001", "country": "India"
    },
    "items": [
      { "sku": "MUG-1", "name": "Ceramic mug", "quantity": 2, "unit_price": 299 }
    ],
    "amount": 598,
    "payment_mode": "cod",
    "cod_amount": 598,
    "awb": "141500123",
    "courier": "Delhivery Surface",
    "shipment": {
      "courier": "Delhivery Surface", "awb": "141500123", "status": "booked",
      "label_url": "https://...", "pickup_scheduled_at": "2026-10-21T04:30:00.000Z"
    },
    "ordered_on": "2026-10-20",
    "ordered_at_time": "10:00",
    "created_at": "2026-10-20T04:30:12.000Z",
    "updated_at": "2026-10-20T06:02:40.000Z"
  }
}

Inventory

GET/inventory

List stock

Physical stock per SKU and how much of it each channel may sell (allocations). A change to allocations counts as an update for updated_since.

Query parameters
sku
stringExact SKU code.
updated_since
stringISO 8601 date or timestamp. Only records changed at or after it.
limit
integer1 to 100 (default 50).
cursor
stringnext_cursor from the previous page.
Example request
curl
curl "https://app.ecomlinx.com/api/v1/inventory?updated_since=2026-10-01" \
  -H "Authorization: Bearer $ECOMLINX_API_KEY"
Response
json
{
  "data": [
    {
      "id": "sku_01HX4",
      "sku": "MUG-1",
      "name": "Ceramic mug",
      "category": "Kitchen",
      "stock": 100,
      "status": "in_stock",
      "reorder_point": 10,
      "selling_price": 299,
      "cogs": 120,
      "warehouse_location": "Rack A3",
      "allocations": { "amazon_in": 40, "shopify": 25 },
      "updated_at": "2026-10-20T06:02:40.000Z"
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMC0yMFQwNjowMjo0MC4wMDBafHNrdV8wMUhYNA"
}
GET/inventory/{sku}

Retrieve a SKU

By SKU id or SKU code. If two of your SKUs share a code you get 409 ambiguous_sku - use the id.

Example request
curl
curl "https://app.ecomlinx.com/api/v1/inventory/MUG-1" \
  -H "Authorization: Bearer $ECOMLINX_API_KEY"
Response
json
{
  "data": {
    "id": "sku_01HX4",
    "sku": "MUG-1",
    "name": "Ceramic mug",
    "category": "Kitchen",
    "stock": 100,
    "status": "in_stock",
    "reorder_point": 10,
    "selling_price": 299,
    "cogs": 120,
    "warehouse_location": "Rack A3",
    "allocations": { "amazon_in": 40, "shopify": 25 },
    "updated_at": "2026-10-20T06:02:40.000Z"
  }
}
PATCH/inventory/{sku}

Set channel allocations

Sets how many units each channel may sell. Channels you leave out are unchanged; 0 stops a channel selling the SKU. The total cannot exceed physical stock (409 insufficient_stock). Marketplaces receive the new numbers on the next channel sync.

Request body
allocationsrequired
objectChannel id to quantity, e.g. { "amazon_in": 40, "flipkart": 30 }. Ids are the ones used in Integrations: amazon_in, amazon_us, amazon_uk, flipkart, meesho, myntra, ajio, nykaa, jiomart, snapdeal, shopify, woocommerce and so on.
Example request
curl
curl -X PATCH "https://app.ecomlinx.com/api/v1/inventory/MUG-1" \
  -H "Authorization: Bearer $ECOMLINX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"allocations":{"amazon_in":40,"shopify":25}}'
Response
json
{
  "data": {
    "id": "sku_01HX4",
    "sku": "MUG-1",
    "name": "Ceramic mug",
    "category": "Kitchen",
    "stock": 100,
    "status": "in_stock",
    "reorder_point": 10,
    "selling_price": 299,
    "cogs": 120,
    "warehouse_location": "Rack A3",
    "allocations": { "amazon_in": 40, "shopify": 25 },
    "updated_at": "2026-10-20T06:02:40.000Z"
  }
}

Listings

GET/listings

List listings

Your catalogue with the 0-100 listing health score and per-channel status.

Query parameters
status
stringactive | inactive | suppressed | error
updated_since
stringISO 8601 date or timestamp. Only records changed at or after it.
limit
integer1 to 100 (default 50).
cursor
stringnext_cursor from the previous page.
Example request
curl
curl "https://app.ecomlinx.com/api/v1/listings?status=active" \
  -H "Authorization: Bearer $ECOMLINX_API_KEY"
Response
json
{
  "data": [
    {
      "id": "lst_01HX4",
      "sku": "MUG-1",
      "name": "Ceramic mug",
      "category": "Kitchen",
      "brand": null,
      "status": "active",
      "health_score": 87,
      "price": 299,
      "stock": 65,
      "channels": ["amazon_in", "shopify"],
      "channel_statuses": { "amazon_in": { "status": "live", "price": 299 } },
      "created_at": "2026-09-02T11:20:00.000Z",
      "updated_at": "2026-10-20T06:02:40.000Z"
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMC0yMFQwNjowMjo0MC4wMDBafHNrdV8wMUhYNA"
}

Webhook events

Add a URL and choose events in Settings → API Keys → Webhooks; the signing secret is shown once when you add it. Events fire when an order's status is changed in EcomLinx. Delivery is a single attempt with a 5-second timeout, so treat webhooks as a prompt to poll /orders, not as the only record.

Verify each delivery: X-EcomLinx-Signature is sha256= followed by the hex HMAC-SHA256 of the raw request body, keyed with your secret.

order.shippedAn order is marked Shipped
order.deliveredAn order is marked Delivered
order.cancelledAn order is marked Cancelled
Webhook delivery
POST https://yourapp.com/hooks/ecomlinx
Content-Type: application/json
X-EcomLinx-Event: order.shipped
X-EcomLinx-Signature: sha256=5f2b8c...
X-EcomLinx-Delivery: wh_01HX4

{
  "event": "order.shipped",
  "timestamp": "2026-10-20T09:45:00.000Z",
  "sellerId": "sel_8KQ2",
  "data": {
    "orderId": "sel_8KQ2:#1001",
    "status": "Shipped",
    "channel": "Shopify",
    "amount": 598,
    "customer": "Kiran Das"
  }
}

Client libraries

There is no official SDK yet. The API is plain REST and JSON, so any HTTP client works - the examples on this page use curl, the fetch built into Node 18+, and Python's requests. Questions: info@ecomlinx.com.