Product identities

Declare the product IDs your sales channel app needs, resolve them, and help merchants fix missing ones.

A sales channel app sends products to another platform, such as an ads catalog or a marketplace, and refers to them in feeds and events. Product identities are the IDs that platform knows each product or variant by. Your app declares which IDs it needs; the merchant chooses where each one comes from; Tringify resolves the value for every product and variant and tells you which ones have no usable ID.

Declare identities#

Declare identities in your app release, under sales_channel.identity_declarations in tringify.app.json. Only sales channel apps can declare them.

json
{
  "sales_channel": {
    "identity_declarations": [
      {
        "key": "meta_variant_id",
        "label": "Meta variant ID",
        "role": "catalog_item",
        "owner_type": "variant",
        "allowed_sources": ["sku", "metafield", "generated"],
        "required": true
      }
    ]
  }
}

Field

Meaning

key

Stable snake_case key. The bindings and the Store API use it.

label

The name merchants see, for example in your settings page.

role

catalog_item: one item in the other platform's catalog. catalog_group: a group of items, such as Meta's item group (products only). provider_reference: an ID your app stores against a product (metafield or app-assigned sources only).

owner_type

product or variant. A product-level catalog_item covers simple products; a catalog_group covers products with variants.

allowed_sources

The sources the merchant may choose from: generated, canonical_id, sku, metafield, app_assigned. A catalog_group cannot use sku.

required

Whether your app needs the identity to work. Show required identities as setup steps until they are configured.

Let the merchant choose a source#

Each declaration is bound to one source. Read the installed contract with GET /channel-identities/contract, the current bindings with GET /channel-identities/bindings, and set a binding with PUT /channel-identities/bindings/{declarationKey} (needs write_products). The contract also names each source in source_labels; show those names to merchants instead of writing your own.

Source

Value

generated

An ID Tringify creates once and keeps for the installation.

canonical_id

The product or variant's own Tringify ID.

sku

The product or variant's SKU.

metafield

A non-translatable string metafield the merchant picks. List the choices with GET /channel-identities/eligible-metafields. Use this to keep IDs a store already uses on the other platform.

app_assigned

Values your app writes with PUT /channel-identities/bindings/{id}/values.

The first time a product or variant is resolved, its value is recorded. After that, a value read from a SKU or metafield follows its source: when the merchant changes it, Tringify replaces the code in the same save, keeps the old one as history, and sends your app channel_identities/rekeyed with both values, so you can remove the item under the old code and send the product under the new one. A change that would give two products the same code keeps the old code, and identity diagnostics report the duplicate. Generated and canonical-ID codes never change. To change codes yourself, use POST /channel-identities/bindings/{id}/rekey for one product or variant, or POST /channel-identities/bindings/{id}/rekey-from-source to take the current values for up to 200 at once.

Resolve identities#

Call POST /channel-identities/bindings/{id}/resolve with up to 200 product or variant IDs (needs write_products). Each result is resolved, with its value, or missing when the source has no value. Resolve before you send products to the other platform and keep the resolved values; replace one when channel_identities/rekeyed tells you it changed.

json
{
  "success": true,
  "data": {
    "items": [
      { "owner_id": 14441, "value": "CUSTOMDIECUT2", "status": "resolved" },
      { "owner_id": 14492, "status": "missing" }
    ]
  }
}

A product or variant without an identity cannot be sent. Leave it out of feeds and out of the product list of an event, and still send the event: a purchase is still a purchase when one product in it has no ID.

Find and fix missing identities#

GET /channel-identities/diagnostics counts, for each declaration, the products or variants in scope that resolve, have no value (missing), or conflict (conflicts: longer than 255 characters, or the same value as another product or variant). Show these counts in your app's settings.

GET /channel-identities/bindings/{id}/gaps lists them, so the merchant can fix each one. It reads the same data as the counts.

Query parameter

Meaning

reason

Comma-separated: missing, too_long, duplicate. Default: all.

product_status

active, draft, archived or scheduled.

search

Product title, variant title or SKU.

cursor

next_cursor from the previous page; empty on the last page.

limit

1 to 100; default 50.

text
GET /api/2025-01/channel-identities/bindings/4299a7a5-8f12-44fc-8963-f5c725e78de3/gaps?reason=missing&limit=50

{
  "success": true,
  "data": {
    "items": [
      {
        "owner_type": "variant",
        "owner_id": 14492,
        "product_id": 4142,
        "product_title": "Custom Die-Cut Stickers",
        "variant_title": "1 Inch",
        "sku": "CUSTOMDIECUT1",
        "product_status": "active",
        "value": null,
        "reason": "missing"
      }
    ],
    "next_cursor": ""
  }
}

Show each row's reason with its name from reason_labels in the contract, and give the row a way to the product, so the merchant can fill in or correct the source. In an embedded app, open it with Admin App Bridge; this works in Store Admin and in the Tringify app:

javascript
await bridge.navigate("/products/" + item.product_id);

Generated and canonical sources never have gaps. App-assigned values never repeat, so they are only ever missing.