Skip to content

Latest commit

 

History

History
296 lines (228 loc) · 6.87 KB

File metadata and controls

296 lines (228 loc) · 6.87 KB

API Reference

Snapshot uses a consistent JSON envelope for API responses, except /health. The health endpoint intentionally returns the smallest possible readiness payload for Docker, reverse proxies, and uptime checks.

Success response:

{
  "success": true,
  "status": "success",
  "message": "File uploaded successfully",
  "data": {}
}

Error response:

{
  "success": false,
  "status": "error",
  "message": "Unauthorized",
  "data": {
    "error_code": "unauthorized",
    "request_id": "b56ec299cf9442848525f0b549b010f9",
    "details": null
  }
}

Every response includes X-Request-ID. Clients can send their own X-Request-ID header to correlate client logs with server logs.

Authentication

Protected endpoints require:

Authorization: Bearer your-api-key

X-API-Key: your-api-key is also supported. Only these two authentication forms are supported.

Protected endpoints:

  • POST /upload
  • GET /list
  • DELETE /raw/{file_id}.{extension}

Public endpoints:

  • GET /
  • GET /health
  • GET /{file_id} (HTML preview page)
  • GET /raw/{file_id}.{extension}
  • GET /{file_id}.{extension} (legacy compatibility redirect to /{file_id})
  • GET /docs when docs are enabled

Rate Limit Headers

Rate-limited responses include:

Header Meaning
Retry-After Seconds until another request should be attempted
X-RateLimit-Limit Requests allowed in the current window
X-RateLimit-Remaining Requests left in the current window
X-RateLimit-Reset Unix timestamp when the limit resets

GET /

Returns project metadata.

curl http://localhost:3000/

Response:

{
  "success": true,
  "status": "success",
  "message": "Service is running",
  "data": {
    "name": "Snapshot",
    "author": "Walkaisa",
    "repository": "https://github.com/Walkaisa/snapshot",
    "version": "1.0.0"
  }
}

GET /health

Health endpoint for Docker, reverse proxies, uptime monitoring, and load balancers.

curl http://localhost:3000/health

Expected status: 200 OK.

Response:

{ "status": "ok" }

POST /upload

Uploads one file. The multipart field name must be file.

curl -X POST http://localhost:3000/upload \
  -H "Authorization: Bearer your-api-key" \
  -F "file=@screenshot.png"

PowerShell:

curl.exe -X POST http://localhost:3000/upload `
  -H "Authorization: Bearer your-api-key" `
  -F "file=@screenshot.png"

Success status: 201 Created.

Response:

{
  "success": true,
  "status": "success",
  "message": "File uploaded successfully",
  "data": {
    "id": "abc123XYZ9",
    "filename": "abc123XYZ9.png",
    "extension": "png",
    "url": "http://localhost:3000/abc123XYZ9",
    "page_url": "http://localhost:3000/abc123XYZ9",
    "raw_url": "http://localhost:3000/raw/abc123XYZ9.png",
    "legacy_url": "http://localhost:3000/abc123XYZ9.png",
    "delete_url": "http://localhost:3000/raw/abc123XYZ9.png",
    "size": 12345,
    "size_human": "12.1 KB",
    "checksum": "sha256...",
    "content_type": "image/png"
  }
}

data.url is the value ShareX and other clients should display. It always equals page_url, the extension-less HTML preview URL — use raw_url directly if you only want the file itself.

data.delete_url always points at the raw delete route (/raw/{id}.{ext}) so deletion keeps working even when data.url is the HTML page. legacy_url points at the old extension-based URL, which redirects to data.url.

Common errors:

Status Error code Reason
400 file_empty The uploaded file is empty
400 invalid_file_type The extension is not allowed
400 invalid_content_type The declared MIME type or file signature is not allowed
401 unauthorized Missing or invalid API key
413 file_too_large File exceeds MAX_FILE_SIZE_BYTES
429 rate_limit_exceeded Too many requests

GET /list

Lists uploaded files. This endpoint is protected because it exposes metadata for all uploads.

curl http://localhost:3000/list \
  -H "Authorization: Bearer your-api-key"

Response:

{
  "success": true,
  "status": "success",
  "message": "Files returned successfully",
  "data": [
    {
      "id": "abc123XYZ9",
      "filename": "abc123XYZ9.png",
      "extension": "png",
      "url": "http://localhost:3000/abc123XYZ9",
      "page_url": "http://localhost:3000/abc123XYZ9",
      "raw_url": "http://localhost:3000/raw/abc123XYZ9.png",
      "legacy_url": "http://localhost:3000/abc123XYZ9.png",
      "delete_url": "http://localhost:3000/raw/abc123XYZ9.png",
      "size": 12345,
      "size_human": "12.1 KB",
      "created_at": "2026-04-27T00:00:00+00:00",
      "modified_at": "2026-04-27T00:00:00+00:00",
      "checksum": "sha256...",
      "content_type": "image/png"
    }
  ]
}

GET /{file_id}

Returns the HTML preview page for a file. The page includes Open Graph and Twitter Card metadata so links unfurl into rich embeds on Discord and other platforms.

curl http://localhost:3000/abc123XYZ9

Expected status: 200 OK with Content-Type: text/html; charset=utf-8 and Cache-Control: public, max-age=300.

Common error:

Status Error code Reason
404 file_not_found No file with that id exists

GET /raw/{file_id}.{extension}

Returns the raw media file.

curl http://localhost:3000/raw/abc123XYZ9.png --output abc123XYZ9.png

Responses use Cache-Control: public, max-age=31536000, immutable and an ETag derived from the file checksum. Add ?download=1 to force a download:

curl -OJ "http://localhost:3000/raw/abc123XYZ9.png?download=1"

With download=1 the response adds Content-Disposition: attachment; filename="abc123XYZ9.png". Without it, no Content-Disposition is set so browsers and crawlers display the file inline.

Common error:

Status Error code Reason
404 file_not_found File does not exist

GET /{file_id}.{extension} (legacy)

Compatibility route for old extension-based links. It looks up the file by file_id alone — the extension you pass is ignored — and, if a file exists, responds with 301 Moved Permanently to GET /{file_id}. Unknown ids return 404. There is no delete route on this path; use DELETE /raw/{file_id}.{extension} instead.

DELETE /raw/{file_id}.{extension}

Deletes an uploaded file.

curl -X DELETE http://localhost:3000/raw/abc123XYZ9.png \
  -H "Authorization: Bearer your-api-key"

Response:

{
  "success": true,
  "status": "success",
  "message": "File deleted successfully",
  "data": {
    "id": "abc123XYZ9",
    "filename": "abc123XYZ9.png"
  }
}

Common errors:

Status Error code Reason
401 unauthorized Missing or invalid API key
404 file_not_found File does not exist