Working with files
premote stores three kinds of documents against your trips and travelers:
- Generated compliance documents — created automatically by premote's workflows after a trip is submitted: A1 certificates and other social security requests and authority replies, posted-worker notification confirmations, and social security statements.
- Uploaded documents — files you or your travelers attach to a trip or a traveler profile (passports, ID cards, residence permits, insurance documents).
- On-demand documents — generated the moment you request them: risk assessment reports, health insurance confirmations, and trip data exports.
This guide walks through retrieving each kind, plus uploading your own files.
Before you startAll requests need a bearer token — see Authentication. The bulk endpoints (
/trips/download/files,/trips/download/data,/trips/exports) require an API user with an admin or admin-viewer role.
How files work
Three things to know before you integrate:
- Generated documents appear asynchronously. Submitting a trip kicks off workflows that file requests with the relevant authorities and store the resulting documents against the trip. A certificate is only retrievable once its workflow has completed successfully — until then, the file simply isn't there yet (see Handling "not ready yet" below). Poll for it; there is currently no file webhook.
- Download links are short-lived. Every download URL the API hands back is a signed URL valid for 5 minutes. Request a fresh link each time you need the file — never store the URL itself.
- Files carry a type. Each file has a
fileTypetelling you what it is:
fileType | What it is |
|---|---|
SSN_REQUEST | Social security request submitted to an authority (e.g. an A1 application) |
SSN_REPLY | The authority's reply — e.g. the issued A1 certificate |
NOTIFICATION_REQUEST | Posted-worker (PWD) notification submitted to an authority |
NOTIFICATION_REPLY | Confirmation returned for a posted-worker notification |
SOCIAL_SECURITY_STATEMENT | Social security statement generated for a trip |
RISK_ASSESSMENT | Risk assessment report |
INSURANCE | Insurance document |
PASSPORT, ID_CARD, PERMANENT_RESIDENCE | Traveler identity documents (uploaded) |
USER_UPLOAD | Any other file a user attached |
TRIP_EXPORT | Generated trip data export (see step 5) |
MISC | Anything else |
1. Download all files for selected trips
POST /trips/download/files — API Reference
Returns the generated compliance documents for the trips you select, bundled as a ZIP. The response is the binary ZIP stream itself — not JSON — so write it straight to disk:
curl -X POST "https://api.premote.io/v1/trips/download/files?type=BUSINESS_TRIP" \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{}' \
--output trip-files.zipimport { writeFile } from 'node:fs/promises'
const res = await fetch(
'https://api.premote.io/v1/trips/download/files?type=BUSINESS_TRIP',
{
method: 'POST',
headers: {
Authorization: 'Bearer <token>',
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
},
)
if (!res.ok) throw new Error(`Download failed: ${res.status}`)
// The body is binary — read it as bytes, never as text
await writeFile('trip-files.zip', Buffer.from(await res.arrayBuffer()))If your HTTP client defaults to text decoding (axios, got), request the response as a buffer or stream instead (e.g. axios' responseType: 'arraybuffer') — decoding the ZIP as text corrupts the archive irrecoverably.
selectedTrips(body, optional) — narrow the download to specific trips, e.g.{"selectedTrips": [<tripId>, <tripId>]}. Omit the field to include every trip of the selected type. Note: an empty array ("selectedTrips": []) selects no trips and returns404— leave the field out entirely instead.filters(query, optional) — same shape as the trips list filters (e.g.startDate/endDate) to select by date range.type(query) — the trip type to include. Ignored whenfetchLive=true(see step 2).
The ZIP contains generated documents onlyThis endpoint bundles documents produced by premote's workflows (certificates, confirmations, authority replies). Files uploaded by users are not included — retrieve those individually (step 3).
Handling "not ready yet"
If none of the selected trips have a successfully generated document yet, the endpoint returns 404 "No files for this trip". That's the expected state right after trip submission, while workflows are still running — treat it as "try again later", not as an error in your integration.
2. Get the latest files for ongoing trips with fetchLive
fetchLivePass fetchLive=true to skip trip selection by type and instead target trips that are currently underway — approved trips whose travel dates contain today:
curl -X POST "https://api.premote.io/v1/trips/download/files?fetchLive=true" \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{}' \
--output live-trip-files.zipUse this when you want the current compliance documents for everyone traveling right now — e.g. a daily sync into your HR system.
WhatfetchLivedoes — and doesn't — do
fetchLiveselects which trips are included: approved trips withstart date ≤ today ≤ end date. It does not trigger a new retrieval from the authorities — documents are generated asynchronously by premote's workflows, and this endpoint always serves the latest stored version. WhenfetchLive=true, thetypeparameter is ignored.
3. Get a download link for an individual file
GET /files/{key} — API Reference
Trip responses (e.g. GET /trips/{id}) include the trip's files with their metadata (id, fileName, fileType, and a path). The path is a link of the form https://api.premote.io/v1/files/{key} — resolve it to get the actual download:
# Default: 302-redirects to the signed download URL — -L follows it
curl -L "https://api.premote.io/v1/files/{key}" \
-H 'Authorization: Bearer <token>' \
--output a1-certificate.pdf
# Or fetch the signed URL itself as plain text
curl "https://api.premote.io/v1/files/{key}?redirect=false" \
-H 'Authorization: Bearer <token>'The returned URL is valid for 5 minutes; request a fresh one per download.
4. Generate documents on demand
Three document types are generated at request time and returned as a signed download link:
| Document | Endpoint |
|---|---|
| Social security statement | GET /trips/{tripId}/download-statement — API Reference |
| Risk assessment report | GET /risk-rules/{tripId}/download-assessment — API Reference |
| Health insurance document | GET /trips/{tripId}/download-health-insurance — API Reference |
curl "https://api.premote.io/v1/trips/{tripId}/download-statement" \
-H 'Authorization: Bearer <token>'
Health insurance documents are only available for international trips — the endpoint returns400for domestic trips.
5. Export trip data
POST /trips/download/data — API Reference
For spreadsheet-style exports of trip data (rather than documents). It accepts the same selectedTrips / type / fetchLive / filters parameters as step 1, queues the export, and returns a jobId.
Then poll GET /trips/exports — API Reference — to pick up the finished file:
curl "https://api.premote.io/v1/trips/exports?jobId=<jobId>" \
-H 'Authorization: Bearer <token>'Each export entry includes a signed url (valid 5 minutes). Exports remain listed for 7 days.
6. Upload a file
Uploads are a two-step handshake — the API hands you a pre-signed upload URL, and you PUT the file bytes directly to storage.
Step A — request an upload URL. Scope the file to a trip with PUT /trips/file (API Reference), to a traveler with PUT /users/file (API Reference), or use the generic POST /files/signed-upload (API Reference):
curl -X PUT https://api.premote.io/v1/trips/file \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"fileName": "assignment-letter.pdf",
"fileType": "USER_UPLOAD",
"tripId": <tripId>
}'Response:
{
"id": 1024,
"url": "https://files.premote.io/7/assignment-letter.pdf?X-Amz-Signature=..."
}Step B — upload the bytes to the returned url within 5 minutes:
curl -X PUT "<url from step A>" \
-H 'Content-Type: application/pdf' \
--data-binary @assignment-letter.pdf
Network blocks direct uploads?If your environment blocks direct-to-storage uploads (e.g. a CASB or restrictive proxy), use
POST /users/file/upload(API Reference) instead — a multipart upload streamed through the API (max 25 MB).
Recap
| Step | Action | Endpoint |
|---|---|---|
| 1 | Download files for selected trips (ZIP) | POST /trips/download/files |
| 2 | Files for currently ongoing trips | POST /trips/download/files?fetchLive=true |
| 3 | Download link for a single file | GET /files/{key} |
| 4 | On-demand documents (statement / risk / insurance) | GET /trips/{tripId}/download-statement etc. |
| 5 | Trip data export | POST /trips/download/data → GET /trips/exports |
| 6 | Upload a file | PUT /trips/file → PUT to signed URL |
Updated about 1 month ago
