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

A
Description quality
100%
Schema completeness
93%
Naming quality
98%
Poisoning risk
100%
Permission match
100%
Protocol compliance
100%

Findings (2)

  • LOWTool 'sortly_list_recently_updated_items' name length outside 3-30 rangein sortly_list_recently_updated_items
  • LOWTool 'sortly_get_purchase_order_receive_status' name length outside 3-30 rangein sortly_get_purchase_order_receive_status

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~6,793Tokens (tool definitions)
~3.0 KBTypical response size
Significant attention impact (5.31% of 128k context)

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-http

What it can do

Tool inventory

Tools (20)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟢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

Rate this Server

Evidence

Recent observations

verifiedversion not recorded20 tools
verifiedversion not recorded20 tools