API Documentation
RESTful API for SAGE promotional products middleware.
Authentication
All API endpoints require authentication via the X-API-Key header.
curl -H "X-API-Key: your-api-key" https://mam-one.vercel.app/inventory/12345
Permission Levels
| Level | Access |
|---|---|
inventory |
Only /inventory/* endpoints |
full |
All API endpoints |
Rate Limiting
API requests are rate limited to ensure fair usage and system stability. Limits vary by endpoint type.
Rate Limits by Endpoint
| Endpoint Type | Limit |
|---|---|
| Standard endpoints | 100 requests/minute |
| Search endpoints | 60 requests/minute |
| Export endpoints | 10 requests/minute |
| Sync endpoints | 5 requests/minute |
Response Headers
Rate limit information is included in response headers:
| X-RateLimit-Limit | Maximum requests allowed in the window |
| X-RateLimit-Remaining | Requests remaining in current window |
| X-RateLimit-Reset | Unix timestamp when the window resets |
Note: When rate limited, you'll receive a 429 Too Many Requests response. Wait until the reset time before retrying.
Inventory
Real-time inventory lookups via SAGE Module 107. FREE - no credits required.
/inventory/{sage_prod_eid}
Get inventory by SAGE product ID
Response
{
"sage_prod_eid": 305466229,
"found": true,
"total_on_hand": 9993,
"is_unlimited": false,
"last_updated": "2024-12-14T10:30:00Z",
"skus": [
{
"attributes": [
{"type_id": 10, "name": "Color", "value": "Black"}
],
"on_hand": 500,
"is_unlimited": false,
"on_order": 0,
"expected_date": null
}
],
"cached": false
}
/inventory/by-item/{supplier_sage_id}/{item_num}
Get inventory by supplier and item number (more reliable)
Example
GET /inventory/by-item/50018/1328
/inventory/bulk
Get inventory for multiple products (up to 100)
Request Body
{
"sage_prod_eids": [305466229, 305466230, 305466231]
}
Products
Access cached product data from the database. Requires full permission.
/products
List products with pagination and filtering
Query Parameters
| supplier_id | Filter by supplier (internal ID) |
| product_type | Filter by product type |
| category_text | Filter by SAGE category |
| search | Search in name and description |
| published_only | Only show published products (default: true) |
| include_facets | Include facet counts for filtering (default: false) |
| page | Page number (default: 1) |
| per_page | Items per page (default: 50, max: 100) |
Response Fields
Each product in the response includes:
retail_min_price- Calculated retail price (minimum)retail_max_price- Calculated retail price (maximum)is_visible- Whether product is visible to customers
/products/{id}
Get product by internal database ID
Returns full product detail including retail pricing tiers when available.
/products/by-sage-id/{sage_prod_eid}
Get product by SAGE product ID
/products/by-slug/{slug}
Get product by URL slug
/products/categories
List available product categories from SAGE
/products/stats/summary
Get database statistics
Parts Pricing & Product Images
Multi-part products (awards in multiple sizes, mugs in multiple colors) include per-part pricing and images
via the parts_pricing field. Simple products have parts_pricing: null.
When parts_pricing is present
Products from PromoStandards suppliers (e.g., SRG) that bundle multiple SKUs under one product ID. Each part has its own pricing tiers and images.
{
"id": 53975,
"item_num": "ARG202-HG",
"name": "Fantasia Award on Hancock Base - Green",
"primary_image_url": "https://...",
"all_images": [{"url": "...", "caption": "", "hasLogo": false}],
"parts_pricing": {
"default_part_id": "ARG2021-HG",
"parts": [
{
"part_id": "ARG2021-HG",
"description": "Fantasia Award on Hancock Green - 3\" Diam",
"tiers": [
{"qty": 1, "prc": 82.5, "net": 41.25},
{"qty": 7, "prc": 81.0, "net": 40.5}
],
"images": [
{"url": "https://.../arg2021-hg-primary.jpg", "caption": ""},
{"url": "https://.../arg2021-hg-blank.jpg", "caption": ""}
]
},
{
"part_id": "ARG2022-HG",
"description": "Fantasia Award on Hancock Green - 4\" Diam",
"tiers": [{"qty": 1, "prc": 125.5, "net": 62.75}],
"images": [
{"url": "https://.../arg2022-hg-primary.jpg", "caption": ""},
{"url": "https://.../arg2022-hg-blank.jpg", "caption": ""}
]
}
]
}
}
Key Fields
| parts_pricing.default_part_id | The default/first part ID. Use to pre-select a variation. |
| parts[].part_id | Unique SKU for this part (e.g., size or color variant) |
| parts[].description | Full description including differentiating attribute (size, color) |
| parts[].tiers | Quantity-based pricing for this specific part. Use tiers[0].prc for qty=1 price. |
| parts[].images | Part-specific images (typically Primary + Blank). Use images[0].url as the variation image. |
Per-Part Images vs Product Images
| Field | Scope | Use For |
|---|---|---|
| primary_image_url | Product-level | Main product image / featured image |
| all_images | Product-level | Gallery / all product images (includes part images) |
| parts[].images | Part-specific | Variation image. Typically 2 per part: Primary (with decoration) and Blank (undecorated). |
Integration tip: Use part.images[0].url as the variation image,
falling back to primary_image_url if the part has no images.
WooCommerce Variable Product Mapping
Map multi-part products to WooCommerce variable products:
| WooCommerce | MAM Source |
|---|---|
| Product type | variable when parts_pricing exists, else simple |
| Parent SKU | item_num |
| Variation SKU | part.part_id |
| Variation price | part.tiers[0].prc (qty=1 price) |
| Variation image | part.images[0].url, fallback to primary_image_url |
| Attribute name | "Option" (generic — parts can be sizes, colors, materials) |
| Default variation | Match default_part_id |
Collections
Award Maven's curated product collections. Requires full permission.
/collections
List all collections
Query Parameters
| active_only | Only active collections (default: true) |
| featured_only | Only featured collections (default: false) |
| parent_id | Filter by parent collection ID |
| enforce_schedule | Apply date-based scheduling (default: true) |
| published_only | Only published collections (default: true) |
/collections/by-slug/{slug}
Get collection by URL slug
/collections/{id}
Get collection by internal ID
/collections/{id}/products
Get products in a collection with pagination
Query Parameters
| page | Page number (default: 1) |
| per_page | Items per page (default: 50, max: 100) |
Families
Product variant families (same product in different sizes/colors). Requires full permission.
/families
List all product families
Query Parameters
| page | Page number (default: 1) |
| per_page | Items per page (default: 50, max: 100) |
/families/by-slug/{slug}
Get family by URL slug
/families/{id}
Get family by internal ID (includes all variant products)
Response includes:
display_mode- How variants display: separate_pages, single_page, cross_linksvariant_axes- Variation dimensions (e.g., ["size", "color"])products- Array of variant products in the family
Export
Export products to WooCommerce-compatible CSV. Requires full permission.
Standard Export
/export/csv
Download WooCommerce CSV export (1 variable + 1 variation per product)
Query Parameters
| supplier_sage_id | Filter by supplier SAGE ID |
| markup_percent | Markup percentage to apply (default: 0, since prc is already customer price) |
| use_prc | Use customer price (prc). Set false to use cost (net). Default: true |
| round_to_quarter | Round final price to nearest $0.25. Default: false |
/export/preview
Preview export without downloading (JSON response)
Variable Export
Groups products by base name as WooCommerce variable products with size/color variations.
/export/variable-csv
Download grouped variable products CSV
Same parameters as /export/csv
/export/variable-preview
Preview variable product grouping
/export/variable-stats
Get variable export statistics
Pricing Formula
retail_price = base_price × (1 + markup_percent / 100) where base_price = prc (default, customer price) or net (if use_prc=false) then optionally round to nearest $0.25
Default behavior: Uses prc (customer price) directly with 0% markup.
Example: To add 5% to list price: markup_percent=5
Suppliers
Access supplier data. Requires full permission.
/suppliers/search
Search SAGE for suppliers by name. Costs 1 credit per call.
Query Parameters
| q | Search query (required) |
/suppliers/export
Export suppliers from database (no SAGE credit cost)
Query Parameters
| updated_since | ISO 8601 timestamp for incremental sync |
| active_only | Only active suppliers (default: true) |
| page | Page number (default: 1) |
| page_size | Items per page (default: 50, max: 100) |
Sync
Sync products from SAGE suppliers. Requires full permission. Costs credits per product.
/sync/preview/{supplier_sage_id}
Preview products without saving (1 credit)
/sync/supplier/{supplier_sage_id}
Sync products to database
/sync/{sync_id}
Check sync status
Error Handling
All errors return JSON with an error message:
{
"detail": "Invalid API key"
}
HTTP Status Codes
| 200 | Success |
| 401 | Missing or invalid API key |
| 403 | Insufficient permissions |
| 404 | Resource not found |
| 429 | Rate limit exceeded. Check X-RateLimit-* headers. |
| 500 | Internal server error |