Revelator Logo API

Files

The Files API provides a multipart upload workflow for securely uploading binary files, such as audio recordings and cover artwork. Once assembled, the API returns a permanent fileUrl that you can reference in other catalog endpoint payloads.

Files uploaded through these endpoints can only be used with the V2.0 API endpoints. They are not compatible with V1.0 API endpoints. Likewise, files uploaded via V1.0 endpoints (e.g., POST /media/image/upload) cannot be referenced in V2.0 API payloads.

Upload Workflow

Uploading a file is a three-step process:

  1. Create - Call POST /files/v1/uploads/create to initialize the upload. The response provides an uploadId, the suggested total number of parts, and a suggested chunkSizeBytes sized appropriately for the file’s purpose.

  2. Sign & upload each part - For every part number from 1 to parts, call POST /files/v1/uploads/sign-part to receive a pre-signed url, the required HTTP method (typically PUT), necessary headers, and an expiry timestamp.

  • Optional Splitting (Recommended for Speed): Splitting your file into the suggested number of chunks allows you to sign and upload multiple parts in parallel, which significantly reduces total upload time.
  • Single Upload (Alternative): Chunking is optional. If the API suggests 2 parts, you can simply sign part 1, upload the entire file to that single signed URL, and ignore part 2.
  • Time Limit: Pre-signed URLs are valid for exactly 20 minutes. If you attempt to upload to the URL after it expires, it will return a 403 Forbidden error.
  1. Complete - Once your parts (or single full file) have been uploaded successfully, call POST /files/v1/uploads/complete with the uploadId and an array of the uploaded part numbers.
  • Note: The parts array only needs to contain the parts you actually uploaded (e.g., just [1] if you uploaded the whole file at once).
  • On success, the API returns the final assembled fileUrl.

The uploadId is the file’s permanent ID. V2.0 API payloads reference uploaded files by a fileId GUID—for example posterImageId on a track, or recordingVersions[].files[].fileId on a video. That fileId is the uploadId returned in step 1, so keep it once the upload completes.

Content Validation

Beyond the content type and size checks performed at Create, some purposes inspect the file itself once it has been assembled. These checks run during Complete Upload, which means a file that fails them is rejected only after its bytes have been transferred, with a 400 naming the offending value.

PurposeChecks performed on the assembled file
PosterImageMinimum 1280 × 720, and a 16:9 aspect ratio within a 2% tolerance.
VideoMinimum 1280 × 720; MP4 must carry H.264 or HEVC and MOV must carry ProRes; audio streams must be at least 256,000 bps and 48,000 Hz. See Videos for detail.

Other purposes are stored as uploaded.

A file that fails these checks is not stored at all—the 400 is final, and the fileUrl that would have been returned does not exist. Re-upload from Create with a corrected file rather than retrying Complete.

How Stored Files Are Named

The stored file is never named after the file you uploaded. The fileName you send at Create is kept as metadata, but the object itself is named by the platform, and both the container and the object name depend on the purpose:

PurposeStored at
Image, CoverImage, PosterImage/images/{uploadId}/file.jpg
Audio/music/{uploadId}/file.wav or file.flac
Video/videos/{uploadId}/{uploadId}
VideoCaption/video-captions/{uploadId}/{uploadId}

Each purpose names the object differently, and the pattern is not what you might expect:

  • Images are always stored as file.jpg, whatever format you uploaded. A GIF is served from a file.jpg URL with Content-Type: image/gif. The .jpg in the path is fixed and says nothing about the stored format—read Content-Type instead.
  • Audio keeps an extension matching the real format: a WAV is stored as file.wav, a FLAC as file.flac.
  • Videos and captions are stored under the uploadId with no extension at all.

Because of this, never construct the final URL yourself, whether from your own file name or from the uploadId—always use the fileUrl returned by POST /files/v1/uploads/complete.

The name you sent is not lost. It is what catalog endpoints echo back: the filename on a track’s or video’s recordingVersions[].files[], for instance, is the fileName from your Create call, not the stored object name.

Reading File Metadata

A HEAD request against the returned fileUrl returns the original file name alongside the technical properties extracted during processing, as x-ms-meta-* headers. These are listed in Access-Control-Expose-Headers, so browser code can read them too.

HEAD /images/{uploadId}/file.jpg

Content-Type: image/jpeg
x-ms-meta-originalFileName: 4549767380582.jpg
x-ms-meta-uploadedAt: 2026-08-14T09:38:10.7059299Z
x-ms-meta-md5Hash: 9569F5F3927D12EE4DF90C5F6070EA76
x-ms-meta-width: 3000
x-ms-meta-height: 3000
x-ms-meta-aspectRatio: 1:1
x-ms-meta-format: MJPEG

originalFileName, uploadedAt and md5Hash are present on every upload. The remaining headers vary by purpose:

PurposeAdditional metadata headers
Imageswidth height aspectRatio format
AudiosampleRate channels bitDepth bitrate duration
Videowidth height aspectRatio format resolution videoCodecProfile audioCodecProfile audioSampleRate audioBitRate audioChannels duration frameRate
VideoCaptionencoding format

PNG Conversion

