Feeds
List feeds, get feed status, and browse transformed feed products with applied rules and mappings.
A feed is an independently configured product data output. Each feed has its own rules, settings, column mappings, and published URL. Every shop starts with a primary feed and can create additional feeds for different languages or markets.
Feed types
| Type | Description |
|---|---|
primary | The default feed created when you install the app. Every shop has exactly one. |
language | A translation feed for a specific locale (e.g., French, German). Uses Shopify’s translation data. |
market | A feed targeting a specific market with independent product selection and configuration. |
List feeds
/v1/feeds Returns all active feeds for your shop.
Required scope: read_feeds
Request
curl https://app.simpleproductfeeds.com/v1/feeds \
-H "Authorization: Bearer spf_live_sk_your_key_here"
Response
{
"data": [
{
"id": "feed_1",
"object": "feed",
"feed_type": "primary",
"locale": null,
"display_name": "Primary",
"feed_url": "https://feeds.simpleproductfeeds.com/abc123/gmcfeed.txt",
"product_count": 1482,
"last_run_at": "2026-03-09T14:30:00Z",
"created_at": "2026-01-10T08:00:00Z"
},
{
"id": "feed_2",
"object": "feed",
"feed_type": "language",
"locale": "fr",
"display_name": "French",
"feed_url": "https://feeds.simpleproductfeeds.com/abc123/gmcfeed-fr.txt",
"product_count": 1482,
"last_run_at": "2026-03-09T14:30:00Z",
"created_at": "2026-02-15T10:00:00Z"
},
{
"id": "feed_3",
"object": "feed",
"feed_type": "market",
"locale": null,
"display_name": "Canada Feed",
"feed_url": "https://feeds.simpleproductfeeds.com/abc123/gmcfeed-canada-feed.txt",
"product_count": 850,
"last_run_at": "2026-03-09T14:30:00Z",
"created_at": "2026-03-01T12:00:00Z"
}
]
}
Response fields
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier with feed_ prefix. |
object | string | Always "feed". |
feed_type | string | Feed type: "primary", "language", or "market". |
locale | string | null | ISO locale code for language feeds (e.g., "fr", "de"). Null for primary and market feeds. |
display_name | string | Human-readable name for the feed. |
feed_url | string | null | Public URL of the feed output file. Null if never generated. |
product_count | integer | Number of products in this feed. |
last_run_at | string | null | ISO 8601 timestamp of the last successful run. |
created_at | string | ISO 8601 timestamp when the feed was created. |
Get a feed
/v1/feeds/:id Returns a feed’s current status, product count, public feed URL, and last generation details.
Required scope: read_feeds
Request
curl https://app.simpleproductfeeds.com/v1/feeds/feed_1 \
-H "Authorization: Bearer spf_live_sk_your_key_here"
The feed_ prefix is optional — both feed_1 and 1 are accepted.
Response
The detail view is a superset of the list shape, adding the feed-scoped status and configuration fields.
{
"data": {
"id": "feed_1",
"object": "feed",
"feed_type": "primary",
"locale": null,
"display_name": "Primary",
"feed_url": "https://feeds.simpleproductfeeds.com/abc123/gmcfeed.txt",
"product_count": 1482,
"last_run_at": "2026-03-09T14:30:00Z",
"created_at": "2026-01-10T08:00:00Z",
"status": "fresh",
"target_market": null,
"product_selection_mode": "all",
"scope_count": 1482,
"last_run_id": "run_567"
}
}
Response fields
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier with feed_ prefix. |
object | string | Always "feed". |
feed_type | string | Feed type: "primary", "language", or "market". |
locale | string | null | ISO locale code for language feeds. Null otherwise. |
display_name | string | Human-readable name for the feed. |
feed_url | string | null | Public URL of the feed output file. Null if never generated. |
product_count | integer | Number of products in the feed. |
last_run_at | string | null | ISO 8601 timestamp of the last successful run. |
created_at | string | ISO 8601 timestamp when the feed was created. |
status | string | Feed-scoped status: "fresh", "generating", or "never_generated". |
target_market | string | null | Market code for market feeds (e.g. "GB"). Null otherwise. |
product_selection_mode | string | Product selection: "all", "collection", or "manual". |
scope_count | integer | null | Total variant count from the feed's scope snapshot. Null if not yet computed. See Get feed scope counts for the full breakdown. |
last_run_id | string | null | ID of the last successful run (with run_ prefix). Null if never run. |
Feed status values
| Status | Description |
|---|---|
fresh | The feed is up to date. No extract is running. |
generating | An extract is currently in progress. |
never_generated | No extracts have been created yet. |
Errors
| Status | Code | Description |
|---|---|---|
| 404 | resource_not_found | No feed found with the given ID. |
Create a feed
/v1/feeds Creates a market or language feed. The new feed inherits the primary feed’s column mapping, parsing settings, and per-feed configuration; customize it afterward with rules, mappings, and settings. The primary feed is created at install and cannot be created via the API.
Creating additional feeds requires a paid plan (Growth or Premium). Free and Starter plans return 403 plan_upgrade_required.
Required scope: write_feeds
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
feed_type | string | Yes | market or language. |
display_name | string | Yes | Human label for the feed; also produces the feed slug. |
target_market | string | No | Market code for a market feed, e.g. GB (uppercased). |
locale | string | No | Language code for a language feed, e.g. fr. Requires translation scopes. |
product_selection_mode | string | No | all (default), collection, or manual. |
selected_collection_title | string | Conditional | Required when product_selection_mode is collection; must match a real collection in your store. |
selected_collection_id | string | No | The Shopify collection GID, when scoping by collection. |
Request
curl -X POST https://app.simpleproductfeeds.com/v1/feeds \
-H "Authorization: Bearer spf_live_sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{"feed_type": "market", "display_name": "UK Feed", "target_market": "GB"}'
Response
Returns the created feed (same shape as Get a feed) with status 201 Created.
Errors
| Status | Code | Description |
|---|---|---|
| 400 | label_required | display_name is missing or blank. |
| 400 | locale_invalid | locale is not a valid language code. |
| 403 | plan_upgrade_required | Your plan does not allow additional feeds. |
| 409 | slug_conflict | A feed with the same name (slug) already exists. |
| 422 | invalid_feed_type | feed_type is not market or language. |
| 422 | collection_not_found | The collection title does not match a collection in your store. |
Update a feed
/v1/feeds/:id Updates a non-primary feed’s editable metadata. locale, product_selection_mode, and feed_type are set at creation and cannot be changed afterward. The primary feed cannot be edited.
Required scope: write_feeds
Parameters
| Parameter | Type | Description |
|---|---|---|
display_name | string | New label for the feed. |
target_market | string | New market code (uppercased). |
target_country | string | New target country. |
Request
curl -X PATCH https://app.simpleproductfeeds.com/v1/feeds/feed_3 \
-H "Authorization: Bearer spf_live_sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{"display_name": "UK Products", "target_market": "GB"}'
Response
Returns the updated feed (same shape as Get a feed).
Errors
| Status | Code | Description |
|---|---|---|
| 403 | primary_feed_immutable | The primary feed cannot be edited. |
| 404 | resource_not_found | No feed found with the given ID. |
| 422 | no_updatable_fields | No editable fields were provided. |
Get feed scope counts
/v1/feeds/:id/scope Returns the feed’s product-variant partition — how many variants are included vs. excluded by the feed’s rules and product selection. Counts come from a cached snapshot computed in the background.
Required scope: read_feeds
Request
curl https://app.simpleproductfeeds.com/v1/feeds/feed_1/scope \
-H "Authorization: Bearer spf_live_sk_your_key_here"
Response
{
"data": {
"feed_id": "feed_1",
"status": "fresh",
"included_count": 1482,
"excluded_count": 56,
"total_count": 1538,
"computed_at": "2026-03-09T14:30:00Z"
}
}
Scope status values
| Status | Description |
|---|---|
fresh | Counts reflect the current feed and rules. |
refreshing | The feed changed since the last computation; cached counts are returned while a refresh runs in the background. Poll until fresh. |
computing | No snapshot exists yet; counts are null while the first computation runs. Poll until fresh. |
Debug row transformations
/v1/feeds/:id/debug_rows Traces up to 5 source rows through the transformation pipeline and answers “why did this row come out this way?” — per row you get the merged source input, the transformed output (materialized even when the row is excluded, so you can see its would-be output), and the exclusion verdict. Pass an optional channel_slug to additionally see the channel-render view: the exact columns and values the export for that channel would ship.
Read-only: nothing is written. row_ids are source variant IDs — the id values from the source data (also returned by the products endpoints).
Required scope: read_feeds
Parameters
| Parameter | Type | Description |
|---|---|---|
row_ids | array of strings | Required. 1–5 source variant IDs to trace. |
channel_slug | string | Optional channel (e.g. google_merchant_center, commission_junction). Must be connected to this feed. Adds the rendered view to non-excluded rows. |
Request
curl -X POST https://app.simpleproductfeeds.com/v1/feeds/feed_1/debug_rows \
-H "Authorization: Bearer spf_live_sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{"row_ids": ["44012345678901"], "channel_slug": "google_merchant_center"}'
Response
{
"data": {
"feed_id": "feed_1",
"channel_slug": "google_merchant_center",
"rows": [
{
"row_id": "44012345678901",
"input": {
"id": "44012345678901",
"title": "Blue T-Shirt - Medium",
"price": "19.99"
},
"output": {
"id": "shopify_US_8012345678901_44012345678901",
"title": "Blue T-Shirt - Medium",
"price": "19.99 USD"
},
"excluded": false,
"exclude_reason": null,
"rendered": {
"renderer": "GoogleShopping",
"columns": ["id", "title", "price"],
"values": {
"id": "shopify_US_8012345678901_44012345678901",
"title": "Blue T-Shirt - Medium",
"price": "19.99 USD"
}
}
}
]
}
}
Response fields
input output excluded rendered Errors
| Status | Code | Description |
|---|---|---|
400 | invalid_row_ids | row_ids missing, not an array, or more than 5 entries. |
404 | resource_not_found | Feed not found, or the channel isn’t connected to this feed. |
404 | rows_not_found | No products matched the given row_ids. |
422 | channel_not_renderable | The channel isn’t configured for rendering yet. |
Regenerate a feed
/v1/feeds/:id/regenerate Re-runs the transform and publish pipeline for this feed from the already-extracted product snapshot — use it after changing rules, mappings, settings, or product overrides to make the published feed reflect them. This does not re-pull products from Shopify; for a fresh extraction use POST /v1/extracts with type: full.
Returns a run you can poll at GET /v1/feeds/:id/runs/:run_id until its status is completed or failed.
Required scope: write_exports
Request
curl -X POST https://app.simpleproductfeeds.com/v1/feeds/feed_1/regenerate \
-H "Authorization: Bearer spf_live_sk_your_key_here"
Response
{
"data": {
"id": "run_42",
"object": "run",
"feed_id": "feed_1",
"status": "running",
"has_output": false,
"created_at": "2026-07-07T17:30:00Z",
"completed_at": null
}
}
Errors
| Status | Code | Description |
|---|---|---|
404 | resource_not_found | Feed not found. |
409 | run_in_progress | A run is already running for this feed — poll it instead of retrying. The message includes the running run’s ID. |
422 | feed_inactive | The feed is inactive; activate it first. |
422 | no_source_extract | No extracted snapshot exists yet — run a full extract first. |
List feed products
/v1/feeds/:id/products Returns transformed feed products with all rules, mappings, and transformations applied. This shows exactly what appears in your published feed, including excluded products and exclusion reasons.
Required scope: read_products
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (minimum 1). |
per_page | integer | 25 | Results per page (maximum 100). |
search | string | — | Search transformed product data. |
sort | string | — | Column name to sort by. |
order | string | asc | Sort direction: asc or desc. |
Request
curl "https://app.simpleproductfeeds.com/v1/feeds/feed_1/products?page=1&per_page=5" \
-H "Authorization: Bearer spf_live_sk_your_key_here"
Response
{
"data": [
{
"object": "feed_product",
"excluded": false,
"excluded_reason": null,
"fields": {
"id": "shopify_US_8012345678901_44012345678901",
"title": "Blue T-Shirt - Medium",
"description": "A comfortable blue cotton t-shirt.",
"link": "https://my-store.myshopify.com/products/blue-t-shirt?variant=44012345678901",
"image_link": "https://cdn.shopify.com/s/files/1/example/shirt-blue.jpg",
"price": "29.99 USD",
"sale_price": "29.99 USD",
"availability": "in_stock",
"brand": "My Brand",
"google_product_category": "Apparel & Accessories > Clothing > Shirts & Tops"
}
},
{
"object": "feed_product",
"excluded": true,
"excluded_reason": "Out of stock",
"fields": {
"id": "shopify_US_8012345678902_44012345678902",
"title": "Red T-Shirt - Large",
"availability": "out_of_stock"
}
}
],
"meta": {
"page": 1,
"per_page": 5,
"total": 1482,
"total_pages": 297,
"has_more": true
}
}
Response fields
| Field | Type | Description |
|---|---|---|
object | string | Always "feed_product". |
excluded | boolean | Whether this product is excluded from the feed by a rule. |
excluded_reason | string | null | Reason for exclusion, if excluded. |
fields | object | All feed column values for this product after transformations are applied. |
Errors
| Status | Code | Description |
|---|---|---|
| 404 | resource_not_found | No feed found with the given ID. |
| 422 | no_feed | No feed data has been generated for this feed yet. |