Skip to main content

API Integrations in PXM

Learn how to create and manage API integrations in PXM, including generating API credentials, authenticating with OAuth2, exploring key endpoints, and following best practices — with working code examples for developers.

Written by Caden Lindquist

Overview

API integrations allow you to connect PXM with external systems such as ERPs, ecommerce platforms, or custom applications. Instead of manually updating data, APIs enable systems to communicate automatically -- saving time, reducing errors, and keeping your product content in sync.

The PXM API is a RESTful HTTP API using JSON for request and response bodies. It supports operations on collections (products), files (digital assets), categories (navigation folders), attributes (metadata fields), and more.

Most API endpoints are versioned under /v2.1/. The search endpoints also support /v2/ and /v3/. See the API Reference below for details.

Data Model & Object Relationships

Understanding how PXM objects relate to each other is essential before building any integration.

Basic PXM Hierarchy

Category Folder
  |-- Sub-Category Folder (nested via parent_id)
  |     |-- Collection / Product
  |           |-- File / Asset (image, PDF, video)
  |           |-- Attribute Values (product metadata)
  |
  |-- Collection / Product
        |-- File / Asset

Categories organize collections (products) into folder structures for navigation. Files are media assets linked to collections. A collection can be associated with one or more categories depending on its parent/direct_parent configuration. Files can also be associated with multiple collections.

Product Variant Hierarchy

Parent Collection (collection_type = "parent")
  |-- Variant Collection (collection_type = "variant", parent_topic_id = parent.id)
  |-- Variant Collection (collection_type = "variant", parent_topic_id = parent.id)
  |-- Variant Collection (collection_type = "variant", parent_topic_id = parent.id)

The variant hierarchy is separate from the category hierarchy. collection_type designates whether a collection is a parent or variant. parent_topic_id links each variant back to its parent collection. A standalone product omits collection_type entirely.

Full Account Structure

Account
  |-- Regions (Org Units) -- localization scopes (e.g. US, EU, global)
  |-- Attributes          -- global metadata field definitions
  |-- Categories          -- folder structure for organizing content
  |     |-- Sub-categories (nested via parent_id)
  |-- Collections         -- product records
        |-- Attribute values (metadata on this product)
        |-- Files            (linked digital assets: images, PDFs, video)
        |-- Variant Collections (collection_type='variant', linked via parent_topic_id)

A Collection is the core product record. It can stand alone, act as a parent (product family), or be a variant (a specific SKU). Collections are placed inside Categories for navigation, linked to Files for media, and carry Attribute values for product data.

Key relationship fields and what they do:

Field

On Object

What it does

parent_id

Collection or Category

Places this object inside a parent Category folder

direct_parent

Collection

Array of Category IDs -- associates the collection with those categories

collection_type

Collection

parent = product family; variant = SKU; omit for standalone product

parent_topic_id

Collection (variant only)

ID of the parent collection this variant belongs to -- required when collection_type is variant

region_ids

Collection, File

Scopes this object to specific regions. Use GET /region to find IDs. If omitted, defaults to the account primary region.

Real-World API Behavior -- Read This First

Before building your integration, be aware of the following known behaviors. They are not bugs -- they are characteristics of the API that every integration needs to handle:

Response shapes are not uniform across endpoints. Some list endpoints return a raw JSON array. Others wrap results in a keyed object. Your code must handle both. See the Response Format Variations section below.

The Swagger documentation and actual runtime behavior sometimes differ. Some fields marked readOnly in the spec are writable in practice. Test against the live API when in doubt.

PUT requests fully replace array fields. If you PUT collections with one ID, all previously linked collections are removed. Always GET first, merge, then PUT. See Understanding PUT Behavior below.

Access tokens are long-lived (1 year). This is unusual for OAuth. Store tokens securely and treat them like passwords.

Before You Begin

Before using the API, you'll need:

1. A PXM account with API access enabled

2. A Client ID and Client Secret (generated in PXM settings)

3. Basic understanding of REST APIs and JSON

