Documentation Index
Fetch the complete documentation index at: https://docs.fanfare.io/llms.txt
Use this file to discover all available pages before exploring further.
Products API
Products represent items that can be distributed through experiences. Use these endpoints to create, manage, and organize products with their variants and media assets.
Create Product
Create a new product or update an existing one (upsert when sync source is provided).
POST /api/v1/products
Authentication
Request Body
interface CreateProductRequest {
name: string;
description?: string;
sku?: string;
price?: number;
currencyCode?: string;
status?: "ACTIVE" | "DRAFT" | "ARCHIVED";
metadata?: Record<string, unknown>;
productMediaAssets?: ProductMediaAssetInput[];
primarySyncSource?: SyncSourceInput;
}
interface ProductMediaAssetInput {
mediaAsset: {
url: string;
type: "IMAGE" | "VIDEO";
altText?: string;
width?: number;
height?: number;
};
purpose: "PRODUCT" | "VARIANT" | "THUMBNAIL" | "GALLERY";
position: number;
}
interface SyncSourceInput {
syncSource: string;
syncSourceId: string;
syncStatus?: "PENDING" | "SUCCESS" | "FAILED";
lastSyncedAt?: string;
sourceData?: Record<string, unknown>;
}
Response
interface Product {
id: string;
organizationId: string;
name: string;
description: string | null;
sku: string | null;
price: number | null;
currencyCode: string | null;
status: "ACTIVE" | "DRAFT" | "ARCHIVED";
metadata: Record<string, unknown> | null;
primarySyncSourceId: string | null;
createdAt: string;
updatedAt: string;
variants?: ProductVariant[];
mediaAssets?: ProductMediaAsset[];
}
Example
curl -X POST https://admin.fanfare.io/api/v1/products \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Limited Edition Sneakers",
"description": "Exclusive release",
"sku": "SNKR-001",
"price": 199.99,
"currencyCode": "USD",
"status": "ACTIVE",
"productMediaAssets": [
{
"mediaAsset": {
"url": "https://cdn.example.com/sneakers-main.jpg",
"type": "IMAGE",
"altText": "Limited Edition Sneakers"
},
"purpose": "PRODUCT",
"position": 0
}
]
}'
Response:
{
"id": "prod_01HXYZ123456789",
"organizationId": "org_01HXYZ123456789",
"name": "Limited Edition Sneakers",
"description": "Exclusive release",
"sku": "SNKR-001",
"price": 199.99,
"currencyCode": "USD",
"status": "ACTIVE",
"metadata": null,
"primarySyncSourceId": null,
"createdAt": "2024-12-01T10:00:00Z",
"updatedAt": "2024-12-01T10:00:00Z",
"variants": [],
"mediaAssets": [
{
"id": "pma_01HXYZ123456789",
"productId": "prod_01HXYZ123456789",
"mediaAssetId": "ma_01HXYZ123456789",
"purpose": "PRODUCT",
"position": 0
}
]
}
Upsert with Sync Source
When a sync source is provided, the endpoint will update an existing product with matching sync source:
curl -X POST https://admin.fanfare.io/api/v1/products \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Sneakers",
"price": 249.99,
"primarySyncSource": {
"syncSource": "shopify",
"syncSourceId": "gid://shopify/Product/12345",
"syncStatus": "SUCCESS",
"sourceData": {
"handle": "limited-edition-sneakers",
"vendor": "Nike"
}
}
}'
List Products
List all products in your organization.
GET /api/v1/products
Authentication
Query Parameters
| Parameter | Type | Description |
|---|
include | string | Relations to include (variants, mediaAssets) |
Example
curl -X GET "https://admin.fanfare.io/api/v1/products?include=variants,mediaAssets" \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Response:
[
{
"id": "prod_01HXYZ123456789",
"name": "Limited Edition Sneakers",
"sku": "SNKR-001",
"price": 199.99,
"status": "ACTIVE",
"variants": [...],
"mediaAssets": [...]
},
{
"id": "prod_01HXYZ123456790",
"name": "Exclusive T-Shirt",
"sku": "TSHIRT-001",
"price": 49.99,
"status": "ACTIVE"
}
]
Search Products
Search for products by sync source.
GET /api/v1/products/search
Authentication
Query Parameters
| Parameter | Type | Description |
|---|
syncSource | string | Sync source type (e.g., shopify) |
syncSourceId | string | External ID from the sync source |
Example
curl -X GET "https://admin.fanfare.io/api/v1/products/search?syncSource=shopify&syncSourceId=gid://shopify/Product/12345" \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Get Product
Get a single product by ID.
GET /api/v1/products/:productId
Authentication
Path Parameters
| Parameter | Type | Description |
|---|
productId | string | The product ID |
Query Parameters
| Parameter | Type | Description |
|---|
include | string | Relations to include (default: mediaAssets) |
Example
curl -X GET "https://admin.fanfare.io/api/v1/products/prod_01HXYZ123456789?include=variants,mediaAssets" \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Error Responses
| Status | Error | Description |
|---|
| 404 | Product not found | Product ID does not exist |
Update Product
Update an existing product.
PUT /api/v1/products/:productId
Authentication
Path Parameters
| Parameter | Type | Description |
|---|
productId | string | The product ID |
Request Body
interface UpdateProductRequest {
name?: string;
description?: string | null;
sku?: string | null;
price?: number | null;
currencyCode?: string | null;
status?: "ACTIVE" | "DRAFT" | "ARCHIVED";
metadata?: Record<string, unknown> | null;
}
Example
curl -X PUT https://admin.fanfare.io/api/v1/products/prod_01HXYZ123456789 \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"price": 179.99,
"status": "DRAFT"
}'
Delete Product
Archive a product.
DELETE /api/v1/products/:productId
Authentication
Path Parameters
| Parameter | Type | Description |
|---|
productId | string | The product ID |
Example
curl -X DELETE https://admin.fanfare.io/api/v1/products/prod_01HXYZ123456789 \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Add a media asset to a product.
POST /api/v1/products/:productId/media-assets
Request Body
interface AddMediaAssetRequest {
mediaAsset?: {
url: string;
type: "IMAGE" | "VIDEO";
altText?: string;
width?: number;
height?: number;
};
mediaAssetId?: string; // Use existing asset
position: number;
purpose: "PRODUCT" | "VARIANT" | "THUMBNAIL" | "GALLERY";
}
Example
curl -X POST https://admin.fanfare.io/api/v1/products/prod_01HXYZ123456789/media-assets \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"mediaAsset": {
"url": "https://cdn.example.com/sneakers-side.jpg",
"type": "IMAGE",
"altText": "Side view"
},
"position": 1,
"purpose": "GALLERY"
}'
GET /api/v1/products/:productId/media-assets
PUT /api/v1/products/:productId/media-assets/:assetId
interface UpdateMediaAssetRequest {
position?: number;
purpose?: "PRODUCT" | "VARIANT" | "THUMBNAIL" | "GALLERY";
}
PUT /api/v1/products/:productId/media-assets/reorder
interface ReorderRequest {
assetOrder: string[]; // Array of media asset IDs in desired order
}
Example
curl -X PUT https://admin.fanfare.io/api/v1/products/prod_01HXYZ123456789/media-assets/reorder \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"assetOrder": ["ma_01HXYZ3", "ma_01HXYZ1", "ma_01HXYZ2"]
}'
DELETE /api/v1/products/:productId/media-assets/:assetId
Product Variant Options
Get Assigned Options
Get variant options assigned to a product.
GET /api/v1/products/:productId/variant-options
Response
interface VariantOptionsResponse {
assignments: Array<{
organizationId: string;
productId: string;
optionId: string;
required: boolean;
sortOrder: number;
option: VariantOption;
values: VariantOptionValue[];
}>;
}
interface VariantOption {
id: string;
name: string;
displayName: string | null;
}
interface VariantOptionValue {
id: string;
optionId: string;
value: string;
displayValue: string | null;
sortOrder: number;
}
Example
curl -X GET https://admin.fanfare.io/api/v1/products/prod_01HXYZ123456789/variant-options \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Response:
{
"assignments": [
{
"organizationId": "org_01HXYZ123456789",
"productId": "prod_01HXYZ123456789",
"optionId": "opt_01HXYZ123456789",
"required": true,
"sortOrder": 0,
"option": {
"id": "opt_01HXYZ123456789",
"name": "size",
"displayName": "Size"
},
"values": [
{ "id": "val_01HXYZ1", "optionId": "opt_01HXYZ", "value": "S", "displayValue": "Small", "sortOrder": 0 },
{ "id": "val_01HXYZ2", "optionId": "opt_01HXYZ", "value": "M", "displayValue": "Medium", "sortOrder": 1 },
{ "id": "val_01HXYZ3", "optionId": "opt_01HXYZ", "value": "L", "displayValue": "Large", "sortOrder": 2 }
]
}
]
}
Assign Options
Assign variant options to a product.
POST /api/v1/products/:productId/variant-options
Request Body
interface AssignOptionsRequest {
options: Array<{
optionId: string;
required?: boolean;
sortOrder?: number;
valueIds: string[];
}>;
}
Example
curl -X POST https://admin.fanfare.io/api/v1/products/prod_01HXYZ123456789/variant-options \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"options": [
{
"optionId": "opt_01HXYZ123456789",
"required": true,
"sortOrder": 0,
"valueIds": ["val_01HXYZ1", "val_01HXYZ2", "val_01HXYZ3"]
}
]
}'
Remove Option
Remove a variant option from a product.
DELETE /api/v1/products/:productId/variant-options/:optionId
Error Responses
| Status | Error | Description |
|---|
| 409 | Cannot remove: variants exist | Delete variants using this option first |
Product Variants
Create Variant
POST /api/v1/products/:productId/variants
Request Body
interface CreateVariantRequest {
name: string;
sku?: string;
price?: number;
compareAtPrice?: number;
inventoryQuantity?: number;
optionValues: Array<{
optionId: string;
valueId: string;
}>;
metadata?: Record<string, unknown>;
}
Example
curl -X POST https://admin.fanfare.io/api/v1/products/prod_01HXYZ123456789/variants \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Limited Edition Sneakers - Size M",
"sku": "SNKR-001-M",
"price": 199.99,
"inventoryQuantity": 50,
"optionValues": [
{
"optionId": "opt_01HXYZ123456789",
"valueId": "val_01HXYZ2"
}
]
}'
List Variants
GET /api/v1/products/:productId/variants
Update Variant
PUT /api/v1/products/:productId/variants/:variantId
Delete Variant
DELETE /api/v1/products/:productId/variants/:variantId
SDK Usage
import { FanfareAdmin } from "@fanfare/admin-sdk";
const admin = new FanfareAdmin({
secretKey: process.env.FANFARE_SECRET_KEY,
});
// Create product
const product = await admin.products.create({
name: "Limited Edition Sneakers",
sku: "SNKR-001",
price: 199.99,
currencyCode: "USD",
productMediaAssets: [
{
mediaAsset: {
url: "https://cdn.example.com/sneakers.jpg",
type: "IMAGE",
},
purpose: "PRODUCT",
position: 0,
},
],
});
// List products
const products = await admin.products.list({
include: ["variants", "mediaAssets"],
});
// Update product
await admin.products.update(product.id, {
price: 179.99,
});
// Add media asset
await admin.products.addMediaAsset(product.id, {
mediaAsset: {
url: "https://cdn.example.com/sneakers-side.jpg",
type: "IMAGE",
},
purpose: "GALLERY",
position: 1,
});
// Assign variant options
await admin.products.assignVariantOptions(product.id, {
options: [{ optionId: "opt_size", required: true, valueIds: ["val_s", "val_m", "val_l"] }],
});
// Create variant
await admin.products.createVariant(product.id, {
name: "Sneakers - Medium",
sku: "SNKR-001-M",
price: 199.99,
inventoryQuantity: 50,
optionValues: [{ optionId: "opt_size", valueId: "val_m" }],
});
// Delete product
await admin.products.delete(product.id);