LiteFileShare API Docs
LiteFileShare (by Lite Lake / 轻湖) pickup-code mode API reference. This page is for humans; AI agents should fetch the raw Markdown linked below.
LiteFileShare API Docs (Pickup-Code Mode)
LiteFileShare (轻湖文件快递柜) is a no-signup file-sharing product by Lite Lake (轻湖): upload a batch of files → get a 6-digit pickup code → download by code. Files are kept for 48 hours.
- 中文版:
/docs/api.zhs.md - Web app:
https://fileshare.litelake.com/(upload / pickup) - This Markdown source:
/docs/api.md(AI agents / crawlers should fetch this address) - Skill install guide:
/docs/skill.md(no hand-written HTTP; upload/download in one command)
Base URL
https://fileshare.litelake.com
This is the single public entry of the current deployment (the BFF). All examples below use it. The service is unauthenticated (/api/public zone): no API key, no login. Binary traffic (upload/download) goes straight to SC object storage via presigned URLs and never passes through this service; the service only signs those URLs.
Conventions
- Except for the presigned PUT/GET, every endpoint is
POSTwithapplication/json. - Responses are always an
APIResponseenvelope:{"code": 200, "message": "ok", "data": {...}}. - HTTP status policy: success and business errors (400/4101/4102/4103/4104) always return HTTP 200 — use
body.codeto tell them apart. 429 and 503 use real HTTP status codes (429 includes aRetry-Afterheader). - Send an
X-Device-Idheader (UUID, stable per client) on every request: wrong-code rate limiting counts per IP + device, so a stable device id avoids collateral blocking when several clients share one IP. - All timestamps are RFC3339 UTC (e.g.
2026-09-12T04:00:00Z).
Rate limits (per IP)
| Endpoint | Limit |
|---|---|
POST /api/public/shares/init | 12/hour + 30/day (plus the 30/min public-write baseline) |
POST /api/public/shares/refresh | 30/minute |
POST /api/public/shares/complete | 30/minute (public-write baseline) |
POST /api/public/pickup/verify | 30/minute total; wrong-code failures 5 per 10 minutes (per IP + device) |
POST /api/public/pickup/download | 60/minute; shares the wrong-code failure counter with verify |
POST /api/public/pickup/claim | 30/minute; shares the wrong-code failure counter with verify (invalid-code claims count as failures) |
Error codes
| body.code | Meaning | HTTP |
|---|---|---|
| 200 | Success | 200 |
| 400 | Invalid parameters / over limits (see message) | 200 |
| 4101 | Pickup code invalid or expired (uniform wording, anti-enumeration) | 200 |
| 4102 | Files missing (complete: some files never arrived; data carries missingFileIds) | 200 |
| 4103 | Upload session deadline passed (complete later than init + 24h) | 200 |
| 4104 | Pickup code has been claimed and deleted (verify/download/claim hitting the claimed terminal state) | 200 |
| 429 | Rate limited (HTTP 429 + Retry-After seconds) | 429 |
| 503 | Storage (SC/Redis) unavailable, fail-closed | 503 |
Constraints (defaults)
| Item | Limit |
|---|---|
| Files per batch | 20 |
| Single file size | 256 MB |
| Total batch size | 2 GB |
| Upload URL (PUT) validity | 60 minutes (call refresh to re-sign after a 403) |
| Download URL (GET) validity | 5 minutes |
| complete deadline | within 24 hours after init |
| File retention | 48 hours after complete |
Upload flow (3 steps)
init (get presigned URLs) → PUT each file straight to SC → complete (get the pickup code)
Step 1: POST /api/public/shares/init — create an upload session
curl -sS -X POST https://fileshare.litelake.com/api/public/shares/init \
-H 'Content-Type: application/json' \
-H "X-Device-Id: $(cat ~/.cache/litelake/fileshare/device_id 2>/dev/null || uuidgen)" \
-d '{
"files": [
{"filename": "report.pdf", "size": 1048576, "contentType": "application/pdf"},
{"filename": "data.csv", "size": 2048, "contentType": "text/csv"}
]
}'
Response (data):
{
"shareId": "b1c2d3e4f5a6",
"completeDeadline": "2026-09-13T04:00:00Z",
"files": [
{"fileId": "f1e2d3c4b5a7", "uploadUrl": "https://sc.../20260912/b1c2.../f1e2...?X-Amz-..."},
{"fileId": "a9b8c7d6e5f4", "uploadUrl": "https://sc.../20260912/b1c2.../a9b8...?X-Amz-..."}
]
}
| Field | Meaning |
|---|---|
shareId | Upload session ID (pass back to complete) |
completeDeadline | Hard deadline for complete (init + 24h); later → 4103 |
files[].fileId | File ID (used by refresh and the 4102 missing list) |
files[].uploadUrl | Presigned PUT URL, valid for 60 minutes |
Step 2: PUT uploadUrl — upload each file straight to SC
For each file, send a PUT to its uploadUrl with the raw file bytes as body. Do not add custom headers (the signature covers only the path and query string):
curl -sS -X PUT "<uploadUrl>" \
-H 'Content-Type: application/pdf' \
--data-binary @report.pdf
- HTTP 200 means success; 403 means the URL expired (>60 min) — re-sign via step 2.5.
- For large files in Python, stream the body (see the skill's
http.clientimplementation) instead of reading the whole file into memory.
Step 2.5 (if needed): POST /api/public/shares/refresh — re-sign expired upload URLs
Call this when a PUT returns 403. Idempotent:
curl -sS -X POST https://fileshare.litelake.com/api/public/shares/refresh \
-H 'Content-Type: application/json' \
-d '{"shareId": "b1c2d3e4f5a6", "fileIds": ["f1e2d3c4b5a7"]}'
Response data: {"files": [{"fileId": "...", "uploadUrl": "..."}]} — retry the PUTs with the fresh uploadUrl values.
Step 3: POST /api/public/shares/complete — finish and get the pickup code
Call after every PUT succeeded:
curl -sS -X POST https://fileshare.litelake.com/api/public/shares/complete \
-H 'Content-Type: application/json' \
-d '{"shareId": "b1c2d3e4f5a6"}'
Response (data):
{
"pickupCode": "K7M2XQ",
"expiresAt": "2026-09-14T04:00:00Z",
"fileCount": 2,
"totalSize": 1050624
}
code=4102:data.missingFileIdslists files that did not land — re-upload them and call complete again.code=4103: the session deadline passed — start over from init.- The pickup code is 6 characters from
0-9A-Z(minus I/L/O/U); it expires 48h after complete.
Download flow (2 steps + optional delete)
verify (check code + list files) → download per file (get a presigned GET URL) → (optional) claim (claim & delete)
POST /api/public/pickup/verify — check a code and list files
curl -sS -X POST https://fileshare.litelake.com/api/public/pickup/verify \
-H 'Content-Type: application/json' \
-H "X-Device-Id: $DEVICE_ID" \
-d '{"code": "K7M2XQ"}'
Pickup codes are tolerantly normalized: paste as-is — the server strips spaces/hyphens, upper-cases, maps O→0 and I/L→1.
Response (data):
{
"expiresAt": "2026-09-14T04:00:00Z",
"files": [
{"fileId": "f1e2d3c4b5a7", "filename": "report.pdf", "size": 1048576},
{"fileId": "a9b8c7d6e5f4", "filename": "data.csv", "size": 2048}
]
}
code=4101 means the code is invalid or expired (not distinguished, anti-enumeration).
code=4104 means the pickup code has been claimed and deleted (the terminal state entered after the recipient deleted it; the cloud files are destroyed and no longer downloadable).
POST /api/public/pickup/download — sign a download URL
curl -sS -X POST https://fileshare.litelake.com/api/public/pickup/download \
-H 'Content-Type: application/json' \
-H "X-Device-Id: $DEVICE_ID" \
-d '{"code": "K7M2XQ", "fileId": "f1e2d3c4b5a7"}'
Response (data): {"url": "https://sc...?...response-content-disposition=...", "filename": "report.pdf"}
The URL is valid for 5 minutes and the response carries Content-Disposition: attachment (non-ASCII filenames RFC2231-encoded). GET it to download:
curl -sS -o "report.pdf" "<url>"
POST /api/public/pickup/claim — claim & delete (idempotent)
After downloading, the recipient can destroy the share with the code: the pickup code is invalidated immediately and the SC cloud objects are deleted right away (like a parcel locker that destroys the compartment after pickup):
curl -sS -X POST https://fileshare.litelake.com/api/public/pickup/claim \
-H 'Content-Type: application/json' \
-H "X-Device-Id: $DEVICE_ID" \
-d '{"code": "K7M2XQ"}'
Response (data):
{
"claimedAt": "2026-09-14T08:30:00Z",
"alreadyClaimed": false
}
| Field | Meaning |
|---|---|
claimedAt | When the claim happened (RFC3339 UTC); on idempotent re-entry this is the first claim time |
alreadyClaimed | true means it was already claimed and deleted before (repeat calls return 200, not an error) |
- Idempotent: repeating the call on a claimed code returns 200 +
alreadyClaimed: true— friendly for flaky-network retries. - Codes are normalized like verify (spaces/hyphens stripped, upper-cased,
O→0,I/L→1). code=4101: invalid or expired code (counts toward the wrong-code failure limit — 5 failures trigger a 10-minute ban; claim destroys data with just a code, so the anti-brute-force rules are not waived).- After a claim: verify/download on that code return 4104 ("This pickup code has been claimed and deleted"); the claimed row is kept for a 7-day troubleshooting window, then physically deleted — after that the code reads as 4101 again.
Usage notes
- init/verify are the most abuse-sensitive endpoints: batch files into a single init (up to 20 files) instead of calling per file.
- 5 consecutive wrong codes trigger a 10-minute ban (per IP + device, shared across verify/download/claim); never brute-force codes.
- On 429, wait for the
Retry-Afterinterval before retrying. - No delete API for the uploader: expired files (48h) and stalled sessions (24h) are cleaned up server-side. Recipient-side deletion goes through
POST /api/public/pickup/claim(idempotent, code-based).