Skip to main content

PXM File Upload API – Integration Guide for IT Teams

A step-by-step guide for IT teams and developers looking to upload files into PXM programmatically via the Public API, including authentication, single and multipart uploads, conflict handling, and publishing.

Written by Caden Lindquist

Overview

This guide explains how to upload files into PXM using the Public API. It is intended for IT teams and developers who need to integrate file uploads programmatically.

Before diving in, there are a few key things to understand about how uploads work:

  • Files are never uploaded directly to the PXM API

  • Files are uploaded directly to Amazon S3 using presigned URLs

  • The PXM API handles authentication, preparing the upload, and finalizing the file record

Every upload requires three steps:

  1. Request an upload session from the PXM API

  2. Upload the file bytes directly to S3

  3. Confirm the upload back in PXM

Upload Flow

Client
  │
  ├── 1. POST /v3/file/request-upload ──────▶ PXM API
  │◀──────── Upload instructions (S3 URLs) ──
  │
  ├── 2. PUT file bytes directly ────────────▶ Amazon S3
  │
  ├── 3. POST /v3/file/confirm-upload ──────▶ PXM API
  │◀──────── File created / published ────────

Step 0: Authentication

All requests require an OAuth access token.

Request an Access Token

POST https://entapi.amplifi.io/v2/oauth/authorize
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/json{
  "grant_type": "client_credentials"
}

Response

{
  "access_token": "<token>",
  "token_type": "bearer"
}

Use this token in the Authorization header for all subsequent requests:

Authorization: Bearer <access_token>

Step 1: Request an Upload

Endpoint: POST /v3/file/request-upload

This call registers the file with PXM, determines whether to use a single or multipart upload, and returns one or more presigned S3 URLs.

Request Body

{
  "filename": "example.jpg",
  "file_name": "example.jpg",
  "mime_type": "image/jpeg",
  "size": 2458392
}

⚠️ Important: Both filename and file_name must be included. Some tenants validate one, some validate the other. The size value must exactly match the file's byte size.

Response: Single-Part Upload

{
  "upload_data": {
    "upload_type": "single",
    "upload_url": "https://s3-presigned-url",
    "file_path": "/incoming/abc123",
    "file_name": "example.jpg"
  }
}

Response: Multipart Upload

{
  "upload_data": {
    "upload_type": "multipart",
    "upload_id": "XYZ123",
    "file_path": "/incoming/abc123",
    "file_name": "example.jpg",
    "parts": [
      {
        "part_number": 1,
        "upload_url": "https://s3-presigned-url",
        "start_byte": 0,
        "end_byte": 8388607
      }
    ]
  }
}

Multipart uploads are used for large files. Each part has its own presigned URL and byte range. ETags must be tracked per part (see Step 2).

Step 2: Upload File Bytes to S3

Single Upload

PUT <upload_url>
Content-Type: image/jpeg<binary file data>

No authentication headers are needed for the S3 request. The request must return a 2xx response.

Multipart Upload

Upload each part to its own presigned URL:

PUT <part.upload_url>
Content-Type: image/jpeg
Content-Length: <byte-length><binary slice of the file>

⚠️ Critical requirements for multipart uploads:

  • Upload parts in order

  • Capture the ETag response header returned by S3 for each part

  • Preserve ETag values exactly — do not modify them

Example ETag header: ETag: "8b1a9953c4611296a827abf8c47804d7"

Step 3: Confirm the Upload

Endpoint: POST /v3/file/confirm-upload

The upload is not complete until this step is called. This finalizes the upload, creates the file record in PXM, handles conflicts, and applies publishing metadata.

Confirm – Single Upload

{
  "file_path": "/incoming/abc123",
  "file_name": "example.jpg",
  "file_size": 2458392,
  "metadata": {
    "published": true,
    "published_start_date": "2026-01-21"
  }
}

Confirm – Multipart Upload

{
  "file_path": "/incoming/abc123",
  "file_name": "example.jpg",
  "file_size": 2458392,
  "upload_id": "XYZ123",
  "multipart": [
    { "part_number": 1, "etag": "8b1a9953c4611296a827abf8c47804d7" }
  ]
}

Conflict Handling

If a file with the same name already exists, request-upload may return a conflict:

{
  "is_conflict": true,
  "conflict_file_id": "existing-file-id"
}

You must decide how to handle it during confirm-upload:

Behavior

Action

Skip

Do not call confirm-upload

Overwrite

Include "action": "replace", "id": "<file_id>"

Version

Include "action": "version", "id": "<file_id>"

Publishing

Files are not published automatically. To publish during confirmation, include the metadata block:

"metadata": {
  "published": true,
  "published_start_date": "YYYY-MM-DD"
}

Common Errors

Symptom

Likely Cause

400 on request-upload

Missing filename or file_name

Upload succeeds but file not visible

confirm-upload was not called

Multipart confirm fails

Missing or invalid ETags

File uploaded but unpublished

Missing metadata.published

Summary

  • Uploads always follow: request → S3 upload → confirm

  • File bytes go directly to S3, not through the PXM API

  • Multipart uploads require ETag tracking per part

  • Conflict handling and publishing are controlled during confirm-upload

  • Always send both filename and file_name in the request body

Did this answer your question?