Skip to content

REST API

The app talks to the Part-DB server over a REST API in JSON-LD / Hydra format. Every request is authenticated with a Bearer token.


Authentication

Each request includes the header:

Authorization: Bearer <token>

The token is read from Flutter Secure Storage every time the app starts. With OAuth login (Part-DB 2.15+) the access token is refreshed automatically before it expires; concurrent requests share a single refresh, and a 401 triggers one refresh-and-retry.

Every request sends Accept: application/ld+json. Plain application/json collections carry no pagination links, so the app would only ever see the first page.


Common parameters

Parameter Description
itemsPerPage Maximum number of results per page (default 30 in Part-DB)
hydra:view / view Pagination – contains hydra:next (next) with the path of the next page
hydra:member / member Array of results in a collection response (both prefixed and unprefixed JSON-LD are supported)

Timeouts

Request type Timeout
Standard (GET/PATCH) 10 s
Attachment upload (POST) 30 s

Endpoints

Token verification

GET /api/tokens/current
Authorization: Bearer <token>

200 response:

{
  "id": 5,
  "user": "/api/users/3",
  "name": "scanner",
  ...
}

Used by the Configuration screen to verify an API token. It only knows API tokens and answers 403 for OAuth tokens, so after an OAuth login the app checks access with GET /api/parts?itemsPerPage=1 and reads the username and granted scopes from the access token (a JWT: sub, scopes).


Search by IPN

GET /api/parts?ipn={ipn}

Response:

{
  "hydra:member": [
    { "id": 42, "name": "Resistor 10k", "ipn": "1234567", ... }
  ]
}

Used when the scanned/typed code is exactly 7 digits.


GET /api/parts?name=%25{query}%25&itemsPerPage=100
GET /api/parts?ipn=%25{query}%25&itemsPerPage=100
GET /api/parts?manufacturer_product_number=%25{query}%25&itemsPerPage=100
GET /api/parts?description=%25{query}%25&itemsPerPage=100

Part-DB's LikeFilter matches exactly unless % wildcards are used, so the query is wrapped in %…%. The four requests run in parallel and the results are merged without duplicates (max 300 per field).

Search by parameter value

Collection responses contain parameter names only, and parameters have no collection endpoint. The "Value" search mode therefore reads GET /api/parts/{id} for parts with parameters and caches the values on the device, keyed by the part's lastModified. Only the first search (or parts changed since) costs extra requests.


Fetch all parts

GET /api/parts?itemsPerPage=100

The app follows hydra:view.hydra:next until it has collected every record. Used by the IPN Generator, the parameter search and the review screen.

The low-stock banner only fetches parts with a minimum stock set: GET /api/parts?minamount[gt]=0.


Part details

GET /api/parts/{id}

Response (excerpt):

{
  "id": 42,
  "name": "Resistor 10k",
  "ipn": "1234567",
  "minamount": 10,
  "description": "...",
  "comment": "...",
  "category": "/api/categories/5",
  "manufacturer": "/api/manufacturers/3",
  "tags": "smd,resistor",
  "partLots": [
    { "id": 7, "amount": 12.5, "instock_unknown": false, "comment": "", "storage_location": { "id": 2, "name": "Drawer A" } }
  ],
  "parameters": [
    { "id": 101, "name": "Resistance", "value_typical": 10000, "value_text": "", "unit": "Ω" }
  ]
}

Note

Amounts are floats (meters, grams…) and are never rounded by the app. Lots with instock_unknown are excluded from the total and disable the low-stock warning.


Update a storage lot

PATCH /api/part_lots/{id}
Content-Type: application/merge-patch+json

{
  "amount": 15,
  "comment": "[2026-09-27] TME delivery\nprevious comment…",
  "last_stocktake_at": "2026-09-27T10:00:00Z"
}

200 response: the updated PartLot object.

  • comment is sent only when the user typed a note: a dated line is prepended to the lot's existing comment (Part-DB's API has no way to attach a comment to the event log entry).
  • last_stocktake_at is sent by Stock Taking for every counted lot, including those without a discrepancy.
  • The lot's description is never modified.

Update a parameter

PATCH /api/parameters/{id}
Content-Type: application/merge-patch+json

{
  "value_text": "SOT-223"
}

The value is written back to the field it came from: value_text for text parameters, value_typical (a number) for single numeric values. Range parameters (value_min/value_max) are read-only in the app.


Assign an IPN

PATCH /api/parts/{id}
Content-Type: application/merge-patch+json

{
  "ipn": "3847291"
}

Fetch categories

GET /api/categories?itemsPerPage=200

The app fetches up to 200 categories, paging through hydra:next. Used by the Category browser.

Response (excerpt):

{
  "hydra:member": [
    { "id": 1, "name": "Resistors", "parent": null },
    { "id": 2, "name": "SMD", "parent": "/api/categories/1" }
  ]
}


Fetch attachment types

GET /api/attachment_types?itemsPerPage=1

Fetches the first available attachment type to use when uploading a photo.


Upload an attachment (photo)

POST /api/attachments
Content-Type: application/ld+json
Authorization: Bearer <token>

{
  "name": "Photo - Resistor 10k",
  "element": "/api/parts/42",
  "attachment_type": "/api/attachment_types/1",
  "upload": {
    "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgAB...",
    "filename": "Resistor_10k_1727430000000.jpg",
    "private": false,
    "becomePreviewIfEmpty": true
  }
}

attachment_type is required by Part-DB; if no attachment type exists on the server, the upload is refused with a clear message.

201 response: the attachment object.

The photo is taken from the camera or gallery, compressed to JPEG and base64-encoded directly in the request body.


Error handling

The app parses error responses in the following order:

  1. The hydra:description field
  2. The violations[].message array (validation errors)
  3. The detail field
  4. The HTTP status text

Errors are shown to the user through a SnackBar.

// Example validation error response (422)
{
  "@type": "ConstraintViolationList",
  "violations": [
    { "propertyPath": "ipn", "message": "This value is already used." }
  ]
}