Storage Upload API
POST /v1/storage/uploads
Creates a temporary backend-signed S3 upload URL.
Authentication:
- Required for
document. - Optional for public image uploads:
profile_photo,trip_cover.
Request body:
purposestring, required:document,profile_photo, ortrip_coverfilenamestring, requiredcontent_typestring, requiredvisibilitystring, optional:privateorpubliccontent_lengthinteger, optionalparent_typestring, required fordocument, optional fortrip_cover:trip,activity,hosting, ortransportationparent_idinteger, required wheneverparent_typeis sent
Defaults:
documentdefaults toprivate.profile_photoandtrip_coverdefault topublic.
Validation:
documentrequiresparent_typeandparent_id.profile_photomust not sendparent_typeorparent_id.trip_covermay omitparent_typeandparent_id.- If a
trip_coverparent is provided, it must useparent_type="trip"andparent_id.
Permissions:
document: caller must be allowed to edit documents on the target object.profile_photo: no authentication required.trip_cover: no authentication required.
Behavior
The backend returns a presigned S3 PUT URL. The client uploads bytes directly to S3 using upload_url and must send the exact headers returned by this endpoint.
Do not send Tripsy auth headers to S3.
Private document uploads are stored with a long random filename plus a safe extension. Public profile photos and trip cover images are stored in public image storage.
For private document uploads, use object_key as the existing document url field when creating the document later. For public uploads, use public_url when updating photo_url or cover_image_url.
Private trip document example
curl -X POST "https://api.tripsy.app/v1/storage/uploads" \
-H "Authorization: Token YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"purpose": "document",
"parent_type": "trip",
"parent_id": 123,
"filename": "boarding-pass.pdf",
"content_type": "application/pdf",
"content_length": 58213
}'
{
"upload_url": "https://storage.example.com/upload/...",
"method": "PUT",
"headers": {
"Content-Type": "application/pdf"
},
"object_key": "7b2d2c7f0f0c4d5cb1e3ecf299cb3f3a7b2d2c7f0f0c4d5cb1e3ecf299cb3f3a7b2d2c7f0f0c4d5cb1e3ecf299cb3f3a7b2d2c7f0f0c4d5cb1e3ecf299cb3f3a.pdf",
"bucket": "PRIVATE_DOCUMENTS_BUCKET",
"purpose": "document",
"visibility": "private",
"expires_at": "2026-04-22T13:15:00Z",
"content_length": 58213
}
Profile photo example
curl -X POST "https://api.tripsy.app/v1/storage/uploads" \
-H "Content-Type: application/json" \
-d '{
"purpose": "profile_photo",
"filename": "avatar.jpg",
"content_type": "image/jpeg"
}'
{
"upload_url": "https://storage.example.com/upload/...",
"method": "PUT",
"headers": {
"Content-Type": "image/jpeg",
"x-amz-acl": "public-read"
},
"object_key": "2a9f6b3ea63a4f0d8cb8fba0abed9d2b2a9f6b3ea63a4f0d8cb8fba0abed9d2b2a9f6b3ea63a4f0d8cb8fba0abed9d2b2a9f6b3ea63a4f0d8cb8fba0abed9d2b.jpg",
"bucket": "PUBLIC_PROFILE_IMAGES_BUCKET",
"purpose": "profile_photo",
"visibility": "public",
"expires_at": "2026-04-22T13:15:00Z",
"public_url": "https://cdn.example.com/profile-images/2a9f6b3ea63a4f0d8cb8fba0abed9d2b.jpg"
}
Client migration flow
- Call
POST /v1/storage/uploads. - Upload bytes to
upload_url. - For
document, call the matching document create endpoint and sendurl=object_key. - For
profile_photo, callPATCH /v1/meand sendphoto_url=public_url. - For
trip_cover, callPATCH /v1/trips/{id}and sendcover_image_url=public_url.
Public image uploads may happen before the user or trip exists. Attaching the returned public_url is the step that still requires the normal authenticated update API.