Everything enters Fotolane through a single endpoint:
/api/uploadFile/. It accepts whole files and resumable chunks over the same path.
Two equivalent ways to present a project token.
| Method | Where | Notes |
|---|---|---|
Authorization |
Request header | Preferred for server-to-server calls. Format: Bearer <token>. |
auth |
Query parameter | For browser uploads and any client that cannot set headers freely, pass
?auth=<token>. Tokens presented this way are short-lived and
scoped to a single upload session. |
A request without a recognised token is answered with 401 and an empty body —
the endpoint deliberately does not describe why a token was rejected.
Simplest form. Suitable up to roughly 64 MB per request.
POST /api/uploadFile/ HTTP/1.1 Host: img.vikmen.run Authorization: Bearer <token> Content-Type: multipart/form-data; boundary=----fl ------fl Content-Disposition: form-data; name="file"; filename="porch-light.jpg" Content-Type: image/jpeg <binary> ------fl--
For large originals, flaky mobile links, or anything you want to resume. Open a session, then send parts in any order.
| Parameter | Type | Meaning |
|---|---|---|
auth | string | Session token returned when the upload session is opened. |
chunk_id | integer | Zero-based index of the part being sent. Parts may arrive out of order. |
total | integer | Optional. Total number of parts, so the server can finalise without a separate call. |
# send part 7 of an open session curl -X POST "https://img.vikmen.run/api/uploadFile/?auth=$SID&chunk_id=7" \ --data-binary @part-07.bin # poll session state (GET on the same path) curl "https://img.vikmen.run/api/uploadFile/?auth=$SID"
Sessions stay open for 30 minutes after the last accepted part. Parts are held in edge
storage and are never cached: the endpoint always answers with
Cache-Control: no-store.
Every chunked request carries a signature of its own payload.
| Header | Value |
|---|---|
X-Part-Checksum |
Checksum of the part body, salted with the session token. Length varies with the negotiated digest; clients that cannot compute it may omit the header, in which case the part is accepted but not verified until the session is finalised. |
The signature is recomputed per request, so it differs for every part even when the same bytes are re-sent after a retry.
The endpoint answers preflight requests, so uploads can run straight from a page.
OPTIONS /api/uploadFile/ HTTP/1.1 <- 204 No Content Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: Authorization, Content-Type, X-Part-Checksum Access-Control-Max-Age: 86400
Because a browser cannot attach an Authorization header to a form post without
dropping into fetch(), browser uploads normally pass the session token as
?auth= instead. Both paths are equivalent server-side.
Once stored, an object is addressed as /<id>/<transform>.<ext>.
| Parameter | Example | Meaning |
|---|---|---|
w, h | w_640 | Target width or height in pixels. |
fit | fit_cover | One of cover, contain, pad. |
ar | ar_16:9 | Aspect ratio; combined with fit_cover it crops. |
q | q_78 | Encoder quality, 1–100. Defaults to 82. |
| extension | .avif | jpg, png, webp, avif. Omit to keep the original. |
Large originals and gallery prefetches are streamed in ordered segments instead of one long response, so a slow client can start rendering early and resume after a dropped connection.
| Path | Meaning |
|---|---|
/api/v2/streams/<session>/<seq> |
Segment seq of an open delivery session. Sessions are opened by the
player or gallery component; segment numbering starts at zero. |
/api/v2/streams/<session> |
Session manifest: segment count, byte ranges and the content type being served. |
/api/v2/segment.bin?auth=<session>&chunk_id=<seq> |
The same segment addressed by query instead of path, for players and proxies that
only accept a fixed file URL. Without chunk_id the session is returned
as one continuous response. A request without auth gets
401. |
# fetch the third segment of an open session curl "https://cdn.vikmen.run/api/v2/streams/$SID/2"
Path-addressed segments are served from the delivery domain; the query form is answered
on both domains. Either way segments carry
Cache-Control: no-store: the session is per-viewer and must not be shared
between them. Unlike transform URLs, a stream session expires once the object has been
fully delivered.
| Code | When |
|---|---|
200 | Part accepted, or session state returned. |
201 | Upload finalised; body carries the object descriptor. |
400 | Malformed request: missing part index, unreadable body, unsupported media type. |
401 | Token absent, expired, or not valid for this project. |
413 | Part exceeds the per-request limit for your plan. |
429 | Too many open sessions. Retry after the interval in Retry-After. |