API Documentation
Integration reference for connecting your Commerce Manager to the Qustom Collectibles storefront. All endpoints require API key authentication and accept JSON request bodies.
Authentication
Every request must include an API key in the X-API-Key header. The key is validated against the store's STORE_API_KEY secret.
X-API-Key: your_store_api_key_hereIf you don't have the API key, request it from the store administrator. Requests without a valid key receive a 401 Unauthorized response.
Products API
Full product management — push upserts, list inventory, unpublish, or permanently delete products from your Commerce Manager.
/api/functions/externalProductsApiaction: "list"
Returns up to 500 products, newest first. Optionally filter by tcg, product_type, status, pokemon_set, or sku. Use this to sync stock levels and product details back to your Commerce Manager.
{
"action": "list",
"tcg": "pokemon",
"product_type": "sealed",
"status": "publish",
"limit": 500
}{
"products": [
{
"id": "abc123...",
"sku": "PRC-SV-001",
"name": "Scarlet & Violet Booster Pack",
"regular_price": "79.99",
"sale_price": "",
"stock_quantity": 48,
"stock_status": "instock",
"tcg": "pokemon",
"product_type": "sealed",
"singles_subcategory": "auto",
"pokemon_set": "Scarlet & Violet",
"status": "publish",
"allowed_payment_methods": [
"eft"
],
"updated_date": "2026-08-01T12:00:00Z"
}
]
}action: "upsert"
Create or update a product. Matches existing records by SKU — if a product with the same SKU exists, it is updated; otherwise a new record is created. The pokemon_set field is manually allocated per product (it is not inferred from the product name or categories), so pass it explicitly to assign the product to a set. Use the taxonomy or listSets action to retrieve the list of valid set names. For singles, pass singles_subcategory to assign the card to a subcategory (SIRs & IRs, Full Arts, Promos, EX Cards, Uncategorized) — use "auto" to let the store detect it from the card name. Pass allowed_payment_methods to restrict the product to specific checkout methods (yoco, payfast, eft) — at checkout, only methods allowed by every item in the cart are shown; omit or pass an empty array to allow all methods.
{
"action": "upsert",
"product": {
"sku": "PRC-SV-001",
"name": "Scarlet & Violet Booster Pack",
"description": "1x Scarlet & Violet base set booster pack.",
"regular_price": "79.99",
"sale_price": "69.99",
"stock_quantity": 48,
"stock_status": "instock",
"image_url": "https://cdn.example.com/sv-pack.jpg",
"categories": [
"Sealed",
"Scarlet & Violet"
],
"tags": [
"pokemon",
"booster"
],
"pokemon_set": "Scarlet & Violet",
"tcg": "pokemon",
"product_type": "sealed",
"singles_subcategory": "auto",
"allowed_payment_methods": [
"eft"
],
"status": "publish"
}
}{
"product": {
"id": "abc123..."
}
}action: "unpublish"
Marks a product as draft (hidden from the storefront). Provide either the internal product id or the SKU.
{
"action": "unpublish",
"sku": "PRC-SV-001"
}{
"success": true
}action: "delete"
Permanently deletes a product from the store. Provide either the internal product id or the SKU. This action cannot be undone.
{
"action": "delete",
"sku": "PRC-SV-001"
}{
"success": true
}action: "taxonomy"
Returns the store's full TCG taxonomy — supported games, product types, and Pokémon sets grouped by era. Set data is sourced dynamically from the PokemonSet entity, which is synced nightly from Scrydex (scrydex.com/pokemon/expansions) and covers all eras from Base Set through the current Mega Evolution era. Use this to populate dropdowns in external platforms so their category structure matches this store exactly.
{
"action": "taxonomy"
}{
"tcg_games": [
{
"value": "pokemon",
"label": "Pokémon"
},
{
"value": "mtg",
"label": "MTG"
},
{
"value": "yugioh",
"label": "Yu-Gi-Oh!"
},
{
"value": "onepiece",
"label": "One Piece"
},
{
"value": "digimon",
"label": "Digimon"
},
{
"value": "other",
"label": "Other"
}
],
"product_types": [
{
"value": "sealed",
"label": "Sealed"
},
{
"value": "singles",
"label": "Singles"
},
{
"value": "graded",
"label": "Graded"
},
{
"value": "figurines",
"label": "Figurines"
},
{
"value": "storage",
"label": "Storage"
},
{
"value": "custom_art",
"label": "Custom Art"
},
{
"value": "grading_service",
"label": "Slabbing"
}
],
"singles_subcategories": [
{
"value": "auto",
"label": "Auto-detect from name"
},
{
"value": "sir_ir",
"label": "SIRs & IRs"
},
{
"value": "full_art",
"label": "Full Arts"
},
{
"value": "hyper_rare",
"label": "Hyper Rares"
},
{
"value": "tg_gg",
"label": "TG & GG"
},
{
"value": "promo",
"label": "Promos"
},
{
"value": "ex",
"label": "EX Cards"
},
{
"value": "uncategorized",
"label": "Uncategorized"
}
],
"pokemon_eras": [
{
"name": "Mega Evolution Era",
"range": "",
"sets": [
"Pitch Black",
"Chaos Rising",
"Perfect Order",
"Ascended Heroes",
"Phantasmal Flames"
]
},
{
"name": "Scarlet & Violet Era",
"range": "",
"sets": [
"Scarlet & Violet",
"Paldea Evolved",
"Obsidian Flames",
"151",
"Prismatic Evolutions"
]
}
],
"pokemon_sets": [
"Pitch Black",
"Chaos Rising",
"Scarlet & Violet",
"Paldea Evolved",
"151"
],
"pokemon_sets_detail": [
{
"name": "Pitch Black",
"tcg_api_id": "me5",
"era": "Mega Evolution Era",
"series": "Mega Evolution",
"release_date": "2026-07-17",
"logo_url": "https://images.scrydex.com/pokemon/me5-logo/logo",
"total_cards": 120,
"status": "released"
},
{
"name": "Scarlet & Violet",
"tcg_api_id": "sv1",
"era": "Scarlet & Violet Era",
"series": "Scarlet & Violet",
"release_date": "2023-03-31",
"logo_url": "https://images.scrydex.com/pokemon/sv1-logo/logo",
"total_cards": 198,
"status": "released"
}
]
}action: "listSets"
Returns all Pokémon TCG sets with full metadata (era, series, release date, logo URL, card count, release status). Data is synced nightly from Scrydex and includes every expansion from Base Set through the latest Mega Evolution sets. Use this to build set pickers, browse-by-set UIs, or sync set imagery to external platforms.
{
"action": "listSets"
}{
"sets": [
{
"name": "Pitch Black",
"tcg_api_id": "me5",
"era": "Mega Evolution Era",
"series": "Mega Evolution",
"release_date": "2026-07-17",
"logo_url": "https://images.scrydex.com/pokemon/me5-logo/logo",
"total_cards": 120,
"status": "released"
},
{
"name": "Chaos Rising",
"tcg_api_id": "me4",
"era": "Mega Evolution Era",
"series": "Mega Evolution",
"release_date": "2026-05-22",
"logo_url": "https://images.scrydex.com/pokemon/me4-logo/logo",
"total_cards": 122,
"status": "released"
}
]
}| Field | Type | Required | Description |
|---|---|---|---|
| sku | string | Yes | Unique product identifier used for matching |
| name | string | No | Product display name |
| description | string | No | Full product description |
| regular_price | string|number | No | Standard price in ZAR |
| sale_price | string|number | No | Sale price (if on sale) |
| stock_quantity | number | No | Units in stock (defaults to 0) |
| stock_status | enum | No | instock | outofstock | onbackorder |
| image_url | string | No | Single image URL (added to images array) |
| images | string[] | No | Array of image URLs (used if image_url omitted) |
| categories | string[] | No | Category labels |
| tags | string[] | No | Product tags |
| pokemon_set | string | No | Pokémon TCG set name (e.g. "Scarlet & Violet", "151"). Manually allocated — not auto-inferred from the product name. Use the taxonomy or listSets action to retrieve valid set names. |
| tcg | enum | No | pokemon | mtg | yugioh | onepiece | digimon | other. Alias: tcg_game |
| product_type | enum | No | sealed | singles | graded | figurines | storage | custom_art | grading_service. Alias: tcg_product_type |
| singles_subcategory | enum | No | auto | sir_ir | full_art | hyper_rare | tg_gg | promo | ex | uncategorized. Only meaningful when product_type is "singles". "auto" detects from the card name (Illustration Rare, Trainer/Galarian Gallery, Hyper Rare, Full Art, Promo, EX keywords); set explicitly to override. Preserved on re-sync if not provided. |
| featured | boolean | No | Featured product flag |
| slug | string | No | URL-friendly slug |
| status | enum | No | publish | draft (defaults to publish) |
| allowed_payment_methods | string[] | No | Restrict checkout to specific methods — yoco | payfast | eft. Empty array (or omitted) allows all methods. At checkout, only methods allowed by every item in the cart are shown (most restrictive item wins). Preserved on re-sync if not provided. |
Orders API
Full order management — list, retrieve, update, and delete orders from your Commerce Manager, matching the control level of the WooCommerce REST API.
/api/functions/externalOrdersApiaction: "list"
Returns up to 500 orders, newest first. Optionally filter by a since timestamp (ISO 8601) to only fetch orders created after that date.
{
"action": "list",
"since": "2026-07-01T00:00:00Z"
}{
"orders": [
{
"id": "ord123...",
"order_number": "QC-1001",
"order_date": "2026-07-31T10:30:00Z",
"customer_name": "Jane Doe",
"customer_email": "jane@example.com",
"phone": "+27821234567",
"shipping_address": "123 Main St, Johannesburg",
"shipping_method": "door",
"payment_method": "yoco",
"payment_status": "paid",
"status": "processing",
"subtotal": 159.98,
"shipping_cost": 99,
"total": 258.98,
"items": [
{
"product_id": "prod123",
"product_name": "Scarlet & Violet Booster Pack",
"sku": "PRC-SV-001",
"quantity": 2,
"price": "79.99",
"total": 159.98
}
]
}
]
}action: "get"
Retrieve a single order by its internal id or order_number.
{
"action": "get",
"order_number": "QC-1001"
}{
"order": {
"id": "ord123...",
"order_number": "QC-1001",
"order_date": "2026-07-31T10:30:00Z",
"customer_id": "usr123...",
"customer_name": "Jane Doe",
"customer_email": "jane@example.com",
"status": "processing",
"payment_status": "paid",
"total": 258.98,
"items": []
}
}action: "create"
Create a new order on the store, linked to a customer. Pass customer_id to map the order to an existing customer (retrieve it via the Customers API). If customer_id is omitted, the order is created with the provided customer_name and email as a guest-style record. An order_number is auto-generated if not supplied.
{
"action": "create",
"customer_id": "usr123...",
"customer_name": "Jane Doe",
"email": "jane@example.com",
"phone": "+27821234567",
"shipping_address": "123 Main St, Johannesburg",
"shipping_method": "door",
"payment_method": "yoco",
"payment_status": "paid",
"status": "processing",
"items": [
{
"product_id": "prod123",
"name": "Scarlet & Violet Booster Pack",
"price": "79.99",
"quantity": 2
}
],
"subtotal": 159.98,
"shipping_cost": 99,
"total": 258.98
}{
"order": {
"id": "ord123...",
"order_number": "QC-1001",
"customer_id": "usr123...",
"status": "processing",
"total": 258.98
}
}action: "update"
Update an order. Provide id or order_number to identify the order, and a fields object with the changes. Updatable fields: status, payment_status, payment_method, customer_name, email, phone, shipping_address, shipping_method, locker_details, subtotal, shipping_cost, total, items, order_number, banking_details.
{
"action": "update",
"order_number": "QC-1001",
"fields": {
"status": "shipped",
"payment_status": "paid"
}
}{
"order": {
"id": "ord123...",
"order_number": "QC-1001",
"status": "shipped",
"payment_status": "paid"
}
}action: "delete"
Permanently deletes an order. Provide id or order_number. This action cannot be undone.
{
"action": "delete",
"order_number": "QC-1001"
}{
"success": true
}| Field | Type | Required | Description |
|---|---|---|---|
| action | string | Yes | list | get | create | update | delete |
| id | string | No | Internal order id (for get/update/delete) |
| order_number | string | No | Order number (alternative to id for get/update/delete) |
| since | string (ISO 8601) | No | list only — only return orders created after this datetime |
| customer_id | string | No | create only — links the order to a customer (from Customers API) |
| fields | object | No | update only — object of fields to change (status, payment_status, etc.) |
Customers API
Manage store customers (users) from your Commerce Manager — list, retrieve, invite new customers, update profiles, or remove access.
/api/functions/externalCustomersApiaction: "list"
Returns up to 500 customers, newest first. Optionally filter by role (user or admin).
{
"action": "list",
"role": "user"
}{
"customers": [
{
"id": "usr123...",
"email": "jane@example.com",
"full_name": "Jane Doe",
"role": "user",
"created_date": "2026-07-15T09:00:00Z"
}
]
}action: "get"
Retrieve a single customer by internal id or email.
{
"action": "get",
"email": "jane@example.com"
}{
"customer": {
"id": "usr123...",
"email": "jane@example.com",
"full_name": "Jane Doe",
"role": "user",
"created_date": "2026-07-15T09:00:00Z"
}
}action: "invite"
Invites a new customer to the store by email. They receive an email to set up their account and password. Pass the customer profile details (first_name, last_name, phone, shipping_address, pudo_locker) to pre-populate their account, and role (defaults to "user").
{
"action": "invite",
"email": "newcustomer@example.com",
"first_name": "John",
"last_name": "Smith",
"phone": "+27821234567",
"shipping_address": "123 Main St, Johannesburg",
"pudo_locker": "",
"role": "user"
}{
"customer": {
"id": "usr456...",
"email": "newcustomer@example.com",
"first_name": "John",
"last_name": "Smith",
"phone": "+27821234567",
"shipping_address": "123 Main St, Johannesburg",
"pudo_locker": "",
"role": "user"
}
}action: "update"
Update a customer profile. Provide id or email to identify the customer, and a fields object. Updatable fields: first_name, last_name, phone, shipping_address, pudo_locker, role.
{
"action": "update",
"email": "jane@example.com",
"fields": {
"first_name": "Jane",
"last_name": "Smith",
"phone": "+27821234567",
"shipping_address": "456 Oak Ave, Johannesburg",
"pudo_locker": "JHB-001",
"role": "user"
}
}{
"customer": {
"id": "usr123...",
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Smith",
"phone": "+27821234567",
"shipping_address": "456 Oak Ave, Johannesburg",
"pudo_locker": "JHB-001",
"role": "user"
}
}action: "delete"
Permanently removes a customer from the store. Provide id or email. This action cannot be undone.
{
"action": "delete",
"email": "jane@example.com"
}{
"success": true
}| Field | Type | Required | Description |
|---|---|---|---|
| action | string | Yes | list | get | invite | update | delete |
| id | string | No | Internal customer id (for get/update/delete) |
| string | No | Customer email (alternative to id for get/update/delete; required for invite) | |
| role | enum | No | user | admin (list filter or invite role; defaults to user) |
| first_name | string | No | invite — customer first name |
| last_name | string | No | invite — customer surname |
| phone | string | No | invite — contact number |
| shipping_address | string | No | invite — default shipping address |
| pudo_locker | string | No | invite — preferred PUDO locker (optional) |
| fields | object | No | update only — object of fields to change (first_name, last_name, phone, shipping_address, pudo_locker, role) |
Error Responses
| Status | Meaning |
|---|---|
| 401 | Missing or invalid X-API-Key header |
| 400 | Missing required fields or unknown action |
| 500 | Server error — see response body for details |
Quick Start Example
A complete cURL example for upserting a product:
curl -X POST https://your-app-domain.base44.app/api/functions/externalProductsApi \
-H "Content-Type: application/json" -H "X-API-Key: your_store_api_key_here" -d '{
"action": "upsert",
"product": {
"sku": "PRC-SV-001",
"name": "Scarlet & Violet Booster Pack",
"regular_price": "79.99",
"stock_quantity": 48,
"stock_status": "instock",
"pokemon_set": "Scarlet & Violet",
"tcg": "pokemon",
"product_type": "sealed"
}
}'