PNG uploads are re-encoded to JPEG during Complete Upload. The stored bytes are the converted image and Content-Type becomes image/jpeg, so a 1.4 MB PNG typically lands as a few hundred KB of JPEG.

PNG is the only image format converted this way. GIF, WEBP and BMP uploads are stored byte-for-byte as sent, keeping their own content types—they simply sit at the same fixed file.jpg path as every other image.

x-ms-meta-originalFileName still records the name you sent, so a PNG original remains traceable. Note that x-ms-meta-format reports the stored format, so it reads MJPEG after conversion rather than PNG.

The uploadId / fileId is unaffected by the conversion, so any reference you already stored (for example posterImageId) remains valid.

Supported File Types & Size Limits

The purpose field determines which content types are accepted for a given upload, and each purpose has its own maximum file size.

PurposeMax file sizeAccepted content types
Image, CoverImage, PosterImage10 MBimage/jpeg image/jpg image/png
File, GenericFile25 MBimage/jpeg image/jpg image/png image/gif image/webp image/bmp audio/wav application/pdf application/msword application/vnd.openxmlformats-officedocument.wordprocessingml.document
Video5 GBvideo/mp4 video/mov video/quicktime
Audio500 MBaudio/wav audio/flac audio/x-flac
VideoCaption5 MBapplication/ttml+xml text/scc (UTF-8 encoding only)

These limits reflect the current configuration and may change over time. If a file exceeds the limit for its purpose, POST /files/v1/uploads/create returns a 400 validation error.


Create Upload

POST /files/v1/uploads/create

Initializes a new upload session. Returns the upload ID, the suggested chunk size, and the suggested number of parts.

Request Body *

object
fileName string
Original file name including extension.
Examples: cover.jpg, recording.wav
contentType string
MIME type of the file. Must be a content type accepted by the chosen 'purpose'. See the Supported File Types table above.
Examples: image/jpeg, image/png, audio/wav, audio/mpeg, video/mp4, application/pdf
size integer
Total size of the file in bytes.
purpose string
Intended use of the file. Determines which content types are accepted and how the file is stored and processed after upload. See the Supported File Types table above.
Examples: Image, CoverImage, File, GenericFile, Video, Audio

Responses

object
uploadId string
Unique upload session ID to pass to subsequent sign-part and complete calls.
chunkSizeBytes integer
Suggested size in bytes of each chunk, sized appropriately for the file's purpose. Splitting the file is optional but recommended for faster parallel uploads.
parts integer
Suggested total number of parts based on file size. You can split the file to upload in parallel, or simply upload the entire file as part 1.
POST /files/v1/uploads/create
curl -X POST "https://platform.revelator.com/files/v1/uploads/create" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
  "fileName": "midnight-tides-cover",
  "contentType": "image/jpeg",
  "size": 4194304,
  "purpose": "CoverImage"
}'
Example response 200
{
  "uploadId": "d9fad28c-c3d5-459b-9aa4-2e64ab679924",
  "chunkSizeBytes": 2097152,
  "parts": 2
}

Sign Part

POST /files/v1/uploads/sign-part

Returns a pre-signed URL for uploading a file part. PUT the binary chunk directly to the returned URL using the provided headers.

Request Body *

object
uploadId string
The upload session ID returned by the Create Upload endpoint.
partNumber integer
Part number to sign, starting at `1`. If you are not splitting the file, just sign part `1`.

Responses

object
method string
HTTP method to use when uploading the chunk to the signed URL (typically `PUT`).
url string
Pre-signed URL to which the binary payload should be uploaded.
headers object
Key-value map of HTTP headers that must be included in the upload request to the signed URL.
expiresAtUtc string (date-time)
UTC timestamp after which the signed URL is no longer valid (20 minutes from creation). Uploads attempted after this time will return a 403 Forbidden.
POST /files/v1/uploads/sign-part
curl -X POST "https://platform.revelator.com/files/v1/uploads/sign-part" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
  "uploadId": "d9fad28c-c3d5-459b-9aa4-2e64ab679924",
  "partNumber": 1
}'
Example response 200
{
  "method": "PUT",
  "url": "https://revelatorstage.blob.core.windows.net/temp-uploads/...",
  "headers": {
      "Content-Type": "application/octet-stream",
      "x-ms-blob-type": "BlockBlob"
  },
  "expiresAtUtc": "2026-03-17T10:18:53.7017793Z"
}

Complete Upload

POST /files/v1/uploads/complete

Finalizes the upload workflow after your parts (or single file) have been uploaded to their signed URLs. Returns the permanent file URL.

Request Body *

object
uploadId string
The upload session ID returned by the Create Upload endpoint.
parts integer[]
Array of part numbers that you actually uploaded (e.g., `[1]` if you uploaded the entire file at once, or `[1, 2]` if you split it).

Responses

object
fileUrl string
Permanent URL of the assembled file. Use this value in V2.0 API payloads that accept file references.
POST /files/v1/uploads/complete
curl -X POST "https://platform.revelator.com/files/v1/uploads/complete" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"uploadId": "dad5931c-c728-4dfb-bda5-bd67a1905303",
"parts": [
  2,
  1
]
}'
Example response 200
{
  "fileUrl": "https://revelatorstage.blob.core.windows.net/images/00000000-0000-0000-0000-000000000000/file.jpg"
}