Search inventory items and folders, low-stock alerts, jobs and purchase orders, and update stock.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Create a stock alert on an item (type Quantity, e.g. threshold_method quantity_less_than with threshold_value 5, or less_than_or_equal_to_min_quantity), or a DateReminder on a datetime custom field (custom_attribute_id + before/after/same_day + threshold_interval). WRITE. Sortly: POST /api/v1/alerts.
Quantity = stock threshold; DateReminder = date custom field.
The item the alert watches.
What triggers it: a quantity_* method for Quantity, before/after/same_day for DateReminder.
The number compared against (or the interval count).
Who is notified: owners, admins, members, limited, or a custom role name. Default owners.
Required for DateReminder; omit for Quantity.
For DateReminder: the datetime custom field to watch.
The server marks this tool as destructive. Running it may delete or overwrite data on the server or in any account you connected with your headers.
Create a stock alert on an item (type Quantity, e.g. threshold_method quantity_less_than with threshold_value 5, or less_than_or_equal_to_min_quantity), or a DateReminder on a datetime custom field (custom_attribute_id + before/after/same_day + threshold_interval). WRITE. Sortly: POST /api/v1/alerts.
| Argument | Type | Description |
|---|---|---|
| type* | string | Quantity = stock threshold; DateReminder = date custom field. |
| item_id* | integer | The item the alert watches. |
| threshold_value | number | The number compared against (or the interval count). |
| recipient_groups | array | Who is notified: owners, admins, members, limited, or a custom role name. Default owners. |
| threshold_method* | string | What triggers it: a quantity_* method for Quantity, before/after/same_day for DateReminder. |
| threshold_interval | string | Required for DateReminder; omit for Quantity. |
| custom_attribute_id | integer | For DateReminder: the datetime custom field to watch. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"item_id",
"type",
"threshold_method"
],
"properties": {
"type": {
"enum": [
"Quantity",
"DateReminder"
],
"type": "string",
"description": "Quantity = stock threshold; DateReminder = date custom field."
},
"item_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The item the alert watches.",
"exclusiveMinimum": 0
},
"threshold_value": {
"type": "number",
"description": "The number compared against (or the interval count)."
},
"recipient_groups": {
"type": "array",
"items": {
"type": "string"
},
"description": "Who is notified: owners, admins, members, limited, or a custom role name. Default owners."
},
"threshold_method": {
"enum": [
"less_than_or_equal_to_min_quantity",
"quantity_greater_than",
"quantity_less_than",
"quantity_less_than_equal_to",
"quantity_greater_than_equal_to",
"before",
"after",
"same_day"
],
"type": "string",
"description": "What triggers it: a quantity_* method for Quantity, before/after/same_day for DateReminder."
},
"threshold_interval": {
"enum": [
"days",
"weeks",
"months",
"years"
],
"type": "string",
"description": "Required for DateReminder; omit for Quantity."
},
"custom_attribute_id": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "For DateReminder: the datetime custom field to watch."
}
}
}Create a trackable item (type item) or a folder (type folder), optionally inside a folder via parent_id, with quantity, price, tags, custom fields, barcodes and a measured quantity. WRITE. Sortly: POST /api/v1/items.
| Argument | Type | Description |
|---|---|---|
| name* | string | Name, max 190 characters. |
| tags | array | Tag names, e.g. ["furniture", "used"]. |
| type* | string | item = trackable stock; folder = a container. |
| notes | string | null | Free-text notes. |
| price | number | null | Unit price. |
| quantity | number | null | How many you have. |
| label_url | string | null | Value encoded in the primary QR code / barcode. |
| parent_id | any | Folder to create it in. Omit/null = root. |
| photo_ids | array | Ids of photos already in the account to attach. |
Create a job (and its job folder) in not_started status. Name must be unique in the company. Then use sortly_pull_items_into_job to record the stock it uses. WRITE. Sortly: POST /api/v1/jobs.
| Argument | Type | Description |
|---|---|---|
| name* | string | Unique job name, max 190 characters. |
| notes | string | Job notes, max 4000 characters. |
| end_date | string | YYYY-MM-DD. |
| start_date | string | YYYY-MM-DD. |
| subfolders | array | Subfolder names to create, up to 25. |
| external_job_link | string | Link to the job in another system. |
| custom_field_values | array | Up to 2 job custom field values. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"name"
],
"properties": {
"name": {
"type": "string",
"maxLength": 190,
"minLength": 1,
"description": "Unique job name, max 190 characters."
},
"notes": {
"type": "string",
"maxLength": 4000,
"description": "Job notes, max 4000 characters."
},
"end_date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "YYYY-MM-DD."
},
"start_date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "YYYY-MM-DD."
},
"subfolders": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"maxItems": 25,
"description": "Subfolder names to create, up to 25."
},
"external_job_link": {
"type": "string",
"format": "uri",
"description": "Link to the job in another system."
},
"custom_field_values": {
"type": "array",
"items": {
"type": "object",
"required": [
"custom_field_id",
"value"
],
"properties": {
"value": {
"type": "string",
"maxLength": 191,
"description": "Value, max 191 characters."
},
"custom_field_id": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Job custom field id."
}
}
},
"maxItems": 2,
"description": "Up to 2 job custom field values."
}
}
}Create a purchase order in draft status (no stock or ordering happens until it is moved on in Sortly). Sortly computes amounts, sub_total and total from the lines; omit purchase_order_number to have one generated. Needs Purchase Orders on the plan (else 402). WRITE. Sortly: POST /api/v1/purchase_orders.
| Argument | Type | Description |
|---|---|---|
| notes | string | |
| terms | string | e.g. Net 30. |
| vendor | object | The vendor, captured on the PO. |
| bill_to | object | Billing address. |
| charges | object | Order-level charges; each defaults to 0. |
| ship_to | object | Shipping address. |
| line_items | array | Up to 100 lines. |
| currency_code* | string | ISO 4217 code, e.g. USD. |
| purchase_order_number | string | Unique PO number, max 20 chars. Omit to auto-generate. |
Fetch a single item or folder by numeric id: quantity, min_quantity, price, tags, sid, barcodes, and optionally custom field values and photos. Sortly: GET /api/v1/items/{item_id}.
| Argument | Type | Description |
|---|---|---|
| include | array | Nested associations to embed: custom_attributes and/or photos. |
| item_id* | integer | The item's or folder's numeric id. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"item_id"
],
"properties": {
"include": {
"type": "array",
"items": {
"enum": [
"custom_attributes",
"photos"
],
"type": "string"
},
"description": "Nested associations to embed: custom_attributes and/or photos."
},
"item_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The item's or folder's numeric id.",
"exclusiveMinimum": 0
}
}
}Fetch a single job: status, folder_id (where its pulled items sit), dates, notes, custom field values and the version needed for updates. Sortly: GET /api/v1/jobs/{job_id}.
| Argument | Type | Description |
|---|---|---|
| job_id* | integer | The job's id. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"job_id"
],
"properties": {
"job_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The job's id.",
"exclusiveMinimum": 0
}
}
}Fetch a single purchase order with its line_items (quantity vs received_quantity), vendor, addresses, charges, totals and version. Sortly: GET /api/v1/purchase_orders/{purchase_order_id}.
| Argument | Type | Description |
|---|---|---|
| purchase_order_id* | integer | The purchase order's id. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"purchase_order_id"
],
"properties": {
"purchase_order_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The purchase order's id.",
"exclusiveMinimum": 0
}
}
}Report the most recent receive against a purchase order: pending / completed / failed, with the line ids received, pending and failed (and why). Returns 404 until something has been received. Sortly: GET /api/v1/purchase_orders/{purchase_order_id}/receive/status.
| Argument | Type | Description |
|---|---|---|
| purchase_order_id* | integer | The purchase order's id. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"purchase_order_id"
],
"properties": {
"purchase_order_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The purchase order's id.",
"exclusiveMinimum": 0
}
}
}List stock (Quantity) and date (DateReminder) alerts, with is_fired showing which have already triggered — the quick way to find low-stock items. Sortly: GET /api/v1/alerts.
| Argument | Type | Description |
|---|---|---|
| page | integer | Page number, starting at 1. |
| per_page | integer | Page size (default 10). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number, starting at 1."
},
"per_page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page size (default 10)."
}
}
}List the account's custom fields (id, name, type, applies_to). Call this before writing custom_attribute_values to get the right custom_attribute_id. Sortly: GET /api/v1/custom_fields.
| Argument | Type | Description |
|---|---|---|
| page | integer | Page number, starting at 1. |
| per_page | integer | Page size (default 10). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number, starting at 1."
},
"per_page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page size (default 10)."
}
}
}List items and folders, newest first. By default the root level; pass folder_id for a folder's direct contents, plus include_subfolders for everything nested under it. Paginated via meta.next_page_url / total_pages. Sortly: GET /api/v1/items.
| Argument | Type | Description |
|---|---|---|
| page | integer | Page number, starting at 1. |
| include | array | Nested associations to embed: custom_attributes and/or photos. |
| per_page | integer | Page size, 1-1000 (default 10). |
| folder_id | integer | Only the direct contents of this folder. Omit for the root level. |
| include_subfolders | boolean | With folder_id: also return everything nested beneath it. Default false. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number, starting at 1."
},
"include": {
"type": "array",
"items": {
"enum": [
"custom_attributes",
"photos"
],
"type": "string"
},
"description": "Nested associations to embed: custom_attributes and/or photos."
},
"per_page": {
"type": "integer",
"maximum": 1000,
"minimum": 1,
"description": "Page size, 1-1000 (default 10)."
},
"folder_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Only the direct contents of this folder. Omit for the root level.",
"exclusiveMinimum": 0
},
"include_subfolders": {
"type": "boolean",
"description": "With folder_id: also return everything nested beneath it. Default false."
}
}
}List jobs (work orders that pull stock out), most recently updated first, filterable by name prefix and status. Paginated via meta.pagination.has_next. Sortly: GET /api/v1/jobs.
| Argument | Type | Description |
|---|---|---|
| name | string | Jobs whose name starts with this (case-insensitive). |
| page | integer | Page number, starting at 1. |
| status | array | Only these statuses. Default all. |
| sort_by | string | Sort field. Default updated_at. |
| per_page | integer | Page size, 1-100 (default 20). |
| sort_direction | string | Default desc. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"name": {
"type": "string",
"description": "Jobs whose name starts with this (case-insensitive)."
},
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number, starting at 1."
},
"status": {
"type": "array",
"items": {
"enum": [
"not_started",
"in_progress",
"completed"
],
"type": "string"
},
"description": "Only these statuses. Default all."
},
"sort_by": {
"enum": [
"name",
"status",
"start_date",
"end_date",
"created_by_name",
"updated_at"
],
"type": "string",
"description": "Sort field. Default updated_at."
},
"per_page": {
"type": "integer",
"maximum": 100,
"minimum": 1,
"description": "Page size, 1-100 (default 20)."
},
"sort_direction": {
"enum": [
"asc",
"desc"
],
"type": "string",
"description": "Default desc."
}
}
}List purchase orders, most recently updated first, filterable by PO number and status. The list leaves out notes, terms, sub_total and line_items — use sortly_get_purchase_order for those. Needs Purchase Orders on the plan (else 402). Sortly: GET /api/v1/purchase_orders.
| Argument | Type | Description |
|---|---|---|
| page | integer | Page number, starting at 1. |
| status | array | Only these statuses. Default all. |
| sort_by | string | Sort field. Default updated_at. |
| per_page | integer | Page size, 1-100 (default 20). |
| sort_direction | string | Default desc. |
| purchase_order_number | string | POs whose number contains this. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number, starting at 1."
},
"status": {
"type": "array",
"items": {
"enum": [
"draft",
"ready_for_review",
"approved",
"ordered",
"partially_received",
"received",
"voided",
"closed"
],
"type": "string"
},
"description": "Only these statuses. Default all."
},
"sort_by": {
"enum": [
"purchase_order_number",
"created_by",
"submitted_by",
"status",
"updated_at",
"total",
"ordered_date",
"expected_delivery_date",
"received_date"
],
"type": "string",
"description": "Sort field. Default updated_at."
},
"per_page": {
"type": "integer",
"maximum": 100,
"minimum": 1,
"description": "Page size, 1-100 (default 20)."
},
"sort_direction": {
"enum": [
"asc",
"desc"
],
"type": "string",
"description": "Default desc."
},
"purchase_order_number": {
"type": "string",
"description": "POs whose number contains this."
}
}
}List items and folders changed since a Unix timestamp — the incremental-sync read ('what moved since yesterday?'). Without updated_since it behaves like sortly_list_items. Sortly: GET /api/v1/items/recent.
| Argument | Type | Description |
|---|---|---|
| page | integer | Page number, starting at 1. |
| include | array | Nested associations to embed: custom_attributes and/or photos. |
| per_page | integer | Page size, 1-100 (default 10). |
| folder_id | integer | Only the direct contents of this folder. Omit for the root level. |
| updated_since | integer | Unix epoch seconds; only items updated after this. |
| include_subfolders | boolean | With folder_id: also return everything nested beneath it. Default false. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number, starting at 1."
},
"include": {
"type": "array",
"items": {
"enum": [
"custom_attributes",
"photos"
],
"type": "string"
},
"description": "Nested associations to embed: custom_attributes and/or photos."
},
"per_page": {
"type": "integer",
"maximum": 100,
"minimum": 1,
"description": "Page size, 1-100 (default 10)."
},
"folder_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Only the direct contents of this folder. Omit for the root level.",
"exclusiveMinimum": 0
},
"updated_since": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 0,
"description": "Unix epoch seconds; only items updated after this."
},
"include_subfolders": {
"type": "boolean",
"description": "With folder_id: also return everything nested beneath it. Default false."
}
}
}List the units of measure available to the account (unit_name, unit_type, scale) — the values measured_quantity and purchase-order lines expect. Sortly: GET /api/v1/units.
No arguments.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {}
}Move some or all of an item's quantity to another folder (items only — relocate a folder with sortly_update_item parent_id). A partial move splits off a new item with the same sid; a full move relocates the item; a matching item at the destination is merged, and the returned id is the destination's. Undo by moving it back. WRITE. Sortly: POST /api/v1/items/{item_id}/move.
| Argument | Type | Description |
|---|---|---|
| item_id* | integer | The item's numeric id. |
| quantity* | number | How much to move. |
| folder_id | integer | Destination folder. Omit to move to the root level. |
| leave_zero_quantity | boolean | Keep a zero-quantity record in the source folder. Default false. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"item_id",
"quantity"
],
"properties": {
"item_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The item's numeric id.",
"exclusiveMinimum": 0
},
"quantity": {
"type": "number",
"description": "How much to move.",
"exclusiveMinimum": 0
},
"folder_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Destination folder. Omit to move to the root level.",
"exclusiveMinimum": 0
},
"leave_zero_quantity": {
"type": "boolean",
"description": "Keep a zero-quantity record in the source folder. Default false."
}
}
}Move quantities of existing items (from any folders) into a job's folder — how usage on a job is recorded. Up to 100 items per call; items are processed independently, so ALWAYS check data.errors (a partial failure still returns 200). Undo with sortly_return_items_from_job. Returns 403 on a completed job. WRITE. Sortly: POST /api/v1/jobs/{job_id}/items.
| Argument | Type | Description |
|---|---|---|
| items* | array | 1-100 items. |
| notes | string | Optional note kept in each item's history. |
| job_id* | integer | The job's id. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"job_id",
"items"
],
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"required": [
"item_id",
"quantity"
],
"properties": {
"item_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Item to move onto the job.",
"exclusiveMinimum": 0
},
"quantity": {
"type": "number",
"description": "Quantity to move.",
"exclusiveMinimum": 0
},
"item_version": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Version from the last read of the item; stale is rejected."
},
"leave_zero_quantity": {
"type": "boolean",
"description": "Keep a zero-quantity copy in the original folder."
}
}
},
"maxItems": 100,
"minItems": 1,
"description": "1-100 items."
},
"notes": {
"type": "string",
"description": "Optional note kept in each item's history."
},
"job_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The job's id.",
"exclusiveMinimum": 0
}
}
}Move items off a job's folder back into inventory (destination_folder_id, or All Items if omitted). Up to 100 per call; check data.errors — items are processed one by one. WRITE. Sortly: POST /api/v1/jobs/{job_id}/items/return.
| Argument | Type | Description |
|---|---|---|
| items* | array | 1-100 items. |
| notes | string | Optional note recorded in the item's history. |
| job_id* | integer | The job's id. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"job_id",
"items"
],
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"required": [
"item_id",
"quantity"
],
"properties": {
"item_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Item on the job to move off it.",
"exclusiveMinimum": 0
},
"quantity": {
"type": "number",
"description": "Quantity to return.",
"exclusiveMinimum": 0
},
"item_version": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Version from the last read of the item; stale is rejected."
},
"leave_zero_quantity": {
"type": "boolean",
"description": "Keep a zero-quantity copy in the job's folder."
},
"destination_folder_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Folder to return it to; omit for All Items.",
"exclusiveMinimum": 0
}
}
},
"maxItems": 100,
"minItems": 1,
"description": "1-100 items."
},
"notes": {
"type": "string",
"description": "Optional note recorded in the item's history."
},
"job_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The job's id.",
"exclusiveMinimum": 0
}
}
}Search items and folders by name, optionally limited to items or folders and scoped to specific folders. Read-only despite being a POST. Paginated: send the same arguments with the next page number. Sortly: POST /api/v1/items/search.
| Argument | Type | Description |
|---|---|---|
| name | string | Name (or part of it) to search for. |
| page | integer | Page number, starting at 1. |
| sort | string | Sort by name, ascending or descending. |
| type | string | Limit to items or folders. Default all. |
| include | array | Nested associations to embed: custom_attributes and/or photos. |
| per_page | integer | Page size, 1-100 (default 100). |
| folder_ids | array | Only search in these folders. |
| include_subfolders | boolean | With folder_ids: also search folders nested under them. Default false. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"name": {
"type": "string",
"maxLength": 190,
"description": "Name (or part of it) to search for."
},
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number, starting at 1."
},
"sort": {
"enum": [
"asc",
"desc"
],
"type": "string",
"description": "Sort by name, ascending or descending."
},
"type": {
"enum": [
"all",
"item",
"folder"
],
"type": "string",
"description": "Limit to items or folders. Default all."
},
"include": {
"type": "array",
"items": {
"enum": [
"custom_attributes",
"photos"
],
"type": "string"
},
"description": "Nested associations to embed: custom_attributes and/or photos."
},
"per_page": {
"type": "integer",
"maximum": 100,
"minimum": 1,
"description": "Page size, 1-100 (default 100)."
},
"folder_ids": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
"description": "Only search in these folders."
},
"include_subfolders": {
"type": "boolean",
"description": "With folder_ids: also search folders nested under them. Default false."
}
}
}Change fields on an existing item or folder — e.g. set a new quantity after a stock count, rename it, or relocate a folder via parent_id. Only the fields you pass change; pass null to clear a nullable field. Sending tags or custom_attribute_values replaces them. WRITE. Sortly: PUT /api/v1/items/{item_id} (returns 204).
| Argument | Type | Description |
|---|---|---|
| name | string | New name. |
| tags | array | Tag names, e.g. ["furniture", "used"]. |
| notes | string | null | Free-text notes. |
| price | number | null | Unit price. |
| item_id* | integer | The item's or folder's numeric id. |
| quantity | number | null | How many you have. |
| label_url | string | null | Value encoded in the primary QR code / barcode. |
| parent_id | any | Move into this folder (null = root). To move PART of an item's stock use sortly_move_item. |
| photo_ids |
| min_quantity | number | null | Minimum level; a Quantity alert can fire when stock reaches it. |
| label_url_type | any | Symbology of the primary code. |
| label_url_extra | string | null | Value encoded in the secondary code. |
| measured_quantity | object | For items measured in something other than units. |
| label_url_extra_type | any | Symbology of the secondary code. |
| custom_attribute_values | array | Custom field values. Look up ids with sortly_list_custom_fields first. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"name",
"type"
],
"properties": {
"name": {
"type": "string",
"maxLength": 190,
"minLength": 1,
"description": "Name, max 190 characters."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Tag names, e.g. [\"furniture\", \"used\"]."
},
"type": {
"enum": [
"item",
"folder"
],
"type": "string",
"description": "item = trackable stock; folder = a container."
},
"notes": {
"type": [
"string",
"null"
],
"description": "Free-text notes."
},
"price": {
"type": [
"number",
"null"
],
"description": "Unit price."
},
"quantity": {
"type": [
"number",
"null"
],
"description": "How many you have."
},
"label_url": {
"type": [
"string",
"null"
],
"description": "Value encoded in the primary QR code / barcode."
},
"parent_id": {
"anyOf": [
{
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
{
"type": "null"
}
],
"description": "Folder to create it in. Omit/null = root."
},
"photo_ids": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"description": "Ids of photos already in the account to attach."
},
"min_quantity": {
"type": [
"number",
"null"
],
"description": "Minimum level; a Quantity alert can fire when stock reaches it."
},
"label_url_type": {
"anyOf": [
{
"enum": [
"org.gs1.UPC-E",
"org.iso.Code39",
"org.iso.Code39Mod43",
"org.gs1.EAN-13",
"org.gs1.EAN-8",
"com.intermec.Code93",
"org.iso.Code128",
"org.iso.PDF417",
"org.iso.Aztec",
"org.iso.QRCode",
"org.ansi.Interleaved2of5",
"org.iso.DataMatrix",
"com.sortly.textEntry"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "Symbology of the primary code."
},
"label_url_extra": {
"type": [
"string",
"null"
],
"description": "Value encoded in the secondary code."
},
"measured_quantity": {
"type": "object",
"required": [
"value",
"type",
"name"
],
"properties": {
"name": {
"enum": [
"lbs",
"g",
"kg",
"oz",
"yd",
"cm",
"ft",
"in",
"m",
"gal",
"ml",
"l",
"ft3",
"in3",
"ft2",
"in2",
"units"
],
"type": "string",
"description": "The unit, e.g. kg, ft, l, units (see sortly_list_units)."
},
"type": {
"enum": [
"weight",
"length",
"volume",
"area",
"count"
],
"type": "string",
"description": "Kind of measurement; set on create only."
},
"value": {
"type": "number",
"description": "The measured amount."
}
},
"description": "For items measured in something other than units."
},
"label_url_extra_type": {
"anyOf": [
{
"enum": [
"org.gs1.UPC-E",
"org.iso.Code39",
"org.iso.Code39Mod43",
"org.gs1.EAN-13",
"org.gs1.EAN-8",
"com.intermec.Code93",
"org.iso.Code128",
"org.iso.PDF417",
"org.iso.Aztec",
"org.iso.QRCode",
"org.ansi.Interleaved2of5",
"org.iso.DataMatrix",
"com.sortly.textEntry"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "Symbology of the secondary code."
},
"custom_attribute_values": {
"type": "array",
"items": {
"type": "object",
"required": [
"custom_attribute_id",
"value"
],
"properties": {
"value": {
"type": [
"string",
"null"
],
"description": "Value to store; null clears it."
},
"custom_attribute_id": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Custom field id, from sortly_list_custom_fields."
}
}
},
"description": "Custom field values. Look up ids with sortly_list_custom_fields first."
}
}
}| expected_delivery_date | string | ISO 8601 timestamp, e.g. 2026-08-20T00:00:00Z. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"currency_code"
],
"properties": {
"notes": {
"type": "string",
"maxLength": 4000
},
"terms": {
"type": "string",
"maxLength": 4000,
"description": "e.g. Net 30."
},
"vendor": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"name": {
"type": "string",
"maxLength": 50
},
"email": {
"type": "string",
"maxLength": 190
},
"line1": {
"type": "string"
},
"line2": {
"type": "string"
},
"phone": {
"type": "string",
"maxLength": 22
},
"state": {
"type": "string"
},
"country": {
"type": "string"
},
"zip_code": {
"type": "string"
}
},
"description": "The vendor, captured on the PO."
},
"bill_to": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"name": {
"type": "string"
},
"line1": {
"type": "string"
},
"line2": {
"type": "string"
},
"state": {
"type": "string"
},
"country": {
"type": "string"
},
"zip_code": {
"type": "string"
}
},
"description": "Billing address."
},
"charges": {
"type": "object",
"properties": {
"tax": {
"anyOf": [
{
"type": "string",
"pattern": "^-?\\d+(\\.\\d+)?$"
},
{
"type": "number"
}
],
"description": "A decimal, e.g. \"10\" or \"2.5\"."
},
"discount": {
"anyOf": [
{
"type": "string",
"pattern": "^-?\\d+(\\.\\d+)?$"
},
{
"type": "number"
}
],
"description": "A decimal, e.g. \"10\" or \"2.5\"."
},
"shipping_cost": {
"anyOf": [
{
"type": "string",
"pattern": "^-?\\d+(\\.\\d+)?$"
},
{
"type": "number"
}
],
"description": "A decimal, e.g. \"10\" or \"2.5\"."
}
},
"description": "Order-level charges; each defaults to 0."
},
"ship_to": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"name": {
"type": "string"
},
"line1": {
"type": "string"
},
"line2": {
"type": "string"
},
"state": {
"type": "string"
},
"country": {
"type": "string"
},
"zip_code": {
"type": "string"
}
},
"description": "Shipping address."
},
"line_items": {
"type": "array",
"items": {
"type": "object",
"required": [
"item_id",
"name",
"quantity",
"unit_of_measure"
],
"properties": {
"name": {
"type": "string",
"maxLength": 191,
"minLength": 1,
"description": "Name recorded on the line."
},
"notes": {
"type": "string",
"maxLength": 314
},
"item_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Sortly item to order (must exist).",
"exclusiveMinimum": 0
},
"quantity": {
"anyOf": [
{
"type": "string",
"pattern": "^-?\\d+(\\.\\d+)?$"
},
{
"type": "number"
}
],
"description": "Quantity, e.g. \"10\" or 2.5."
},
"unit_rate": {
"anyOf": [
{
"type": "string",
"pattern": "^-?\\d+(\\.\\d+)?$"
},
{
"type": "number"
}
],
"description": "Price per unit. Omit for an unpriced line."
},
"item_number": {
"type": "string",
"maxLength": 25
},
"unit_of_measure": {
"type": "string",
"description": "Unit abbreviation, e.g. units, ft, kg."
},
"variant_options": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"value"
],
"properties": {
"name": {
"type": "string"
},
"value": {
"type": "string"
}
}
},
"maxItems": 3
}
}
},
"maxItems": 100,
"description": "Up to 100 lines."
},
"currency_code": {
"type": "string",
"maxLength": 3,
"minLength": 3,
"description": "ISO 4217 code, e.g. USD."
},
"purchase_order_number": {
"type": "string",
"maxLength": 20,
"description": "Unique PO number, max 20 chars. Omit to auto-generate."
},
"expected_delivery_date": {
"type": "string",
"description": "ISO 8601 timestamp, e.g. 2026-08-20T00:00:00Z."
}
}
}| array |
| Ids of photos already in the account to attach. |
| min_quantity | number | null | Minimum level; a Quantity alert can fire when stock reaches it. |
| label_url_type | any | Symbology of the primary code. |
| label_url_extra | string | null | Value encoded in the secondary code. |
| measured_quantity | object | New measured amount for a measured item. |
| label_url_extra_type | any | Symbology of the secondary code. |
| custom_attribute_values | array | Custom field values. Look up ids with sortly_list_custom_fields first. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"item_id"
],
"properties": {
"name": {
"type": "string",
"maxLength": 190,
"minLength": 1,
"description": "New name."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Tag names, e.g. [\"furniture\", \"used\"]."
},
"notes": {
"type": [
"string",
"null"
],
"description": "Free-text notes."
},
"price": {
"type": [
"number",
"null"
],
"description": "Unit price."
},
"item_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The item's or folder's numeric id.",
"exclusiveMinimum": 0
},
"quantity": {
"type": [
"number",
"null"
],
"description": "How many you have."
},
"label_url": {
"type": [
"string",
"null"
],
"description": "Value encoded in the primary QR code / barcode."
},
"parent_id": {
"anyOf": [
{
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
{
"type": "null"
}
],
"description": "Move into this folder (null = root). To move PART of an item's stock use sortly_move_item."
},
"photo_ids": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"description": "Ids of photos already in the account to attach."
},
"min_quantity": {
"type": [
"number",
"null"
],
"description": "Minimum level; a Quantity alert can fire when stock reaches it."
},
"label_url_type": {
"anyOf": [
{
"enum": [
"org.gs1.UPC-E",
"org.iso.Code39",
"org.iso.Code39Mod43",
"org.gs1.EAN-13",
"org.gs1.EAN-8",
"com.intermec.Code93",
"org.iso.Code128",
"org.iso.PDF417",
"org.iso.Aztec",
"org.iso.QRCode",
"org.ansi.Interleaved2of5",
"org.iso.DataMatrix",
"com.sortly.textEntry"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "Symbology of the primary code."
},
"label_url_extra": {
"type": [
"string",
"null"
],
"description": "Value encoded in the secondary code."
},
"measured_quantity": {
"type": "object",
"required": [
"value"
],
"properties": {
"value": {
"type": "number",
"description": "The measured amount (the unit is fixed at creation)."
}
},
"description": "New measured amount for a measured item."
},
"label_url_extra_type": {
"anyOf": [
{
"enum": [
"org.gs1.UPC-E",
"org.iso.Code39",
"org.iso.Code39Mod43",
"org.gs1.EAN-13",
"org.gs1.EAN-8",
"com.intermec.Code93",
"org.iso.Code128",
"org.iso.PDF417",
"org.iso.Aztec",
"org.iso.QRCode",
"org.ansi.Interleaved2of5",
"org.iso.DataMatrix",
"com.sortly.textEntry"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "Symbology of the secondary code."
},
"custom_attribute_values": {
"type": "array",
"items": {
"type": "object",
"required": [
"custom_attribute_id",
"value"
],
"properties": {
"value": {
"type": [
"string",
"null"
],
"description": "Value to store; null clears it."
},
"custom_attribute_id": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Custom field id, from sortly_list_custom_fields."
}
}
},
"description": "Custom field values. Look up ids with sortly_list_custom_fields first."
}
}
}