Creating an API Authorization

To generate your API credentials in PXM:

1. Log in to PXM and navigate to Settings

2. Go to IntegrationsAPI

3. Click Create New Integration

4. Give your integration a name and save

5. You may now use the Client ID and Client Secret

6. The Client ID and Client Secret are tied to the individual user. Deactivation of the user will deactivate the Client ID and Client Secret.

Authentication & Getting a Token

The PXM API uses the OAuth 2.0 Client Credentials flow. You exchange your Client ID and Client Secret for a Bearer token included on every subsequent API request.

Headers:

Authorization: Basic <base64(client_id:client_secret)>Content-Type: application/json

Request Body:

{"grant_type": "client_credentials"}

Python Example (Option A -- recommended):

import requestsAUTH_URL  = "https://entapi.amplifi.io/v2.1/oauth/authorize"BASE_URL  = "https://entapi.amplifi.io/v2.1"resp = requests.post(    AUTH_URL,    auth=(client_id, client_secret),    json={"grant_type": "client_credentials"})token = resp.json()["access_token"]headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}

Python Example (Option B -- manual Base64):

import requests, base64credentials = base64.b64encode(f"{client_id}:{client_secret}".encode("utf-8")).decode("utf-8")resp = requests.post(    "https://entapi.amplifi.io/v2.1/oauth/authorize",    headers={        "Authorization": f"Basic {credentials}",        "Content-Type": "application/json",    },    json={"grant_type": "client_credentials"},)token = resp.json()["access_token"]

Response:

{  "access_token": "eyJhb...",  "token_type": "Bearer",  "expires_in": "31536000"}

The expires_in value is 31,536,000 seconds (1 year). Tokens are long-lived -- cache and reuse them rather than generating a new one per request.

Include the token on every API call:

Authorization: Bearer <your_token>

Token Security

* Treat your token like a password -- never expose it in client-side code, logs, or version control

* Store it in environment variables or a secrets manager (e.g., AWS Secrets Manager, HashiCorp Vault)

* Rotate tokens proactively before expiry rather than waiting for them to expire in production

* If a token is compromised, revoke it from PXM Settings immediately and generate a new one

Accessing the PXM API Documentation

The full interactive API documentation (Swagger UI) is available at:

Note: The Swagger spec is a useful reference for endpoint structure and field names, but some runtime behaviors differ -- for example, some fields marked readOnly are writable in practice. Treat it as a starting point and validate against the live API when in doubt.

Key Concepts

Concept

What It Is

Collection

A product record in PXM. Holds attribute values, linked files, and metadata. Can be standalone, a parent (product family), or a variant (specific SKU).

File

A digital asset (image, video, PDF, etc.) managed in PXM's DAM. Files are uploaded via a two-step presigned URL process and can be linked to collections.

Category

A folder in PXM used to organize collections and files. Categories support nested hierarchies via parent_id.

Attribute

A metadata field attached to a collection, file, or category. Attributes have typed values: Text, Date, List, Pick List, Boolean, or Number.

Attribute Group

A named grouping of attributes on a collection, used to organize related metadata fields together.

Region

A localization scope in PXM. Content can be scoped to specific regions. Omitting region_ids defaults to the account primary region. Use GET /region to get region IDs.

Resource

A URL-based reference (document, link, spec sheet) that can be attached to a category or collection.

Response Format Variations

Different endpoints return data in different shapes. Do not assume every endpoint returns the same wrapper format -- inspect each endpoint's documented response shape and write your parser accordingly.

Endpoint

Response Shape

How to Access Items

GET /v2.1/file

Raw JSON array

resp.json() directly

GET /v2.1/collection

{"collections": [...]}

resp.json()["collections"]

GET /v2.1/category

Raw JSON array

resp.json() directly

GET /v3/{entity}/search

{"hits": [...], "total": N}

resp.json()["hits"]

GET /v2.1/category -- returns a raw JSON array:

