Developer API Documentation

Integrate Inventory Now with your own applications, automations, and third-party services.

Getting Started

Step 1: Create an API Key

  1. Sign in to the web app as the account owner (subusers cannot manage API keys).
  2. Click Manage API Keys below (or navigate to the API Keys page).
  3. Enter a descriptive title (e.g. "Zapier Integration") and click Generate Key.
  4. Copy the full key immediately. It is shown only once.

Manage API Keys

Your key will look like: inv_api_a1b2c3d4e5f67890_aBcDeFgHiJkLmNoPqRsTuVwXyZ...

Step 2: Make Requests

Include your key in the Authorization header as a Bearer token. JSON responses are automatic when using an API key — no need to set Content-Type or Accept headers.

curl -X GET "https://www.inventorynow.app/items" \
  -H "Authorization: Bearer YOUR_API_KEY"

Step 3: Handle Responses

All successful responses return JSON. Errors return a JSON object with an error or success: false field and an appropriate HTTP status code.

Status CodeMeaning
200Success
400Bad request / validation error
403Unauthorized / invalid or revoked API key
404Resource not found
500Server error

Items

GET /items

Returns a paginated list of your inventory items.

Query Parameters
ParamTypeDescription
pageIntegerPage number (default: 1)
per_pageIntegerItems per page (default: 50)
searchStringSearch across name, category, subcategory, location, notes, barcode, SKU
categoryStringFilter by exact category (case-insensitive)
subcategoryStringFilter by exact subcategory (case-insensitive)
locationStringFilter by exact location (case-insensitive)
from_dateDateFilter items with date on or after this value
to_dateDateFilter items with date on or before this value
sortStringSort field: name, category, subcategory, place, updated_at, created_at, bought, sold, cost, paid (default: updated_at)
dirStringasc or desc (default: desc)
Response

Array of item objects:

[
  {
    "id": 123,
    "name": "Widget A",
    "category": "Electronics",
    "subcategory": "Adapters",
    "place": "Warehouse 1",
    "notes": "Fragile, handle with care",
    "barcode": "1234567890",
    "sku": "WIDGET-A",
    "internal_id": "abc-def-123",
    "data_set": null,
    "date": "2025-06-01T00:00:00.000Z",
    "bought": 100.0,
    "sold": 25.0,
    "received": 100.0,
    "shipped": 25.0,
    "delivered": 25.0,
    "loss": 2.0,
    "cost": 500.0,
    "paid": 750.0,
    "unit_cost_buy": 5.0,
    "unit_cost_sell": 30.0,
    "low_stock_threshold": 10.0,
    "complete": false,
    "completed_at": null,
    "deleted": false,
    "image_name": "https://example.com/photo.jpg",
    "custom_one": "Color: Red",
    "custom_two": "Size: Large",
    "custom_three": null,
    "created_at": "2025-06-01T12:00:00.000Z",
    "updated_at": "2025-06-15T08:30:00.000Z"
  }
]

GET /items/:id

Returns a single item by ID, including its photos.

Response
{
  "id": 123,
  "name": "Widget A",
  ... (same fields as above),
  "item_photos": [
    {
      "id": 1,
      "item_id": 123,
      "external_image_url": "https://example.com/photo.jpg",
      "order_index": 0,
      "created_at": "2025-06-01T12:00:00.000Z",
      "updated_at": "2025-06-01T12:00:00.000Z"
    }
  ]
}

POST /items

Creates a new inventory item. If an item with the same internal_id already exists, it will be updated instead.

⚠️ Note: Avoid updating stock counts (bought, sold, cost, paid) directly through this endpoint. Changes made here do not create order records, which means your order history and reports will be inaccurate. Use the Buy & Sell Order endpoints below to modify stock properly.
Request Body
FieldTypeRequiredDescription
nameStringNo*Item name (*auto-generated if blank)
categoryStringNoCategory grouping
subcategoryStringNoSubcategory grouping
placeStringNoStorage location
notesStringNoFree-text notes
barcodeStringNoBarcode / UPC value
skuStringNoSKU identifier
internal_idStringNoYour unique ID (used for upsert matching)
data_setStringNoDataset name (for multi-dataset accounts)
dateDateTimeNoItem date (e.g. purchase date)
boughtDecimalNoQuantity purchased (default: 0)
soldDecimalNoQuantity sold (default: 0)
receivedDecimalNoQuantity received (default: 0)
shippedDecimalNoQuantity shipped (default: 0)
deliveredDecimalNoQuantity delivered (default: 0)
lossDecimalNoQuantity lost / shrinkage (default: 0)
costDecimalNoTotal cost paid for stock (default: 0)
paidDecimalNoTotal revenue received from sales (default: 0)
unit_cost_buyDecimalNoDefault unit purchase cost
unit_cost_sellDecimalNoDefault unit sale price
low_stock_thresholdDecimalNoPer-item low-stock alert threshold
completeBooleanNoWhether item is marked complete
image_nameStringNoPrimary image URL
custom_oneStringNoCustom field 1
custom_twoStringNoCustom field 2
custom_threeStringNoCustom field 3
Example
curl -X POST "https://www.inventorynow.app/items" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "item": {
      "name": "Widget A",
      "sku": "WIDGET-A",
      "category": "Electronics",
      "place": "Warehouse 1",
      "bought": 100,
      "cost": 500.00,
      "unit_cost_buy": 5.00,
      "unit_cost_sell": 30.00
    }
  }'
