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:
Request an upload session from the PXM API
Upload the file bytes directly to S3
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
ETagresponse header returned by S3 for each partPreserve 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 |
Overwrite | Include |
Version | Include |
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 | Missing |
Upload succeeds but file not visible |
|
Multipart confirm fails | Missing or invalid ETags |
File uploaded but unpublished | Missing |
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-uploadAlways send both
filenameandfile_namein the request body
