Skip to content

Inventory API

Enterprise feature

The Inventory API is available on Enterprise plans. Compare plans to find the right fit for your team.

The Inventory API lets you manage parts and supplies, track stock across warehouses and service vehicles, adjust quantities, transfer stock between locations, and review transaction history. Use it to integrate your inventory data with ERP systems, procurement platforms, or custom dashboards.


Endpoints summary

Method Path Scope Description
GET /api/v1/inventory inventory:read List items
GET /api/v1/inventory?id={id} inventory:read Get a single item
POST /api/v1/inventory inventory:write Create an item
PUT /api/v1/inventory?id={id} inventory:write Update an item (full)
PATCH /api/v1/inventory?id={id} inventory:write Update an item (partial)
GET /api/v1/inventory?id={id}&sub=stock inventory:read Get item stock
GET /api/v1/inventory?id={id}&sub=transactions inventory:read Get item transactions
POST /api/v1/inventory?id={id}&sub=adjust inventory:write Adjust stock
POST /api/v1/inventory?sub=transfer inventory:transfer Transfer stock
GET /api/v1/inventory?sub=locations inventory:read List locations
GET /api/v1/inventory?sub=locations&location_id={id} inventory:read Get a single location
GET /api/v1/inventory?sub=low-stock inventory:read Low stock alerts

Scopes

Your API key must include the appropriate scope for each endpoint.

Scope Access
inventory:read List items, get item details, view stock, transactions, locations, and low-stock alerts
inventory:write Create items, update items (PUT/PATCH), and adjust stock. Implies inventory:read access.
inventory:transfer Transfer stock between locations. Does not imply read or write access.

Tip

Most integrations need inventory:read and inventory:write. Add inventory:transfer only if your integration moves stock between locations.


Item object

Every item returned by the API contains these fields:

Field Type Description
id integer Unique item identifier
part_number string SKU or part number (unique within your company)
part_name string Display name
description string Free-text description, or null
category string Category name, or null
serial_number string Serial number, or null
quantity_on_hand integer Total quantity across all locations
min_stock_level integer Low-stock alert threshold
reorder_quantity integer Suggested reorder amount
cost_per_unit float Cost price, or null
price_per_unit float Sell price, or null
supplier_id integer Linked supplier ID, or null
created_at string Creation timestamp (UTC)
updated_at string Last update timestamp (UTC)

Stock entry object

Stock entries represent inventory levels at a specific location.

Field Type Description
location_id integer Location identifier
location_name string Location display name, or null
location_type string warehouse, vehicle, technician, job_site, other, or null
quantity integer Total quantity at this location
reserved_quantity integer Quantity reserved for jobs
available integer Available quantity (quantity - reserved_quantity)
last_updated string Last stock change timestamp

Transaction object

Transactions record every stock movement for a full audit trail.

Field Type Description
id integer Transaction identifier
transaction_type string One of: Add, Remove, Transfer_out, Transfer_in, Adjust, Reserve, Release, Job_complete
quantity integer Signed quantity change (positive = increase, negative = decrease)
location_id integer Primary location, or null
location_name string Primary location name, or null
related_location_id integer Secondary location (for transfers), or null
related_location_name string Secondary location name, or null
job_id integer Associated job ID, or null
user_name string User who performed the action, "API" for API-initiated changes, or null
notes string Transaction notes or reason, or null
created_at string Transaction timestamp

Location object

Locations represent warehouses, service vehicles, and other places where you store inventory.

Field Type Description
id integer Location identifier
location_name string Display name
location_type string warehouse, vehicle, technician, job_site, or other
address string Street address, or null
city string City, or null
state string State or province, or null
zip string ZIP or postal code, or null
is_active boolean Whether the location is active
created_at string Creation timestamp
updated_at string Last update timestamp

List items

GET /api/v1/inventory
Scope: inventory:read

Returns a paginated list of inventory items.

Query parameters

Parameter Type Description
category string Filter by exact category name
search string Search by part number or part name
low_stock boolean If true, return only items at or below their minimum stock level
page integer Page number (default: 1)
per_page integer Results per page (default: 50, max: 100)

Example request

curl -X GET "https://fsmnavigator.com/api/v1/inventory?category=Filters&per_page=25" \
  -H "X-API-Key: YOUR_API_KEY"

Example response