[
  {
    "id": "cat_abc123",
    "name": "Apparel",
    "parent_id": null
  },
  {
    "id": "cat_def456",
    "name": "Jackets",
    "parent_id": "cat_abc123"
  }
]

GET /v2.1/collection -- returns an object with a collections key:

{
  "collections": [
    {
      "id": "col_ghi789",
      "name": "Women's Rain Jacket",
      "parent_id": "cat_def456"
    }
  ]
}

GET /v2.1/file -- returns a raw JSON array:

[
  {
    "id": "file_jkl012",
    "file_name": "rain-jacket-hero.jpg",
    "collections": [
      { "id": "col_ghi789" }
    ]
  }
]

GET /v3/folder/search -- returns an object with hits and total:

{
  "hits": [
    { "id": "col_ghi789", "name": "Women's Rain Jacket" }
  ],
  "total": 1
}

Defensive pagination helper (handles all response shapes):

page = resp.json()if isinstance(page, list):    items = pageelif isinstance(page, dict):    items = (        page.get("collections") or        page.get("files") or        page.get("items") or        page.get("data") or        []    )else:    items = []

API Reference

All endpoints use https://entapi.amplifi.io as the base URL. Most are versioned at /v2.1/. Include your Bearer token in every request.

Categories

Categories are folder structures used to organize collections and files in PXM. They support nested hierarchies.

Method

Endpoint

Description

GET

/v2.1/category

List all categories

POST

/v2.1/category

Create a category

GET

/v2.1/category/{id}

Get category by ID

PUT

/v2.1/category/{id}

Update a category

DELETE

/v2.1/category/{id}

Delete a category

GET

/v2.1/category/{id}/files

Get files in a category

To create a category, only name is required. Use parent_id to nest it inside another category.

{  "name": "Apparel",  "parent_id": "parent-category-uuid"}

Collections (Products)

Collections are product records in PXM. They hold attribute values, linked files, and product metadata. A collection can be a standalone product, a parent (product family), or a variant (specific SKU).

Method

Endpoint

Description

GET

/v2.1/collection

List all collections

POST

/v2.1/collection

Create a collection

GET

/v2.1/collection/{id}

Get a collection by ID

PUT

/v2.1/collection/{id}

Update a collection

DELETE

/v2.1/collection/{id}

Delete a collection

GET

/v2.1/collection/{id}/files

Get files linked to a collection

GET

/v2.1/collection/{id}/image-stacks

Get image variants (filter by size, file_type, stack_ids)

GET

/v2.1/collection/{id}/relationships/related

Get related collections (association groups)

List Parameters (GET /v2.1/collection)

Parameter

Type

Description

ids

array

Comma-separated collection IDs to fetch

region_ids

array

Filter results to collections scoped to these regions

limit

integer

Records per page

offset

integer

Records to skip

parent_id

string

Filter by parent category or collection ID

folder_level

string

direct (immediate children) or leaf (deepest level only)

minified

boolean

Return a trimmed response -- useful for large catalogs

metaonly

boolean

Return only metadata, no attribute values

CREATING a Collection -- POST /v2.1/collection

Only name is required. All other fields are optional on create.

{  "name": "Blue Rain Jacket",  "additional_title": "SKU-BRJ-001",  "parent_id": "category-uuid-here",  "published": true,  "published_start_date": "2025-01-01T00:00:00Z"}

To create a parent collection (product family):

{  "name": "Rain Jacket Collection",  "collection_type": "parent"}

To create a variant linked to a parent:

{  "name": "Blue Rain Jacket - Size M",  "collection_type": "variant",  "parent_topic_id": "parent-collection-uuid"}

UPDATING a Collection -- PUT /v2.1/collection/{id}

Only include the fields you want to change. You do not need to send the full object.

⚠️ Array fields are fully replaced: direct_parent and attributes replace their entire previous values on every PUT. Always GET the current state first, merge your changes, and then PUT the full merged value.

