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.PXM_CLIENT_ID;
const clientSecret = process.env.PXM_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, requests
client_id = os.environ['PXM_CLIENT_ID']
client_secret = os.environ['PXM_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 smaller product payload (less attribute data). Good for list views where you don't need full detail. Send as the string |
| boolean | Return only pagination metadata ( |
| string | Applies only when |
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();
// List responses may be a plain array or { collections, pagination }
const items = Array.isArray(data) ? data : (data.collections ?? []);
if (!items.length) break; // No more results
products.push(...items);
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) |
ℹ️ Each size holds one entry per image format (jpg, png, webp), and each entry has a link, for example variants.thumb.webp.link. Use master_link for the original file. The size names available depend on your account's image settings. Some accounts use thumbnail instead of thumb, and preview may not exist, so check the variants keys in a real response before you rely on a size.
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}` } }
);
if (!res.ok) throw new Error(`Could not load files: HTTP ${res.status}`);
const files = await res.json();
// Variants are keyed by size, then format: variants.thumb.webp.link
// Size names depend on your account's image settings (e.g. 'thumbnail' vs 'thumb')
const variantLink = (f, size) =>
f.variants?.[size]?.webp?.link ?? f.variants?.[size]?.jpg?.link ?? f.variants?.[size]?.png?.link;
const images = files.filter(f => f.type === 'image');
const documents = files.filter(f => f.type === 'document');
return {
gallery: images.map(img => ({
id: img.id,
thumb: variantLink(img, 'thumb'),
medium: variantLink(img, 'medium'),
full: variantLink(img, 'large') ?? img.master_link,
altText: img.caption || img.file_name,
})),
downloads: documents.map(doc => ({
id: doc.id,
name: doc.file_name,
url: doc.master_link, // master_link serves the original file (e.g. the PDF)
})),
};
}
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 a smaller response (omits some metadata). Send as the string |
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: the file name, file type, size, publish status, CDN links, and any attributes attached to that asset.
Example Response:
{
"id": "f1a2b3c4-0000-1111-aaaa-bbbbccccdddd",
"file_name": "garden-hose-50ft-hero.jpg",
"type": "image",
"format": "jpg",
"file_size": 2048576,
"published": true,
"master_link": "https://{cdn-host}/p/f1a2b3c4-0000-1111-aaaa-bbbbccccdddd",
"variants_links": [
"https://{cdn-host}/p/f1a2b3c4-0000-1111-aaaa-bbbbccccdddd?..."
]
}
ℹ️ Alt text tip: File lists (such as GET /collection/{id}/files) include a caption field, which is a great source for image alt text, and an auto_label array of AI-generated tags from Google Vision that can supplement your SEO metadata. Use master_link for the original file, for example as a PDF download link.
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.
ℹ️ Unpublished items: Search results can include unpublished products when you use Admin Integrations credentials. If your site should only show published items, filter the results before displaying them, for example by checking each product's published status.
📝 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 per source IP address, so everything that calls from the same outgoing IP address shares that budget. If you exceed this, you'll receive a
429response withRetry-After: 60andX-RateLimit-Limit: 1000headers. Build in retry logic.🔗 Use CDN URLs for asset delivery — All file variants are hosted on the Pattern PXM 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 Pattern PXM 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 |
403 | Forbidden | Your credentials don't have permission for this resource, or the record is hidden from your integration, or the endpoint isn't available to integrations. Check the API user's role and Org Unit access. |
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. |
422 | Unprocessable Entity |
|
429 | Too Many Requests | You've exceeded 1,000 requests per 60 seconds, or too many very large pages are loading at once. Check the |
500 | Internal Server Error | Unexpected server-side error. Retry with exponential backoff. If it persists, contact Pattern PXM support. |
503 | Service Unavailable | The service is temporarily busy, for example with other very large pages. Wait the number of seconds in |
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 browsers
const BASE_URL = 'https://entapi.amplifi.io';
// 1. Authenticate
async function authenticate() {
const creds = Buffer.from(
`${process.env.PXM_CLIENT_ID}:${process.env.PXM_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 Pattern PXM account team, browse the Help Center at intercom.help/amplifiio, email pxmsupport@pattern.com, or use the in-app chat. Your client_id and client_secret are created by a PXM admin under Settings > System > Integrations > Register Application, and your account manager can help if you don't have them yet. Depending on your account setup, credentials may instead be created on the Integrations page of the Admin portal, where they are scoped by privilege and Org Unit. Get them before beginning your integration.