{
  "data": [
    {
      "id": 1,
      "part_number": "FLT-001",
      "part_name": "HVAC Air Filter 20x25x1",
      "description": "Standard residential air filter",
      "category": "Filters",
      "serial_number": null,
      "quantity_on_hand": 150,
      "min_stock_level": 20,
      "reorder_quantity": 50,
      "cost_per_unit": 8.50,
      "price_per_unit": 15.99,
      "supplier_id": null,
      "created_at": "2026-02-24T10:00:00Z",
      "updated_at": "2026-02-24T10:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 25,
    "total": 14,
    "total_pages": 1
  },
  "request_id": "a1b2c3d4e5f6"
}

Get a single item

GET /api/v1/inventory?id={id}
Scope: inventory:read

Retrieves full details for one item, including stock levels broken down by location.

Example request

curl -X GET "https://fsmnavigator.com/api/v1/inventory?id=1" \
  -H "X-API-Key: YOUR_API_KEY"

Example response

{
  "data": {
    "item": {
      "id": 1,
      "part_number": "FLT-001",
      "part_name": "HVAC Air Filter 20x25x1",
      "description": "Standard residential air filter",
      "category": "Filters",
      "serial_number": null,
      "quantity_on_hand": 150,
      "min_stock_level": 20,
      "reorder_quantity": 50,
      "cost_per_unit": 8.50,
      "price_per_unit": 15.99,
      "supplier_id": null,
      "created_at": "2026-02-24T10:00:00Z",
      "updated_at": "2026-02-24T10:00:00Z"
    },
    "stock": [
      {
        "location_id": 1,
        "location_name": "Main Warehouse",
        "location_type": "warehouse",
        "quantity": 100,
        "reserved_quantity": 0,
        "available": 100,
        "last_updated": "2026-02-24T12:00:00Z"
      },
      {
        "location_id": 3,
        "location_name": "Van #1 — Alex Johnson",
        "location_type": "vehicle",
        "quantity": 50,
        "reserved_quantity": 0,
        "available": 50,
        "last_updated": "2026-02-24T12:00:00Z"
      }
    ]
  },
  "request_id": "a1b2c3d4e5f6"
}

Create an item

POST /api/v1/inventory
Scope: inventory:write

Creates a new inventory item. Returns 201 Created on success.

Request body

Field Type Required Description
part_number string Yes Unique SKU or part number within your company
part_name string Yes Display name
description string No Free-text description
category string No Category name
serial_number string No Serial number
quantity_on_hand integer No Initial total quantity (default: 0)
min_stock_level integer No Low-stock alert threshold (default: 0)
reorder_quantity integer No Suggested reorder amount (default: 0)
cost_per_unit float No Cost price
price_per_unit float No Sell price
supplier_id integer No Associated supplier ID

Example request

curl -X POST "https://fsmnavigator.com/api/v1/inventory" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "part_number": "CAP-002",
    "part_name": "Run Capacitor 35/5 MFD",
    "description": "Dual run capacitor for HVAC systems",
    "category": "Capacitors",
    "min_stock_level": 10,
    "reorder_quantity": 25,
    "cost_per_unit": 12.50,
    "price_per_unit": 24.99
  }'

Example response 201 Created

{
  "success": true,
  "data": {
    "id": 15,
    "part_number": "CAP-002",
    "part_name": "Run Capacitor 35/5 MFD",
    "description": "Dual run capacitor for HVAC systems",
    "category": "Capacitors",
    "serial_number": null,
    "quantity_on_hand": 0,
    "min_stock_level": 10,
    "reorder_quantity": 25,
    "cost_per_unit": 12.50,
    "price_per_unit": 24.99,
    "supplier_id": null,
    "created_at": "2026-02-24T14:30:00Z",
    "updated_at": "2026-02-24T14:30:00Z"
  },
  "item_id": 15,
  "request_id": "a1b2c3d4e5f6"
}

Error responses

HTTP code Error Description
400 missing_part_number part_number was not provided or is empty
400 missing_part_name part_name was not provided or is empty
400 duplicate_part_number Another item already uses this part number

Update an item (full)

PUT /api/v1/inventory?id={id}
Scope: inventory:write

Replaces all fields on an existing item. Fields not included in the request body are reset to their defaults (null or 0).

Stock is not updated by PUT

The quantity_on_hand field is read-only on item endpoints. Use Adjust stock or Transfer stock to change stock levels.

Request body

Field Type Required Description
part_number string Yes Unique SKU (must not conflict with other items)
part_name string Yes Display name
description string No Defaults to null if omitted
category string No Defaults to null if omitted
serial_number string No Defaults to null if omitted
min_stock_level integer No Defaults to 0 if omitted
reorder_quantity integer No Defaults to 0 if omitted
cost_per_unit float No Defaults to null if omitted
price_per_unit float No Defaults to null if omitted
supplier_id integer No Defaults to null if omitted