{  "name": "Updated Product Name",  "published": true,  "published_start_date": "2025-11-01T00:00:00Z",  "direct_parent": ["category-uuid-1", "category-uuid-2"],  "attributes": [    {      "id": "attribute-uuid",      "type": "update",      "value": "New Value"    }  ]}

Collection Fields Reference

Field

Type

Create

Update

Description

name

string

Required

Optional

Product/collection name

additional_title

string

Optional

Optional

Secondary or alternate title

parent_id

string

Optional

Optional

Primary parent Category ID

direct_parent

array

Optional

Optional (full replace)

Array of Category IDs to associate with

published

boolean

Optional

Optional

Whether the collection is published

published_start_date

date-time

If published=true

If published=true

Format: YYYY-MM-DDTHH:MM:SSZ

published_end_date

date-time

Optional

Optional

Format: YYYY-MM-DDTHH:MM:SSZ

collection_type

string

Optional

Optional

Omit for standalone. parent = product family. variant = SKU.

parent_topic_id

string

If variant

If variant

ID of parent collection -- required when collection_type is variant

attributes

array

Optional

Optional (full replace)

Array of attribute ops -- each with id, type (update/delete), value

region_ids

array

Optional

Optional

Region UUIDs to scope this collection. Omit = default/primary region.

Files (Digital Assets)

Files are digital assets -- images, PDFs, videos, and other media -- stored in PXM's Digital Asset Manager (DAM). Files are uploaded via a presigned URL flow and can be linked to one or more collections.

Method

Endpoint

Description

GET

/v2.1/file

List all files

GET

/v2.1/file/{id}

Get file by ID

PUT

/v2.1/file/{id}

Update file metadata

POST

/v2.1/file/request-upload

Request presigned upload URL

POST

/v2.1/file/confirm-upload

Confirm and finalize upload

GET

/v2.1/file/search/{file_name}

Search files by filename

List Parameters (GET /v2.1/file)

Parameter

Type

Description

collection_ids

array

Return only files linked to these collections

region_ids

array

Scope results to files in these regions

limit

integer

Number of files per page

offset

integer

Records to skip (for pagination)

created_start_date

date

Filter files created on or after this date (YYYY-MM-DD)

created_end_date

date

Filter files created on or before this date (YYYY-MM-DD)

updated_start_date

date

Filter files updated on or after this date (YYYY-MM-DD)

updated_end_date

date

Filter files updated on or before this date (YYYY-MM-DD)

minified

boolean

Return a trimmed response -- useful when listing many files

File Upload Lifecycle

Uploading a file to PXM is a multi-step process:

1. Request Upload -- Call POST /v2.1/file/request-upload to get a presigned S3 URL

{  "filename": "product-hero.jpg",  "file_name": "product-hero.jpg",  "mime_type": "image/jpeg",  "size": 2048000}

Note: Send both filename and file_name for compatibility across tenant configurations.

2. Check Upload Type -- The response includes upload_type: either standard (single PUT) or multipart (multiple parts for large files)

3. Upload to S3 (Single) -- If upload_type == "standard", PUT the file bytes directly to the presigned URL

4. Upload to S3 (Multipart) -- If upload_type == "multipart": upload each part to its presigned URL, capture the ETag header from each response, then confirm with the upload_id and array of parts

5. Confirm Upload -- Call POST /v2.1/file/confirm-upload to register the file in PXM:

{  "file_path": "s3path/temp/upl_abc123/product-hero.jpg",  "file_name": "product-hero.jpg",  "file_size": 1024000,  "metadata": {    "published": true,    "published_start_date": "2025-01-01T00:00:00Z",    "region_ids": ["your-region-uuid"]  }}

🌍 region_ids: Include the region UUID(s) where this file should be available. Use GET /v2.1/region to get your region IDs. If omitted, the file goes into the account's default primary region.

6. Processing -- PXM processes the file asynchronously (OCR, auto-labeling via Google Vision)

7. Available -- File is available via GET /v2.1/file/{id} and can be linked to collections

Confirm Upload for Multipart

