---
title: "Create or update a product POS mapping"
method: POST
path: "/public/v1/product-pos-mappings"
tags: ["ProductPosMapping"]
---

# Create or update a product POS mapping

`POST /public/v1/product-pos-mappings`

## Request

- Base URL: `https://app.distru.com`
- URL: `https://app.distru.com/public/v1/product-pos-mappings`
- Auth: HTTP bearer

Create or update the link between one of your Distru products and its matching product in a single external POS catalog (Blaze, Dutchie, or Treez). This link is what lets Distru recognize the same product on both sides when it reconciles catalogs, menus, and inventory with that retailer, so mapping a product is a prerequisite for that retailer's POS integration to act on it.

You do not send a POS type. It is derived from which POS fields you supply, and you must supply exactly one complete pair:
• Blaze: `blaze_product_id` + `blaze_retailer_id` (optionally `blaze_asset_id`).
• Dutchie: `dutchie_product_id` + `dutchie_retailer_id`.
• Treez: `treez_product_id` + `treez_retailer_id` (optionally `treez_photo_url`).

Supplying no complete pair, or fields belonging to more than one POS, returns 400 — a mapping targets one POS only.

Create vs. update is decided for you: the request matches an existing mapping by product plus the retailer of the supplied POS. A match is updated in place and returns 200; no match creates a new mapping and returns 201. Because the match key is stable, sending the same body twice is idempotent and never produces a duplicate.

Before the mapping is written, several things are checked and any failure returns 400 with a human-readable message:
• The `product_id` must be a product in your company.
• The supplied retailer must be a POS retailer connected to your company.
• The supplied POS product must already exist in Distru's synced copy of that retailer's catalog — you cannot map to a product Distru has not yet pulled from the POS.
• For Blaze only, the product's category must already have a Blaze category mapping configured for that retailer.

Uniqueness is enforced on both sides: a given POS product can back only one Distru product per retailer, and a Distru product can have only one mapping per retailer. Violating either returns 400.

On update, only the fields you send are changed — the request is sparse. The `product_id` plus the complete POS pair must always be present (they form the match key and are re-validated), but the optional fields are treated per-field: omit `blaze_asset_id` or `treez_photo_url` to keep its current value, or send it as `null` to clear it. Repointing to a different POS product for the same retailer is a normal update: send the new `..._product_id` with the same `product_id` and retailer id.

This endpoint only maintains the link record — it does not itself move inventory or push the product to the POS; it makes the product eligible for that retailer's sync.

Required permission: `products_permissions_edit`.

## Request body

- UpsertProductPosMapping: Body for creating or updating a product POS mapping. Send `product_id` plus exactly one complete POS pair; the POS type is derived from which pair you supply — do not send it. Mixing fields from more than one POS is rejected. Which existing mapping (if any) gets updated is keyed on `product_id` and the retailer of the supplied POS.
  - `blaze_asset_id` string: Optional Blaze asset (image) id, accepted only on a Blaze mapping. Omit on update to leave the current value untouched; send `null` to clear it. May be null even on a Blaze mapping.
  - `blaze_product_id` string: Blaze's own id for the product to link to. Provide together with `blaze_retailer_id` to make this a Blaze mapping. Must already exist in Distru's synced copy of that Blaze retailer's catalog.
  - `blaze_retailer_id` string: Distru ID of the connected Blaze retailer to scope the mapping to. Provide together with `blaze_product_id`.
  - `dutchie_product_id` integer: Dutchie's own numeric id for the product to link to. Provide together with `dutchie_retailer_id` to make this a Dutchie mapping. Must already exist in Distru's synced copy of that Dutchie retailer's catalog.
  - `dutchie_retailer_id` string: Distru ID of the connected Dutchie retailer to scope the mapping to. Provide together with `dutchie_product_id`.
  - `product_id` string, required: ID of the Distru product to map. Must be a product in your company. Required.
  - `treez_photo_url` string: Optional product photo URL, accepted only on a Treez mapping. Omit on update to leave the current value untouched; send `null` to clear it. May be null even on a Treez mapping.
  - `treez_product_id` string: Treez's own id for the product to link to. Provide together with `treez_retailer_id` to make this a Treez mapping. Must already exist in Distru's synced copy of that Treez retailer's catalog.
  - `treez_retailer_id` integer: Distru id of the connected Treez retailer to scope the mapping to, as an integer. Provide together with `treez_product_id`.

## Response `200`

Updated existing mapping

- ProductPosMappingResponse
  - `data` ProductPosMapping, required: A link between a Distru product and the matching product in an external point-of-sale (POS) system such as Blaze, Dutchie, or Treez. A mapping always targets exactly one POS, given by `pos_type`; only that POS's fields are present in the response, and the fields for the other two POS systems are omitted entirely.
    - `blaze_asset_id` string, nullable: Blaze asset (image) id for the product, or null if none was set. Present only when `pos_type` is `BLAZE`.
    - `blaze_product_id` string: Blaze's own id for the mapped product. Present and non-null only when `pos_type` is `BLAZE`; omitted entirely for other POS types.
    - `blaze_retailer_id` string: Distru ID of the connected Blaze retailer this mapping is scoped to. Present and non-null only when `pos_type` is `BLAZE`; omitted entirely for other POS types.
    - `dutchie_product_id` integer: Dutchie's own numeric id for the mapped product (a Dutchie identifier, not a Distru id). Present and non-null only when `pos_type` is `DUTCHIE`; omitted entirely for other POS types.
    - `dutchie_retailer_id` string: Distru ID of the connected Dutchie retailer this mapping is scoped to. Present and non-null only when `pos_type` is `DUTCHIE`; omitted entirely for other POS types.
    - `id` string, required: ID of this mapping. Use it to fetch or delete the mapping. Always present.
    - `inserted_datetime` string, datetime, required: When the mapping was created, in UTC. Always present.
    - `pos_type` 'BLAZE' | 'DUTCHIE' | 'TREEZ', required: Which external POS this mapping targets. One of `BLAZE`, `DUTCHIE`, or `TREEZ` (SCREAMING_CASE). Determines which POS-specific fields below are present. Always present.
    - `product_id` string, required: ID of the linked Distru product. Always present.
    - `treez_photo_url` string, nullable: URL of the product photo in Treez, or null if none was set. Present only when `pos_type` is `TREEZ`.
    - `treez_product_id` string: Treez's own id for the mapped product (a Treez identifier, not a Distru id). Present and non-null only when `pos_type` is `TREEZ`; omitted entirely for other POS types.
    - `treez_retailer_id` integer: ID of the connected Treez retailer this mapping is scoped to, as an integer. Present and non-null only when `pos_type` is `TREEZ`; omitted entirely for other POS types.
    - `updated_datetime` string, datetime, required: When the mapping was last updated, in UTC. Equals `inserted_datetime` until the first update. Always present.

## Other responses

- `201`: Created new mapping
- `400`: Invalid parameters
- `401`: Missing or invalid API token
- `403`: The API token lacks the required permission, or team restrictions hide the record

---

[API](https://skmtc.dev/distru/apis/distru-api.md) - [All operations](https://skmtc.dev/distru/apis/distru-api/llms.txt) - [OpenAPI document](https://skmtc.dev/distru/apis/distru-api/revisions/9d851a88e82f?raw)