Example request

curl -X PUT "https://fsmnavigator.com/api/v1/inventory?id=15" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "part_number": "CAP-002-V2",
    "part_name": "Run Capacitor 35/5 MFD (Updated)",
    "description": "Dual run capacitor v2",
    "category": "Capacitors",
    "min_stock_level": 15,
    "reorder_quantity": 30,
    "cost_per_unit": 13.00,
    "price_per_unit": 25.99
  }'

Example response

{
  "success": true,
  "data": {
    "id": 15,
    "part_number": "CAP-002-V2",
    "part_name": "Run Capacitor 35/5 MFD (Updated)",
    "description": "Dual run capacitor v2",
    "category": "Capacitors",
    "serial_number": null,
    "quantity_on_hand": 0,
    "min_stock_level": 15,
    "reorder_quantity": 30,
    "cost_per_unit": 13.00,
    "price_per_unit": 25.99,
    "supplier_id": null,
    "created_at": "2026-02-24T14:30:00Z",
    "updated_at": "2026-02-24T14:35:00Z"
  },
  "request_id": "a1b2c3d4e5f6"
}

Error responses

HTTP code Error Description
400 missing_part_number part_number was not provided or is empty
400 missing_part_name part_name was not provided or is empty
400 duplicate_part_number Another item already uses this part number
404 not_found Item ID does not exist

Update an item (partial)

PATCH /api/v1/inventory?id={id}
Scope: inventory:write

Updates only the fields you include in the request body. All other fields remain unchanged.

Request body

Include any combination of these fields:

Field Type Description
part_number string Cannot be empty; duplicate check applies
part_name string Cannot be empty
description string Set to null to clear
category string Set to null to clear
serial_number string Set to null to clear
min_stock_level integer Low-stock alert threshold
reorder_quantity integer Suggested reorder amount
cost_per_unit float Set to null to clear
price_per_unit float Set to null to clear
supplier_id integer Set to null to clear

Example request

curl -X PATCH "https://fsmnavigator.com/api/v1/inventory?id=15" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "min_stock_level": 25,
    "price_per_unit": 27.99
  }'

Example response

{
  "success": true,
  "data": {
    "id": 15,
    "part_number": "CAP-002-V2",
    "part_name": "Run Capacitor 35/5 MFD (Updated)",
    "description": "Dual run capacitor v2",
    "category": "Capacitors",
    "serial_number": null,
    "quantity_on_hand": 0,
    "min_stock_level": 25,
    "reorder_quantity": 30,
    "cost_per_unit": 13.00,
    "price_per_unit": 27.99,
    "supplier_id": null,
    "created_at": "2026-02-24T14:30:00Z",
    "updated_at": "2026-02-24T14:40:00Z"
  },
  "request_id": "a1b2c3d4e5f6"
}

Tip

Use PATCH when you want to update one or two fields without resending the entire item. Use PUT when you want to replace all fields at once.

Error responses

HTTP code Error Description
400 invalid_part_number part_number was provided but is empty
400 invalid_part_name part_name was provided but is empty
400 duplicate_part_number Another item already uses this part number
400 no_fields No recognized fields in the request body
404 not_found Item ID does not exist

Get item stock

GET /api/v1/inventory?id={id}&sub=stock
Scope: inventory:read

Returns stock levels for a specific item, broken down by location.

Example request

curl -X GET "https://fsmnavigator.com/api/v1/inventory?id=1&sub=stock" \
  -H "X-API-Key: YOUR_API_KEY"

Example response

{
  "data": [
    {
      "location_id": 1,
      "location_name": "Main Warehouse",
      "location_type": "warehouse",
      "quantity": 100,
      "reserved_quantity": 5,
      "available": 95,
      "last_updated": "2026-02-24T12:00:00Z"
    },
    {
      "location_id": 3,
      "location_name": "Van #1 — Alex Johnson",
      "location_type": "vehicle",
      "quantity": 50,
      "reserved_quantity": 0,
      "available": 50,
      "last_updated": "2026-02-24T12:00:00Z"
    }
  ],
  "item_id": 1,
  "request_id": "a1b2c3d4e5f6"
}

Get item transactions

GET /api/v1/inventory?id={id}&sub=transactions
Scope: inventory:read

Returns a paginated transaction history for a specific item.

Query parameters

