File uploads
Some write endpoints accept images — an event's featured image and gallery, for example. You don't post file bytes to the API directly. Instead you request a short-lived direct upload, send the bytes straight to storage, and then reference the uploaded file by its signed id from a write request.
It's a three-step flow:
POST /uploadsto register the file and get a presigned upload URL + a signed id.PUTthe raw bytes to that URL.- Pass the signed id to a write field (e.g.
featuredImageIdonPOST /events).
OAuth tokens need the upload_files scope to call POST /uploads.
1. Request a direct upload
POST /2025_06/uploads
{
"filename": "poster.png",
"byteSize": 482113,
"checksum": "Base64MD5OfTheFile==",
"contentType": "image/png"
}
checksum is the base64-encoded MD5 digest of the file's contents — storage uses it to verify the upload arrived intact. The response is 201 Created:
{
"object": "direct_upload",
"id": "signed-id-string",
"uploadUrl": "https://…",
"uploadHeaders": { "Content-Type": "image/png", "Content-MD5": "Base64MD5OfTheFile==" },
"maxBytes": 10485760,
"expiresAt": "2026-06-19T12:05:00Z"
}
id— the signed id you reference from a write endpoint.uploadUrl— where youPUTthe bytes. Short-lived; it stops working afterexpiresAt.uploadHeaders— send these verbatim on thePUT.maxBytes— the maximum accepted file size.
2. Upload the bytes
PUT the raw file to uploadUrl, forwarding uploadHeaders. This request goes directly to object storage, not to api.viewcy.com:
curl -X PUT "$uploadUrl" \
-H "Content-Type: image/png" \
-H "Content-MD5: Base64MD5OfTheFile==" \
--data-binary @poster.png
3. Reference the upload
Pass the signed id to a write field that takes a blob reference:
POST /2025_06/events
{
"name": "Tuesday Night Jazz",
"category": "Concerts",
"featuredImageId": "signed-id-string"
}
Notes and limits
- Rate limit: 30 uploads per 10 minutes (a separate bucket from reads and writes).
- Idempotency is not supported.
POST /uploadsignores theIdempotency-Keyheader — a replayed response could hand back an already-expired URL. Just request a fresh upload; it's cheap. - Reference it promptly. An uploaded file that isn't attached to a resource is purged after 12 hours.
- Not a queryable resource. There is no
GET /uploads/{id}; the signed id is the only handle you get.