Contents
REST API - Plugixa Inventory
Everything the admin screens do, they do through this API. There is no private back channel, which is why it is worth documenting: if the app can do it, so can you.
Namespace
/wp-json/plugixa-inventory/v1/
Entities
Each registered entity gets the same CRUD surface, named after the entity:
| Entity | Base |
|---|---|
| Item | /items |
| Category | /categories |
| Warehouse | /warehouses |
| Recipient | /recipients |
| Stock movement | /stock-movements |
| Transaction (ledger) | /transactions |
| Transfer PRO | /transfers |
| Adjustment PRO | /adjustments |
| Unit PRO | /units |
GET /items list, with search, filters, sorting and paging
POST /items create
GET /items/{id} read one
PUT /items/{id} update
DELETE /items/{id} trash
An absent module has no routes. A free site answers rest_no_route for
/transfers, because the module is not installed - not because a licence check
refused it. The same is true of an app switched off in the
App Manager.
Routes that answer a question
Not everything is a record. These are the ones that are not:
| Route | Answers |
|---|---|
GET /bootstrap |
Everything the app needs to start: settings, apps, vocabulary |
GET /dashboard |
The dashboard’s figures |
GET /warehouse-overview |
One location’s figures |
GET /items/low-stock |
What is at or below its reorder level |
GET /lookup |
One item from a barcode, SKU or serial |
GET /lookup/search |
Several items from part of a name or code |
GET /stock-movements/types |
The document types this build offers |
GET /meta/entities |
What entities exist, and their fields |
GET /apps / POST /apps |
Read and change the App Manager |
GET /settings / POST /settings |
Read and save settings |
GET /notifications |
The bell, with /unread-count and /read-all |
POST /notifications/preferences |
Per-person alert choices |
GET /import-targets, /imports |
The importer’s mapping targets and runs |
GET /export/{entity} |
A list as CSV |
POST /stock/reconcile, GET /stock/health |
The stock check |
POST /stock/seed-layers |
Open cost layers from the ledger |
GET /reports/... PRO |
The reporting screens |
GET /roles/vocabulary, /roles/enforcement PRO |
The permission model, and whether it is being enforced |
GET /user-roles PRO |
WordPress roles and their inventory capabilities |
GET /custom-fields/types PRO |
The twelve field types |
GET /pwa/manifest PRO |
The installable app manifest |
Authentication and permissions
Standard WordPress: a logged-in session with a nonce, or application passwords for a script.
Every route answers through one permission method, and that method is handed the record, not just the action. This is what lets the Pro Roles module answer whose records without a single controller changing, and it is why the shortcode needed no authorisation code of its own: the front end talks to this same API and inherits the same answers.
A refused request is a refusal, not a redirect, and a list you may not read is empty rather than partial.
Filters are read after the permission check. A visitor who may not read an entity cannot learn which fields it has by asking what it can be filtered by.
What is never writable
- The ledger. There is no route to update or delete a transaction row, and a veto in the data layer refuses it even if code tried.
- On hand. Stock is the result of finalised documents. It is not in the list of fields an item update may touch.
- A finalised document. Post the opposite document instead.
These are not permissions you can grant. See The Stock Ledger.
Errors
Ordinary WordPress error shapes, with a code you can branch on: 422 for a
validation problem naming the field, 409 for a conflict such as a duplicate SKU
or a document that cannot be trashed - with the blocking reasons listed - and
403 for a refusal.
One deliberate exception: GET /lookup answers 200 with found: false for
an unknown code, rather than 404. A scanning loop that had to tell an HTTP error
apart from a miss would treat a network failure as an unknown item.
Extending it
plugixa_inventory_register_rest_routes fires with the namespace and the
container, so your own routes can sit in the same namespace and reuse the same
permission model. See Hooks.
Troubleshooting
| Symptom | Usual cause |
|---|---|
rest_no_route |
The module is absent, or its app is switched off. |
401 from a script |
Use an application password, or send a nonce. |
403 on a record you can see in a list |
A Pro permission profile scopes edit or delete more narrowly than read. |
| A list is empty for one user and full for another | Permission scoping. That is the feature. |
409 on create |
A duplicate SKU or barcode. The message names the other record. |
409 on delete |
Something depends on it. The blockers are in the response. |
| On hand will not update | Correct. Post a stock movement. |
| A lookup miss returns 200 | By design, so a miss cannot be confused with a failure. |
What to do next
- Hook into events: Hooks.
- Long-running jobs: WP-CLI.
- Who may call what: Roles and Permissions PRO.