Parameter Type Description
type string Filter by transaction type: Add, Remove, Transfer_out, Transfer_in, Adjust, Reserve, Release, Job_complete
page integer Page number (default: 1)
per_page integer Results per page (default: 50, max: 100)

Example request

curl -X GET "https://fsmnavigator.com/api/v1/inventory?id=1&sub=transactions&type=Adjust" \
  -H "X-API-Key: YOUR_API_KEY"

Example response

{
  "data": [
    {
      "id": 42,
      "transaction_type": "Adjust",
      "quantity": -5,
      "location_id": 1,
      "location_name": "Main Warehouse",
      "related_location_id": null,
      "related_location_name": null,
      "job_id": null,
      "user_name": "API",
      "notes": "Damaged units removed",
      "created_at": "2026-02-24T14:00:00Z"
    }
  ],
  "item_id": 1,
  "pagination": {
    "page": 1,
    "per_page": 50,
    "total": 1,
    "total_pages": 1
  },
  "request_id": "a1b2c3d4e5f6"
}

Transaction types

Type Description
Add Stock added to a location
Remove Stock removed from a location
Transfer_out Stock sent to another location
Transfer_in Stock received from another location
Adjust Manual stock adjustment (add or remove)
Reserve Stock reserved for an upcoming job
Release Reserved stock released back to available
Job_complete Stock consumed when a job is completed

Adjust stock

POST /api/v1/inventory?id={id}&sub=adjust
Scope: inventory:write

Adds or removes stock for an item at a specific location. Every adjustment is recorded in the transaction history for a complete audit trail.

Request body

Field Type Required Description
location_id integer Yes Location to adjust stock at
quantity integer Yes Signed adjustment — positive to add, negative to remove. Cannot be 0.
reason string Yes Explanation for the audit trail

Example request — add stock

curl -X POST "https://fsmnavigator.com/api/v1/inventory?id=1&sub=adjust" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "location_id": 1,
    "quantity": 25,
    "reason": "Shipment received from supplier"
  }'

Example request — remove stock

curl -X POST "https://fsmnavigator.com/api/v1/inventory?id=1&sub=adjust" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "location_id": 1,
    "quantity": -5,
    "reason": "Damaged units removed from inventory"
  }'

Example response

{
  "success": true,
  "data": {
    "new_quantity": 120
  },
  "message": "Stock adjusted",
  "request_id": "a1b2c3d4e5f6"
}

The new_quantity value reflects the updated quantity at the specified location after the adjustment.

Error responses

HTTP code Error Description
400 missing_location_id location_id was not provided
400 missing_quantity quantity was not provided or is not numeric
400 missing_reason reason was not provided
400 invalid_quantity quantity is 0
400 location_not_found Location does not exist in your company
400 insufficient_stock A negative adjustment would reduce stock below zero
404 not_found Item ID does not exist

Transfer stock

POST /api/v1/inventory?sub=transfer
Scope: inventory:transfer

Moves stock from one location to another. The transfer creates two transaction records — a Transfer_out at the source location and a Transfer_in at the destination.

Request body

Field Type Required Description
item_id integer Yes Inventory item to transfer
from_location_id integer Yes Source location
to_location_id integer Yes Destination location
quantity integer Yes Number of units to transfer (must be positive)
notes string No Optional notes for the audit trail

Example request

curl -X POST "https://fsmnavigator.com/api/v1/inventory?sub=transfer" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "item_id": 1,
    "from_location_id": 1,
    "to_location_id": 3,
    "quantity": 10,
    "notes": "Restocking service van for Monday jobs"
  }'

Example response

{
  "success": true,
  "data": {
    "from_location": {
      "location_id": 1,
      "location_name": "Main Warehouse",
      "new_quantity": 90
    },
    "to_location": {
      "location_id": 3,
      "location_name": "Van #1 — Alex Johnson",
      "new_quantity": 60
    }
  },
  "message": "Stock transferred",
  "request_id": "a1b2c3d4e5f6"
}

Reserved stock

Transfers check available stock (total minus reserved). If 100 units are at a location but 20 are reserved for jobs, you can transfer up to 80 units.

Error responses

HTTP code Error Description
400 missing_item_id item_id was not provided
400 missing_from_location_id from_location_id was not provided
400 missing_to_location_id to_location_id was not provided
400 invalid_quantity quantity is not a positive integer
400 same_location Source and destination are the same location
400 from_location_not_found Source location does not exist
400 to_location_not_found Destination location does not exist
400 no_stock No stock record exists at the source location
400 insufficient_stock Available stock is less than the requested transfer amount
404 item_not_found Item ID does not exist

