Next Restaurant 6.1.0: move your data in, run payroll, and connect other systems Next Inventory 6.2.0: a REST API and webhooks for your other systems Next DB 6.1: Auto-Updating Tables, Printing, Phone Layout and SEO Next Task 6.0.0: a task manager for Joomla Next Inventory 6.1.1: smoother Check Out, no more list limits, and much faster PHP2Shell: Is Your Joomla Site Safe? What to Do Today Introducing Next Boards: Kanban project and task boards for Joomla Building the Future of Joomla Extensions
NextSoftware

Create Stock Movement

POST /stock-movements

Record a check-in, check-out, stock addition or stock removal

Scope stock:write, plus the owner's role permission for the type (transactions.checkin, checkout, add_stock, remove_stock).

With is_draft: false the movement is finalized at once: stock changes and ledger rows are written. With is_draft: true (the default) nothing changes until POST /stock-movements/{id}/finalize.

Rules, the same as in Next Inventory itself: check_out needs a recipient_id; check_out / remove_stock are refused (400) when an item has less stock than requested; check_in / check_out take assets only, add_stock / remove_stock consumables and sellables only.

Request

POST https://example.com/api/index.php/v1/nextinventory/stock-movements

Parameters

Name Type In Required Description
Idempotency-Key string header No Optional. Any unique string (1 to 191 printable ASCII characters, no spaces; a UUID is ideal). The request runs once: a retry with the same key gets the first response back, with the header Idempotent-Replayed: true, instead of running again. Keys are kept for 24 hours per token. 409 IDEMPOTENCY_IN_PROGRESS while the first request is still running; 422 IDEMPOTENCY_KEY_REUSED if the key comes with a different request. A 5xx answer is not kept, so it can be retried with the same key. (min length 1, max length 191, pattern ^[\x21-\x7E]+$)

Request body

Content type: application/json

Field Type Required Description
movement_type string Yes One of check_in, check_out, add_stock, remove_stock.
movement_date string Yes (date)
warehouse_id integer Yes
recipient_id integer No Required for check_out.
reference string No
details string No
is_draft boolean No Defaults to true.
items object[] Yes
items.item_id integer Yes
items.quantity number Yes
items.cost_per_unit number No Stock increases under FIFO/LIFO; defaults to the item's unit price.
items.weight number No
items.weight_unit string No
{
    "movement_type": "add_stock",
    "is_draft": false,
    "movement_date": "2026-11-11",
    "warehouse_id": 1,
    "reference": "PO-1042",
    "items": [
        {
            "item_id": 17,
            "quantity": 40,
            "cost_per_unit": 3.2
        }
    ]
}

Responses

201 — Created.

{
    "data": {
        "id": 1
    }
}
Field Type Meaning
data.id integer

Errors

Status Code When
4 A refusal. Common codes: MISSING_TOKEN / INVALID_TOKEN (401); API_DISABLED, ACCOUNT_UNUSABLE, ACCESS_DENIED, TASK_NOT_ALLOWED, MISSING_SCOPE, APP_DISABLED, DEMO_LOCKED, FORBIDDEN (403); NOT_FOUND (404); BAD_REQUEST / INVALID_JSON / INVALID_IDEMPOTENCY_KEY (400, validation and stock rules, with the reason in title); IDEMPOTENCY_IN_PROGRESS (409); PRECONDITION_FAILED (412, the record changed since the If-Match ETag was read); IDEMPOTENCY_KEY_REUSED (422); RATE_LIMITED / TOO_MANY_FAILED_LOGINS (429, with a Retry-After header in seconds); SERVER_ERROR (500).

Examples

curl

curl -s -X POST "https://example.com/api/index.php/v1/nextinventory/stock-movements" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"movement_type":"add_stock","is_draft":false,"movement_date":"2026-11-11","warehouse_id":1,"reference":"PO-1042","items":[{"item_id":17,"quantity":40,"cost_per_unit":3.2}]}'

PHP

<?php
$ch = curl_init('https://example.com/api/index.php/v1/nextinventory/stock-movements');

curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . getenv('API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS     => '{"movement_type":"add_stock","is_draft":false,"movement_date":"2026-11-11","warehouse_id":1,"reference":"PO-1042","items":[{"item_id":17,"quantity":40,"cost_per_unit":3.2}]}',
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);

JavaScript

const API_TOKEN = process.env.API_TOKEN;

const response = await fetch("https://example.com/api/index.php/v1/nextinventory/stock-movements", {
  method: 'POST',
  headers: {
    "Authorization": `Bearer ${API_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "movement_type": "add_stock",
    "is_draft": false,
    "movement_date": "2026-11-11",
    "warehouse_id": 1,
    "reference": "PO-1042",
    "items": [
      {
        "item_id": 17,
        "quantity": 40,
        "cost_per_unit": 3.2
      }
    ]
  }),
});
const data = await response.json();

All Extensions