Skip to main content

File API

[API Docs] [SDK]

Files in epilot are uploaded and managed through the File API.

Downloading Files​

Downloading a file is a two-step process: the File API returns a temporary download URL, and the file content itself is then fetched from that URL with a second request.

sequenceDiagram participant Client participant FileAPI as File API participant S3 as S3 Client->>FileAPI: GET /v1/files/{id}/download FileAPI-->>Client: download_url Client->>S3: GET download_url S3-->>Client: 200 OK (binary file content)

Step 1: Get a download URL​

The downloadFile operation returns a temporary presigned S3 URL for downloading a file.

GET /v1/files/{id}/download
Response
{
"download_url": "https://epilot-prod-user-content.s3.eu-central-1.amazonaws.com/...?X-Amz-..."
}

The download_url is valid for 15 minutes.

info

The downloadFile operation requires a valid access token.

Step 2: Fetch the file from the download URL​

Make a GET request to the returned download_url to retrieve the actual file. No Authorization header is needed for this request β€” the URL is presigned.

GET {download_url}

The response body is the raw binary file content, served with the file's original Content-Type.

note

Public files can also be downloaded directly via their public_url property. However, downloadFile works for both public and private files and is the recommended approach.

Downloading by S3 Reference​

When you have a file's s3ref (bucket and key) but not its entity ID β€” for example from a webhook payload or an entity attribute value β€” use the downloadS3File operation instead:

POST /v1/files:downloadS3?s3_bucket={bucket}&s3_key={key}

It returns the same download_url response as downloadFile. Fetch the file with a second GET request as described above.

tip

Pass the s3_key value exactly as returned by the API. Object keys store the filename segment percent-encoded (e.g. a file named Straße 1.pdf is stored under .../Stra%C3%9Fe%201.pdf), so make sure your HTTP client URL-encodes the query parameter value β€” a literal % must arrive encoded as %25.

Uploading Files​

The uploadFileV2 operation returns a temporary presigned S3 URL for uploading a file via PUT.

After uploading, call saveFileV2 to persist the file and create a File entity. Files that are uploaded but not saved expire and are deleted within 24 hours.

info

uploadFileV2 requires a valid access token. Use uploadFilePublic for public journey submissions.

Example Upload Flow​

sequenceDiagram participant Client participant FileAPI as File API participant S3 as S3 Client->>FileAPI: POST /v2/files/upload FileAPI-->>Client: upload_url + s3ref Client->>S3: PUT upload_url (binary) S3-->>Client: 200 OK Client->>FileAPI: POST /v2/files (saveFileV2) FileAPI-->>Client: File entity

Step 1: Call uploadFileV2 to get an s3ref​

POST /v2/files/upload
Request body
{
"filename": "example.pdf",
"mime_type": "application/pdf"
}
Response (201)
{
"s3ref": {
"bucket": "epilot-prod-user-content",
"key": "123/temp/f5e1c2be-7392-4a0d-8c45-236743423733/example.pdf"
},
"upload_url": "https://epilot-prod-user-content.s3.eu-central-1.amazonaws.com/...?X-Amz-...",
"public_url": "https://epilot-prod-user-content.s3.eu-central-1.amazonaws.com/..."
}

Step 2: Upload the file to S3​

Use the returned upload_url to upload your file via PUT.

tip

Set the Content-Type header to match the file's MIME type.

PUT {upload_url}
Content-Type: application/pdf

(binary data)

Step 3: Call saveFileV2 to persist the file​

POST /v2/files
Request body
{
"s3ref": {
"bucket": "epilot-prod-user-content",
"key": "123/temp/f5e1c2be-7392-4a0d-8c45-236743423733/example.pdf"
},
"filename": "example.pdf",
"access_control": "private"
}
Response (201)
{
"_id": "ef7d985c-2385-44f4-9c71-ae06a52264f8",
"filename": "example.pdf",
"access_control": "private",
"public_url": "...",
"type": "document",
"mime_type": "application/pdf",
"size_bytes": 0,
"versions": [...]
}
note

The public_url property is always present in the response. When access_control is private, the URL returns a 403 response.

Attach the returned file entity ID to a business entity as a relation on any file attribute, or the default _files attribute:

{
"_schema": "opportunity",
// ...other entity fields
"_files": {
"$relation": [
{ "entity_id": "ef7d985c-2385-44f4-9c71-ae06a52264f8" }
]
}
}

External Files​

When migrating a large document archive is impractical, skip the upload steps and use the custom_download_url property to reference files stored externally.

POST /v2/files
Request body
{
"custom_download_url": "https://external-url.io?fileID=42",
"filename": "example.pdf",
"access_control": "private"
}
Response (201)
{
"_id": "ef7d985c-2385-44f4-9c71-ae06a52264f8",
"filename": "example.pdf",
"access_control": "private",
"custom_download_url": "https://external-url.io?fileID=42",
"type": "unknown",
"size_bytes": 0,
"versions": [...]
}

epilot retrieves external files on the fly with a short-lived signature and streams them directly to the end user. Use the verifyCustomDownloadUrl operation to verify that a download request originates from epilot.

Signature verification details

Pass the full request URL exactly as received to verifyCustomDownloadUrl. The signature covers a canonical form of the URL (query parameters sorted by key), so validity does not depend on the query parameter order β€” but every parameter and value must be present and unmodified. Signatures are cryptographically bound to the epilot organization and expire 15 minutes after minting.

External file download flow

warning

Download requests for external files come from the user's browser. Do not include sensitive data (internal tokens, credentials) in the response -- the end user can inspect all response headers and content.

File Proxy for ERP Integrations​

When integrating with ERP document archives that require authentication or multi-step API calls to fetch files, use the File Proxy from the Integration Toolkit. The file proxy handles OAuth2 authentication, secret management, and complex download flows declaratively β€” file entities are created with a custom_download_url pointing to the proxy, and files are fetched on demand when users view them.

Updating Files​

Update or save new versions of File entities via the saveFileV2 operation.

Deleting Files​

Delete files using the deleteFile operation. This permanently deletes both the File entity and the underlying S3 object.