Overview
Pattern PXM's open API lets you integrate your website directly with your PXM (Product Experience Management) system. You can fetch real-time product data, digital assets, and metadata without manual exports or file transfers — keeping your site always in sync with what's in Pattern PXM.
This guide covers the endpoints most relevant for website integrations: authentication, product data, file/asset retrieval, attribute lookup, and search. It is written for web developers and system integrators and includes working code examples in JavaScript and Python.
Base URL: https://entapi.amplifi.io | API Version: v2.1 | Auth: OAuth2 Client Credentials
⚠️ Not using Shopify? This guide is for custom website integrations. If you're on Shopify, Pattern PXM has a dedicated native integration — contact your account manager for details.
How a typical product page integration works:
Authenticate — Exchange your credentials for a bearer token
Fetch product —
GET /collection/{id}Fetch files —
GET /collection/{id}/filesFetch attributes —
GET /attributeRender page — Display product data on your website
Key Concepts: Terminology
Pattern PXM uses specific terminology in its API that differs from everyday language. Understanding these two mappings will save you a lot of confusion.
Collection = Product — A "collection" is a product record. It holds attributes and linked files.
Category = Folder — A "category" is an organizational folder, not a product itself. You query Collections to get product data; Categories are purely organizational.
Term | What it means |
| A data field on a product or file — e.g. "Color", "Weight", "Description". Attributes have types (Text, Number, List, Pick List, Boolean, Date). |
| A digital asset (image, PDF, video, etc.) stored in Pattern PXM and optionally associated to one or more products. |
| A group of product images organized for display — useful for rendering hero images and galleries efficiently in a single call. |
| A locale or market segment. Collections and files can be scoped to specific regions (e.g., US, UK, EU). |
| A parent collection groups variant collections (e.g., a t-shirt in sizes S, M, L). Variants share the parent but have their own attributes. |
Authentication
Pattern PXM uses OAuth 2.0 Client Credentials — the standard machine-to-machine auth flow. You exchange your client_id and client_secret for a bearer token, then include that token in every subsequent API call.
⚠️ Keep your credentials server-side. Never expose your client_id or client_secret in browser JavaScript, mobile apps, or public repositories. All Pattern PXM API calls should be made from your backend server, which then passes safe data to your frontend.
POST /v2.1/oauth/authorize
When to use: Call this once when your server starts, or when your token expires. Cache the returned token and reuse it — tokens are valid for approximately one year. Do not re-authenticate on every request.
Send a POST with your credentials as a Base64-encoded Basic Auth header and a JSON body specifying the grant type.
POST https://entapi.amplifi.io/v2.1/oauth/authorize
Authorization: Basic Base64(client_id:client_secret)
Content-Type: application/json{
"grant_type": "client_credentials"
}
JavaScript example:
const clientId = process.env.AMPLIFI_CLIENT_ID;
const clientSecret = process.env.AMPLIFI_CLIENT_SECRET;
const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');const response = await fetch('https://entapi.amplifi.io/v2.1/oauth/authorize', {
method: 'POST',
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ grant_type: 'client_credentials' }),
});const { access_token } = await response.json();
// Reuse this token — store it in memory or a short-lived cache
// Authorization header for all subsequent calls:
// 'Authorization': `Bearer ${access_token}`
Python example:
import os, base64, requestsclient_id = os.environ['AMPLIFI_CLIENT_ID']
client_secret = os.environ['AMPLIFI_CLIENT_SECRET']
credentials = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()response = requests.post(
'https://entapi.amplifi.io/v2.1/oauth/authorize',
headers={
'Authorization': f'Basic {credentials}',
'Content-Type': 'application/json',
},
json={'grant_type': 'client_credentials'}
)access_token = response.json()['access_token']
HEADERS = {'Authorization': f'Bearer {access_token}'}
# Reuse HEADERS in all subsequent requests
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": "31536000",
"user": {
"email": "api-user@yourcompany.com",
"hostname": "yourcompany.pxm.pattern.com"
}
}
GET /collection — List Products
Returns a paginated list of product collections. Use this to power catalog pages, product listings, and navigation menus.
Best for: Category/browse pages, sitemaps, bulk syncs of your product catalog, or building a search index. Use limit and offset to paginate through large catalogs. Filter by parent_id to fetch products within a specific category folder.
Query Parameters
Parameter | Type | Description |
| integer | Number of records to return. Use for pagination. |
| integer | Number of records to skip. Combine with |
| string | Return only collections inside this category folder (by category ID). |
| array | Comma-separated list of specific collection IDs to fetch in bulk. |
| array | Filter to collections available in specific regions/locales. |
| date | Only return collections updated after this date (YYYY-MM-DD). Great for incremental syncs. |
| date | Only return collections updated before this date. |
| boolean | Return a lighter response (less attribute data). Good for list views where you don't need full detail. |
| boolean | Return only IDs and names — no attributes. Fastest response, ideal for building navigation. |
| string |
|
JavaScript — Paginated catalog fetch:
// Fetch all products in a category, 50 at a time
async function fetchAllProductsInCategory(categoryId, token) {
const products = [];
let offset = 0;
const limit = 50; while (true) {
const url = new URL('https://entapi.amplifi.io/v2.1/collection');
url.searchParams.set('parent_id', categoryId);
url.searchParams.set('limit', limit);
url.searchParams.set('offset', offset); const res = await fetch(url, {
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await res.json(); if (!data.length) break; // No more results
products.push(...data);
offset += limit;
} return products;
}
GET /collection/{id} — Get a Single Product
Returns the full data for a single product (collection) by its unique ID — including all attributes like title, description, specs, pricing, and more.
Best for: Product detail pages (PDPs). When a user lands on a product page, call this endpoint with the product's collection ID to get the full spec sheet. Also useful for populating comparison tables.
Path Parameters
Parameter | Type | Description |
| string (UUID) | The unique ID of the collection/product. |
Example Response:
{
"id": "a1b2c3d4-1234-5678-abcd-ef1234567890",
"name": "Heavy Duty 5/8\" Garden Hose - 50ft",
"additional_title": "Model HG-5058",
"parent_id": "cat-uuid-garden-category",
"collection_type": "variant",
"published": true,
"attributes": [
{ "id": "attr-uuid-001", "label": "Color", "value": "Green", "value_type": "Text" },
{ "id": "attr-uuid-002", "label": "Length", "value": "50ft", "value_type": "Text" },
{ "id": "attr-uuid-004", "label": "Max PSI", "value": 150, "value_type": "Number" },
{ "id": "attr-uuid-005", "label": "In Stock", "value": true, "value_type": "Boolean" }
],
"created_date": "2024-01-15T10:23:00Z",
"update_date": "2024-11-02T08:45:00Z"
}
💡 Working with attributes: Attributes are returned as an array. Iterate over them and map by label (the human-readable name) to display on your page. The value_type field tells you how to render the value — use a checkbox for Boolean, a formatted number for Number, or plain text for Text.
JavaScript — Fetch and render a product:
async function getProduct(collectionId, token) {
const res = await fetch(
`https://entapi.amplifi.io/v2.1/collection/${collectionId}`,
{ headers: { 'Authorization': `Bearer ${token}` } }
);
const product = await res.json(); // Convert attributes array to a convenient key-value map
const attrs = Object.fromEntries(
product.attributes.map(a => [a.label, a.value])
); return {
id: product.id,
name: product.name,
description: attrs['Description'] ?? '',
color: attrs['Color'] ?? '',
inStock: attrs['In Stock'] ?? false,
};
}
GET /collection/{id}/files — Get Product Assets
Returns all files (images, PDFs, videos, documents) associated with a specific product. Use this to power product image galleries, downloadable spec sheets, and media libraries.
Best for: Loading all assets for a product detail page. Each file includes CDN URLs at multiple sizes so you can choose the right resolution for every context (thumbnail, gallery, full-size). For pure image gallery use, also consider /collection/{id}/image-stacks for more structured image presentation.
File Variant Sizes
Variant Key | Typical Use |
| Thumbnails, product cards in listing pages |
| Compact product images, mobile views |
| Standard product images, gallery grid |
| Full-width hero images, lightbox views |
| High-quality preview (between medium and large) |
JavaScript — Build a product image gallery:
async function getProductImages(collectionId, token) {
const res = await fetch(
`https://entapi.amplifi.io/v2.1/collection/${collectionId}/files`,
{ headers: { 'Authorization': `Bearer ${token}` } }
);
const files = await res.json(); const images = files.filter(f => f.metadata?.mime_type?.startsWith('image/'));
const documents = files.filter(f => f.metadata?.mime_type === 'application/pdf'); return {
gallery: images.map(img => ({
id: img.id,
thumb: img.variants?.thumb,
medium: img.variants?.medium,
full: img.variants?.large,
altText: img.metadata?.caption ?? img.metadata?.file_name,
})),
downloads: documents.map(doc => ({
id: doc.id,
name: doc.metadata?.file_name,
url: doc.variants?.preview ?? doc.metadata?.cdn_url,
})),
};
}
GET /collection/{id}/image-stacks — Get Structured Product Images
Returns product images organized into named stacks — pre-grouped sets of images (e.g., "Front View", "Lifestyle", "Detail Shots"). This is the most efficient way to populate a product image gallery when images have been organized in Pattern PXM.
Best for: Product detail page image galleries where images are organized into named groups. Lets you request a specific image size and format in one call. Ideal when you need images in a specific format (e.g., WebP for performance) or a specific size tier.
Query Parameters
Parameter | Type | Description |
| string | One of: |
| string | One of: |
| array | Comma-separated list of specific stack IDs to fetch. |
JavaScript — Fetch WebP gallery images:
async function getProductGallery(collectionId, token) {
const url = new URL(
`https://entapi.amplifi.io/v2.1/collection/${collectionId}/image-stacks`
);
url.searchParams.set('size', 'medium');
url.searchParams.set('file_type', 'webp'); const res = await fetch(url, { headers: { 'Authorization': `Bearer ${token}` } });
const stacks = await res.json(); return stacks.map(stack => ({
name: stack.name,
images: stack.files ?? [],
}));
}
💡 Performance tip: Request file_type=webp and the appropriate size for your layout. Serving WebP at the correct size is one of the biggest wins for page load speed on image-heavy product pages.
GET /file — List Files
Returns a list of files, optionally filtered by collection IDs, date ranges, or region. Use this when you need to query assets across multiple products at once.
Best for: Bulk asset operations — syncing a media library, generating a sitemap of all assets, or fetching all files updated since a given date for an incremental sync. For files associated with a specific product, prefer GET /collection/{id}/files instead.
Query Parameters
Parameter | Type | Description |
| array | Comma-separated list of collection IDs — returns files linked to any of those products. |
| array | Filter to files available in specific regions. |
| integer | Number of files to return per page. |
| integer | Pagination offset. |
| date | Only return files updated after this date. Ideal for delta syncs. |
| boolean | Return lighter responses (omits some metadata). |
JavaScript — Incremental sync since last run:
async function getUpdatedFiles(lastSyncDate, token) {
const url = new URL('https://entapi.amplifi.io/v2.1/file');
url.searchParams.set('updated_start_date', lastSyncDate); // "2025-01-01"
url.searchParams.set('limit', 100); const res = await fetch(url, { headers: { 'Authorization': `Bearer ${token}` } });
return res.json();
}
GET /file/{id} — Get a Single File
Returns the full metadata and CDN URLs for a single file by its unique ID.
Best for: When you already have a file ID (e.g., from a collection's file list or a search result) and need the full details: CDN URLs at all sizes, metadata, dimensions, file type, and any attributes attached to that asset.
Example Response:
{
"id": "f1a2b3c4-0000-1111-aaaa-bbbbccccdddd",
"metadata": {
"file_name": "garden-hose-50ft-hero.jpg",
"caption": "Green 50ft garden hose coiled on white background",
"mime_type": "image/jpeg"
},
"file_dimension": "3000px x 3000px",
"file_size": 2048576,
"variants": {
"thumb": "https://cdn.amplifi.io/.../thumb/garden-hose-50ft-hero.jpg",
"small": "https://cdn.amplifi.io/.../small/garden-hose-50ft-hero.jpg",
"medium": "https://cdn.amplifi.io/.../medium/garden-hose-50ft-hero.jpg",
"large": "https://cdn.amplifi.io/.../large/garden-hose-50ft-hero.jpg"
},
"auto_label": ["garden", "hose", "outdoor", "green"]
}
ℹ️ Alt text tip: The metadata.caption field is a great source for image alt text. The auto_label array contains AI-generated tags from Google Vision that can supplement your SEO metadata.
GET /attribute — Get Attribute Definitions
Returns the global attribute schema — all attribute definitions configured in your Pattern PXM account. Use this to understand the structure of your product data before displaying it.
Best for: Bootstrapping your integration. Fetch the attribute list once (or cache it) to build a map of attribute IDs to human-readable labels and types. Also useful for building faceted search filters (e.g., filter by Color, Size, Material).
Attribute Value Types
value_type | How to render | Example |
| Plain string | "Forest Green" |
| Numeric, apply units from label | 150 |
| Yes/No, checkbox, badge | true |
| Format with locale date library | "2025-06-01" |
| Comma-separated or multi-value | "Red, Green, Blue" |
| Single value from predefined options | "Large" |
JavaScript — Build an attribute lookup map:
// Fetch once and cache — attribute definitions rarely change
async function buildAttributeMap(token) {
const res = await fetch('https://entapi.amplifi.io/v2.1/attribute', {
headers: { 'Authorization': `Bearer ${token}` }
});
const attrs = await res.json(); return Object.fromEntries(
attrs.map(a => [a.id, { label: a.label, type: a.value_type }])
);
}function renderAttributeValue(value, type) {
switch (type) {
case 'Boolean': return value ? 'Yes' : 'No';
case 'Number': return Number(value).toLocaleString();
case 'Date': return new Date(value).toLocaleDateString();
default: return String(value ?? '');
}
}
GET /file/search/{filename} — Search Files by Name
Search for a file by its exact or partial filename. Returns matching file records including all metadata and CDN URLs.
Best for: Looking up a specific asset when you know its filename but not its Pattern PXM file ID. Useful for migration scripts, filename-based DAM workflows, or when your existing system references assets by filename rather than ID.
⚠️ URL-encode filenames. Filenames with spaces, ampersands, or special characters must be URL-encoded before including them in the path. Use encodeURIComponent() in JavaScript or urllib.parse.quote() in Python.
async function searchFileByName(filename, token) {
const encoded = encodeURIComponent(filename);
const res = await fetch(
`https://entapi.amplifi.io/v2.1/file/search/${encoded}`,
{ headers: { 'Authorization': `Bearer ${token}` } }
);
return res.json();
}
GET /v2/{entity}/search — Keyword Search
Full-text keyword search across either products (collections, referred to as "folders" in this endpoint) or files. Use this to power your site's search bar.
Best for: Site search functionality — when users type a query into your search box and you need to return matching products or assets. The folder entity searches product collections; the file entity searches digital assets.
📝 Terminology note: This endpoint uses folder to refer to what Pattern PXM calls a "collection" (a product). This is the only endpoint where this naming occurs. A v3 endpoint is also available at /v3/{entity}/search — it returns the same results but includes a total count in the response, useful for building paginated search UIs.
Query Parameters
Parameter | Type | Description |
| string | Either |
| string | The search term. Searches across product names and attribute values. |
| integer | Pagination offset. Default: 0. Max: 10,000. |
| integer | Number of results to return. Default: 100. Max: 1,000. |
JavaScript — v2 search:
async function searchProducts(keyword, token, page = 0, pageSize = 20) {
const url = new URL('https://entapi.amplifi.io/v2/folder/search');
url.searchParams.set('keyword', keyword);
url.searchParams.set('from', page * pageSize);
url.searchParams.set('size', pageSize); const res = await fetch(url, { headers: { 'Authorization': `Bearer ${token}` } });
const hits = await res.json();
return hits;
}
JavaScript — v3 search (with total count for paginated UIs):
async function searchProductsV3(keyword, token, page = 0, pageSize = 20) {
const url = new URL('https://entapi.amplifi.io/v3/folder/search');
url.searchParams.set('keyword', keyword);
url.searchParams.set('from', page * pageSize);
url.searchParams.set('size', pageSize); const res = await fetch(url, { headers: { 'Authorization': `Bearer ${token}` } });
const { hits, total } = await res.json(); return {
results: hits,
total: total,
totalPages: Math.ceil(total / pageSize),
currentPage: page,
};
}
Best Practices & Rate Limits
🔐 Keep auth server-side — Never expose your
client_idorclient_secretin frontend code. All Pattern PXM API calls should originate from your backend.♻️ Cache your token — Tokens last approximately one year. Store the token in memory and only re-authenticate when you receive a
401response.📄 Paginate large requests — Always use
limitandoffsetwhen fetching collections or files. Don't attempt to fetch all records in a single request.⚡ Cache attribute definitions — Fetch
GET /attributeonce at startup and cache the result. Attribute schemas change infrequently — daily re-fetching is sufficient.🖼️ Use the right image size — Use
thumbfor listing pages,mediumfor gallery grids, andlargefor lightboxes. Requestwebpformat for best performance.🔄 Use incremental syncs — For background sync jobs, use
updated_start_dateon/collectionand/fileto fetch only what changed since your last sync run.🌐 Use v3 search for pagination UI — Use
GET /v3/{entity}/searchwhen you need a total result count to build "Page X of Y" pagination.🗺️ URL-encode search terms — Always pass search keywords and filenames through
encodeURIComponent()before including them in URLs.⏱️ Respect the rate limit — The API allows up to 1,000 requests per 60 seconds. If you exceed this, you'll receive a
429response with aRetry-Afterheader. Build in retry logic.🔗 Use CDN URLs for asset delivery — All file variants are hosted on Amplifi's CDN. These URLs are permanent, publicly accessible, and globally fast — link to them directly from your website.
👤 Use a dedicated API user — Create a single dedicated API user (e.g.,
api@yourcompany.com) in your Pattern PXM instance for all API requests.
ℹ️ API URL stability: The Amplifi API base URL (https://entapi.amplifi.io) is not affected by the platform's URL migration from amplifi.io to pxm.pattern.com. Your integration does not need to change if your customers update their instance URLs.
Error Codes
Code | Meaning | Common Cause & Fix |
400 | Bad Request | Invalid query parameter or malformed JSON. Check parameter names and types against the docs above. |
401 | Unauthorized | Your token is missing, expired, or malformed. Re-authenticate by calling |
404 | Not Found | The ID in the path doesn't exist (or you don't have access to it). Verify the collection or file ID is correct. |
429 | Too Many Requests | You've exceeded 1,000 requests per 60 seconds. Check the |
500 | Internal Server Error | Unexpected server-side error. Retry with exponential backoff. If it persists, contact Pattern PXM support. |
Recommended retry logic
async function apiFetch(url, token, refreshToken) {
let res = await fetch(url, {
headers: { 'Authorization': `Bearer ${token}` }
}); // Handle rate limiting — respect the Retry-After header
if (res.status === 429) {
const retryAfter = parseInt(res.headers.get('Retry-After') ?? '60', 10);
await new Promise(r => setTimeout(r, retryAfter * 1000));
res = await fetch(url, { headers: { 'Authorization': `Bearer ${token}` } });
} // Re-authenticate on 401 and retry once
if (res.status === 401) {
const newToken = await refreshToken();
res = await fetch(url, { headers: { 'Authorization': `Bearer ${newToken}` } });
} // Retry 500s with simple backoff
if (res.status === 500) {
await new Promise(r => setTimeout(r, 1000));
res = await fetch(url, { headers: { 'Authorization': `Bearer ${token}` } });
} if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(`API error ${res.status}: ${err.message ?? 'Unknown error'}`);
} return res.json();
}
Quick Start — Full Product Page Example
Here's a complete minimal example that authenticates, fetches a product, and retrieves its images — the core of any product detail page integration.
import { Buffer } from 'buffer'; // Node.js — not needed in browsersconst BASE_URL = 'https://entapi.amplifi.io';// 1. Authenticate
async function authenticate() {
const creds = Buffer.from(
`${process.env.AMPLIFI_CLIENT_ID}:${process.env.AMPLIFI_CLIENT_SECRET}`
).toString('base64'); const res = await fetch(`${BASE_URL}/v2.1/oauth/authorize`, {
method: 'POST',
headers: { 'Authorization': `Basic ${creds}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ grant_type: 'client_credentials' }),
}); const { access_token } = await res.json();
return access_token;
}// 2. Fetch product + images
async function getProductPageData(collectionId, token) {
const headers = { 'Authorization': `Bearer ${token}` }; // Fetch product details and images in parallel
const [product, images] = await Promise.all([
fetch(`${BASE_URL}/v2.1/collection/${collectionId}`, { headers }).then(r => r.json()),
fetch(`${BASE_URL}/v2.1/collection/${collectionId}/image-stacks?size=medium&file_type=webp`, { headers }).then(r => r.json()),
]); const attrs = Object.fromEntries(
product.attributes.map(a => [a.label, a.value])
); return {
id: product.id,
name: product.name,
description: attrs['Description'] ?? '',
specs: product.attributes,
gallery: images.flatMap(stack => stack.files ?? []),
};
}// 3. Use it
const token = await authenticate();
const pageData = await getProductPageData('YOUR-COLLECTION-ID-HERE', token);console.log(pageData.name); // "Heavy Duty 5/8\" Garden Hose - 50ft"
console.log(pageData.gallery[0]); // First gallery image with CDN URL
✅ Need help? Contact your Amplifi account team or reach out via the support portal at support.amplifi.io. Your client_id and client_secret are provided by your account manager — if you don't have them yet, request them before beginning your integration.
