Skip to content

API Reference

0neShot edited this page Sep 9, 2026 · 3 revisions

REST API Reference

SmartParts exposes a token-authenticated REST API for programmatic component lookup, diagnostic inspection, and automated ingestion under:

/plugin/smartparts/api/

This interface enables external scripts, automated receiving stations, warehouse barcode scanners, CAD tools, and CI/CD pipelines to query distributors and ingest components directly into InvenTree.


🔐 Authentication

All SmartParts API endpoints require authentication via an InvenTree user account with appropriate permissions (part.view_part for lookup, part.add_part for creation).

1. InvenTree API Token (Recommended for Scripts & Automation)

Generate an API token in InvenTree under User Profile > API Tokens. Pass the token in the Authorization HTTP header on all requests:

Authorization: Token 0123456789abcdef0123456789abcdef01234567

2. Active Browser Session (Same-Origin)

Calls made from client-side extensions or scripts sharing an active InvenTree browser session authenticate via Django session cookies (csrftoken cookie required for non-exempt POST requests).


📡 API Endpoints

1. Single-Shot Import Endpoint

Path: POST /plugin/smartparts/api/v1/import/
CSRF: Exempt (@csrf_exempt)
Permissions: part.view_part (preview/lookup), part.add_part (when auto_create=true and dry_run=false)

Performs multi-distributor lookups, merges results according to priority, applies fuzzy category mapping, detects duplicates, filters parameters against category templates, and optionally persists the part into InvenTree in a single atomic call.

Request Headers

Content-Type: application/json
Authorization: Token <your-inventree-token>

Request Body Parameters

Field Type Default Description
mpn string required Manufacturer Part Number to look up.
auto_create bool false Set true to persist the part, manufacturer, and supplier links in InvenTree.
dry_run bool false When true, prevents database writes regardless of auto_create.
update_existing bool | null null null = follow plugin's DUPLICATE_ACTION setting; true = update existing part; false = skip.
full_response bool false When true, includes complete merged PartData, per-source raw payloads, and normalized parameters.

Structural Category Protection & Atomic Rollback

When auto_create=true, InvenTree categories marked as structural=True are rejected. The API returns HTTP 400 Bad Request with an explanatory error and executes an atomic rollback (transaction.atomic()):

{
  "error": "Cannot assign part to structural category 'Passives' (ID: 5). Please select a non-structural leaf category.",
  "category_id": 5
}

Standard Response (dry_run=true or auto_create=false)

{
  "mpn": "STM32F103C8T6",
  "found": true,
  "manufacturer": "STMicroelectronics",
  "description": "IC MCU 32BIT 64KB FLASH 48LQFP",
  "category_suggestion": {
    "id": 12,
    "path": "ICs > Microcontrollers",
    "score": 91.5,
    "distributor_category": "Microcontrollers - MCU"
  },
  "duplicate": {
    "is_duplicate": false
  },
  "sources_queried": ["mouser", "digikey", "lcsc"],
  "sources_found": ["mouser", "lcsc"],
  "dry_run": true,
  "auto_create": false,
  "created": false,
  "action": null,
  "part_id": null,
  "part_name": null,
  "dropped_parameters": [
    {
      "supplier_key": "Factory Pack Quantity",
      "value": "2500",
      "reason": "not_in_category_templates"
    }
  ],
  "message": "",
  "errors": []
}

Full Response Fields (full_response=true)

When full_response=true, the following dictionary objects are added to the JSON response:

  • merged: Complete normalized PartData object.
  • sources: Per-distributor raw dictionaries ({"mouser": {...}, "digikey": null, ...}).
  • parameters: List of whitelisted, SI-normalized technical parameters.
  • supplier_data: Aggregated supplier pricing, stock levels, and packaging options.
  • dropped_parameters: Audit list of all parameters filtered out by LIMIT_PARAMETERS_TO_CATEGORY.

2. Barcode Classification & Part Lookup Endpoint

Path: POST /plugin/smartparts/api/barcode/lookup/ (also accepts GET)
CSRF: Exempt (auth_exempt = True)
Permissions: Any authenticated or internal session

Decodes 2D DataMatrix strings or InvenTree barcodes. Automatically discriminates between internal InvenTree objects and distributor packaging.

Request Body

{
  "barcode": "[)>06~1PSTM32F103C8T6~Q10~30PMSR123"
}

Response (Distributor Part Found in InvenTree)

