Upload API
Upload an image
Stores an image sent as multipart/form-data and returns a share-page URL, a direct file URL, and a tokenized delete URL. The stored content type is detected from the file's bytes; SVG files are sanitized before storage. Each stored file consumes one upload unit of the monthly quota.
/api/v1/uploadAuthentication
Send your API key as a bearer token on every request: Authorization: Bearer sw_.... Create keys in the dashboard; see the authentication docs for details.
Parameters
Request content type: multipart/form-data
| Parameter | Type | Default | Description |
|---|---|---|---|
filerequired | file (binary) | — | The image, sent as a multipart form part named "file". Allowed formats: PNG, JPEG, GIF, WebP, SVG, AVIF — detected from the file's bytes, not its filename or declared content type. Maximum size 10 MB. |
expires_in | integer | — | Lifetime of the link in seconds, from 60 (one minute) to 31,536,000 (one year). Defaults when omitted: no scheduled expiry on an active paid plan; the 30-day plan maximum on Free. Free-plan links are capped at 30 days regardless of the value sent. Range: 60–31,536,000. |
Examples
curl -X POST https://shotwisp.com/api/v1/upload \
-H "Authorization: Bearer $SHOTWISP_API_KEY" \
-F "file=@./screenshot.png" \
-F "expires_in=86400"const form = new FormData();
form.append("file", new Blob([bytes], { type: "image/png" }), "screenshot.png");
form.append("expires_in", "86400"); // optional
const res = await fetch("https://shotwisp.com/api/v1/upload", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.SHOTWISP_API_KEY}` },
body: form,
});
if (!res.ok) throw new Error((await res.json()).error.message);
const upload = await res.json();
console.log(upload.url);import os, requests
res = requests.post(
"https://shotwisp.com/api/v1/upload",
headers={"Authorization": f"Bearer {os.environ['SHOTWISP_API_KEY']}"},
files={"file": open("screenshot.png", "rb")},
data={"expires_in": "86400"}, # optional
)
res.raise_for_status()
print(res.json()["url"])Response
Success status: 201. The upload was stored. Content types: application/json.
{
"id": "u7Kd2mXq9RfW4bZn",
"slug": "k7mwq2ax",
"url": "https://shotwisp.com/i/k7mwq2ax",
"file_url": "https://shotwisp.com/f/k7mwq2ax",
"delete_url": "https://shotwisp.com/api/uploads/u7Kd2mXq9RfW4bZn/delete?token=Fj3kW9sLq2Xv7Rp4Tz8mNc5d",
"expires_at": "2026-08-13T14:05:00.000Z",
"size_bytes": 481290,
"content_type": "image/png",
"filename": "screenshot.png"
}x-shotwisp-id.Errors
Every error uses the envelope {"error": {"code", "message"}}. This endpoint can return:
| Code | HTTP status | Retryable | Meaning |
|---|---|---|---|
unauthorized | 401 | no | The API key is missing, malformed, revoked, or the account is suspended or unverified. Do not retry with the same key. Fix the Authorization header or create a new API key. |
quota_exceeded | 402 | no | The monthly upload or render quota is used up and overages are off or unavailable on the plan. Do not retry until the monthly quota resets, the plan is upgraded, or overages are enabled. |
file_too_large | 413 | no | An uploaded file exceeds the 10 MB per-file limit. Do not retry unchanged. Reduce the file below the limit. |
unsupported_type | 415 | no | The file's bytes do not match a supported image format (PNG, JPEG, GIF, WebP, SVG, AVIF). Do not retry unchanged. Convert the file to a supported image format. |
validation_error | 422 | no | A request field failed validation. The message states which field and why. Do not retry unchanged. The message names the failing field; fix it first. |
rate_limited | 429 | yes | The plan's per-minute request budget is spent. Rejected requests are not metered. Retry after waiting the number of seconds in the Retry-After header, then back off exponentially with jitter. |
internal | 500 | yes | Unexpected error on Shotwisp's side. The request was not metered. Safe to retry with exponential backoff. |
Limits and machine-readable spec
Plan quotas, rate limits, and every fixed limit are consolidated in Limits. This endpoint is also fully described in the OpenAPI 3.1 specification (operationId createUpload). Building with an AI agent? Read the AI agent guide.