List locations

GET /api/v1/inventory?sub=locations
Scope: inventory:read

Returns a paginated list of inventory locations (warehouses, vehicles, and other storage points).

Query parameters

Parameter Type Description
type string Filter by type: warehouse, vehicle, technician, job_site, other
active_only boolean Set to false to include inactive locations (default: true)
page integer Page number (default: 1)
per_page integer Results per page (default: 50, max: 100)

Example request

curl -X GET "https://fsmnavigator.com/api/v1/inventory?sub=locations&type=warehouse" \
  -H "X-API-Key: YOUR_API_KEY"

Example response

{
  "data": [
    {
      "id": 1,
      "location_name": "Main Warehouse",
      "location_type": "warehouse",
      "address": "123 Industrial Blvd",
      "city": "Tampa",
      "state": "FL",
      "zip": "33601",
      "is_active": true,
      "created_at": "2026-01-01T00:00:00Z",
      "updated_at": "2026-02-20T10:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 50,
    "total": 3,
    "total_pages": 1
  },
  "request_id": "a1b2c3d4e5f6"
}

Get a single location

GET /api/v1/inventory?sub=locations&location_id={id}
Scope: inventory:read

Retrieves details for one location, including a summary of all items stocked there.

Example request

curl -X GET "https://fsmnavigator.com/api/v1/inventory?sub=locations&location_id=1" \
  -H "X-API-Key: YOUR_API_KEY"

Example response

{
  "data": {
    "location": {
      "id": 1,
      "location_name": "Main Warehouse",
      "location_type": "warehouse",
      "address": "123 Industrial Blvd",
      "city": "Tampa",
      "state": "FL",
      "zip": "33601",
      "is_active": true,
      "created_at": "2026-01-01T00:00:00Z",
      "updated_at": "2026-02-20T10:00:00Z"
    },
    "stock_summary": [
      {
        "part_name": "HVAC Air Filter 20x25x1",
        "part_number": "FLT-001",
        "quantity": 100,
        "reserved_quantity": 5,
        "available": 95
      },
      {
        "part_name": "Run Capacitor 35/5 MFD",
        "part_number": "CAP-002",
        "quantity": 30,
        "reserved_quantity": 0,
        "available": 30
      }
    ]
  },
  "request_id": "a1b2c3d4e5f6"
}

Low stock alerts

GET /api/v1/inventory?sub=low-stock
Scope: inventory:read

Returns items that are at or below their minimum stock level. Results are sorted with the most critical items first. Only items with a configured min_stock_level greater than 0 are included.

Query parameters

Parameter Type Description
page integer Page number (default: 1)
per_page integer Results per page (default: 50, max: 100)

Example request

curl -X GET "https://fsmnavigator.com/api/v1/inventory?sub=low-stock" \
  -H "X-API-Key: YOUR_API_KEY"

Example response

{
  "data": [
    {
      "id": 8,
      "part_number": "THM-001",
      "part_name": "Thermostat Wire 18/5",
      "description": null,
      "category": "Wire & Cable",
      "serial_number": null,
      "quantity_on_hand": 3,
      "min_stock_level": 10,
      "reorder_quantity": 20,
      "cost_per_unit": 0.45,
      "price_per_unit": 0.89,
      "supplier_id": null,
      "created_at": "2026-02-24T10:00:00Z",
      "updated_at": "2026-02-24T09:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 50,
    "total": 3,
    "total_pages": 1
  },
  "request_id": "a1b2c3d4e5f6"
}

Automate reordering

Poll the low-stock endpoint on a schedule to detect items that need reordering. Combine it with the reorder_quantity field to know how much to order.


Error responses

See Error codes for the full reference. These errors can occur on any Inventory API endpoint:

HTTP code Error Description
400 invalid_json Request body contains malformed JSON
400 validation_failed Missing required fields or invalid values
401 unauthorized Missing or invalid API key
403 forbidden IP address is not whitelisted for this API key
403 feature_not_available Enterprise plan with Inventory feature required
403 insufficient_scope API key lacks the required scope for this endpoint
404 not_found Requested resource does not exist
405 method_not_allowed HTTP method not supported (only GET, POST, PUT, and PATCH are available)
429 rate_limit_exceeded Rate limit exceeded — check the Retry-After header
500 internal_error Unexpected server error

Include the request ID in support tickets

Every response includes a request_id field. Include this value when contacting support so we can quickly trace the issue.