Response

Returns the created item object (same shape as GET /items/:id, without item_photos).


PUT /items/:id

Updates an existing item. Only the fields you include in the request body will be changed.

⚠️ Note: Avoid updating stock counts (bought, sold, cost, paid) directly through this endpoint. Changes made here do not create order records, which means your order history and reports will be inaccurate. Use the Buy & Sell Order endpoints below to modify stock properly.
Request Body

Same fields as POST /items (all optional). Wrap in an "item" key.

Example
curl -X PUT "https://www.inventorynow.app/items/123" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "item": {
      "sold": 30,
      "paid": 900.00,
      "notes": "Restocked on June 20"
    }
  }'
Response

Returns the updated item object.


DELETE /items/:id

Soft-deletes an item (sets deleted: true). The item will no longer appear in lists.

Response
{ "result": "success" }

PUT /items/:id/move

Moves a quantity of stock to a different location. If an item with the same name/category/subcategory exists at the target location, it merges. Otherwise, a new item is created.

Request Body
FieldTypeRequiredDescription
locationStringYesTarget location name
quantityDecimalYesQuantity to move
move_costsBooleanNoWhether to move proportional costs

GET /items/summary

Returns a summary of your inventory metrics.

Response
{
  "sum": 1234
}

The sum value is a computed aggregate of (bought − sold − cost + paid + 1) across all non-deleted items.

Orders (Buy & Sell)

Orders represent purchase (buy) and sale (sell) transactions against your items.

GET /orders

Returns a paginated list of orders (excludes cancelled).

Query Parameters
ParamTypeDescription
pageIntegerPage number (default: 1)
order_typeStringFilter by buy or sell
item_idIntegerFilter orders containing this item
assigned_user_idIntegerFilter by assigned fulfillment user
searchStringSearch across item names, categories, locations, customer info
Response
[
  {
    "id": 456,
    "order_type": "sell",
    "notes": "Shipped via FedEx",
    "customer_info": "Jane Doe, 123 Main St",
    "tax_rate": 8.25,
    "discount_rate": 0.0,
    "fees": 5.0,
    "paid": true,
    "cancelled": false,
    "completed_at": "2025-06-15T14:00:00.000Z",
    "user_id": 1,
    "created_by_user_id": 1,
    "assigned_user_id": null,
    "created_at": "2025-06-15T12:00:00.000Z",
    "updated_at": "2025-06-15T14:00:00.000Z",
    "order_items": [
      {
        "id": 789,
        "order_id": 456,
        "item_id": 123,
        "quantity": 5.0,
        "cost": 150.0,
        "item_name": "Widget A",
        "item": { "id": 123, "name": "Widget A", ... }
      }
    ],
    "created_by_user": { "id": 1, "username": "owner", ... },
    "assigned_user": null
  }
]

GET /orders/:id

Returns a single order with its line items, related items, and assigned user.

Response

Same shape as a single element from the list above.


📦 Stock Adjustment

When using an API key, creating an order automatically updates item stock counts — incrementing bought/cost for buy orders, or sold/paid for sell orders. You can disable this by passing ?adjust_item=false.

To explicitly control: POST /orders?adjust_item=true or POST /orders?adjust_item=false

POST /items/:item_id/orders — Buy Order

Creates a buy (purchase) order for the specified item. This records that you are purchasing stock.

Request Body
FieldTypeRequiredDescription
order[order_type]StringYesMust be "buy"
order[notes]StringNoOrder notes
order[customer_info]StringNoSupplier / vendor info
order[tax_rate]DecimalNoTax rate as percentage (e.g. 8.25)
order[discount_rate]DecimalNoDiscount rate as percentage
order[fees]DecimalNoAdditional fees
order[order_items_attributes]ArrayYesLine items (see below)
Order Item Fields
FieldTypeRequiredDescription
item_idIntegerYesID of the item being purchased
quantityDecimalYesQuantity to purchase (must be > 0)
costDecimalNoTotal cost for this line (defaults to quantity × item's unit_cost_buy)
Example
curl -X POST "https://www.inventorynow.app/items/123/orders" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "order": {
      "order_type": "buy",
      "notes": "Restocking from supplier",
      "order_items_attributes": [
        { "item_id": 123, "quantity": 50, "cost": 250.00 }
      ]
    }
  }'
Response

Returns the created order object (same shape as GET /orders/:id).


POST /items/:item_id/orders — Sell Order

Creates a sell (sale) order for the specified item. This records a sale of stock to a customer.

Request Body