{  "file_path": "s3path/temp/upl_abc123/large-video.mp4",  "file_name": "large-video.mp4",  "file_size": 524288000,  "upload_id": "upload-id-from-request-upload",  "multipart": [    { "part_number": 1, "etag": "etag-from-s3-response-part-1" },    { "part_number": 2, "etag": "etag-from-s3-response-part-2" }  ],  "metadata": {    "published": true,    "region_ids": ["your-region-uuid"]  }}

Updating a File

Use PUT /v2.1/file/{id} to update file metadata. Like collections, array fields are fully replaced:

Link a file to collections:

{  "collections": [    {"id": "collection-uuid-1"},    {"id": "collection-uuid-2"}  ]}

Update region access on a file:

{  "region_ids": ["region-uuid-1", "region-uuid-2"]}

region_ids: Include region UUIDs to scope access. Omit to use the account default region. This is a full replace -- GET first and merge if needed.

File Response Fields

Field

Type

Description

collections

array

Collection IDs this file is linked to -- array of objects with an id property

file_size

number

File size in bytes

file_dimension

string

Image dimensions, e.g., 3000px x 3000px

is_converting

boolean

true if the file is still being processed or converted

region_ids

array

Region UUIDs this file is scoped to

auto_label

array

Auto-generated labels from Google Vision API

ocr_text

string

Text extracted via OCR (Google Vision)

variants

object

Links to preview, large, medium, small, and thumb renditions

Attributes

Attributes are metadata fields that can be attached to collections, files, or categories. Global attributes are defined at the account level and assigned to objects.

Method

Endpoint

Description

GET

/v2.1/attribute

List all global attributes

POST

/v2.1/attribute

Create a global attribute

GET

/v2.1/attribute/{id}

Get attribute by ID

PUT

/v2.1/attribute/{id}

Update a global attribute definition

DELETE

/v2.1/attribute/{id}

Delete a global attribute

GET

/v2.1/{entity}/{entity_id}/attribute

Get attributes on a specific object (entity = collection, file, category)

PUT

/v2.1/{entity}/{entity_id}/attribute/{id}

Update the value of a specific attribute on an object

Attribute types supported: Text, Date, List, Pick List, Boolean, Number

To update attributes via collection PUT, include them in the attributes array. Each entry requires an id and a type:

type value

What it does

Notes

update

Set or change the attribute value

Requires a value field

delete

Clear / remove the attribute value

No value field needed

"attributes": [  {    "id": "attr-uuid-1",    "type": "update",    "value": "Red"  },  {    "id": "attr-uuid-2",    "type": "delete"  }]

Attribute Groups

Attribute groups organize related attributes into named sections on a collection. They are display-only groupings and do not affect API calls to individual attributes.

Method

Endpoint

Description

GET

/v2.1/attribute-group

List all attribute groups

POST

/v2.1/attribute-group

Create an attribute group

GET

/v2.1/attribute-group/{id}

Get an attribute group by ID

PUT

/v2.1/attribute-group/{id}

Update an attribute group

DELETE

/v2.1/attribute-group/{id}

Delete an attribute group

Search endpoints allow full-text keyword search across folders (collections) and files.

Method

Endpoint

Description

GET

/v2/{entity}/search?keyword={term}

Search (no total count)

GET

/v3/{entity}/search?keyword={term}

Search with total count in response

Entity can be folder or file.

v3 Response Shape:

{  "hits": [{ "id": "...", "name": "..." }],  "total": 42}

Regions

Regions define localization scopes in PXM. Files and collections can be scoped to specific regions for multi-market deployments.

Note: In the PXM platform UI, Regions are also referred to as Org Units. The terms are interchangeable -- the API uses region_ids, but you may see "Org Unit" in the platform settings.

Method

Endpoint

Description

GET

/v2.1/region

List all regions

Use GET /v2.1/region to retrieve all region IDs for your account. The primary region has is_primary: true. When you include region_ids on a file or collection, it scopes that content to those specific regions. If you omit region_ids, content defaults to the account's primary/default region.

Field

Type

Description

id

string

