Sortly MCP by usefulapi
Search inventory items and folders, low-stock alerts, jobs and purchase orders, and update stock.
Should I use this
Quality & Safety
Findings (2)
- LOWin sortly_list_recently_updated_items
- LOWin sortly_get_purchase_order_receive_status
Based on automated analysis of tool definitions and protocol compliance.
Context Cost
This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.
Install
One-Click Install
Add this to your `claude_desktop_config.json` file:
{
"mcpServers": {
"sortly": {
"url": "https://sortly.usefulapi.io/mcp"
}
}
}Remote endpoints
https://sortly.usefulapi.io/mcpstreamable-httpWhat it can do
Tool inventory
Tools (20)
🟢sortly_list_items(folder_id, include_subfolders, include, per_page, page)
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.
Input Schema
{
"type": "object",
"properties": {
"folder_id": {
"description": "Only the direct contents of this folder. Omit for the root level.",
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"include_subfolders": {
"description": "With folder_id: also return everything nested beneath it. Default false.",
"type": "boolean"
},
"include": {
"description": "Nested associations to embed: custom_attributes and/or photos.",
"type": "array",
"items": {
"type": "string",
"enum": [
"custom_attributes",
"photos"
]
}
},
"per_page": {
"description": "Page size, 1-1000 (default 10).",
"type": "integer",
"minimum": 1,
"maximum": 1000
},
"page": {
"description": "Page number, starting at 1.",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢sortly_get_item(item_id, include)
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}.
Input Schema
{
"type": "object",
"properties": {
"item_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "The item's or folder's numeric id."
},
"include": {
"description": "Nested associations to embed: custom_attributes and/or photos.",
"type": "array",
"items": {
"type": "string",
"enum": [
"custom_attributes",
"photos"
]
}
}
},
"required": [
"item_id"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢sortly_search_items(name, type, folder_ids, include_subfolders, sort, ...)
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.
Input Schema
{
"type": "object",
"properties": {
"name": {
"description": "Name (or part of it) to search for.",
"type": "string",
"maxLength": 190
},
"type": {
"description": "Limit to items or folders. Default all.",
"type": "string",
"enum": [
"all",
"item",
"folder"
]
},
"folder_ids": {
"description": "Only search in these folders.",
"type": "array",
"items": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
}
},
"include_subfolders": {
"description": "With folder_ids: also search folders nested under them. Default false.",
"type": "boolean"
},
"sort": {
"description": "Sort by name, ascending or descending.",
"type": "string",
"enum": [
"asc",
"desc"
]
},
"include": {
"description": "Nested associations to embed: custom_attributes and/or photos.",
"type": "array",
"items": {
"type": "string",
"enum": [
"custom_attributes",
"photos"
]
}
},
"per_page": {
"description": "Page size, 1-100 (default 100).",
"type": "integer",
"minimum": 1,
"maximum": 100
},
"page": {
"description": "Page number, starting at 1.",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢sortly_list_recently_updated_items(updated_since, folder_id, include_subfolders, include, per_page, ...)
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.
Input Schema
{
"type": "object",
"properties": {
"updated_since": {
"description": "Unix epoch seconds; only items updated after this.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"folder_id": {
"description": "Only the direct contents of this folder. Omit for the root level.",
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"include_subfolders": {
"description": "With folder_id: also return everything nested beneath it. Default false.",
"type": "boolean"
},
"include": {
"description": "Nested associations to embed: custom_attributes and/or photos.",
"type": "array",
"items": {
"type": "string",
"enum": [
"custom_attributes",
"photos"
]
}
},
"per_page": {
"description": "Page size, 1-100 (default 10).",
"type": "integer",
"minimum": 1,
"maximum": 100
},
"page": {
"description": "Page number, starting at 1.",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢sortly_list_custom_fields(per_page, page)
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.
Input Schema
{
"type": "object",
"properties": {
"per_page": {
"description": "Page size (default 10).",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"page": {
"description": "Page number, starting at 1.",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢sortly_list_units
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.
Input Schema
{
"type": "object",
"properties": {},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢sortly_list_alerts(per_page, page)
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.
Input Schema
{
"type": "object",
"properties": {
"per_page": {
"description": "Page size (default 10).",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"page": {
"description": "Page number, starting at 1.",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢sortly_list_jobs(name, status, sort_by, sort_direction, per_page, ...)
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.
Input Schema
{
"type": "object",
"properties": {
"name": {
"description": "Jobs whose name starts with this (case-insensitive).",
"type": "string"
},
"status": {
"description": "Only these statuses. Default all.",
"type": "array",
"items": {
"type": "string",
"enum": [
"not_started",
"in_progress",
"completed"
]
}
},
"sort_by": {
"description": "Sort field. Default updated_at.",
"type": "string",
"enum": [
"name",
"status",
"start_date",
"end_date",
"created_by_name",
"updated_at"
]
},
"sort_direction": {
"description": "Default desc.",
"type": "string",
"enum": [
"asc",
"desc"
]
},
"per_page": {
"description": "Page size, 1-100 (default 20).",
"type": "integer",
"minimum": 1,
"maximum": 100
},
"page": {
"description": "Page number, starting at 1.",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢sortly_get_job(job_id)
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}.
Input Schema
{
"type": "object",
"properties": {
"job_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "The job's id."
}
},
"required": [
"job_id"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢sortly_list_purchase_orders(purchase_order_number, status, sort_by, sort_direction, per_page, ...)
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.
Input Schema
{
"type": "object",
"properties": {
"purchase_order_number": {
"description": "POs whose number contains this.",
"type": "string"
},
"status": {
"description": "Only these statuses. Default all.",
"type": "array",
"items": {
"type": "string",
"enum": [
"draft",
"ready_for_review",
"approved",
"ordered",
"partially_received",
"received",
"voided",
"closed"
]
}
},
"sort_by": {
"description": "Sort field. Default updated_at.",
"type": "string",
"enum": [
"purchase_order_number",
"created_by",
"submitted_by",
"status",
"updated_at",
"total",
"ordered_date",
"expected_delivery_date",
"received_date"
]
},
"sort_direction": {
"description": "Default desc.",
"type": "string",
"enum": [
"asc",
"desc"
]
},
"per_page": {
"description": "Page size, 1-100 (default 20).",
"type": "integer",
"minimum": 1,
"maximum": 100
},
"page": {
"description": "Page number, starting at 1.",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢sortly_get_purchase_order(purchase_order_id)
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}.
Input Schema
{
"type": "object",
"properties": {
"purchase_order_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "The purchase order's id."
}
},
"required": [
"purchase_order_id"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢sortly_get_purchase_order_receive_status(purchase_order_id)
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.
Input Schema
{
"type": "object",
"properties": {
"purchase_order_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "The purchase order's id."
}
},
"required": [
"purchase_order_id"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🔴sortly_create_item(name, type, parent_id, price, quantity, ...)
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.
Input Schema
{
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 190,
"description": "Name, max 190 characters."
},
"type": {
"type": "string",
"enum": [
"item",
"folder"
],
"description": "item = trackable stock; folder = a container."
},
"parent_id": {
"description": "Folder to create it in. Omit/null = root.",
"anyOf": [
{
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"price": {
"description": "Unit price.",
"type": [
"number",
"null"
]
},
"quantity": {
"description": "How many you have.",
"type": [
"number",
"null"
]
},
"min_quantity": {
"description": "Minimum level; a Quantity alert can fire when stock reaches it.",
"type": [
"number",
"null"
]
},
"notes": {
"description": "Free-text notes.",
"type": [
"string",
"null"
]
},
"tags": {
"description": "Tag names, e.g. [\"furniture\", \"used\"].",
"type": "array",
"items": {
"type": "string"
}
},
"custom_attribute_values": {
"description": "Custom field values. Look up ids with sortly_list_custom_fields first.",
"type": "array",
"items": {
"type": "object",
"properties": {
"custom_attribute_id": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Custom field id, from sortly_list_custom_fields."
},
"value": {
"description": "Value to store; null clears it.",
"type": [
"string",
"null"
]
}
},
"required": [
"custom_attribute_id",
"value"
]
}
},
"label_url": {
"description": "Value encoded in the primary QR code / barcode.",
"type": [
"string",
"null"
]
},
"label_url_type": {
"description": "Symbology of the primary code.",
"anyOf": [
{
"type": "string",
"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": "null"
}
]
},
"label_url_extra": {
"description": "Value encoded in the secondary code.",
"type": [
"string",
"null"
]
},
"label_url_extra_type": {
"description": "Symbology of the secondary code.",
"anyOf": [
{
"type": "string",
"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": "null"
}
]
},
"photo_ids": {
"description": "Ids of photos already in the account to attach.",
"type": "array",
"items": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"measured_quantity": {
"description": "For items measured in something other than units.",
"type": "object",
"properties": {
"value": {
"type": "number",
"description": "The measured amount."
},
"type": {
"type": "string",
"enum": [
"weight",
"length",
"volume",
"area",
"count"
],
"description": "Kind of measurement; set on create only."
},
"name": {
"type": "string",
"enum": [
"lbs",
"g",
"kg",
"oz",
"yd",
"cm",
"ft",
"in",
"m",
"gal",
"ml",
"l",
"ft3",
"in3",
"ft2",
"in2",
"units"
],
"description": "The unit, e.g. kg, ft, l, units (see sortly_list_units)."
}
},
"required": [
"value",
"type",
"name"
]
}
},
"required": [
"name",
"type"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🔴sortly_update_item(item_id, name, parent_id, price, quantity, ...)
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).
Input Schema
{
"type": "object",
"properties": {
"item_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "The item's or folder's numeric id."
},
"name": {
"description": "New name.",
"type": "string",
"minLength": 1,
"maxLength": 190
},
"parent_id": {
"description": "Move into this folder (null = root). To move PART of an item's stock use sortly_move_item.",
"anyOf": [
{
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"price": {
"description": "Unit price.",
"type": [
"number",
"null"
]
},
"quantity": {
"description": "How many you have.",
"type": [
"number",
"null"
]
},
"min_quantity": {
"description": "Minimum level; a Quantity alert can fire when stock reaches it.",
"type": [
"number",
"null"
]
},
"notes": {
"description": "Free-text notes.",
"type": [
"string",
"null"
]
},
"tags": {
"description": "Tag names, e.g. [\"furniture\", \"used\"].",
"type": "array",
"items": {
"type": "string"
}
},
"custom_attribute_values": {
"description": "Custom field values. Look up ids with sortly_list_custom_fields first.",
"type": "array",
"items": {
"type": "object",
"properties": {
"custom_attribute_id": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Custom field id, from sortly_list_custom_fields."
},
"value": {
"description": "Value to store; null clears it.",
"type": [
"string",
"null"
]
}
},
"required": [
"custom_attribute_id",
"value"
]
}
},
"label_url": {
"description": "Value encoded in the primary QR code / barcode.",
"type": [
"string",
"null"
]
},
"label_url_type": {
"description": "Symbology of the primary code.",
"anyOf": [
{
"type": "string",
"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": "null"
}
]
},
"label_url_extra": {
"description": "Value encoded in the secondary code.",
"type": [
"string",
"null"
]
},
"label_url_extra_type": {
"description": "Symbology of the secondary code.",
"anyOf": [
{
"type": "string",
"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": "null"
}
]
},
"photo_ids": {
"description": "Ids of photos already in the account to attach.",
"type": "array",
"items": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"measured_quantity": {
"description": "New measured amount for a measured item.",
"type": "object",
"properties": {
"value": {
"type": "number",
"description": "The measured amount (the unit is fixed at creation)."
}
},
"required": [
"value"
]
}
},
"required": [
"item_id"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🔴sortly_move_item(item_id, quantity, folder_id, leave_zero_quantity)
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.
Input Schema
{
"type": "object",
"properties": {
"item_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "The item's numeric id."
},
"quantity": {
"type": "number",
"exclusiveMinimum": 0,
"description": "How much to move."
},
"folder_id": {
"description": "Destination folder. Omit to move to the root level.",
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"leave_zero_quantity": {
"description": "Keep a zero-quantity record in the source folder. Default false.",
"type": "boolean"
}
},
"required": [
"item_id",
"quantity"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🔴sortly_create_alert(item_id, type, threshold_method, threshold_value, threshold_interval, ...)
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.
Input Schema
{
"type": "object",
"properties": {
"item_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "The item the alert watches."
},
"type": {
"type": "string",
"enum": [
"Quantity",
"DateReminder"
],
"description": "Quantity = stock threshold; DateReminder = date custom field."
},
"threshold_method": {
"type": "string",
"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"
],
"description": "What triggers it: a quantity_* method for Quantity, before/after/same_day for DateReminder."
},
"threshold_value": {
"description": "The number compared against (or the interval count).",
"type": "number"
},
"threshold_interval": {
"description": "Required for DateReminder; omit for Quantity.",
"type": "string",
"enum": [
"days",
"weeks",
"months",
"years"
]
},
"custom_attribute_id": {
"description": "For DateReminder: the datetime custom field to watch.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"recipient_groups": {
"description": "Who is notified: owners, admins, members, limited, or a custom role name. Default owners.",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"item_id",
"type",
"threshold_method"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🔴sortly_create_job(name, notes, start_date, end_date, external_job_link, ...)
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.
Input Schema
{
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 190,
"description": "Unique job name, max 190 characters."
},
"notes": {
"description": "Job notes, max 4000 characters.",
"type": "string",
"maxLength": 4000
},
"start_date": {
"description": "YYYY-MM-DD.",
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
},
"end_date": {
"description": "YYYY-MM-DD.",
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
},
"external_job_link": {
"description": "Link to the job in another system.",
"type": "string",
"format": "uri"
},
"subfolders": {
"description": "Subfolder names to create, up to 25.",
"maxItems": 25,
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"custom_field_values": {
"description": "Up to 2 job custom field values.",
"maxItems": 2,
"type": "array",
"items": {
"type": "object",
"properties": {
"custom_field_id": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Job custom field id."
},
"value": {
"type": "string",
"maxLength": 191,
"description": "Value, max 191 characters."
}
},
"required": [
"custom_field_id",
"value"
]
}
}
},
"required": [
"name"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🔴sortly_pull_items_into_job(job_id, items, notes)
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.
Input Schema
{
"type": "object",
"properties": {
"job_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "The job's id."
},
"items": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"type": "object",
"properties": {
"item_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "Item to move onto the job."
},
"quantity": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Quantity to move."
},
"item_version": {
"description": "Version from the last read of the item; stale is rejected.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"leave_zero_quantity": {
"description": "Keep a zero-quantity copy in the original folder.",
"type": "boolean"
}
},
"required": [
"item_id",
"quantity"
]
},
"description": "1-100 items."
},
"notes": {
"description": "Optional note kept in each item's history.",
"type": "string"
}
},
"required": [
"job_id",
"items"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🔴sortly_return_items_from_job(job_id, items, notes)
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.
Input Schema
{
"type": "object",
"properties": {
"job_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "The job's id."
},
"items": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"type": "object",
"properties": {
"item_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "Item on the job to move off it."
},
"quantity": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Quantity to return."
},
"item_version": {
"description": "Version from the last read of the item; stale is rejected.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"destination_folder_id": {
"description": "Folder to return it to; omit for All Items.",
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"leave_zero_quantity": {
"description": "Keep a zero-quantity copy in the job's folder.",
"type": "boolean"
}
},
"required": [
"item_id",
"quantity"
]
},
"description": "1-100 items."
},
"notes": {
"description": "Optional note recorded in the item's history.",
"type": "string"
}
},
"required": [
"job_id",
"items"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🔴sortly_create_purchase_order(currency_code, purchase_order_number, vendor, ship_to, bill_to, ...)
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.
Input Schema
{
"type": "object",
"properties": {
"currency_code": {
"type": "string",
"minLength": 3,
"maxLength": 3,
"description": "ISO 4217 code, e.g. USD."
},
"purchase_order_number": {
"description": "Unique PO number, max 20 chars. Omit to auto-generate.",
"type": "string",
"maxLength": 20
},
"vendor": {
"description": "The vendor, captured on the PO.",
"type": "object",
"properties": {
"name": {
"type": "string",
"maxLength": 50
},
"email": {
"type": "string",
"maxLength": 190
},
"line1": {
"type": "string"
},
"line2": {
"type": "string"
},
"city": {
"type": "string"
},
"state": {
"type": "string"
},
"zip_code": {
"type": "string"
},
"country": {
"type": "string"
},
"phone": {
"type": "string",
"maxLength": 22
}
}
},
"ship_to": {
"description": "Shipping address.",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"line1": {
"type": "string"
},
"line2": {
"type": "string"
},
"city": {
"type": "string"
},
"state": {
"type": "string"
},
"zip_code": {
"type": "string"
},
"country": {
"type": "string"
}
}
},
"bill_to": {
"description": "Billing address.",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"line1": {
"type": "string"
},
"line2": {
"type": "string"
},
"city": {
"type": "string"
},
"state": {
"type": "string"
},
"zip_code": {
"type": "string"
},
"country": {
"type": "string"
}
}
},
"notes": {
"type": "string",
"maxLength": 4000
},
"terms": {
"description": "e.g. Net 30.",
"type": "string",
"maxLength": 4000
},
"charges": {
"description": "Order-level charges; each defaults to 0.",
"type": "object",
"properties": {
"discount": {
"anyOf": [
{
"type": "string",
"pattern": "^-?\\d+(\\.\\d+)?$"
},
{
"type": "number"
}
],
"description": "A decimal, e.g. \"10\" or \"2.5\"."
},
"tax": {
"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\"."
}
}
},
"expected_delivery_date": {
"description": "ISO 8601 timestamp, e.g. 2026-08-20T00:00:00Z.",
"type": "string"
},
"line_items": {
"description": "Up to 100 lines.",
"maxItems": 100,
"type": "array",
"items": {
"type": "object",
"properties": {
"item_id": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991,
"description": "Sortly item to order (must exist)."
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 191,
"description": "Name recorded on the line."
},
"quantity": {
"anyOf": [
{
"type": "string",
"pattern": "^-?\\d+(\\.\\d+)?$"
},
{
"type": "number"
}
],
"description": "Quantity, e.g. \"10\" or 2.5."
},
"unit_of_measure": {
"type": "string",
"description": "Unit abbreviation, e.g. units, ft, kg."
},
"unit_rate": {
"description": "Price per unit. Omit for an unpriced line.",
"anyOf": [
{
"type": "string",
"pattern": "^-?\\d+(\\.\\d+)?$"
},
{
"type": "number"
}
]
},
"item_number": {
"type": "string",
"maxLength": 25
},
"variant_options": {
"maxItems": 3,
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": [
"name",
"value"
]
}
},
"notes": {
"type": "string",
"maxLength": 314
}
},
"required": [
"item_id",
"name",
"quantity",
"unit_of_measure"
]
}
}
},
"required": [
"currency_code"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}Community
Evidence