Skip to content
Public API: beta. The response schema may change without notice. v2 will be the first stable version, published once the public API leaves beta: evaluate on v1, but pin to v2 for production.

REST API

The REST API lets you work with your Logistified data over plain HTTP (send a request to a URL, get JSON back) without speaking MCP or writing code. It’s the same data and the same keys as AI / Agent access, exposed as ordinary REST resources.

https://prod.logistified.app/api/v1

Authenticate with an API key (see Authentication):

Terminal window
curl -s -H "Authorization: Bearer $LSTK_TOKEN" \
"https://prod.logistified.app/api/v1/purchase-orders?limit=5"

Every successful response is wrapped in a small envelope:

{
"data": {
"purchaseOrders": [
/* … */
],
"totalCount": 42,
"cursor": "2"
},
"meta": { "requestId": "…", "apiVersion": "1.5" }
}

A complete purchase order, start to finish. Each step is one call; the ids come from the previous response. You’ll need a write-scope key and the supplierId / locationId / variantId values from the app (or from AI / Agent access; the REST API has no reference-data endpoints yet).

  1. Create the draft. The body is the PO header plus, optionally, its opening line items.

    Terminal window
    curl -s -X POST "https://prod.logistified.app/api/v1/purchase-orders" \
    -H "Authorization: Bearer $LSTK_TOKEN" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: $(uuidgen)" \
    -d '{
    "poName": "Q3 restock",
    "supplierId": "sup_8f21",
    "locationId": "loc_412",
    "lineItems": [{ "variantId": "var_9a01", "quantityOrdered": 30, "unitCost": 12.5 }]
    }'

    201 Created, with a Location: /api/v1/purchase-orders/po_7c3e header:

    {
    "data": {
    "purchaseOrder": {
    "purchaseOrderId": "po_7c3e",
    "poNumber": "PO-1042",
    "poName": "Q3 restock",
    "status": "Draft",
    "previousStatus": "Draft",
    "supplierId": "sup_8f21",
    "locationId": "loc_412",
    "itemCount": 1,
    "totalValue": 375,
    "lineItems": [
    {
    "poLineItemId": "pol_31aa",
    "variantId": "var_9a01",
    "quantityOrdered": 30,
    "quantityConfirmed": 0,
    "quantityReceived": 0,
    "quantityPending": 30,
    "unitCost": 12.5,
    "lineItemStatus": "Pending"
    }
    ]
    }
    },
    "meta": { "requestId": "9d1f…", "apiVersion": "1.5" }
    }
  2. Send it to the supplier.

    Terminal window
    curl -s -X POST ".../api/v1/purchase-orders/po_7c3e/status" \
    -H "Authorization: Bearer $LSTK_TOKEN" -H "Content-Type: application/json" \
    -d '{ "status": "Sent" }'
    {
    "data": {
    "purchaseOrder": {
    "purchaseOrderId": "po_7c3e",
    "status": "Sent",
    "previousStatus": "Draft",
    "lineItems": [
    /* … */
    ]
    },
    "transition": { "from": "Draft", "to": "Sent" },
    "sideEffects": { "incoming": { "outcome": "applied" } }
    },
    "meta": { "requestId": "b204…", "apiVersion": "1.5" }
    }
  3. Confirm what the supplier committed to. confirmAll accepts the ordered quantities as-is and moves the PO to In Progress; pass lines instead to confirm different amounts.

    Terminal window
    curl -s -X POST ".../api/v1/purchase-orders/po_7c3e/confirm" \
    -H "Authorization: Bearer $LSTK_TOKEN" -H "Content-Type: application/json" \
    -d '{ "confirmAll": true }'
    {
    "data": {
    "purchaseOrder": {
    "purchaseOrderId": "po_7c3e",
    "status": "In Progress",
    "lineItems": [
    /* … */
    ]
    },
    "status": { "before": "Sent", "after": "In Progress", "autoTransitioned": true },
    "updatedLineItemIds": ["pol_31aa"],
    "sideEffects": {}
    },
    "meta": { "requestId": "1e77…", "apiVersion": "1.5" }
    }
  4. Receive the goods. Quantities are the new totals for each line, not amounts to add, so sending the same call twice is safe.

    Terminal window
    curl -s -X POST ".../api/v1/purchase-orders/po_7c3e/receive" \
    -H "Authorization: Bearer $LSTK_TOKEN" -H "Content-Type: application/json" \
    -d '{ "lines": [{ "lineItemId": "pol_31aa", "quantityReceived": 30 }] }'
    {
    "data": {
    "purchaseOrder": {
    "purchaseOrderId": "po_7c3e",
    "status": "Received",
    "lineItems": [
    /* … */
    ]
    },
    "status": { "before": "In Progress", "after": "Received", "autoTransitioned": true },
    "sideEffects": {
    "shopifySync": { "status": "queued", "syncedLineItemCount": 1 },
    "incoming": { "outcome": "applied" }
    }
    },
    "meta": { "requestId": "c5a0…", "apiVersion": "1.5" }
    }
  5. Complete it. This also runs the cost sync back to your products, when enabled; Shopify cost updates are asynchronous (queued after completion), so check GET /purchase-orders/{id}/cost-sync-history for their outcome.

    Terminal window
    curl -s -X POST ".../api/v1/purchase-orders/po_7c3e/complete" \
    -H "Authorization: Bearer $LSTK_TOKEN" -H "Content-Type: application/json" -d '{}'
    {
    "data": {
    "purchaseOrder": {
    "purchaseOrderId": "po_7c3e",
    "status": "Completed",
    "lineItems": [
    /* … */
    ]
    },
    "status": { "before": "Received", "after": "Completed" },
    "costSync": { "mode": "shopify", "syncedVariantCount": 1, "skippedCustomItemCount": 0, "warnings": [] },
    "sideEffects": {}
    },
    "meta": { "requestId": "77b2…", "apiVersion": "1.5" }
    }

REST 1.5 adds 67 planning routes (17 GET, 50 writes) in six collections:

CollectionPathWhat it holds
Inventory commitments/api/v1/inventory-commitmentsKnown or possible future sales, with probability and dates; can create purchase and transfer orders
New product plans/api/v1/new-product-plansLaunch demand built from similar products, per location, with size groups; can create purchase orders
Sales plans/api/v1/sales-plansUnit and revenue targets per location, seeded from last year
Promotional events/api/v1/promotional-eventsHolidays and sales events that lift the forecast once switched on
Promotional event catalogue/api/v1/promotional-event-catalogueThe built-in holiday catalogue to create events from
Inventory planning options/api/v1/inventory-plan-optionsThe demand types, reasons and sources plans are tagged with

Each plan collection has the same core routes (list, detail, paged items, status, create, edit, delete) plus its own actions. Planning dates are YYYY-MM-DD UTC days; order actions can succeed partly, so send an Idempotency-Key and read failed before retrying.

The REST API and the Agent access surface share the same lstk_ API keys, the same scopes, and the same per-shop rate limit, and act on the same data with the same rules. Every REST write runs the identical operation an AI agent would, with the same lifecycle guards and business rules. REST documents its own strict request bodies and public response fields in the reference. If you already use Agent access, your keys work here unchanged.