PartsDNA API Reference
Documentation

API Reference

Read and write the parts catalogue over HTTP — models, aliases, fitments, virtual parts and stock alerts — plus the read-only Shopify mirrors and the public storefront endpoints.

Getting a key

Sign in to create a key

  • Scope controls what the key can touch: * for everything, parts.read / parts.write for every parts resource below, or a single <resource>.read / <resource>.write pair — see the scope line under each resource in the Resources section.
  • Origin restriction is optional. Leave it empty for server-to-server use (no browser involved). Set one or more origins (e.g. https://yourstore.myshopify.com) and the key only works for requests carrying a matching Origin header — for a browser-side integration you don't want the raw token leaking further than that one storefront.
  • The token (tk_…) is shown exactly once, right when you create or regenerate the key. Store it somewhere safe — if you lose it, regenerate the key for a new one; the old token stops working immediately.

Authentication

Send the token as a bearer token:

Authorization header
Authorization: Bearer tk_...

or, when a custom header is easier to configure than the standard one, the same token as:

X-API-Key fallback
X-API-Key: tk_...

The rule in one sentence: reads are open, every write needs a key. Every GET below is public except alerts (it holds customer email addresses, so even reading it needs a key); every POST, PATCH and DELETE needs a key whose scope covers the resource.

Example response — 401, missing or invalid token
{
    "success": false,
    "message": "Missing API token"
}
Example response — 403, token lacks scope
{
    "success": false,
    "message": "API token lacks scope models.write"
}

Resources

One block per entry in PartsRest::resources() — generated straight from that registry, so this page can't describe a field, verb or filter the API doesn't actually have.

/partsapi/models — model (partmodel)

Reads open Verbs: GET POST PATCH DELETE

Scope: partmodel.read / partmodel.write (or * / parts.read / parts.write).

FieldTypeWritableRequired to create
id integer — —
model_number string
model_norm string — —
title string
brand string —
status string —
product_ref integer —
superseded_by_ref integer —
part_count integer — —
published_at string — —
external_eid string — —
notes string —
keywords string —
keywords_norm string — —
shop_eid string —
created_at string — —
updated_at string — —

Filters: brand= status= model_number=

Search: q= — fuzzy match over model_number / title / brand / keywords or the fitment graph / model aliases, so a part number typed here surfaces the models it fits. Combines with the filters above.

Sort: sort= one of model_number , title , brand , created_at , updated_at , part_count — default model_number ASC.

Natural key: model_norm — a write that collides with an existing row gets 409, not 500.

List — GET /partsapi/models

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/models"
Example response — 200
[
    {
        "id": 12,
        "model_number": "MYT4219000",
        "model_norm": "myt4219000",
        "title": "Trail Groomer 420",
        "brand": "Yeti",
        "status": "active",
        "product_ref": null,
        "superseded_by_ref": null,
        "part_count": 6,
        "published_at": "2026-01-15 09:00:00",
        "external_eid": null,
        "notes": null,
        "keywords": null,
        "keywords_norm": null,
        "shop_eid": null,
        "created_at": "2026-01-10 08:30:00",
        "updated_at": "2026-08-20 14:05:00"
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/models/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/models/12"
Example response — 200
{
    "id": 12,
    "model_number": "MYT4219000",
    "model_norm": "myt4219000",
    "title": "Trail Groomer 420",
    "brand": "Yeti",
    "status": "active",
    "product_ref": null,
    "superseded_by_ref": null,
    "part_count": 6,
    "published_at": "2026-01-15 09:00:00",
    "external_eid": null,
    "notes": null,
    "keywords": null,
    "keywords_norm": null,
    "shop_eid": null,
    "created_at": "2026-01-10 08:30:00",
    "updated_at": "2026-08-20 14:05:00"
}
Example response — 404
{
    "success": false,
    "message": "Model not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Create — POST /partsapi/models

curl
curl -X POST "https://partsdna-74a225.tiknix.com/partsapi/models" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model_number": "MYT4219000",
    "title": "Trail Groomer 420",
    "brand": "Yeti",
    "status": "active"
}'
Example response — 201
{
    "id": 12,
    "model_number": "MYT4219000",
    "model_norm": "myt4219000",
    "title": "Trail Groomer 420",
    "brand": "Yeti",
    "status": "active",
    "product_ref": null,
    "superseded_by_ref": null,
    "part_count": 6,
    "published_at": "2026-01-15 09:00:00",
    "external_eid": null,
    "notes": null,
    "keywords": null,
    "keywords_norm": null,
    "shop_eid": null,
    "created_at": "2026-01-10 08:30:00",
    "updated_at": "2026-08-20 14:05:00"
}
Example response — 422, missing a required field
{
    "success": false,
    "message": "Validation failed.",
    "errors": {
        "model_number": "'model_number' is required.",
        "title": "'title' is required."
    }
}
Try it — POST fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Update — PATCH /partsapi/models/{id}

curl
curl -X PATCH "https://partsdna-74a225.tiknix.com/partsapi/models/12" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "status": "discontinued"
}'
Example response — 200
{
    "id": 12,
    "model_number": "MYT4219000",
    "model_norm": "myt4219000",
    "title": "Trail Groomer 420",
    "brand": "Yeti",
    "status": "discontinued",
    "product_ref": null,
    "superseded_by_ref": null,
    "part_count": 6,
    "published_at": "2026-01-15 09:00:00",
    "external_eid": null,
    "notes": null,
    "keywords": null,
    "keywords_norm": null,
    "shop_eid": null,
    "created_at": "2026-01-10 08:30:00",
    "updated_at": "2026-08-20 14:05:00"
}
Example response — 409, natural key collision
{
    "success": false,
    "message": "Model already exists.",
    "errors": {
        "model_norm": "Model already exists."
    }
}
Try it — PATCH fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Delete — DELETE /partsapi/models/{id}

curl
curl -X DELETE "https://partsdna-74a225.tiknix.com/partsapi/models/12" \
  -H "Authorization: Bearer tk_..."
Example response — 204
(no body)
Try it — DELETE fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

/partsapi/aliases — alias (partalias)

Reads open Verbs: GET POST PATCH DELETE

Scope: partalias.read / partalias.write (or * / parts.read / parts.write).

FieldTypeWritableRequired to create
id integer — —
model_ref integer —
part_ref integer —
virtualpart_ref integer —
alias string
alias_norm string — —
kind string —
created_at string — —

Filters: model_ref= part_ref= virtualpart_ref= kind=

Sort: sort= one of alias , created_at — default created_at DESC.

List — GET /partsapi/aliases

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/aliases"
Example response — 200
[
    {
        "id": 41,
        "model_ref": 12,
        "part_ref": 1,
        "virtualpart_ref": 1,
        "alias": "Trail 420",
        "alias_norm": "trail420",
        "kind": "alt_name",
        "created_at": "2026-01-11 10:00:00"
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/aliases/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/aliases/41"
Example response — 200
{
    "id": 41,
    "model_ref": 12,
    "part_ref": 1,
    "virtualpart_ref": 1,
    "alias": "Trail 420",
    "alias_norm": "trail420",
    "kind": "alt_name",
    "created_at": "2026-01-11 10:00:00"
}
Example response — 404
{
    "success": false,
    "message": "Alias not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Create — POST /partsapi/aliases

curl
curl -X POST "https://partsdna-74a225.tiknix.com/partsapi/aliases" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model_ref": 12,
    "alias": "Trail 420",
    "kind": "alt_name"
}'
Example response — 201
{
    "id": 41,
    "model_ref": 12,
    "part_ref": 1,
    "virtualpart_ref": 1,
    "alias": "Trail 420",
    "alias_norm": "trail420",
    "kind": "alt_name",
    "created_at": "2026-01-11 10:00:00"
}
Example response — 422, missing a required field
{
    "success": false,
    "message": "Validation failed.",
    "errors": {
        "alias": "'alias' is required."
    }
}
Try it — POST fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Update — PATCH /partsapi/aliases/{id}

curl
curl -X PATCH "https://partsdna-74a225.tiknix.com/partsapi/aliases/41" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "alias": "Trail Groomer 420 (alt)"
}'
Example response — 200
{
    "id": 41,
    "model_ref": 12,
    "part_ref": 1,
    "virtualpart_ref": 1,
    "alias": "Trail Groomer 420 (alt)",
    "alias_norm": "trail420",
    "kind": "alt_name",
    "created_at": "2026-01-11 10:00:00"
}
Try it — PATCH fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Delete — DELETE /partsapi/aliases/{id}

curl
curl -X DELETE "https://partsdna-74a225.tiknix.com/partsapi/aliases/41" \
  -H "Authorization: Bearer tk_..."
Example response — 204
(no body)
Try it — DELETE fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

/partsapi/fitments — fitment (fitment)

Reads open Verbs: GET POST PATCH DELETE

Scope: fitment.read / fitment.write (or * / parts.read / parts.write).

FieldTypeWritableRequired to create
id integer — —
partmodel_id integer
part_ref integer —
virtualpart_ref integer —
variant_ref integer —
kind string
position integer —
qty integer —
note string —
created_at string — —

Filters: partmodel_id= part_ref= virtualpart_ref= kind=

Sort: sort= one of position , kind , created_at — default position ASC.

Natural key: partmodel_id + part_ref + virtualpart_ref + variant_ref — a write that collides with an existing row gets 409, not 500.

List — GET /partsapi/fitments

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/fitments"
Example response — 200
[
    {
        "id": 301,
        "partmodel_id": 12,
        "part_ref": 4051,
        "virtualpart_ref": null,
        "variant_ref": null,
        "kind": "belt",
        "position": 1,
        "qty": 1,
        "note": null,
        "created_at": "2026-01-12 11:00:00"
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/fitments/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/fitments/301"
Example response — 200
{
    "id": 301,
    "partmodel_id": 12,
    "part_ref": 4051,
    "virtualpart_ref": null,
    "variant_ref": null,
    "kind": "belt",
    "position": 1,
    "qty": 1,
    "note": null,
    "created_at": "2026-01-12 11:00:00"
}
Example response — 404
{
    "success": false,
    "message": "Fitment not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Create — POST /partsapi/fitments

curl
curl -X POST "https://partsdna-74a225.tiknix.com/partsapi/fitments" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "partmodel_id": 12,
    "part_ref": 4051,
    "kind": "belt",
    "position": 1,
    "qty": 1
}'
Example response — 201
{
    "id": 301,
    "partmodel_id": 12,
    "part_ref": 4051,
    "virtualpart_ref": null,
    "variant_ref": null,
    "kind": "belt",
    "position": 1,
    "qty": 1,
    "note": null,
    "created_at": "2026-01-12 11:00:00"
}
Example response — 422, missing a required field
{
    "success": false,
    "message": "Validation failed.",
    "errors": {
        "partmodel_id": "'partmodel_id' is required.",
        "kind": "'kind' is required."
    }
}
Try it — POST fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Update — PATCH /partsapi/fitments/{id}

curl
curl -X PATCH "https://partsdna-74a225.tiknix.com/partsapi/fitments/301" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "qty": 2
}'
Example response — 200
{
    "id": 301,
    "partmodel_id": 12,
    "part_ref": 4051,
    "virtualpart_ref": null,
    "variant_ref": null,
    "kind": "belt",
    "position": 1,
    "qty": 2,
    "note": null,
    "created_at": "2026-01-12 11:00:00"
}
Example response — 409, natural key collision
{
    "success": false,
    "message": "Fitment already exists.",
    "errors": {
        "_conflict": "This part is already attached to that model."
    }
}
Try it — PATCH fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Delete — DELETE /partsapi/fitments/{id}

curl
curl -X DELETE "https://partsdna-74a225.tiknix.com/partsapi/fitments/301" \
  -H "Authorization: Bearer tk_..."
Example response — 204
(no body)
Try it — DELETE fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

/partsapi/virtualparts — virtual part (virtualpart)

Reads open Verbs: GET POST PATCH DELETE

Scope: virtualpart.read / virtualpart.write (or * / parts.read / parts.write).

FieldTypeWritableRequired to create
id integer — —
name string
part_number string
part_number_norm string — —
brand string —
description string —
image_url string —
price_estimate number —
status string —
notes string —
keywords string —
keywords_norm string — —
shop_eid string —
created_at string — —
updated_at string — —

Filters: brand= status=

Search: q= — fuzzy match over name / part_number / brand / keywords or the fitment graph / model aliases, so a part number typed here surfaces the models it fits. Combines with the filters above.

Sort: sort= one of name , part_number , created_at , updated_at — default name ASC.

Natural key: part_number_norm — a write that collides with an existing row gets 409, not 500.

List — GET /partsapi/virtualparts

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/virtualparts"
Example response — 200
[
    {
        "id": 88,
        "name": "OEM Deck Belt (no Shopify listing)",
        "part_number": "2130-200104-OEM",
        "part_number_norm": "2130200104oem",
        "brand": "Yeti",
        "description": "Manufacturer part, not yet stocked online.",
        "image_url": null,
        "price_estimate": 24.5,
        "status": "active",
        "notes": "Sourced on request.",
        "keywords": null,
        "keywords_norm": null,
        "shop_eid": null,
        "created_at": "2026-02-01 09:00:00",
        "updated_at": "2026-02-01 09:00:00"
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/virtualparts/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/virtualparts/88"
Example response — 200
{
    "id": 88,
    "name": "OEM Deck Belt (no Shopify listing)",
    "part_number": "2130-200104-OEM",
    "part_number_norm": "2130200104oem",
    "brand": "Yeti",
    "description": "Manufacturer part, not yet stocked online.",
    "image_url": null,
    "price_estimate": 24.5,
    "status": "active",
    "notes": "Sourced on request.",
    "keywords": null,
    "keywords_norm": null,
    "shop_eid": null,
    "created_at": "2026-02-01 09:00:00",
    "updated_at": "2026-02-01 09:00:00"
}
Example response — 404
{
    "success": false,
    "message": "Virtual part not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Create — POST /partsapi/virtualparts

curl
curl -X POST "https://partsdna-74a225.tiknix.com/partsapi/virtualparts" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "OEM Deck Belt (no Shopify listing)",
    "part_number": "2130-200104-OEM",
    "brand": "Yeti",
    "status": "active"
}'
Example response — 201
{
    "id": 88,
    "name": "OEM Deck Belt (no Shopify listing)",
    "part_number": "2130-200104-OEM",
    "part_number_norm": "2130200104oem",
    "brand": "Yeti",
    "description": "Manufacturer part, not yet stocked online.",
    "image_url": null,
    "price_estimate": 24.5,
    "status": "active",
    "notes": "Sourced on request.",
    "keywords": null,
    "keywords_norm": null,
    "shop_eid": null,
    "created_at": "2026-02-01 09:00:00",
    "updated_at": "2026-02-01 09:00:00"
}
Example response — 422, missing a required field
{
    "success": false,
    "message": "Validation failed.",
    "errors": {
        "name": "'name' is required.",
        "part_number": "'part_number' is required."
    }
}
Try it — POST fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Update — PATCH /partsapi/virtualparts/{id}

curl
curl -X PATCH "https://partsdna-74a225.tiknix.com/partsapi/virtualparts/88" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "price_estimate": 26
}'
Example response — 200
{
    "id": 88,
    "name": "OEM Deck Belt (no Shopify listing)",
    "part_number": "2130-200104-OEM",
    "part_number_norm": "2130200104oem",
    "brand": "Yeti",
    "description": "Manufacturer part, not yet stocked online.",
    "image_url": null,
    "price_estimate": 26,
    "status": "active",
    "notes": "Sourced on request.",
    "keywords": null,
    "keywords_norm": null,
    "shop_eid": null,
    "created_at": "2026-02-01 09:00:00",
    "updated_at": "2026-02-01 09:00:00"
}
Example response — 409, natural key collision
{
    "success": false,
    "message": "Virtual part already exists.",
    "errors": {
        "part_number_norm": "Virtual part already exists."
    }
}
Try it — PATCH fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Delete — DELETE /partsapi/virtualparts/{id}

curl
curl -X DELETE "https://partsdna-74a225.tiknix.com/partsapi/virtualparts/88" \
  -H "Authorization: Bearer tk_..."
Example response — 204
(no body)
Try it — DELETE fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

/partsapi/alerts — alert (partalert)

Key required, even to read Verbs: GET PATCH DELETE

Scope: partalert.read / partalert.write (or * / parts.read / parts.write).

FieldTypeWritableRequired to create
id integer — —
email string — —
part_ref integer — —
virtualpart_ref integer — —
partmodel_ref integer — —
query_text string — —
status string —
ip_address string — —
shop_eid string — —
created_at string — —
notified_at string — —
cancelled_at string — —

Filters: status= part_ref= virtualpart_ref= partmodel_ref=

Sort: sort= one of created_at , status — default created_at DESC.

List — GET /partsapi/alerts

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/alerts" \
  -H "Authorization: Bearer tk_..."
Example response — 200
[
    {
        "id": 515,
        "email": "customer@example.com",
        "part_ref": 4051,
        "virtualpart_ref": null,
        "partmodel_ref": 12,
        "query_text": "2130-200104 back in stock?",
        "status": "pending",
        "ip_address": "203.0.113.14",
        "shop_eid": null,
        "created_at": "2026-08-01 16:22:00",
        "notified_at": null,
        "cancelled_at": null
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/alerts/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/alerts/515" \
  -H "Authorization: Bearer tk_..."
Example response — 200
{
    "id": 515,
    "email": "customer@example.com",
    "part_ref": 4051,
    "virtualpart_ref": null,
    "partmodel_ref": 12,
    "query_text": "2130-200104 back in stock?",
    "status": "pending",
    "ip_address": "203.0.113.14",
    "shop_eid": null,
    "created_at": "2026-08-01 16:22:00",
    "notified_at": null,
    "cancelled_at": null
}
Example response — 404
{
    "success": false,
    "message": "Alert not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Update — PATCH /partsapi/alerts/{id}

curl
curl -X PATCH "https://partsdna-74a225.tiknix.com/partsapi/alerts/515" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "status": "notified"
}'
Example response — 200
{
    "id": 515,
    "email": "customer@example.com",
    "part_ref": 4051,
    "virtualpart_ref": null,
    "partmodel_ref": 12,
    "query_text": "2130-200104 back in stock?",
    "status": "notified",
    "ip_address": "203.0.113.14",
    "shop_eid": null,
    "created_at": "2026-08-01 16:22:00",
    "notified_at": null,
    "cancelled_at": null
}
Try it — PATCH fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Delete — DELETE /partsapi/alerts/{id}

curl
curl -X DELETE "https://partsdna-74a225.tiknix.com/partsapi/alerts/515" \
  -H "Authorization: Bearer tk_..."
Example response — 204
(no body)
Try it — DELETE fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

/partsapi/products — product (shopifyproduct)

Reads open Verbs: GET PATCH

Scope: shopifyproduct.read / shopifyproduct.write (or * / parts.read / parts.write).

FieldTypeWritableRequired to create
id integer — —
product_eid string — —
title string — —
handle string — —
status string — —
vendor string — —
product_type string — —
total_inventory integer — —
image_url string — —
sku_norm string — —
is_part boolean — —
shop_eid string — —
updated_at_shop string — —
keywords string —
keywords_norm string — —

Filters: status= vendor= product_type= is_part=

Sort: sort= one of title , total_inventory , updated_at_shop — default title ASC.

Natural key: product_eid — a write that collides with an existing row gets 409, not 500.

List — GET /partsapi/products

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/products"
Example response — 200
[
    {
        "id": 4051,
        "product_eid": "gid://shopify/Product/9743105982693",
        "title": "Drive Belt 42in",
        "handle": "drive-belt-42in",
        "status": "ACTIVE",
        "vendor": "Yeti",
        "product_type": "belt",
        "total_inventory": 14,
        "image_url": "https://cdn.shopify.com/s/files/1/0000/0001/products/belt.jpg",
        "sku_norm": "213020010",
        "is_part": true,
        "shop_eid": null,
        "updated_at_shop": "2026-08-19 22:00:00",
        "keywords": null,
        "keywords_norm": null
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/products/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/products/4051"
Example response — 200
{
    "id": 4051,
    "product_eid": "gid://shopify/Product/9743105982693",
    "title": "Drive Belt 42in",
    "handle": "drive-belt-42in",
    "status": "ACTIVE",
    "vendor": "Yeti",
    "product_type": "belt",
    "total_inventory": 14,
    "image_url": "https://cdn.shopify.com/s/files/1/0000/0001/products/belt.jpg",
    "sku_norm": "213020010",
    "is_part": true,
    "shop_eid": null,
    "updated_at_shop": "2026-08-19 22:00:00",
    "keywords": null,
    "keywords_norm": null
}
Example response — 404
{
    "success": false,
    "message": "Product not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Update — PATCH /partsapi/products/{id}

curl
curl -X PATCH "https://partsdna-74a225.tiknix.com/partsapi/products/4051" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '[]'
Example response — 200
{
    "id": 4051,
    "product_eid": "gid://shopify/Product/9743105982693",
    "title": "Drive Belt 42in",
    "handle": "drive-belt-42in",
    "status": "ACTIVE",
    "vendor": "Yeti",
    "product_type": "belt",
    "total_inventory": 14,
    "image_url": "https://cdn.shopify.com/s/files/1/0000/0001/products/belt.jpg",
    "sku_norm": "213020010",
    "is_part": true,
    "shop_eid": null,
    "updated_at_shop": "2026-08-19 22:00:00",
    "keywords": null,
    "keywords_norm": null
}
Example response — 409, natural key collision
{
    "success": false,
    "message": "Product already exists.",
    "errors": {
        "product_eid": "Product already exists."
    }
}
Try it — PATCH fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

/partsapi/variants — variant (shopifyvariant)

Read-only mirror Verbs: GET

Scope: shopifyvariant.read (or * / parts.read).

FieldTypeWritableRequired to create
id integer — —
product_eid string — —
product_title string — —
variant_eid string — —
variant_title string — —
sku string — —
price number — —
stock integer — —
shop_eid string — —

Filters: product_eid= sku=

Sort: sort= one of sku , price , stock — default id ASC.

Natural key: variant_eid — a write that collides with an existing row gets 409, not 500.

List — GET /partsapi/variants

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/variants"
Example response — 200
[
    {
        "id": 9051,
        "product_eid": "gid://shopify/Product/9743105982693",
        "product_title": "Drive Belt 42in",
        "variant_eid": "gid://shopify/ProductVariant/47812345678901",
        "variant_title": "42in",
        "sku": "2130-200104",
        "price": 89.99,
        "stock": 14,
        "shop_eid": null
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/variants/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/variants/9051"
Example response — 200
{
    "id": 9051,
    "product_eid": "gid://shopify/Product/9743105982693",
    "product_title": "Drive Belt 42in",
    "variant_eid": "gid://shopify/ProductVariant/47812345678901",
    "variant_title": "42in",
    "sku": "2130-200104",
    "price": 89.99,
    "stock": 14,
    "shop_eid": null
}
Example response — 404
{
    "success": false,
    "message": "Variant not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

/partsapi/synonyms — synonym (searchsynonym)

Reads open Verbs: GET POST PATCH DELETE

Scope: searchsynonym.read / searchsynonym.write (or * / parts.read / parts.write).

FieldTypeWritableRequired to create
id integer — —
term string
term_norm string — —
canonical string
canonical_norm string — —
kind string —
weight string —
is_active string —
shop_eid string — —
notes string —
created_at string — —
updated_at string — —

Filters: kind= is_active=

Sort: sort= one of term , created_at — default term ASC.

List — GET /partsapi/synonyms

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/synonyms"
Example response — 200
[
    {
        "id": 1,
        "term": null,
        "term_norm": null,
        "canonical": null,
        "canonical_norm": null,
        "kind": null,
        "weight": null,
        "is_active": null,
        "shop_eid": null,
        "notes": null,
        "created_at": null,
        "updated_at": null
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/synonyms/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/synonyms/1"
Example response — 200
{
    "id": 1,
    "term": null,
    "term_norm": null,
    "canonical": null,
    "canonical_norm": null,
    "kind": null,
    "weight": null,
    "is_active": null,
    "shop_eid": null,
    "notes": null,
    "created_at": null,
    "updated_at": null
}
Example response — 404
{
    "success": false,
    "message": "Synonym not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Create — POST /partsapi/synonyms

curl
curl -X POST "https://partsdna-74a225.tiknix.com/partsapi/synonyms" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "term": null,
    "canonical": null,
    "kind": null,
    "weight": null,
    "is_active": null,
    "notes": null
}'
Example response — 201
{
    "id": 1,
    "term": null,
    "term_norm": null,
    "canonical": null,
    "canonical_norm": null,
    "kind": null,
    "weight": null,
    "is_active": null,
    "shop_eid": null,
    "notes": null,
    "created_at": null,
    "updated_at": null
}
Example response — 422, missing a required field
{
    "success": false,
    "message": "Validation failed.",
    "errors": {
        "term": "'term' is required.",
        "canonical": "'canonical' is required."
    }
}
Try it — POST fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Update — PATCH /partsapi/synonyms/{id}

curl
curl -X PATCH "https://partsdna-74a225.tiknix.com/partsapi/synonyms/1" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '[]'
Example response — 200
{
    "id": 1,
    "term": null,
    "term_norm": null,
    "canonical": null,
    "canonical_norm": null,
    "kind": null,
    "weight": null,
    "is_active": null,
    "shop_eid": null,
    "notes": null,
    "created_at": null,
    "updated_at": null
}
Try it — PATCH fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Delete — DELETE /partsapi/synonyms/{id}

curl
curl -X DELETE "https://partsdna-74a225.tiknix.com/partsapi/synonyms/1" \
  -H "Authorization: Bearer tk_..."
Example response — 204
(no body)
Try it — DELETE fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

/partsapi/suggestions — suggestion (searchsuggestion)

Key required, even to read Verbs: GET PATCH DELETE

Scope: searchsuggestion.read / searchsuggestion.write (or * / parts.read / parts.write).

FieldTypeWritableRequired to create
id integer — —
kind string — —
target_type string — —
target_ref integer — —
target_label string — —
term string —
canonical string —
source string — —
score string — —
evidence string — —
status string —
shop_eid string — —
created_at string — —
updated_at string — —

Filters: status= kind= target_type=

Sort: sort= one of score , created_at — default score DESC.

List — GET /partsapi/suggestions

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/suggestions" \
  -H "Authorization: Bearer tk_..."
Example response — 200
[
    {
        "id": 1,
        "kind": null,
        "target_type": null,
        "target_ref": 1,
        "target_label": null,
        "term": null,
        "canonical": null,
        "source": null,
        "score": null,
        "evidence": null,
        "status": null,
        "shop_eid": null,
        "created_at": null,
        "updated_at": null
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/suggestions/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/suggestions/1" \
  -H "Authorization: Bearer tk_..."
Example response — 200
{
    "id": 1,
    "kind": null,
    "target_type": null,
    "target_ref": 1,
    "target_label": null,
    "term": null,
    "canonical": null,
    "source": null,
    "score": null,
    "evidence": null,
    "status": null,
    "shop_eid": null,
    "created_at": null,
    "updated_at": null
}
Example response — 404
{
    "success": false,
    "message": "Suggestion not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Update — PATCH /partsapi/suggestions/{id}

curl
curl -X PATCH "https://partsdna-74a225.tiknix.com/partsapi/suggestions/1" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '[]'
Example response — 200
{
    "id": 1,
    "kind": null,
    "target_type": null,
    "target_ref": 1,
    "target_label": null,
    "term": null,
    "canonical": null,
    "source": null,
    "score": null,
    "evidence": null,
    "status": null,
    "shop_eid": null,
    "created_at": null,
    "updated_at": null
}
Try it — PATCH fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Delete — DELETE /partsapi/suggestions/{id}

curl
curl -X DELETE "https://partsdna-74a225.tiknix.com/partsapi/suggestions/1" \
  -H "Authorization: Bearer tk_..."
Example response — 204
(no body)
Try it — DELETE fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

/partsapi/redirects — redirect (searchredirect)

Key required, even to read Verbs: GET POST PATCH DELETE

Scope: searchredirect.read / searchredirect.write (or * / parts.read / parts.write).

FieldTypeWritableRequired to create
id integer — —
term string
term_norm string — —
url string
notes string —
is_active string —
shop_eid string —
created_at string — —
updated_at string — —

Filters: is_active=

Sort: sort= one of term , created_at — default term ASC.

List — GET /partsapi/redirects

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/redirects" \
  -H "Authorization: Bearer tk_..."
Example response — 200
[
    {
        "id": 1,
        "term": null,
        "term_norm": null,
        "url": null,
        "notes": null,
        "is_active": null,
        "shop_eid": null,
        "created_at": null,
        "updated_at": null
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/redirects/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/redirects/1" \
  -H "Authorization: Bearer tk_..."
Example response — 200
{
    "id": 1,
    "term": null,
    "term_norm": null,
    "url": null,
    "notes": null,
    "is_active": null,
    "shop_eid": null,
    "created_at": null,
    "updated_at": null
}
Example response — 404
{
    "success": false,
    "message": "Redirect not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Create — POST /partsapi/redirects

curl
curl -X POST "https://partsdna-74a225.tiknix.com/partsapi/redirects" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "term": null,
    "url": null,
    "notes": null,
    "is_active": null,
    "shop_eid": null
}'
Example response — 201
{
    "id": 1,
    "term": null,
    "term_norm": null,
    "url": null,
    "notes": null,
    "is_active": null,
    "shop_eid": null,
    "created_at": null,
    "updated_at": null
}
Example response — 422, missing a required field
{
    "success": false,
    "message": "Validation failed.",
    "errors": {
        "term": "'term' is required.",
        "url": "'url' is required."
    }
}
Try it — POST fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Update — PATCH /partsapi/redirects/{id}

curl
curl -X PATCH "https://partsdna-74a225.tiknix.com/partsapi/redirects/1" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '[]'
Example response — 200
{
    "id": 1,
    "term": null,
    "term_norm": null,
    "url": null,
    "notes": null,
    "is_active": null,
    "shop_eid": null,
    "created_at": null,
    "updated_at": null
}
Try it — PATCH fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Delete — DELETE /partsapi/redirects/{id}

curl
curl -X DELETE "https://partsdna-74a225.tiknix.com/partsapi/redirects/1" \
  -H "Authorization: Bearer tk_..."
Example response — 204
(no body)
Try it — DELETE fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

/partsapi/pages — page (shopifypage)

Key required, even to read Verbs: GET PATCH

Scope: shopifypage.read / shopifypage.write (or * / parts.read / parts.write).

FieldTypeWritableRequired to create
id integer — —
page_eid string — —
title string — —
handle string — —
body_summary string — —
updated_at_shop string — —
shop_eid string — —
is_excluded string —

Filters: is_excluded=

Sort: sort= one of title , updated_at_shop — default title ASC.

List — GET /partsapi/pages

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/pages" \
  -H "Authorization: Bearer tk_..."
Example response — 200
[
    {
        "id": 1,
        "page_eid": null,
        "title": null,
        "handle": null,
        "body_summary": null,
        "updated_at_shop": null,
        "shop_eid": null,
        "is_excluded": null
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/pages/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/pages/1" \
  -H "Authorization: Bearer tk_..."
Example response — 200
{
    "id": 1,
    "page_eid": null,
    "title": null,
    "handle": null,
    "body_summary": null,
    "updated_at_shop": null,
    "shop_eid": null,
    "is_excluded": null
}
Example response — 404
{
    "success": false,
    "message": "Page not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Update — PATCH /partsapi/pages/{id}

curl
curl -X PATCH "https://partsdna-74a225.tiknix.com/partsapi/pages/1" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '[]'
Example response — 200
{
    "id": 1,
    "page_eid": null,
    "title": null,
    "handle": null,
    "body_summary": null,
    "updated_at_shop": null,
    "shop_eid": null,
    "is_excluded": null
}
Try it — PATCH fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

/partsapi/collections — collection (shopifycollection)

Key required, even to read Verbs: GET PATCH

Scope: shopifycollection.read / shopifycollection.write (or * / parts.read / parts.write).

FieldTypeWritableRequired to create
id integer — —
collection_eid string — —
title string — —
handle string — —
description string — —
image_url string — —
updated_at_shop string — —
shop_eid string — —
is_excluded string —

Filters: is_excluded=

Sort: sort= one of title , updated_at_shop — default title ASC.

List — GET /partsapi/collections

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/collections" \
  -H "Authorization: Bearer tk_..."
Example response — 200
[
    {
        "id": 1,
        "collection_eid": null,
        "title": null,
        "handle": null,
        "description": null,
        "image_url": null,
        "updated_at_shop": null,
        "shop_eid": null,
        "is_excluded": null
    }
]
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Get one — GET /partsapi/collections/{id}

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/collections/1" \
  -H "Authorization: Bearer tk_..."
Example response — 200
{
    "id": 1,
    "collection_eid": null,
    "title": null,
    "handle": null,
    "description": null,
    "image_url": null,
    "updated_at_shop": null,
    "shop_eid": null,
    "is_excluded": null
}
Example response — 404
{
    "success": false,
    "message": "Collection not found."
}
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Update — PATCH /partsapi/collections/{id}

curl
curl -X PATCH "https://partsdna-74a225.tiknix.com/partsapi/collections/1" \
  -H "Authorization: Bearer tk_..." \
  -H "Content-Type: application/json" \
  -d '[]'
Example response — 200
{
    "id": 1,
    "collection_eid": null,
    "title": null,
    "handle": null,
    "description": null,
    "image_url": null,
    "updated_at_shop": null,
    "shop_eid": null,
    "is_excluded": null
}
Try it — PATCH fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

Three read endpoints that answer from the fitment engine rather than from one resource's table — the same queries the public finder pages run, under the API surface. All three are public: no key, no scope, read-only.

GET /partsapi/suggest

Type-ahead payload for a dropdown that polls per keystroke: up to 8 matching machines and 8 matching parts. The response is identical in shape to the public /parts/suggest endpoint — an integration built against either works against both. Under 2 characters of q returns empty arrays, not an error.

Build against this one. /parts/suggest is deprecated — it still answers (existing bookmarks and snippets keep working), but the find page's own type-ahead now calls /partsapi/suggest, and new integrations should too.
qrequired, 2+ characters — under 2 chars returns empty arrays, not an error
brandaccepted for parameter parity with /partsapi/search, but ignored — q already matches brand text
Example response
{
  "success": true,
  "query": "trail",
  "models": [
    { "id": 12, "model_number": "MYT4219000", "title": "Trail Groomer 420", "brand": "Yeti" }
  ],
  "parts": [
    {
      "id": 4051,
      "source": "shopify",
      "title": "Drive Belt 42in",
      "sku": "2130-200104",
      "image": "https://cdn.shopify.com/s/files/1/0000/0001/products/belt.jpg",
      "purchasable": true
    }
  ],
  "terms": [
    { "text": "drive belt", "kind": "phrase", "count": 3 },
    { "text": "trail groomer", "kind": "model", "count": 1 }
  ]
}

terms is always present ([] below the 2-character minimum, same as models/parts) — "did you mean" chips mined from this same query's hits. A plural query and its singular (e.g. blade / blades) mine the SAME terms list — de-duplication is by word stem, not literal text.

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/suggest?q=trail"
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

GET /partsapi/find

The ranked, faceted, scoped search — one call over the same engine that ranks search()'s and the models resource's q=, but unioning parts and models into one paged, sorted, filterable list with facet counts. Build new integrations against this one; search/suggest stay for the two-question and type-ahead shapes.

qrequired — free text, a part number, or a machine number
category / subtypeoptional — narrows to a shopifyproduct category/subtype key (see facets.category/facets.subtype); excludes virtual parts, which carry neither column
fitsoptional — a machine number or alias; restricts parts to those fitted to the resolved model (aliases/supersession honoured). Fails to resolve → zero results, named in fits_model, not a 400
sourceoptional — shopify or virtual
in_stockoptional — 1/0/true/false; shopify parts only, a virtual part has no stock column and is excluded when set
kindoptional — part / model / all (default)
sortoptional — relevance (default) / title / price / stock
page / per_pageoptional — 1-based, per_page defaults to 24, capped at 100

Each row in items carries a rank (its 1-based position across the whole match set, not just this page) and a matched_via — sku / alias / keyword / stem / synonym / text — so a UI can show why a row matched. A plural and its singular (e.g. blade / blades) return the same rows. A zero-result query is still success: true, total: 0, same rule as search/suggest.

Example response — trimmed
{
  "success": true,
  "query": "blade",
  "expanded": ["BLADE"],
  "stemmed": [],
  "recommendations": [
    { "text": "mower blade", "kind": "phrase", "count": 2 },
    { "text": "high lift blade", "kind": "keyword", "count": 1 }
  ],
  "shop": null,
  "filters": { "category": null, "subtype": null, "fits": "MYT4219000", "source": null, "in_stock": null, "kind": "all", "sort": "relevance" },
  "page": 1,
  "per_page": 24,
  "total": 1,
  "items": [
    { "id": 4051, "source": "shopify", "title": "Drive Belt 42in", "sku": "2130-200104", "purchasable": true, "rank": 1, "matched_via": "keyword" }
  ],
  "facets": { "category": [], "subtype": [], "source": [ { "k": "shopify", "label": "Shopify", "n": 1 } ], "availability": [ { "k": "1", "label": "In stock", "n": 1 }, { "k": "0", "label": "Out of stock", "n": 0 } ] },
  "fits_model": { "id": 12, "model_number": "MYT4219000", "title": "Trail Groomer 420", "brand": "Yeti", "kind": "", "qty": 1, "superseded": false }
}

recommendations — { text, kind, count } chips, kind one of phrase / keyword / synonym / model — is mined from this same query's hits, the same engine suggest's terms uses. De-duplication is by word stem, so blade and blades return the SAME recommendations list, not two near-duplicate ones.

curl
curl "https://partsdna-74a225.tiknix.com/partsapi/find?q=blade&fits=MYT4219000"
Try it — GET fires a real request against this instance
Response will appear here after you click Run. Requires JavaScript — see the curl example above for the no-JS path.

The models resource above also takes a q= filter — the same fuzzy match (text columns, plus the fitment graph and aliases, so a part number surfaces the models it fits) as a paginated resource list instead of a ranked search.

Errors

Every error response is JSON with the same envelope — a success: false boolean and a human-readable message; validation (422) and most conflict (409) responses add a field-keyed errors object:

Shape
{
    "success": false,
    "message": "...",
    "errors": {
        "field": "reason"
    }
}
StatusMeaningWhen
400Bad RequestMalformed JSON body, or a required query parameter is missing.
401UnauthorizedThe resource needs a key and none was sent, or the token is invalid or expired.
403ForbiddenThe token is valid but its scope doesn't cover this resource/action.
404Not FoundNo row exists with that id.
405Method Not AllowedThe verb isn't one of this resource's allowed verbs — e.g. POST to a read-only mirror.
409ConflictThe write collides with an existing row's natural key (see each resource's "Natural key" note).
422Unprocessable EntityA required field is missing, an unknown/non-writable field was sent, or a structural rule failed (see fitments).
429Too Many RequestsRate limit exceeded for this key or IP.

Read-only mirrors

products and variants accept GET only — no POST, PATCH or DELETE, ever. Both tables are mirrors kept current by the connected Shopify store's sync pipelines; a write made here would simply be overwritten, silently, the next time either pipeline runs. To change a product or variant, change it in Shopify — the sync catches up on its own schedule.

Public storefront endpoints

These live on the main site, not under /partsapi, and need no key at all — they're shaped for a storefront to call directly. Full detail, request/response samples and their own Try-it consoles are on the Parts setup guide; this is just the map.

RouteMethodParamsReturns
/parts/lookup GETmodel (required), brand (optional) JSON — model + its parts list
/parts/fits GETsku or product_id (one required) JSON — which models a part fits
/parts/suggest deprecated GETq (required, 2+ chars) JSON — type-ahead models + parts; use /partsapi/suggest
/parts/catalog GETnone JSON — the whole catalogue, ETag + gzip
curl
curl "https://partsdna-74a225.tiknix.com/parts/lookup?model=MYT4219000"

Embedding the parts finder in a Shopify theme? See the theme snippet on the setup guide.

OpenAPI

A machine-readable OpenAPI 3.1 document, generated from the same PartsRest::resources() registry as this page — /apidocs/spec.

curl
curl "https://partsdna-74a225.tiknix.com/apidocs/spec"