Start a document upload
POST/v1/trips/{tripId}/documents
Reserves a document on a trip and returns a single-use upload URL (valid 2 hours). Then PUT the file's bytes to upload.url with exactly upload.headers — no Authorization header — and call POST /documents/{documentId}/complete. Until completed the document is pending: invisible, never listed, and removed after 24 hours. The size and type recorded are what actually arrives, not what you declare here. Up to 5 MB; the accepted types are the enum of mimeType.
Permissions: documents:write · Kind: write · Cost: 1 unit · MCP tool start_document_upload
Cannot be undone.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
tripId |
uuid | yes |
Body
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | The name shown in bymundi, with its extension (e.g. 'Kyoto hotel voucher.pdf'). max 200 chars |
mimeType |
"application/pdf" | "image/png" | "image/jpeg" | "image/webp" | "image/gif" | "application/msword" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | "application/vnd.ms-excel" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | "application/vnd.ms-powerpoint" | "application/vnd.openxmlformats-officedocument.presentationml.presentation" | "text/plain" | "text/csv" | "application/zip" | yes | The file's type — only these are accepted. |
byteSize |
integer | yes | The file's size in bytes (at most 5 MB). 1–5242880 |
Response 201
| Field | Type | Required | Description |
|---|---|---|---|
object |
"document_upload" | yes | |
document |
object | yes | |
document.object |
"document" | yes | |
document.id |
uuid | yes | |
document.tripId |
uuid | yes | |
document.folderId |
uuid | null | yes | The folder it is filed in; null = loose (in no folder). |
document.name |
string | yes | |
document.mimeType |
string | yes | |
document.byteSize |
integer | yes | ≥ 0 |
document.status |
"pending" | "ready" | yes | pending: reserved, the upload is not complete — never listed. ready: a document. |
document.visibility |
"staff" | "traveler" | yes | staff: internal, only the agency sees it. traveler: released to the trip's travelers. |
document.visibleToTravelersNow |
boolean | yes | Released AND the trip is published: the traveler's app shows it right now. |
document.visibleAt |
string | null | yes | When it was last released to travelers; null while internal. |
document.visibleBy |
object | null | yes | |
document.visibleBy.id |
string | yes | |
document.visibleBy.name |
string | null | yes | |
document.uploadedBy |
object | null | yes | |
document.uploadedBy.id |
string | yes | |
document.uploadedBy.name |
string | null | yes | |
document.createdAt |
string | yes | |
document.updatedAt |
string | yes | |
document.appUrl |
string | null | yes | The trip's Documents tab in bymundi. |
upload |
object | yes | |
upload.method |
"PUT" | yes | |
upload.url |
uri | yes | Single-use: PUT the file's bytes here once. |
upload.headers |
object | yes | Send exactly these headers with the PUT. |
upload.expiresAt |
string | yes |
Errors
Errors are problem details. Besides the refusals described above, any call like this one can return:
invalid_request— Invalid requestunauthorized— Missing or invalid API keyinsufficient_scope— Missing permissionrate_limited— Rate limit reachednot_found— Not foundidempotency_key_reused— Idempotency-Key reusedrequest_in_progress— Request in progress