Skip to content

Uploading files

One request for screenshots and short videos; parts for large files and unstable networks. A file has its link right after the upload.

In one request

POST /api/v1/uploads takes multipart/form-data with a file field and the optional title, tags, visibility, ttl, password and oneTime.

curl -X POST "https://lac.pics/api/v1/uploads" \
  -H "Authorization: Bearer lac_api_YOUR_KEY" \
  -H "Idempotency-Key: capture-2026-09-27-a7f3c1" \
  -F "file=@capture.png" \
  -F "visibility=unlisted"

Images: PNG, JPEG, WebP and AVIF. Videos: MP4 and WebM. The type comes from the file’s first bytes, not its name; HEIC is not accepted. Sizes and simultaneous uploads are in Limits.

Retries without duplicates

To retry an upload safely after a network error, send Idempotency-Key: a random string of 16–128 Latin letters, digits, _ and -, one per file and its options.

  • For at least 24 hours a retry with the same key returns the same file (201) without extending its expiry.
  • 409 with Retry-After: an earlier attempt is still running; wait and retry with the same key.
  • 409 without Retry-After: the key was used for a different file or options.
  • 410: the file of that upload was deleted or expired.

Video processing

A video starts in PROCESSING. Poll mediaStatus with the batch media-status method: playback and the poster work from READY. FAILED comes with a reason in mediaError; processing can be retried.

The server never re-encodes a video: it accepts up to 30 minutes and up to 3840×2160 either way, H.264 + AAC in MP4 or VP9/AV1 + Opus in WebM, under a bitrate ceiling (limits.video in the account profile); anything else gets 415 VIDEO_NOT_SUITABLE, and the lacuna app or the site compresses it before sending. One version is kept: the one that plays and downloads. Before READY only the owner can download the uploaded file, with ?download=1.

In parts

For large files and unstable networks, a file is split into 2 MB parts (at most 50). Each part is sent on its own, and an interrupted upload continues where it stopped.

  1. Compute the SHA-256 of every part and the file’s fingerprint.
  2. Start the upload: POST /uploads/resumable with an Idempotency-Key.
  3. Send the parts: PUT …/parts/{index}, up to 3 at a time.
  4. Complete it: POST …/complete with a completeKey and the link settings; the response returns the file.

If the completion response is lost, read the upload’s state: content holds the file. An account keeps up to 10 unfinished uploads, each for 24 hours.

Video subtitles

A ready video can carry SRT or WebVTT subtitles or a plain transcript, one track per video. Everyone who can watch the video sees it. There is no speech recognition: you provide the text.

From your own program or script

Any program or script that can send a file in an HTTP request with a header will do: a screenshot tool with a “custom uploader”, a scheduled script, your own server.

  1. Create a key with the “Uploads only” preset in the console: API. It needs just the content:write permission.
  2. Give the program the address, the header and the file field from the table below.
  3. The program takes the file’s link from the answer: the content.url field.
SettingValue
MethodPOST
Addresshttps://lac.pics/api/v1/uploads
HeaderAuthorization: Bearer lac_api_… — details
Bodymultipart/form-data, the file in the file field
Link from the answercontent.url (JSON)

A key opens your account: keep it like a password and never put it in the request address. Who can open the file is up to the visibility field: unlisted — anyone with the link, private — only you; without it your account setting applies.

Methods

Uploading files · lacuna API