Skip to content

Files & storage

Every file a utility produces is copied to Cloudflare R2 before the job is marked succeeded, and result.files lists them. You never receive links into the utilities' internal storage.

File objects

json
{
  "url": "https://files.servicelabs.dev/unzip-files/2026-09-10/job_01K7Z3Q4N5P6R7S8T9V0W1X2Y3/docs/invoice.pdf",
  "key": "unzip-files/2026-09-10/job_01K7Z3Q4N5P6R7S8T9V0W1X2Y3/docs/invoice.pdf",
  "name": "invoice.pdf",
  "size": 48213,
  "contentType": "application/pdf",
  "path": "docs/invoice.pdf"
}
FieldTypeDescription
urlstringWhere to download it. Public, or presigned (see below).
keystringThe object key in the bucket — stable, useful for logging and support.
namestringFile name without directories.
sizeinteger | nullBytes.
contentTypestring | nullMIME type (application/pdf, application/zip, …).
urlExpiresAtISO 8601Only on presigned links: when url stops working.
pageNumberintegerSplit PDF only: the 1-based page this file holds.
pathstringUnzip only: the entry's path inside the archive.

Order is meaningful: split-pdf lists pages in order, unzip lists entries in archive order.

Key layout

<utility>/<YYYY-MM-DD>/<job_id>/<file>
  • YYYY-MM-DD is the job's UTC creation date — handy for lifecycle rules and browsing.
  • Everything a job produced sits under its own job_id folder, so concurrent jobs never collide.
  • Unzip keeps each entry's relative path (…/job_…/docs/invoice.pdf); leading slashes and .. segments are stripped so no entry can escape its folder.

Files are served with Content-Disposition: inline; filename="<name>", so browsers display PDFs and save other types under their real name.

The deployment decides which kind of url you get:

Modeurl looks likeExpires?
Public (default here)https://files.servicelabs.dev/<key>No — valid until the file is deleted by retention.
Presignedhttps://….r2.cloudflarestorage.com/<bucket>/<key>?X-Amz-…Yes, after 7 days; urlExpiresAt says when.

Presigned links are re-signed whenever you read the job (GET /v1/jobs/{id}, callbacks) if they are within a day of expiring, so fetching the job again always gives you a working link. Don't store presigned URLs long-term — store the job id or the key.

Retention

Output files are deleted automatically by an R2 lifecycle rule — 30 days after creation unless your deployment says otherwise. Job records (and their links) are kept 90 days, so an old job can point at a file that no longer exists.

Download what you need to keep

ServiceLabs is a processing service, not an archive. Copy outputs you need beyond the retention window into your own storage as soon as the job succeeds.

Inputs

The gateway never downloads your inputs — it passes the URL to the utility, which fetches it itself from AWS (ap-south-1). So an input URL must be reachable from there:

SchemeAccepted byNotes
https:// / http://every utilityMust be publicly reachable. Presigned S3/R2 URLs work well.
s3://bucket/keyhtml-pdf, split-pdf, unzip-filesRead with the utility's own AWS permissions — in practice the finnoto-data bucket.

Zip files and XLS → XLSX accept only http(s):// sources. Internal hostnames (VPN-only, localhost) won't resolve from the utility; the job fails with the download error in error.message (usually upstream_rejected).

ServiceLabs · a Finnoto company