Same structure as the buy order, but set order_type to "sell". The cost defaults to quantity × item's unit_cost_sell if omitted.

Example
curl -X POST "https://www.inventorynow.app/items/123/orders" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "order": {
      "order_type": "sell",
      "customer_info": "Jane Doe, jane@example.com",
      "tax_rate": 8.25,
      "order_items_attributes": [
        { "item_id": 123, "quantity": 10, "cost": 300.00 }
      ]
    }
  }'

POST /orders — Multi-Item Order

Create an order with multiple items in a single request. Works for both buy and sell orders.

Example
curl -X POST "https://www.inventorynow.app/orders" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "order": {
      "order_type": "sell",
      "customer_info": "Acme Corp",
      "tax_rate": 7.0,
      "discount_rate": 5.0,
      "fees": 10.00,
      "order_items_attributes": [
        { "item_id": 123, "quantity": 5, "cost": 150.00 },
        { "item_id": 456, "quantity": 3, "cost": 90.00 }
      ]
    }
  }'

PUT /orders/:id/complete

Marks an order as completed and paid. Updates lifecycle tracking fields if enabled in your settings (e.g. increments received for buy orders when "Track Received" is on, or shipped for sell orders when "Track Shipped" is on).

Response

Returns the updated order object.


PUT /orders/:id/cancel

Cancels an order and reverses any stock adjustments that were made.

Response

Returns the cancelled order object.

Order Items

Add or remove individual line items from an existing order. The order must not be completed or cancelled.

📦 Stock Adjustment

When using an API key, adding or removing order items automatically updates item stock counts by default. Pass ?adjust_item=false to disable.

POST /order_items

Adds a line item to an existing order.

Request Body
FieldTypeRequiredDescription
order_idIntegerYesID of the order to add the item to
item_idIntegerYesID of the item
quantityDecimalYesQuantity (must be > 0)
costDecimalNoTotal cost for this line (defaults to quantity × item's unit cost)
Query Parameters
ParamTypeDescription
adjust_itemBooleanOverride stock adjustment (default: true for API key auth)
Example
curl -X POST "https://www.inventorynow.app/order_items" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "order_id": 456,
    "item_id": 123,
    "quantity": 5,
    "cost": 75.00
  }'
Response
{
  "id": 890,
  "order_id": 456,
  "item_id": 123,
  "quantity": 5.0,
  "cost": 75.0,
  "item_name": "Widget A",
  "item": { "id": 123, "name": "Widget A", ... }
}

DELETE /order_items/:id

Removes a line item from its order. If it was the last item, the order is also deleted.

Query Parameters
ParamTypeDescription
adjust_itemBooleanOverride stock reversal (default: true for API key auth)
Example
curl -X DELETE "https://www.inventorynow.app/order_items/890" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response
{
  "success": true
}

If the deleted item was the last on the order, the order is also destroyed and the response reflects that.

User Settings

GET /user_settings

Returns your account settings (currency, labels, lifecycle toggles, etc.).

Response
{
  "id": 1,
  "user_id": 1,
  "category_name": "Category",
  "subcategory_name": "Subcategory",
  "location_name": "Location",
  "currency_symbol": "$",
  "low_stock_threshold": 5.0,
  "received_status_enabled": true,
  "shipped_status_enabled": true,
  "delivered_status_enabled": false,
  "back_orders_enabled": false,
  "auto_complete_enabled": false,
  "check_in_status_enabled": false,
  "track_loss": true,
  "hide_complete": false,
  "custom_one_name": "Color",
  "custom_two_name": "Size",
  "custom_three_name": null,
  "company_name": "Acme Inc",
  "company_info": "123 Main St, Springfield",
  "invoice_info": "Thank you for your business!",
  "data_set": null,
  ...
}

PUT /user_settings

Updates your account settings. Only include the fields you want to change.

Request Body
{
  "user_setting": {
    "currency_symbol": "€",
    "low_stock_threshold": 10,
    "custom_one_name": "Material"
  }
}

Error Responses

All errors return a JSON object. The format varies slightly by endpoint but will always include an error indicator:

// Validation / bad request (400)
{ "success": false, "error": "Invalid Quantity Entered." }

// Unauthorized (403)
{ "result": "failure. invalid permissions" }

// Server error (500)
{ "error": "Something went wrong" }

JavaScript / Fetch Example

const API_KEY = "inv_api_your_key_here";
const BASE_URL = "https://www.inventorynow.app";

// List items
const items = await fetch(`${BASE_URL}/items?page=1`, {
  headers: { "Authorization": `Bearer ${API_KEY}` }
}).then(r => r.json());

// Create a sell order (stock adjustment is automatic with API keys)
const order = await fetch(`${BASE_URL}/orders`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${API_KEY}`
  },
  body: JSON.stringify({
    order: {
      order_type: "sell",
      customer_info: "Jane Doe",
      order_items_attributes: [
        { item_id: items[0].id, quantity: 2, cost: 60.00 }
      ]
    }
  })
}).then(r => r.json());