Product catalog export & import
Export your products as Shopify or WooCommerce CSV files, import them into your store, keep SKUs in sync, and bulk-create products from a spreadsheet with the API.
Your store needs products whose variant SKUs match your SKUs here — that is how orders find their way back to us. The fastest way to get there is to create products here and export them to your store.
Export to your store
In the dashboard open Products, optionally select products, then Export and pick a format. The download is a CSV ready for your store's importer:
| Format | File | Import it in |
|---|---|---|
| Shopify CSV | UTF-8, one row per variant, extra rows for additional images | Shopify admin → Products → Import |
| WooCommerce CSV | UTF-8 with BOM, a variable parent row + one variation row per variant |
WooCommerce → Products → Import |
| CSV | UTF-8 with BOM, one row per variant | Spreadsheets or any other platform |
Shopify and WooCommerce files contain enabled variants only (the generic CSV lists every variant with an enabled column). Archived products are left out unless you select them.
Shopify columns
| Column | Value |
|---|---|
Title, URL handle, Description (HTML), Tags |
From your product |
Vendor |
Your brand name |
Type |
The catalog product (e.g. Classic Unisex Tee) |
Status, Published on online store |
active / draft from your product |
Option1 name / Option1 value, Option2 …, Option3 … |
Variant options (e.g. Color, Size) |
SKU |
Your SKU — do not change it in Shopify |
Price |
Your retail price |
Weight value (grams), Requires shipping, Charge tax |
Shipping weight, TRUE, TRUE |
Inventory tracker |
Empty (print on demand: never out of stock) |
Fulfillment service |
manual (your server forwards the order — see the Shopify recipe) |
Product image URL, Variant image URL |
Our rendered mockups |
WooCommerce columns
Type (variable / variation / simple), SKU (parent SKU on the variable row, your SKU on each variation), Parent, Name, Published, Description, Regular price (your retail price), Attribute N name / value(s) / visible / global, Images (mockups), Categories, Tags, Tax status, In stock? and Weight (lbs) or Weight (kg) (choose the unit your store uses).
Generic CSV columns
product_id, product_title, product_status, product_external_id, catalog_product_id, variant_id, sku, catalog_variant_id, variant_title, color, size, options, enabled, retail_price, currency, variant_external_id, tags, image_url, created_at.
Keep your store in sync
- New variants or products — export again and import with "overwrite existing products" (Shopify matches on
URL handle; WooCommerce onSKU). - Price changes — wholesale price changes arrive as
catalog.price_changedevents; your retail prices are yours to adjust. - Changing a SKU — change it here first (
PATCH /products/{id}/variants/{variant_id}), then in your store. Until both match, orders for that variant fail with400 resource_missingonitems[i].sku. - Archiving — archive the product here (
DELETE /products/{id}) and unpublish it in your store.
Import into Swaglists: bulk-create from a spreadsheet
Have many designs? Create products with the API from a CSV of artwork URLs and SKUs. Example input:
title,artwork_url,catalog_product_id,sku_prefix
Sunset Vibes Tee,https://cdn.example.com/art/sunset.png,cp_01k8w1a2s3d4f5g6h7j8k9m0n1,SUNSET
Mountain Air Tee,https://cdn.example.com/art/mountain.png,cp_01k8w1a2s3d4f5g6h7j8k9m0n1,MOUNTAIN// bulk-create.mjs — node bulk-create.mjs designs.csv
import { readFile } from "node:fs/promises";
const API = "https://swaglists.com/api/v1";
const headers = { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json" };
const [header, ...rows] = (await readFile(process.argv[2], "utf8")).trim().split(/\r?\n/).map((l) => l.split(","));
const col = Object.fromEntries(header.map((h, i) => [h, i]));
for (const row of rows) {
const catalogProductId = row[col.catalog_product_id];
const catalog = await (await fetch(`${API}/catalog/products/${catalogProductId}`, { headers })).json();
const placement = catalog.placements[0].key;
const res = await fetch(`${API}/products`, {
method: "POST",
headers: { ...headers, "Idempotency-Key": `bulk-${row[col.sku_prefix]}` },
body: JSON.stringify({
catalog_product_id: catalogProductId,
title: row[col.title],
designs: [{ placement, layers: [{ url: row[col.artwork_url] }] }], // we download the artwork
variants: catalog.variants
.filter((v) => v.available)
.map((v) => ({ catalog_variant_id: v.id, sku: [row[col.sku_prefix], v.color, v.size].filter(Boolean).join("-").toUpperCase().replace(/[^A-Z0-9-]/g, "") })),
}),
});
const body = await res.json();
console.log(res.ok ? `✓ ${body.id} ${body.title} (${body.variants.length} variants)` : `✗ ${row[col.title]}: ${body.error.code} ${body.error.message}`);
for (const w of body.warnings ?? []) console.log(` ⚠ ${w.code}: ${w.message}`);
}# bulk_create.py — python bulk_create.py designs.csv
import csv, os, re, sys, requests
API = "https://swaglists.com/api/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['API_KEY']}"
with open(sys.argv[1], newline="") as f:
for row in csv.DictReader(f):
catalog = session.get(f"{API}/catalog/products/{row['catalog_product_id']}").json()
variants = [
{"catalog_variant_id": v["id"], "sku": re.sub(r"[^A-Z0-9-]", "", "-".join(filter(None, [row["sku_prefix"], v["color"], v["size"]])).upper())}
for v in catalog["variants"] if v["available"]
]
res = session.post(
f"{API}/products",
headers={"Idempotency-Key": f"bulk-{row['sku_prefix']}"},
json={
"catalog_product_id": row["catalog_product_id"],
"title": row["title"],
"designs": [{"placement": catalog["placements"][0]["key"], "layers": [{"url": row["artwork_url"]}]}],
"variants": variants,
},
)
body = res.json()
print(f"✓ {body['id']} {body['title']}" if res.ok else f"✗ {row['title']}: {body['error']['code']} {body['error']['message']}")Then export the new products to your store as described above. Respect the rate limit for large batches (the scripts make two requests per product).