Product Catalog
Get all product swaps for a shop
Retrieves all configured product swap automations for the authenticated shop. Product swaps allow automatic replacement of products in subscription orders based on billing cycles or recurring schedules.
What are Product Swaps? Product swaps enable merchants to automatically replace products in subscription orders at specific billing cycles. This is useful for seasonal products, progression paths (e.g., beginner → intermediate → advanced), or variety subscriptions.
Key Features:
- View all configured swap automations
- See source and destination product mappings
- Check which billing cycles trigger swaps
- Identify recurring vs one-time swaps
- Review discount carry-forward settings
Swap Configuration Types:
- One-Time Swap: Occurs at a specific billing cycle
- Recurring Swap: Occurs at every order
- Conditional Swap: Based on billing cycle number
Use Cases:
- Seasonal product rotations (summer → fall → winter products)
- Subscription progression (trial → full product)
- Variety boxes with automatic product rotation
- Product lifecycle management in subscriptions
- A/B testing different products in subscriptions
Authentication: Requires valid X-API-Key header
GET
/
api
/
external
/
v2
/
product-swaps
Get all product swaps for a shop
curl --request GET \
--url https://subscription-admin.appstle.com/api/external/v2/product-swapsimport requests
url = "https://subscription-admin.appstle.com/api/external/v2/product-swaps"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://subscription-admin.appstle.com/api/external/v2/product-swaps', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const url = 'https://subscription-admin.appstle.com/api/external/v2/product-swaps';
const options = {method: 'GET'};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://subscription-admin.appstle.com/api/external/v2/product-swaps",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://subscription-admin.appstle.com/api/external/v2/product-swaps"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://subscription-admin.appstle.com/api/external/v2/product-swaps")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body[
{
"active": true,
"carryDiscountForward": true,
"checkForEveryRecurringOrder": false,
"createdAt": "2024-01-15T10:30:00Z",
"destinationVariants": "[{\"id\":67890,\"displayName\":\"Fall Blend Coffee\",\"imageSrc\":\"https://cdn.shopify.com/image2.jpg\",\"quantity\":2}]",
"discountCarryForward": "PERCENTAGE",
"forBillingCycle": 4,
"id": 10782,
"name": "Seasonal Coffee Rotation",
"shop": "example-shop.myshopify.com",
"sourceVariants": "[{\"id\":12345,\"displayName\":\"Summer Blend Coffee\",\"imageSrc\":\"https://cdn.shopify.com/image1.jpg\",\"quantity\":2}]",
"stopSwapEmails": false,
"updatedFirstOrder": false
},
{
"active": true,
"carryDiscountForward": false,
"checkForEveryRecurringOrder": true,
"destinationVariants": "[{\"id\":33333,\"displayName\":\"Advanced Kit\",\"imageSrc\":\"https://cdn.shopify.com/kit2.jpg\",\"quantity\":1}]",
"discountCarryForward": "NONE",
"forBillingCycle": null,
"id": 10783,
"name": "Monthly Variety Swap",
"shop": "example-shop.myshopify.com",
"sourceVariants": "[{\"id\":22222,\"displayName\":\"Beginner Kit\",\"imageSrc\":\"https://cdn.shopify.com/kit1.jpg\",\"quantity\":1}]",
"stopSwapEmails": true,
"updatedFirstOrder": false
}
]{
"detail": "Valid X-API-Key header is required",
"status": 401,
"title": "Authentication required",
"type": "https://example.com/errors/unauthorized"
}{
"detail": "API key does not have permission to view product swaps",
"status": 403,
"title": "Insufficient permissions",
"type": "https://example.com/errors/forbidden"
}Headers
Response
Successfully retrieved product swaps
Available options:
NONE, EXISTING_PLAN, PRODUCT_PLAN, PRODUCT_THEN_EXISTING ⌘I
Get all product swaps for a shop
curl --request GET \
--url https://subscription-admin.appstle.com/api/external/v2/product-swapsimport requests
url = "https://subscription-admin.appstle.com/api/external/v2/product-swaps"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://subscription-admin.appstle.com/api/external/v2/product-swaps', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const url = 'https://subscription-admin.appstle.com/api/external/v2/product-swaps';
const options = {method: 'GET'};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://subscription-admin.appstle.com/api/external/v2/product-swaps",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://subscription-admin.appstle.com/api/external/v2/product-swaps"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://subscription-admin.appstle.com/api/external/v2/product-swaps")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body[
{
"active": true,
"carryDiscountForward": true,
"checkForEveryRecurringOrder": false,
"createdAt": "2024-01-15T10:30:00Z",
"destinationVariants": "[{\"id\":67890,\"displayName\":\"Fall Blend Coffee\",\"imageSrc\":\"https://cdn.shopify.com/image2.jpg\",\"quantity\":2}]",
"discountCarryForward": "PERCENTAGE",
"forBillingCycle": 4,
"id": 10782,
"name": "Seasonal Coffee Rotation",
"shop": "example-shop.myshopify.com",
"sourceVariants": "[{\"id\":12345,\"displayName\":\"Summer Blend Coffee\",\"imageSrc\":\"https://cdn.shopify.com/image1.jpg\",\"quantity\":2}]",
"stopSwapEmails": false,
"updatedFirstOrder": false
},
{
"active": true,
"carryDiscountForward": false,
"checkForEveryRecurringOrder": true,
"destinationVariants": "[{\"id\":33333,\"displayName\":\"Advanced Kit\",\"imageSrc\":\"https://cdn.shopify.com/kit2.jpg\",\"quantity\":1}]",
"discountCarryForward": "NONE",
"forBillingCycle": null,
"id": 10783,
"name": "Monthly Variety Swap",
"shop": "example-shop.myshopify.com",
"sourceVariants": "[{\"id\":22222,\"displayName\":\"Beginner Kit\",\"imageSrc\":\"https://cdn.shopify.com/kit1.jpg\",\"quantity\":1}]",
"stopSwapEmails": true,
"updatedFirstOrder": false
}
]{
"detail": "Valid X-API-Key header is required",
"status": 401,
"title": "Authentication required",
"type": "https://example.com/errors/unauthorized"
}{
"detail": "API key does not have permission to view product swaps",
"status": 403,
"title": "Insufficient permissions",
"type": "https://example.com/errors/forbidden"
}