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.
{
"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 |
|---|---|
|
Stable snake_case key. The bindings and the Store API use it. |
|
The name merchants see, for example in your settings page. |
|
|
|
|
|
The sources the merchant may choose from: |
|
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 |
|---|---|
|
An ID Tringify creates once and keeps for the installation. |
|
The product or variant's own Tringify ID. |
|
The product or variant's SKU. |
|
A non-translatable string metafield the merchant picks. List the choices with |
|
Values your app writes with |
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.
{
"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 |
|---|---|
|
Comma-separated: |
|
|
|
Product title, variant title or SKU. |
|
|
|
1 to 100; default 50. |
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:
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.