Overview
Product APIs enable you to create and manage your product catalog in MartianPay. A product represents an item or service you sell, supporting everything from simple products to complex items with multiple variants, subscription plans, and rich media.
What is a Product?
A product represents an item or service that you sell to your customers. Products can be simple items with fixed pricing, or complex items with multiple variants (such as different sizes, colors, or configurations). The Product API allows you to create, manage, and organize your product catalog with support for options, variants, media assets, and subscription plans.
Each product:
- 🛍️ Represents an item or service for sale
- 💰 Supports one-time purchases or subscriptions
- 🎨 Has variants (size, color, etc.)
- 📸 Includes media assets (images, videos)
- 🏷️ Contains pricing and tax information
- 🔄 Links to Payment Links for selling
🔗 Related APIs: Products are used with Payment Links, Subscriptions, and Payment Intents.
Key Features
| Feature | Description |
|---|---|
| Product Variants | Support multiple variations (size, color, material) |
| Media Management | Attach images and videos with ordering |
| Subscription Support | Enable recurring billing with selling plans |
| Tax Integration | Tax code support and address collection |
| Version Control | Track changes with version numbers |
| Flexible Pricing | Per-variant pricing or fixed product pricing |
| Metadata | Custom key-value pairs for your needs |
Product Types
MartianPay supports various product configurations:
| Type | Description | Use Case |
|---|---|---|
| Variant Products | Products with options (size, color) and multiple variants | Most e-commerce products (clothing, accessories) |
| Subscription Products | Requires selling plan, recurring billing only | SaaS subscriptions, memberships |
| Hybrid Products | Supports both one-time and subscription purchases | Software with one-time or monthly options |
📌 Important: All products require options and variants. Simple products without variants are not supported.
Key Components
1. Product Types:
- All products require options and variants (simple products without variants are not supported)
- Complex products with options and variants (e.g., size, color)
- Subscription-only products requiring selling plans
- Products supporting both one-time and subscription purchases
2. Product Information:
- Product information (name, description, pricing)
- Options (e.g., Color, Size) with configurable values
- Variants (combinations of option values)
- Media assets (images, videos) with ordering
- Selling plans for subscription billing
- Tax codes and address collection settings
3. Version Control:
- All products use version numbers for audit tracking
- Optimistic locking prevents concurrent update conflicts
- Historical snapshots allow rollback to previous versions
4. Typical Workflow:
- Create products with options and variants
- Associate media assets and selling plans
- Update product configuration as needed
- Manage active/inactive status
- Delete inactive products when no longer needed
Product Structure
Hierarchy:
Product
├── Options (e.g., Size, Color)
│ └── Values (e.g., Small, Medium, Large)
├── Variants (combinations of option values)
│ ├── Variant 1: Small + Red
│ ├── Variant 2: Medium + Blue
│ └── Variant 3: Large + Red
├── Media Assets (images, videos)
└── Selling Plans (subscription options)
Use Cases
Common Scenarios:
- 👕 Apparel: T-shirts with sizes (S, M, L) and colors
- 📱 Electronics: Phones with storage options (64GB, 128GB, 256GB)
- 💼 SaaS: Software with subscription tiers (Basic, Pro, Enterprise)
- 🎮 Digital Goods: Games with edition variants (Standard, Deluxe, Ultimate)
- 🛒 E-commerce: Any product with multiple options and pricing
- 🎫 Events: Tickets with seating categories (VIP, Regular, Budget)
Best Practices
✅ DO:
- Use clear, descriptive product names
- Add high-quality media assets in the correct order
- Specify accurate tax codes for compliance
- Use metadata to link to your internal product IDs
- Keep variants organized with logical option names
- Enable address collection when shipping physical goods
❌ DON'T:
- Create products without variants (not supported)
- Use too many variants (keep it manageable)
- Forget to set product as active when ready to sell
- Mix unrelated options (e.g., "Color" with "Subscription Plan")
- Leave descriptions empty (helps customers make decisions)
API Reference
2. Create Product
Creates a new product in your catalog. Supports simple products with fixed pricing or complex products with options and variants.
For detailed API reference, see: Create Product API
Request Parameters:
name(required): Name of the productdescription(optional): Detailed description of the productactive(optional): Whether the product is currently available (default: true)default_currency(optional): Base currency for the product/variantscollect_shipping_address(optional): Collect shipping address during checkoutcollect_tax_address(optional): Collect billing/tax address during checkouttax_code(optional): Tax classification code for the productrequires_selling_plan(optional): true=subscription only, false=one-time or subscriptionmetadata(optional): Additional custom data as key-value pairsprice(optional): Default price for simple productsfixed_price(optional): Fixed price overridemedia_order(optional): Array of media asset IDs in display orderoptions(optional): Array of product options (e.g., Color, Size)variants(optional): Array of product variantsselling_plan_group_ids(optional): Associated selling plan groups for subscriptions
Request Example (Simple Product):
curl --location --request POST 'https://api.martianpay.com/v1/products' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"name": "Premium T-Shirt",
"description": "High-quality cotton t-shirt",
"active": true,
"default_currency": "USD",
"price": {
"amount": 29.99,
"asset_id": "USD"
},
"collect_shipping_address": true,
"collect_tax_address": true,
"tax_code": "txcd_99999999",
"metadata": {
"category": "apparel",
"sku": "TSHIRT-001"
}
}'
Request Example (Product with Variants):
curl --location --request POST 'https://api.martianpay.com/v1/products' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"name": "Premium T-Shirt",
"description": "High-quality cotton t-shirt in multiple sizes and colors",
"active": true,
"default_currency": "USD",
"collect_shipping_address": true,
"collect_tax_address": true,
"options": [
{
"name": "Size",
"sort_order": 1,
"values": [
{
"value": "Small",
"sort_order": 1
},
{
"value": "Medium",
"sort_order": 2
},
{
"value": "Large",
"sort_order": 3
}
]
},
{
"name": "Color",
"sort_order": 2,
"values": [
{
"value": "Black",
"sort_order": 1,
"swatch": {
"type": "color",
"value": "#000000"
}
},
{
"value": "White",
"sort_order": 2,
"swatch": {
"type": "color",
"value": "#FFFFFF"
}
}
]
}
],
"variants": [
{
"active": true,
"option_values": {
"Size": "Small",
"Color": "Black"
},
"price": {
"amount": 29.99,
"asset_id": "USD"
},
"inventory_quantity": 100
},
{
"active": true,
"option_values": {
"Size": "Medium",
"Color": "Black"
},
"price": {
"amount": 29.99,
"asset_id": "USD"
},
"inventory_quantity": 150
},
{
"active": true,
"option_values": {
"Size": "Large",
"Color": "White"
},
"price": {
"amount": 32.99,
"asset_id": "USD"
},
"inventory_quantity": 75
}
],
"metadata": {
"category": "apparel",
"brand": "Premium Basics"
}
}'
Response:
{
"error_code": "success",
"msg": "success",
"data": {
"id": "prod_abc123xyz",
"name": "Premium T-Shirt",
"description": "High-quality cotton t-shirt in multiple sizes and colors",
"active": true,
"default_currency": "USD",
"created_at": 1701234567,
"updated_at": 1701234567,
"version": 1,
"collect_shipping_address": true,
"collect_tax_address": true,
"tax_code": "txcd_99999999",
"requires_selling_plan": false,
"selling_plan_group_ids": [],
"metadata": {
"category": "apparel",
"brand": "Premium Basics"
},
"media_order": [],
"options": [
{
"name": "Size",
"sort_order": 1,
"metadata": {},
"values": [
{
"value": "Small",
"sort_order": 1,
"metadata": {}
},
{
"value": "Medium",
"sort_order": 2,
"metadata": {}
},
{
"value": "Large",
"sort_order": 3,
"metadata": {}
}
]
},
{
"name": "Color",
"sort_order": 2,
"metadata": {},
"values": [
{
"value": "Black",
"sort_order": 1,
"metadata": {},
"swatch": {
"type": "color",
"value": "#000000"
}
},
{
"value": "White",
"sort_order": 2,
"metadata": {},
"swatch": {
"type": "color",
"value": "#FFFFFF"
}
}
]
}
],
"variants": [
{
"id": "var_123",
"active": true,
"version": 1,
"inventory_quantity": 100,
"option_values": {
"Size": "Small",
"Color": "Black"
},
"price": {
"amount": 29.99,
"asset_id": "USD"
},
"media_order": [],
"selling_plan_group_ids": []
},
{
"id": "var_124",
"active": true,
"version": 1,
"inventory_quantity": 150,
"option_values": {
"Size": "Medium",
"Color": "Black"
},
"price": {
"amount": 29.99,
"asset_id": "USD"
},
"media_order": [],
"selling_plan_group_ids": []
},
{
"id": "var_125",
"active": true,
"version": 1,
"inventory_quantity": 75,
"option_values": {
"Size": "Large",
"Color": "White"
},
"price": {
"amount": 32.99,
"asset_id": "USD"
},
"media_order": [],
"selling_plan_group_ids": []
}
],
"includes": {
"media": []
},
"selling_plan_groups": []
}
}
Important Notes:
-
Version Control: The product is created with
version: 1. Always include the current version number when updating. -
Options and Variants:
- Options define the configurable attributes (e.g., Size, Color)
- Variants represent specific combinations of option values
- Each variant must have a unique combination of option values
- All products must have options and variants - simple products without variants are not supported
- Complete variant coverage required: You must provide variants for all possible combinations of option values (Cartesian product)
-
Variant Required Fields:
priceis required for each variant - variants without pricing will be rejected (Error code 223: variant_price_required)inventory_quantityis required for each variant - variants without inventory will be rejected (Error code 224: variant_inventory_required)- Ensure all variants include both fields to avoid validation errors
-
Pricing:
- The
pricefield at the product level is optional and serves as a default - Each variant must have its own
pricefield specified - Prices are specified with
amountandasset_id(currency)
- The
-
Inventory: The
inventory_quantityfield is required for all variants and is used to track stock levels. -
Subscriptions: Set
requires_selling_plan: trueto make a product subscription-only. Associate selling plan groups usingselling_plan_group_ids. -
Metadata: Use metadata to store custom information like SKU, category, brand, or any other data relevant to your business.
Understanding the Response
How to Check if the Request Was Successful:
| Field | Value | Meaning |
|---|---|---|
error_code | "success" | ✅ Product created successfully |
error_code | "invalid_request_error" | ❌ Invalid product configuration or variant setup |
error_code | "variant_price_required" | ❌ All variants must have a price specified (Error 223) |
error_code | "variant_inventory_required" | ❌ All variants must have inventory_quantity specified (Error 224) |
error_code | "variants_incomplete" | ❌ Variants don't cover all option combinations (Error 235) |
error_code | Other value | ❌ Other error occurred |
Key Fields:
| Field | Description |
|---|---|
id | Unique product identifier (use for updates, payouts, payment links) |
version | Product version number (starts at 1, increment on updates) |
active | Whether product is available for sale |
variants | Array of product variants with unique id for each |
options | Product configuration options (Size, Color, etc.) |
media_order | Ordered list of media asset IDs |
selling_plan_group_ids | Associated subscription plans |
Version Control:
- Product created with
version: 1 - MUST include version number when updating
- Version increments automatically on updates
- Enables optimistic locking to prevent conflicts
Variant Structure:
- Each variant gets a unique
id(e.g., "var_123") - All variants have
version: 1initially - Required fields:
priceandinventory_quantity - Complete coverage: Must provide variants for ALL option combinations
Common Errors and Solutions:
| Error Code | Problem | Solution |
|---|---|---|
| 223 (variant_price_required) | Missing variant price | Add price field to all variants |
| 224 (variant_inventory_required) | Missing inventory quantity | Add inventory_quantity to all variants |
| 235 (variants_incomplete) | Incomplete variant combinations | Provide variants for all option combinations (Cartesian product) |
Next Steps:
- Save the product
idfor use in payment links and payment intents - Note the
versionnumber for future updates - Add media assets using Media API and update
media_order - Create selling plan groups if offering subscriptions
- Use variant
idvalues when processing orders - Set
active: truewhen ready to sell
3. List Products
Retrieves a paginated list of products from your catalog. Supports filtering by active status.
For detailed API reference, see: List Products API
Request:
curl --location --request GET 'https://api.martianpay.com/v1/products?page=0&page_size=10&active=true' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'
Query Parameters:
page(optional): Page number, zero-based (default: 0)page_size(optional): Items per page, 1-50 (default: 10)active(optional): Filter by active status (true=active, false=inactive)
Response:
{
"error_code": "success",
"msg": "success",
"data": {
"page": 0,
"page_size": 10,
"total": 25,
"products": [
{
"id": "prod_abc123xyz",
"name": "Premium T-Shirt",
"description": "High-quality cotton t-shirt in multiple sizes and colors",
"active": true,
"default_currency": "USD",
"created_at": 1701234567,
"updated_at": 1701234567,
"version": 1,
"collect_shipping_address": true,
"collect_tax_address": true,
"tax_code": "txcd_99999999",
"requires_selling_plan": false,
"selling_plan_group_ids": [],
"metadata": {
"category": "apparel",
"brand": "Premium Basics"
},
"price": {
"amount": 29.99,
"asset_id": "USD"
},
"media_order": ["media_001", "media_002"],
"options": [
{
"name": "Size",
"sort_order": 1,
"values": [
{
"value": "Small",
"sort_order": 1
},
{
"value": "Medium",
"sort_order": 2
}
]
}
],
"variants": [
{
"id": "var_123",
"active": true,
"version": 1,
"inventory_quantity": 100,
"option_values": {
"Size": "Small"
},
"price": {
"amount": 29.99,
"asset_id": "USD"
},
"media_order": []
}
],
"includes": {
"media": [
{
"id": "media_001",
"url": "https://cdn.example.com/image1.jpg",
"content_type": "image/jpeg",
"alt_text": "Premium T-Shirt Front View",
"width": 1200,
"height": 1600
}
]
},
"selling_plan_groups": []
}
]
}
}
Important Notes:
-
Pagination: Use
pageandpage_sizeto navigate through large product catalogs. Thetotalfield shows the total number of products matching the filter. -
Filtering: Use the
activeparameter to show only active or inactive products. Omit this parameter to retrieve all products. -
Expanded Data: The response includes expanded variants, media assets, and selling plan groups for convenience.
-
Media Assets: Product images and videos are returned in the
includes.mediaarray, ordered according tomedia_order.
Understanding the Response
How to Check if the Request Was Successful:
| Field | Value | Meaning |
|---|---|---|
error_code | "success" | ✅ Products retrieved successfully |
error_code | Other value | ❌ Error occurred |
Key Fields:
- products: Array of product objects
- total: Total number of products matching the filter
- page: Current page number (0-based)
- page_size: Number of items per page
Pagination:
- Use
pageandpage_sizeto navigate through results - If
total>page_size, there are more pages available - Next page: increase
pageby 1
Filtering:
active=true: Show only active productsactive=false: Show only inactive products- Omit
active: Show all products
Expanded Data: Response includes complete product details:
- Full variant information with prices and inventory
- Media assets in
includes.mediaarray - Selling plan groups if product has subscriptions
- Options and their values
Product Status:
| active Field | Meaning | Use Case |
|---|---|---|
true | ✅ Available for sale | Show in storefront, accept orders |
false | ❌ Not available | Hidden from customers, no sales |
Next Steps:
- Loop through
productsarray to display catalog - Use product
idfor details, updates, or payment links - Check
activestatus before showing to customers - Filter by
active: truefor customer-facing catalogs - Use pagination for large product lists
4. Get Product
Retrieves comprehensive information about a specific product, including all variants, options, pricing, media assets, and metadata.
For detailed API reference, see: Get Product API
Request:
curl --location --request GET 'https://api.martianpay.com/v1/products/prod_abc123xyz' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'
Request (Get Specific Version):
curl --location --request GET 'https://api.martianpay.com/v1/products/prod_abc123xyz?version=2' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'
Query Parameters:
version(optional): Retrieve a specific historical version of the product
Response:
{
"error_code": "success",
"msg": "success",
"data": {
"id": "prod_abc123xyz",
"name": "Premium T-Shirt",
"description": "High-quality cotton t-shirt in multiple sizes and colors",
"active": true,
"default_currency": "USD",
"created_at": 1701234567,
"updated_at": 1701345678,
"version": 3,
"collect_shipping_address": true,
"collect_tax_address": true,
"tax_code": "txcd_99999999",
"requires_selling_plan": false,
"selling_plan_group_ids": ["spg_001"],
"metadata": {
"category": "apparel",
"brand": "Premium Basics",
"featured": "true"
},
"price": {
"amount": 29.99,
"asset_id": "USD"
},
"fixed_price": null,
"media_order": ["media_001", "media_002", "media_003"],
"options": [
{
"name": "Size",
"sort_order": 1,
"metadata": {},
"values": [
{
"value": "Small",
"sort_order": 1,
"metadata": {}
},
{
"value": "Medium",
"sort_order": 2,
"metadata": {}
},
{
"value": "Large",
"sort_order": 3,
"metadata": {}
}
]
},
{
"name": "Color",
"sort_order": 2,
"metadata": {},
"values": [
{
"value": "Black",
"sort_order": 1,
"metadata": {},
"swatch": {
"type": "color",
"value": "#000000"
}
},
{
"value": "White",
"sort_order": 2,
"metadata": {},
"swatch": {
"type": "color",
"value": "#FFFFFF"
}
}
]
}
],
"variants": [
{
"id": "var_123",
"active": true,
"version": 3,
"inventory_quantity": 85,
"option_values": {
"Size": "Small",
"Color": "Black"
},
"price": {
"amount": 29.99,
"asset_id": "USD"
},
"media_order": ["media_001"],
"selling_plan_group_ids": ["spg_001"],
"selling_plan_groups": [
{
"id": "spg_001",
"name": "Monthly Subscription",
"description": "Subscribe and save 10%",
"status": "active",
"options": ["1 month"],
"selling_plans": [
{
"id": "sp_001",
"name": "Monthly Plan",
"description": "Billed monthly",
"status": "active",
"billing_policy_type": "RECURRING",
"billing_policy": {},
"pricing_policy": [],
"priority": "1",
"trial_period_days": "7",
"created_at": 1701234567,
"updated_at": 1701234567,
"valid_from": 1701234567,
"valid_until": 1735689600,
"version": 1
}
]
}
],
"selling_plan_pricing": [
{
"selling_plan_id": "sp_001",
"selling_plan_name": "Monthly Plan",
"billing_cycle": "month",
"currency": "USD",
"trial_period_days": 7,
"pricing_tiers": [
{
"policy_type": "RECURRING",
"after_cycle": 1,
"cycle_description": "Cycle 1 onwards",
"total_cycles": 0,
"base_price": "29.99",
"selling_plan_discount": "3.00",
"subtotal_before_policy": "29.99",
"subtotal_after_policy": "26.99"
}
]
}
]
}
],
"includes": {
"media": [
{
"id": "media_001",
"url": "https://cdn.example.com/tshirt-front.jpg",
"content_type": "image/jpeg",
"alt_text": "Premium T-Shirt Front View",
"width": 1200,
"height": 1600
},
{
"id": "media_002",
"url": "https://cdn.example.com/tshirt-back.jpg",
"content_type": "image/jpeg",
"alt_text": "Premium T-Shirt Back View",
"width": 1200,
"height": 1600
},
{
"id": "media_003",
"url": "https://cdn.example.com/tshirt-detail.jpg",
"content_type": "image/jpeg",
"alt_text": "Premium T-Shirt Fabric Detail",
"width": 1200,
"height": 1200
}
]
},
"selling_plan_groups": [
{
"id": "spg_001",
"name": "Monthly Subscription",
"description": "Subscribe and save 10%",
"status": "active",
"options": ["1 month"],
"selling_plans": [
{
"id": "sp_001",
"name": "Monthly Plan",
"description": "Billed monthly",
"status": "active",
"billing_policy_type": "RECURRING",
"billing_policy": {},
"pricing_policy": [],
"priority": "1",
"trial_period_days": "7",
"created_at": 1701234567,
"updated_at": 1701234567,
"valid_from": 1701234567,
"valid_until": 1735689600,
"version": 1
}
]
}
]
}
}
Important Notes:
-
Version History: Use the
versionquery parameter to retrieve historical snapshots of the product. This is useful for auditing changes or rolling back to a previous version. -
Expanded Data: The response includes complete details about:
- All variants with their prices and inventory
- Media assets with URLs and metadata
- Selling plan groups and pricing tiers
- Subscription pricing calculations
-
Selling Plans: For subscription products, the response includes:
- Product-level selling plan groups
- Variant-level selling plan associations
- Detailed pricing tiers showing discounts and final prices
- Trial period information
-
Media Assets: Images and videos are ordered according to
media_orderfor consistent display across your storefront.
Understanding the Response
How to Check if the Request Was Successful:
| Field | Value | Meaning |
|---|---|---|
error_code | "success" | ✅ Product retrieved successfully |
error_code | "product_not_found" | ❌ No product exists with this ID |
error_code | Other value | ❌ Other error occurred |
Key Product Information:
| Field | Description |
|---|---|
id | Product identifier |
version | Current version number (for updates) |
active | Whether product is available for sale |
variants | Complete variant details with pricing and inventory |
options | Product configuration options |
media_order | Ordered media asset IDs |
selling_plan_groups | Subscription plans (if applicable) |
Version History:
- Use
?version=Nquery parameter to retrieve specific historical version - Useful for auditing changes or rollback scenarios
- Current version shown in response
Expanded Details: The response includes complete information:
- Variants: Full details with prices, inventory, and variant-specific data
- Media Assets: Images and videos in
includes.mediawith URLs - Selling Plans: Subscription pricing tiers and trial periods
- Selling Plan Pricing: Calculated pricing for each subscription tier
Subscription Product Information: For products with subscriptions:
selling_plan_groups: Available subscription plansselling_plan_pricing: Pricing breakdown per variant and plantrial_period_days: Free trial durationpricing_tiers: Cycle-by-cycle pricing with discounts
Next Steps:
- Note the
versionnumber for updates - Use variant
idvalues when creating payment intents - Check
activestatus before showing to customers - Display media from
includes.mediain your UI - Show subscription pricing if
selling_plan_groupsis present
5. Update Product
Updates an existing product with version control. All changes increment the product version for audit tracking. You can update product details, pricing, variants, options, active status, and media.
For detailed API reference, see: Update Product API
Request:
curl --location --request POST 'https://api.martianpay.com/v1/products/prod_abc123xyz' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"version": 3,
"name": "Premium T-Shirt - Updated",
"description": "High-quality organic cotton t-shirt in multiple sizes and colors",
"active": true,
"price": {
"amount": 34.99,
"asset_id": "USD"
},
"metadata": {
"category": "apparel",
"brand": "Premium Basics",
"featured": "true",
"organic": "true"
},
"variants": [
{
"id": "var_123",
"active": true,
"option_values": {
"Size": "Small",
"Color": "Black"
},
"price": {
"amount": 34.99,
"asset_id": "USD"
},
"inventory_quantity": 85
}
]
}'
Request (Deactivate Product):
curl --location --request POST 'https://api.martianpay.com/v1/products/prod_abc123xyz' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"version": 3,
"active": false
}'
Response:
{
"error_code": "success",
"msg": "success",
"data": {
"id": "prod_abc123xyz",
"name": "Premium T-Shirt - Updated",
"description": "High-quality organic cotton t-shirt in multiple sizes and colors",
"active": true,
"default_currency": "USD",
"created_at": 1701234567,
"updated_at": 1701456789,
"version": 4,
"collect_shipping_address": true,
"collect_tax_address": true,
"tax_code": "txcd_99999999",
"requires_selling_plan": false,
"selling_plan_group_ids": ["spg_001"],
"metadata": {
"category": "apparel",
"brand": "Premium Basics",
"featured": "true",
"organic": "true"
},
"price": {
"amount": 34.99,
"asset_id": "USD"
},
"media_order": ["media_001", "media_002", "media_003"],
"options": [
{
"name": "Size",
"sort_order": 1,
"values": [
{
"value": "Small",
"sort_order": 1
}
]
},
{
"name": "Color",
"sort_order": 2,
"values": [
{
"value": "Black",
"sort_order": 1,
"swatch": {
"type": "color",
"value": "#000000"
}
}
]
}
],
"variants": [
{
"id": "var_123",
"active": true,
"version": 4,
"inventory_quantity": 85,
"option_values": {
"Size": "Small",
"Color": "Black"
},
"price": {
"amount": 34.99,
"asset_id": "USD"
},
"media_order": [],
"selling_plan_group_ids": []
}
],
"includes": {
"media": []
},
"selling_plan_groups": []
}
}
Important Notes:
-
Version Requirement: You MUST include the current
versionnumber in your update request. This implements optimistic locking to prevent concurrent update conflicts. -
Version Mismatch Error: If the version number doesn't match the current product version, you'll receive a 409 Conflict error. Fetch the latest product data and retry with the correct version.
-
Incremented Version: On successful update, the product version is incremented (from 3 to 4 in the example above).
-
Partial Updates: You can update specific fields without providing all product data. However, when updating arrays (like variants), provide the complete array with all items.
-
Active Status: Set
active: falseto deactivate a product. Inactive products won't appear in payment links or customer-facing catalogs. -
Variant Updates: When updating variants, include the variant
idfor existing variants. Variants without anidwill be created as new variants. -
Metadata Updates: Metadata is merged, not replaced. To remove a metadata key, explicitly set its value to null or empty string.
Error Responses:
{
"code": 400,
"error_code": "invalid_request_error",
"msg": "Invalid product configuration or variant setup"
}
{
"code": 409,
"error_code": "version_conflict",
"msg": "Version conflict - product was modified by another request"
}
Variant Validation Error Codes:
{
"code": 223,
"error_code": "variant_price_required",
"msg": "All variants must have a price specified"
}
{
"code": 224,
"error_code": "variant_inventory_required",
"msg": "All variants must have inventory_quantity specified"
}
{
"code": 235,
"error_code": "variants_incomplete",
"msg": "Product variants do not cover all possible option combinations. Please provide variants for all combinations of option values (Cartesian product)."
}
Understanding the Response
How to Check if the Request Was Successful:
| Field | Value | Meaning |
|---|---|---|
error_code | "success" | ✅ Product updated successfully |
error_code | "invalid_request_error" | ❌ Invalid product configuration or variant setup |
error_code | "version_conflict" | ❌ Version mismatch - product was modified by another request (409) |
error_code | "variant_price_required" | ❌ Missing variant price (Error 223) |
error_code | "variant_inventory_required" | ❌ Missing inventory quantity (Error 224) |
error_code | "variants_incomplete" | ❌ Incomplete variant combinations (Error 235) |
error_code | Other value | ❌ Other error occurred |
Key Update Indicators:
| Field | What Changed |
|---|---|
version | Incremented from old version to new version |
updated_at | Timestamp updated to reflect modification time |
| Modified fields | Reflect your changes (name, price, variants, etc.) |
Version Control:
- MUST provide current version: Include
versionfield matching current product version - Version incremented: New version = old version + 1 (e.g., 3 → 4)
- Optimistic Locking: Prevents concurrent update conflicts
- 409 Conflict Error: If version mismatch, fetch latest and retry
What You Can Update:
- ✅ Product details (name, description, metadata)
- ✅ Pricing (product-level or variant-level)
- ✅ Variants (add new, update existing, deactivate)
- ✅ Active status (activate or deactivate product)
- ✅ Media order
- ✅ Selling plan associations
- ❌ Cannot change product
id
Partial vs Complete Updates:
- Update specific fields without providing all data
- Exception: When updating arrays (variants), provide complete array
- Metadata is merged, not replaced
Active Status Updates:
- Set
active: falseto deactivate (hide from customers) - Set
active: trueto activate (show to customers) - Omit field to leave status unchanged
Variant Updates:
- Include variant
idfor existing variants - Variants without
idare created as new - Must include:
priceandinventory_quantityfor all variants - Must provide: Complete variant coverage for all option combinations
Common Errors:
| Error | Code | Solution |
|---|---|---|
| Version conflict | 409 | Fetch latest product, retry with correct version |
| Missing price | 223 | Add price to all variants |
| Missing inventory | 224 | Add inventory_quantity to all variants |
| Incomplete variants | 235 | Provide variants for all option combinations |
Next Steps:
- Note the new
versionnumber for future updates - Verify changes in response match your request
- If 409 error, fetch latest version and retry
- Test updated product in payment links/intents
- Update product
versionin your local cache/database
6. Delete Product
Soft-deletes an inactive product from your catalog. Only inactive products that are not used in any payment links can be deleted. Product data is retained for historical records but marked as deleted.
For detailed API reference, see: Delete Product API
Request:
curl --location --request DELETE 'https://api.martianpay.com/v1/products/prod_abc123xyz' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'
Response:
{
"error_code": "success",
"msg": "success",
"data": {
"deleted": true,
"id": "prod_abc123xyz"
}
}
Important Notes:
-
Inactive Products Only: You can only delete products that have
active: false. Set a product to inactive first, then delete it. -
Not in Use: Products that are currently used in active payment links cannot be deleted. Remove the product from all payment links first.
-
Soft Delete: This is a soft delete operation. The product data is retained in the database for historical records and audit purposes, but marked as deleted.
-
Cannot Be Undone: Once deleted, a product cannot be restored. You would need to create a new product with the same details.
-
Historical References: Deleted products remain visible in historical payment intents, invoices, and subscriptions for record-keeping.
Error Responses:
{
"code": 400,
"error_code": "invalid_request_error",
"msg": "Cannot delete active product. Set active=false first."
}
{
"code": 400,
"error_code": "invalid_request_error",
"msg": "Cannot delete product that is used in active payment links"
}
{
"code": 404,
"error_code": "resource_not_found",
"msg": "Product not found"
}
Understanding the Response
How to Check if the Request Was Successful:
| Field | Value | Meaning |
|---|---|---|
error_code | "success" | ✅ Product deleted successfully |
error_code | "invalid_request_error" | ❌ Cannot delete (product is active or in use) |
error_code | "resource_not_found" | ❌ Product not found (404) |
error_code | Other value | ❌ Other error occurred |
Success Response:
| Field | Description |
|---|---|
deleted | true = product successfully deleted |
id | ID of the deleted product |
Deletion Requirements:
| Requirement | Check |
|---|---|
| Product must be inactive | Set active: false before deleting |
| Not used in payment links | Remove from all payment links first |
| Not used in active subscriptions | Ensure no active subscriptions reference this product |
What Happens:
- ✅ Product marked as deleted in database
- ✅ No longer appears in product lists
- ✅ Cannot be used for new payments or payment links
- ✅ Historical data retained for auditing
- ❌ Cannot be undone - deletion is permanent
Common Deletion Errors:
| Error | Reason | Solution |
|---|---|---|
| Cannot delete active product | Product has active: true | Update product with active: false first |
| Cannot delete (in use) | Product used in payment links | Remove from all payment links |
| Product not found (404) | Invalid product ID | Verify product ID is correct |
Soft Delete vs Hard Delete:
- Soft Delete: Product data retained in database but marked as deleted
- Visible in History: Still appears in historical payment intents, orders, subscriptions
- Cannot Be Restored: No API to restore deleted products
- Recreate if Needed: Create new product with same details if needed
Alternatives to Deletion:
- Deactivate Instead: Set
active: falseto hide from customers while preserving product - Keep for History: Leave inactive products for historical reference
- Only Delete: When product is truly obsolete and not referenced
Next Steps:
- Confirm product is deleted using List Products API
- Update any internal systems that referenced this product ID
- If you need this product again, create a new one (cannot restore)
- Review payment links to ensure they don't reference deleted product
Best Practices
-
Version Control:
- Always fetch the latest product before updating to get the current version number
- Handle 409 Conflict errors by refetching and retrying with the updated version
- Use version history to audit changes and rollback if needed
-
Product Organization:
- Use meaningful product names and descriptions for easy identification
- Leverage metadata to categorize and tag products (e.g., category, brand, SKU)
- Organize media assets in a logical order for consistent display
-
Variants Management:
- All products must have options and variants - simple products are not supported
- Create options and variants for products with multiple configurations
- Use descriptive option names (Size, Color, Material) and values
- Ensure complete coverage: Provide variants for all possible combinations of option values (Cartesian product)
- Always specify
pricefor each variant (required field) - Always specify
inventory_quantityfor each variant (required field) - Track inventory at the variant level for accurate stock management
-
Pricing Strategy:
- Product-level
priceis optional and serves as a default - Each variant must have its own
pricespecified - this is a required field - Use selling plans to offer subscription discounts
- Consider using
fixed_pricefor promotional pricing
- Product-level
-
Media Assets:
- Upload high-quality product images for better conversion
- Use descriptive
alt_textfor accessibility - Order media assets using
media_orderfor consistent display - Attach variant-specific images when applicable
-
Subscription Products:
- Set
requires_selling_plan: truefor subscription-only products - Associate appropriate selling plan groups at product or variant level
- Clearly communicate subscription terms in product descriptions
- Use trial periods to encourage subscription adoption
- Set
-
Active Status Management:
- The
activefield behavior during updates: omitting the field (nil) = no change,true= activate,false= deactivate - The same behavior applies to variant
activefields - Set products/variants to inactive instead of deleting when temporarily unavailable
- Keep historical products inactive for record-keeping
- Only delete products that are truly obsolete and not referenced anywhere
- The
-
Tax and Shipping:
- Set appropriate tax codes for tax calculation
- Enable address collection when shipping products
- Use
collect_tax_addressfor accurate tax calculations
-
Testing:
- Test product creation with various option and variant combinations
- Verify pricing calculations, especially for subscription products
- Test with both simple and complex product configurations
- Validate media asset display on your storefront
-
Error Handling:
- Implement retry logic for version conflicts
- Validate product data before submission
- Handle error responses gracefully in your application
- Log errors for debugging and monitoring