Region ID -- use this value in region_ids fields on other objects

name

string

Region display name

is_primary

boolean

Whether this is the primary/default region

language

string

Localization language code

topics

array

Collection (product) IDs associated with this region

Always GET before PUT on array fields -- collections, direct_parent, and region_ids are fully replaced on every PUT. Merge existing values with your updates before writing.

Resources

Resources are URL-based references -- spec sheets, external documents, or links -- that can be attached to categories or collections.

Method

Endpoint

Description

GET

/v2.1/resource

List all resources

POST

/v2.1/resource

Create a resource

GET

/v2.1/resource/{id}

Get a resource by ID

PUT

/v2.1/resource/{id}

Update a resource

DELETE

/v2.1/resource/{id}

Delete a resource

Required: description, link

{  "description": "Product Specification Sheet",  "link": "https://example.com/spec-sheet.pdf",  "category_id": "category-uuid-here"}

{  "description": "Assembly Instructions",  "link": "https://example.com/instructions.pdf",  "collections": ["collection-uuid-1", "collection-uuid-2"]}

Field

Type

Required

Description

description

string

Yes

Human-readable label for the resource

link

string

Yes

The URL of the resource

category_id

string

No

Category this resource belongs to

collections

array

No

Collection IDs this resource is linked to

Pagination

All list endpoints support limit and offset for pagination. The default limit is typically 20. Fetch the next page by incrementing offset by limit. Stop when the returned count is less than limit.

# Page 1GET /v2.1/collection?limit=100&offset=0# Page 2GET /v2.1/collection?limit=100&offset=100# Page 3GET /v2.1/collection?limit=100&offset=200

The same limit/offset approach works for /v2.1/file, /v2.1/category, and other list endpoints.

Understanding PUT Behavior

The PXM API uses PUT for updates -- not PATCH. This has an important implication for array fields: sending a partial array replaces the entire array, not just the items you specify.

Fields affected by full-replacement:

* collections on a file

* direct_parent on a collection

* region_ids on a file or collection

* attributes on a collection (when passed as an array)

Safe update pattern:

# 1. GET the current statecurrent = requests.get(f"{BASE_URL}/v2.1/collection/{id}", headers=headers).json()# 2. Merge your changesexisting_parents = current.get("direct_parent", [])new_parents = existing_parents + ["new-category-uuid"]# 3. PUT the merged valuepayload = {"direct_parent": new_parents}requests.put(f"{BASE_URL}/v2.1/collection/{id}", headers=headers, json=payload)

Production Integration Patterns

Rate Limiting

The PXM API allows 1,000 requests per 60 seconds. When you exceed this limit, you'll receive a 429 Too Many Requests response:

HTTP/1.1 429 Too Many RequestsRetry-After: 60X-RateLimit-Limit: 1000{  "error": "Rate limit exceeded.",  "retry_after": 60}

For bulk operations, target 950 requests per 60 seconds to stay safely under the limit.

Retry Logic

import time, requestsdef api_request_with_retry(method, url, **kwargs):    for attempt in range(3):        resp = requests.request(method, url, **kwargs)        if resp.status_code == 429:            wait = int(resp.headers.get("Retry-After", 60))            print(f"Rate limited. Waiting {wait}s...")            time.sleep(wait)            continue        resp.raise_for_status()        return resp    raise Exception("Max retries exceeded")

Delta Sync Pattern

Rather than re-fetching all data on every sync, use date filters to fetch only changed records:

from datetime import datetime, timedeltayesterday = (datetime.utcnow() - timedelta(days=1)).strftime("%Y-%m-%dT%H:%M:%SZ")# Fetch only collections updated in the last 24 hourspayload = requests.get(    f"{BASE_URL}/v2.1/collection",    headers=headers,    params={        "updated_start_date": yesterday,        "limit": 100,        "offset": 0,    }).json()

Concurrency with Rate Limiting (Python asyncio)

