Skip to content
Leanmerce Availability

Inventory Integration REST API

Documented build: Pro 1.1.0-dev.15. Set your own approved WooCommerce site URL and token; never publish a real credential. Production requests require HTTPS.

Authentication

All routes use:

Authorization: Bearer <integration-id.secret>

The credential must be active and have the required read/write permission. Location restrictions are enforced after authentication.

Base namespace: /wp-json/leanmerce-availability/v1.

Method Route Permission
GET /locations read
GET /locations/{id} read
GET /products?sku={exact-sku} read
GET /products/{id}/inventory read
PUT /inventory/balances write
POST /inventory/balances/batch write
GET /inventory/batches/{external_batch_id} read
GET /integration/status read

Read examples

: "${STORE_URL:?Set STORE_URL to the approved HTTPS WooCommerce site base URL}"
curl -i -H "Authorization: Bearer TOKEN" "$STORE_URL/wp-json/leanmerce-availability/v1/locations"
$site = (Read-Host 'Approved HTTPS WooCommerce site base URL').TrimEnd('/')
$base = "$site/wp-json/leanmerce-availability/v1"
$headers = @{ Authorization = 'Bearer YOUR-INTEGRATION-ID.YOUR-SECRET' }
Invoke-WebRequest -Method Get -Uri "$base/locations" -Headers $headers -SkipHttpErrorCheck

Success is HTTP 200 with {"locations":[...]}. Each row has id, label, active, archived, and capabilities. A credential restricted to online receives only that location. GET /locations/store-1 returns HTTP 403 when outside scope.

Negative test:

try {
    Invoke-WebRequest -Method Get -Uri "$base/locations" -Headers @{ Authorization = 'Bearer invalid' } -UseBasicParsing
} catch {
    [int]$_.Exception.Response.StatusCode
    $_.ErrorDetails.Message
}

Expected HTTP 401, code invalid_auth.

Product reads

GET /products?sku=DEMO-MUG-001 resolves one exact non-empty SKU. Unknown SKU is 404; duplicate SKU is 409. The response contains id, product_id, variation_id, stock_owner_id, sku, and type.

GET /products/{id}/inventory adds inventory_mode and balances filtered to allowed locations.

Absolute On Hand write

Prerequisites: write permission; allowed active location; Inventory Mode active; authority external; this integration recorded as authority source.

: "${STORE_URL:?Set STORE_URL to the approved HTTPS WooCommerce site base URL}"
curl -i -X PUT "$STORE_URL/wp-json/leanmerce-availability/v1/inventory/balances" \
  -H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" \
  -d '{"external_event_id":"erp-2026-09-14-001","sku":"DEMO-MUG-001","location_id":"online","on_hand":"12.00000000"}'
$eventId = "example-event-$([DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds())"
$body = @{ external_event_id=$eventId; sku='YOUR-CONTROLLED-SKU'; location_id='online'; on_hand='12.00000000' } | ConvertTo-Json -Compress
$first = Invoke-WebRequest -Method Put -Uri "$base/inventory/balances" -Headers $headers -ContentType 'application/json' -Body $body -SkipHttpErrorCheck
$replay = Invoke-WebRequest -Method Put -Uri "$base/inventory/balances" -Headers $headers -ContentType 'application/json' -Body $body -SkipHttpErrorCheck
[pscustomobject]@{ FirstStatus=[int]$first.StatusCode; ReplayStatus=[int]$replay.StatusCode; ReplayBody=$replay.Content }

Success returns changed or unchanged, identifiers, On Hand, Reserved, Available, and idempotent_replay. The write sets absolute On Hand while preserving Reserved. A later finalize/synchronize warning can return warning: reconciliation_required; inspect diagnostics before retrying with a new event.

Reusing the same event ID and identical identity returns the stored result with idempotent_replay: true. Reusing it for different product/location/quantity returns HTTP 409 idempotency_conflict. An in-progress duplicate can return 409 idempotency_in_progress.

Batch write

{
  "external_batch_id": "erp-batch-001",
  "items": [
    {"external_event_id":"erp-item-001","sku":"DEMO-MUG-001","location_id":"online","on_hand":"12"}
  ]
}

POST it to /inventory/balances/batch. A batch contains 1–1000 items. Up to 100 items are processed synchronously; larger valid batches are queued. A queued response is HTTP 202; completed responses are HTTP 200. Poll /inventory/batches/erp-batch-001. Reusing the batch ID with different content is HTTP 409. Batch items can partially fail; inspect counts and each indexed result.

Errors and sequencing limits

Typical codes: invalid_auth 401; permission_denied 403; insecure_transport 403 in non-SSL production; invalid_event_id/invalid_quantity 400; unknown_product/unknown_sku/unknown_location 404; duplicate_sku, location_inactive, inventory_mode_off, reconciliation_required, external_source_not_owner, and idempotency conflicts 409; oversized batch 413; persistence failure 500.

Idempotency covers one integration/event identity or batch content. It is not a versioned compare-and-swap contract across unrelated external events. Concurrent absolute writes with different event IDs can arrive in either order; the connector must provide sequencing. Do not write WooCommerce _stock, reservations or Leanmerce tables directly. Revoke a credential to make subsequent authentication fail.