{
  "found": true,
  "part_id": 142,
  "part_name": "STM32F103C8T6",
  "part_ipn": "MCU-STM32F103-LQFP48",
  "part_url": "/web/part/142/",
  "mpn": "STM32F103C8T6",
  "distributor": "mouser",
  "barcode_data": {
    "mpn": "STM32F103C8T6",
    "quantity": 10,
    "supplier_sku": "MSR123"
  }
}

Response (Native InvenTree Barcode / QR Code)

When an internal InvenTree payload is scanned (e.g. {"purchaseorder": 4}, {"stocklocation": 12}, or INV-SL12):

{
  "found": true,
  "is_native": true,
  "native_type": "purchaseorder",
  "part_id": null,
  "part_name": "PO-2026-004",
  "part_ipn": "",
  "part_url": "/web/purchasing/purchase-order/4/",
  "mpn": "",
  "distributor": null,
  "barcode_data": {
    "type": "purchaseorder",
    "pk": 4
  }
}

Note

If an unrecognized internal JSON payload is scanned, the endpoint returns is_native: true with mpn: "" and an error message. Internal payloads will never trigger part import suggestions.


3. Raw Distributor Diagnostic Endpoint

Path: POST /plugin/smartparts/api/v1/raw-lookup/
Permissions: part.view_part

Queries all enabled distributors and returns raw, unmerged JSON responses per distributor. Bypasses category mapping, deduplication, and parameter normalization.

Request Body

{
  "mpn": "STM32F103C8T6"
}

Response Structure

{
  "mpn": "STM32F103C8T6",
  "sources": {
    "mouser": { "mpn": "STM32F103C8T6", "stock_available": 4320, "description": "..." },
    "digikey": { "error": "disabled" },
    "lcsc": { "mpn": "STM32F103C8T6", "supplier_sku": "C8734" },
    "element14": { "error": "disabled" },
    "tme": null
  },
  "queried_at": "2026-09-08T11:00:00Z"
}

4. Category Parameter Whitelist Endpoint

Path: GET /plugin/smartparts/api/category/parameters/?category_id=<id>
Path: POST /plugin/smartparts/api/category/parameters/
Permissions: part.view_part

Inspects parameter templates defined for a category hierarchy (including ancestor inheritance and child overrides), or tests candidate attributes against the category whitelist.

Request Body (POST)

{
  "category_id": 12,
  "attributes": [
    { "name": "Resistance", "value": "10k" },
    { "name": "Factory Packaging", "value": "Tape & Reel" }
  ]
}

Response Structure

{
  "category_id": 12,
  "category_path": "Passives > Resistors",
  "structural": false,
  "templates": [
    { "name": "Resistance", "units": "Ω" },
    { "name": "Tolerance", "units": "%" }
  ],
  "accepted_parameters": [
    { "name": "Resistance", "value": "10", "unit": "" }
  ],
  "dropped_parameters": [
    {
      "supplier_key": "Factory Packaging",
      "value": "Tape & Reel",
      "reason": "not_in_category_templates"
    }
  ]
}

💻 Code Examples

cURL: Preview Component with Dropped Parameters Audit

curl -X POST https://inventree.example.com/plugin/smartparts/api/v1/import/ \
  -H "Authorization: Token your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "mpn": "STM32F103C8T6",
    "dry_run": true,
    "full_response": true
  }'

Python: Automated Ingestion Script

import requests

BASE_URL = "https://inventree.example.com"
TOKEN = "your_token_here"
HEADERS = {
    "Authorization": f"Token {TOKEN}",
    "Content-Type": "application/json"
}

# 1. Preview component lookup
resp = requests.post(
    f"{BASE_URL}/plugin/smartparts/api/v1/import/",
    headers=HEADERS,
    json={"mpn": "STM32F103C8T6", "dry_run": True, "full_response": True}
)
resp.raise_for_status()
preview = resp.json()

if preview["found"]:
    print(f"Found: {preview['manufacturer']} - {preview['description']}")
    print(f"Suggested Category: {preview['category_suggestion']['path']}")

    # 2. Ingest part into database
    create_resp = requests.post(
        f"{BASE_URL}/plugin/smartparts/api/v1/import/",
        headers=HEADERS,
        json={"mpn": "STM32F103C8T6", "auto_create": True}
    )
    result = create_resp.json()
    if result.get("created"):
        print(f"Successfully created Part ID: {result['part_id']} ({result['part_name']})")
    elif "error" in result:
        print(f"Creation failed: {result['error']}")

Next Steps

Clone this wiki locally