import asyncio, aiohttpclass RateLimiter:    def __init__(self, max_calls=950, period=60.0):        self._semaphore = asyncio.Semaphore(max_calls)        self.period = period        self.max_calls = max_calls    async def __aenter__(self):        await self._semaphore.acquire()    async def __aexit__(self, *_):        await asyncio.sleep(self.period / self.max_calls)        self._semaphore.release()rate_limiter = RateLimiter()async def fetch(session, url):    async with rate_limiter:        async with session.get(url, headers=headers) as resp:            return await resp.json()

Token Caching

PXM tokens are valid for 1 year. Avoid requesting a new token on every script run:

import os, requestsTOKEN_FILE = ".pxm_token"def get_token():    if os.path.exists(TOKEN_FILE):        with open(TOKEN_FILE) as f:            return f.read().strip()    resp = requests.post(        "https://entapi.amplifi.io/v2.1/oauth/authorize",        auth=(CLIENT_ID, CLIENT_SECRET),        json={"grant_type": "client_credentials"},    )    token = resp.json()["access_token"]    with open(TOKEN_FILE, "w") as f:        f.write(token)    return token

Error Codes

Code

Meaning

Common Cause

Retry?

400

Bad Request

Invalid payload or missing required field

No -- fix the request

401

Unauthorized

Missing or expired Bearer token

No -- re-authenticate

403

Forbidden

Token lacks permission for this resource

No -- check credentials

404

Not Found

Resource ID does not exist or was deleted

No -- verify the ID

429

Too Many Requests

Rate limit exceeded (1,000 req/60s)

Yes -- wait Retry-After seconds

500

Server Error

Unexpected error on the PXM side

Yes -- retry with backoff

502

Bad Gateway

Upstream service unavailable

Yes -- retry with backoff

503

Service Unavailable

Temporary outage or maintenance

Yes -- retry with backoff

Swagger / OpenAPI Notes

The PXM API has an interactive Swagger UI available at https://entapi.amplifi.io/docs/index.html. It is a useful starting point for endpoint discovery and field reference, but there are a few things to be aware of when using it for integration work.

Topic

What to Know

Field writability

Some fields are marked readOnly in the Swagger spec but are writable in practice depending on endpoint behavior and account configuration. Use this article as the authoritative reference for what to send.

Response wrappers

Some response schemas in Swagger may be simplified or may not fully reflect real response wrappers (e.g., {"collections": [...]} vs a raw array). See the Response Format Variations section above for actual shapes.

API version paths

OAuth/token endpoints and resource endpoints may use different API version paths (e.g., /v2.1/ vs /v3/). Follow the endpoint versions documented in this article.

Sandbox testing

Always test in a non-production environment before running bulk updates or writes. The Swagger UI can be used to make live API calls against your account.

Spec currency

The Swagger spec may not always reflect the latest endpoint additions or behavior changes. When in doubt, validate against the live API and refer to this article or reach out to your CSM.

This article reflects practical, tested behavior. Where Swagger and this documentation differ, follow this article.

Best Practices

* Always GET before PUT on array fields -- collections, direct_parent, and region_ids are fully replaced on every PUT. Merge existing values with your updates before writing.

* Handle response shapes defensively -- Use the defensive parsing pattern in the Response Format Variations section. Do not assume all list endpoints return the same JSON structure.

* Validate payloads before sending -- Several issues in integrations come from incorrect data values, not platform bugs. Test against the API schema before scaling up.

* Respect rate limits -- Target 950 requests/60s to leave a buffer. Implement retry logic with exponential backoff for 429s.

* Cache your token -- Tokens last 1 year. There is no need to request a new one on every run.

* Use delta syncs -- Use updated_start_date / updated_end_date filters on list endpoints to fetch only changed records rather than pulling everything every time.

* Test in a sandbox first -- Run bulk write operations on a small batch before scaling to your full catalog. Confirm the behavior matches expectations before processing thousands of records.

Need Help?

If you run into issues with the API or need help with a specific integration, reach out to your Customer Success Manager or contact PXM Support through the in-app chat.

Did this answer your question?