Product Feeds
product_feed_updated
Sent when a product feed changes, including status changes after a sync.
relationships.object.data identifies the product feed, and included contains the product feed.
The payload below is the default JSON:API document. The webhook's payload_include, payload_fields and payload_transformation_template change it, and its filter decides whether the event is sent at all.
Request
We send the event to your webhook's url with POST (or the webhook's http_method) and a JSON:API document as the body (Content-Type: application/vnd.api+json). See Receiving Webhooks for retries and Webhook Event Signatures to verify the request.
Headers
| Header | Description |
|---|---|
X-TINT-Signature | timestamp,signature, where timestamp is the Unix time (in seconds) at which the delivery was signed and signature is the Base64-encoded HMAC-SHA256 of timestamp.body, keyed with the webhook's signing secret. Only sent when the webhook has a signing secret. Every attempt is signed again, so retries carry a new timestamp. See Webhook Event Signatures. |
API-Version | The API version the payload was serialized with, unless the webhook overrides this header. |
User-Agent | Always TINT Webhook/2.0, unless the webhook overrides this header. |
Payload
| Field | Type | Description |
|---|---|---|
data | object | |
data.id | string | The event ID. It stays the same on every retry of this event, so use it to detect duplicate deliveries. It is also the ID to use with Retrieve a webhook event. |
data.type | string | Always event. One of event. |
data.attributes | object | |
data.attributes.name | string | The event name. One of product_feed_updated. |
data.attributes.created_at | string (date-time) | When the event happened (the event was recorded), not when this delivery was sent. Retries keep the original value. |
data.relationships | object | |
data.relationships.object | object | The product feed this event is about. |
data.relationships.object.data | object | |
data.relationships.object.data.type | string | One of product_feed. |
data.relationships.object.data.id | string | |
data.relationships.team | object | The team the webhook belongs to. |
data.relationships.team.data | object | |
data.relationships.team.data.type | string | One of team. |
data.relationships.team.data.id | string |
Included resources
The sideloaded resources: the product feed.
resource
| Field | Type | Description |
|---|---|---|
type | string | The resource type. One of product_feed. |
attributes (optional) | object | |
attributes.name (optional) | string or null | The name of the product feed. When not given, it's derived from the source: the file name of a csv feed, the file path of an ftp, sftp, http or s3 feed, the catalog name of a facebook feed, or the product account name. |
attributes.source (optional) | string | The source of the products: the type of the product account (product integration) it syncs from, csv for a CSV file imported from a URL, or manual for products managed using the API. |
attributes.status (optional) | string | active while the product feed is being kept in sync, archived once it's no longer synced, and error when the last sync or import failed (see error_message). One of active, archived, error. |
attributes.options (optional) | object | Source-specific options. |
attributes.options.delete_files_once_processed (optional) | boolean | Whether to delete the file from the server or bucket once it has been imported. Only used when source is ftp, sftp or s3. |
attributes.last_ingested_at (optional) | string or null (date-time) | When products were last imported, or null if they haven't been imported yet. |
attributes.error_message (optional) | string or null | The reason the last sync or import failed, or null when it succeeded. |
relationships (optional) | object | |
relationships.product_account (optional) | object | The product account (product integration) the feed syncs from; data is null for csv and manual feeds. data is only present when include=product_account is requested; otherwise meta.included is false. |
relationships.product_account.data (optional) | object or null | |
relationships.product_account.meta (optional) | object | |
relationships.catalog (optional) | object | The catalog the feed syncs from (resource type catalog, with a name attribute); data is null when the feed has no catalog. data is only present when include=catalog is requested; otherwise meta.included is false. |
relationships.catalog.data (optional) | object or null | |
relationships.catalog.meta (optional) | object | |
relationships.products (optional) | object | The products of the feed. Only returned when the access token has the products:read scope. data (the first 25 products) is only present when include=products is requested. |
relationships.products.data (optional) | array of object | The first 25 products of the feed. |
relationships.products.meta (optional) | object | |
id | string | The unique identifier of the resource. |
Example
{
"data": {
"id": "1377462",
"type": "event",
"attributes": {
"created_at": "2025-03-14T16:42:07.000Z",
"name": "product_feed_updated"
},
"relationships": {
"object": {
"data": {
"type": "product_feed",
"id": "88"
}
},
"team": {
"data": {
"type": "team",
"id": "1"
}
}
}
},
"included": [
{
"id": "88",
"type": "product_feed",
"attributes": {
"source": "shopify",
"name": "Acme store catalog",
"status": "active",
"last_ingested_at": "2025-03-14T16:42:07.000Z",
"error_message": null,
"options": {}
},
"relationships": {
"product_account": {
"meta": {
"included": false
}
},
"catalog": {
"meta": {
"included": false
}
}
}
}
]
}Responses
| Status | Description |
|---|---|
404 | 404 Not Found or 410 Gone stops delivery of this event immediately: it is marked failure and not retried. The attempt still counts toward the webhook's failure limit. |
410 | 404 Not Found or 410 Gone stops delivery of this event immediately: it is marked failure and not retried. The attempt still counts toward the webhook's failure limit. |
2XX | Any status below 400 (typically 2XX) acknowledges the event: we mark it success and don't send it again. The response body is ignored (we store it with the attempt, for your reference). Redirects are not followed, and a 3XX response also counts as acknowledged, so point the webhook at the final URL. |
| Other | Any other 4XX or 5XX status, a timeout or a connection error fails the attempt, and we retry up to 7 more times with an increasing delay (roughly 1 minute, 1 minute, 2 minutes, 13 minutes, 1 hour, 4 hours, then 13 hours later), after which the event is marked failure. More than 50 failed attempts for the same webhook within a week, without a successful delivery in between, set the webhook to inactive. |