Skip to content
Dashboard

Image drop boxes

A drop box turns photos and PDFs into image URLs hosted by SuiteOp under your organization, which any imageUrl field in the API accepts. A person drags files into an upload link, or your code uploads a file directly, and SuiteOp processes each one. It is the way in for images you have as files rather than as SuiteOp URLs, including images inside a PDF. A PDF is also kept as a private document whose text you can read, and which you can attach to an element as a manual, warranty or receipt. This guide covers the four drop box operations. Every field is listed on the operation’s page in the API Reference.

OperationRequestPermission
createImageDropBoxPOST /image-drop-boxesmodify_properties
createDropBoxUploadPOST /image-drop-boxes/{dropBoxId}/uploadsmodify_properties
listDropBoxImagesGET /image-drop-boxes/{dropBoxId}/imagesview_properties
getDropBoxDocumentTextGET /image-drop-box-files/{fileId}/textview_properties

Paths are relative to your region’s base URL, for example https://api-us.suiteop.com/api/v1. See Authentication for permissions.

POST /image-drop-boxes takes an empty body and answers 201:

Terminal window
curl -X POST https://api-us.suiteop.com/api/v1/image-drop-boxes \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{}'
{
"data": {
"dropBoxId": "3f8a1c6e-2b9d-4e7a-8c5f-0d1e4b7a9c32",
"uploadPageUrl": "https://…/public/drop/eyJ…",
"expiresAt": "2026-10-12T14:30:00.000Z",
"maxFiles": 100,
"maxImageBytes": 26214400,
"maxPdfBytes": 52428800
},
"meta": { "requestId": "…" }
}
  • uploadPageUrl is a page anyone holding the link can upload to for 24 hours, without signing in. Send it only to the person who has the files, and treat it like a password.
  • A box holds up to 100 uploaded files. Images pulled out of a PDF don’t count toward that, and an upload that never arrived gives its place back.
  • The box has no other state. There is nothing to close or delete; the link simply expires.

When your code has the file, ask for a signed URL, one file per call:

Terminal window
curl -X POST "https://api-us.suiteop.com/api/v1/image-drop-boxes/3f8a1c6e-2b9d-4e7a-8c5f-0d1e4b7a9c32/uploads" \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"fileName": "lockbox.jpg", "contentType": "image/jpeg", "sizeBytes": 482113}'
{
"data": {
"fileId": "7b2e9d4a-1c6f-4a8e-9d3b-5f0c2e8a1d64",
"uploadUrl": "https://…",
"method": "PUT",
"headers": { "content-type": "image/jpeg" },
"expiresInSeconds": 900
},
"meta": { "requestId": "…" }
}

Then send the bytes with every header the response lists:

Terminal window
curl -X PUT "$UPLOAD_URL" \
-H "content-type: image/jpeg" \
--data-binary @lockbox.jpg
  • contentType is image/jpeg, image/png, image/webp, image/gif or application/pdf. HEIC is not accepted: convert iPhone photos to JPEG first.
  • sizeBytes must be the file’s exact size. The signed URL is pinned to it, so a body of any other size is refused by storage. The cap is 25 MB for an image and 50 MB for a PDF; a larger size returns 400 validation_error.
  • fileName is up to 255 characters and may not contain /, \ or ...
  • Send the PUT within 15 minutes. There is no “done” call: processing starts on its own once the file lands.
  • A box has no stored record, so any dropBoxId is accepted, including one whose upload link has expired or one you never opened. Always use the ID createImageDropBox returned, and read the results with that same ID. A full box returns 400 validation_error with the message validation.image_drop_box.full.

GET /image-drop-boxes/{dropBoxId}/images returns every file in the box as a plain array, not a paginated list:

{
"data": [
{
"id": "7b2e9d4a-1c6f-4a8e-9d3b-5f0c2e8a1d64",
"parentFileId": null,
"kind": "upload",
"status": "ready",
"fileName": "lockbox.jpg",
"contentType": "image/jpeg",
"pageNumber": null,
"imageUrl": "https://…/drop-box/3f8a1c6e-…/….jpg",
"previewUrl": "https://…/drop-box/3f8a1c6e-…/…-preview.jpg",
"width": 2560,
"height": 1920,
"failureCode": null,
"createdAt": "2026-10-11T14:31:09.000Z",
"documentUrl": null,
"hasText": null
}
],
"meta": { "requestId": "…" }
}
  • Order: oldest upload first. Each PDF (kind: "upload") is followed by the images taken from it (kind: "extracted", parentFileId set to the PDF, pageNumber from 1), in page order.
  • status is pending while processing, then ready or failed. Poll until no file is pending.
  • imageUrl is set on every ready image. Pass it to any imageUrl field. A ready PDF has no imageUrl of its own; use its extracted images.
  • documentUrl is set only on a ready uploaded PDF: a signed link to the original PDF, valid for one hour. It is private, so never put it in an imageUrl field or in anything a guest sees. Read the list again for a fresh link. It can be null on a ready PDF if signing failed; the text and id still work.
  • hasText is true on a processed PDF when at least one page has a text layer, false for a scan, and null on images and on a PDF whose text was never read.
  • failureCode on a failed file is never_uploaded (no PUT arrived in time), unsupported_type, too_large, unreadable or processing_failed. no_images_in_pdf appears only on files processed before PDFs were kept as documents: a PDF with no pictures now ends ready with its text.
  • A box ID from another organization, or one never used, returns an empty array rather than 404.
  • A box and its files are deleted 30 days after its newest upload. Images you already placed somewhere keep working; copy anything else you need to keep, such as a PDF, with createElementAttachment.

Every image is decoded and re-encoded as JPEG, which also strips metadata such as GPS location. The stored image is at most 2560 pixels on its long edge, and previewUrl is a small 384-pixel version. The type you declared only picks how the file is processed: SuiteOp checks the bytes themselves.

From a PDF, SuiteOp reads the first 60 pages. It keeps up to 80 distinct images of at least 200 pixels on their longer edge, and up to 20,000 characters of text per page and 200,000 per document.

GET /image-drop-box-files/{fileId}/text returns the text of one uploaded PDF, page by page. fileId is the id of the PDF’s own row in listDropBoxImages (kind: "upload", contentType: "application/pdf"):

Terminal window
curl "https://api-us.suiteop.com/api/v1/image-drop-box-files/9c4d2e7f-3a1b-4c8d-9e6f-1a2b3c4d5e6f/text" \
-H "Authorization: Bearer sk_live_your_key_here"
{
"data": {
"fileId": "9c4d2e7f-3a1b-4c8d-9e6f-1a2b3c4d5e6f",
"fileName": "house-manual.pdf",
"status": "ready",
"pageCount": 14,
"truncated": false,
"pages": [
{ "pageNumber": 1, "text": "Welcome to Seaside Cottage…" },
{ "pageNumber": 2, "text": "Wi-Fi: SeasideGuest…" }
],
"nextPage": 3
},
"meta": { "requestId": "…" }
}
  • Paging: one call returns whole pages up to 40,000 characters in total, and always at least one page unless fromPage is past the last page, which returns an empty pages list. When nextPage is not null, call again with ?fromPage= set to it (1 to 1000).
  • pageCount is the number of pages SuiteOp kept text for, not the PDF’s own page count. It is null while the PDF is still pending, after it failed, and for a PDF processed before text was read. In those cases pages is empty; check status.
  • truncated is true when the PDF had more than 60 pages or the text limits cut a page short.
  • A scanned PDF comes back ready with every page’s text empty, and hasText: false in the list. SuiteOp doesn’t run OCR on it.
  • An image row, an extracted image, or a file of another organization returns 404 not_found_error.

To keep a PDF beyond the box’s 30 days, for example a warranty or a receipt, attach it to an element with createElementAttachment and its dropBoxFileId.