---
name: stow
description: Upload a file to stow.sh and get back a public, unguessable link, with optional image and video transforms (resize, crop, convert, poster frames, short clips). Use when the user asks to upload, host or share a file, screenshot, render or video, to "put it on Stow", or needs a public URL, thumbnail, poster frame or resized version of an image or video.
---

# Stow

Stow stores a file and gives back a public URL:
`https://stow.sh/{26-character id}/{filename}`. Anyone with the link can open
the file; nobody can list or guess links. Give the user the URL exactly as
returned.

## Pick a route

1. **Stow MCP tools available** (`put_file`, `put_text`, `put_from_url`,
   `create_upload_url`, `list_files`, `delete_file`, `transform_url`,
   `get_account`): use them. They are signed in already. To add them, connect
   `https://stow.sh/mcp`, or run `stow mcp` as a stdio server.
2. **A `stow` command on PATH**: use the CLI (below). `stow schema` prints
   every command, flag, output and error as JSON.
3. **Otherwise**: use the HTTP API with curl (below). It is described at
   https://stow.sh/openapi.json.

The CLI and API need an API key. Look in `STOW_TOKEN`, then
`~/.config/stow/token`. If neither exists, ask the user to create a key at
https://stow.sh/account (under API keys) and save it to
`~/.config/stow/token` with `chmod 600`. Never print the key or put it in a
file that gets committed. An "Upload only" key can add files but not list or
delete them; keys can expire after 30 or 90 days.

## Upload

With the CLI:

```bash
stow put ./render.png                 # prints the URL
stow put a.jpg b.mp4                  # one URL per line
stow put https://example.com/x.jpg    # re-host a remote file
stow put ./clip.mp4 --json            # { url, key, size, contentType }
```

With curl:

```bash
TOKEN="${STOW_TOKEN:-$(cat ~/.config/stow/token)}"
curl -sS -T ./render.png -H "Authorization: Bearer $TOKEN" \
  https://stow.sh/api/files/render.png
# => {"url":"https://stow.sh/.../render.png","key":"...","size":1234,"contentType":"image/png"}
```

The last part of the path becomes the filename in the link, so URL-encode it.
The extension sets the content type. To re-host a remote file without the
CLI or MCP, download it first, then upload it.

## Limits and errors

Files can be up to 100 MB. A Personal plan holds 10 GB and a Studio plan
100 GB. Requests to `/api` and `/mcp` are limited to 120 a minute per key.
Errors come back as `{"code", "error", "retryable", "docs"}`. Retry only when
`retryable` is true; `docs` links to https://stow.sh/docs/errors.

| Status and code | What to do |
| --- | --- |
| 401 `unauthorized` | The key is missing, wrong, revoked or expired. Ask for a new one. |
| 402 `payment_required` | The account has no plan. Tell the user to subscribe at https://stow.sh/account. Don't retry. |
| 403 `forbidden` | An upload-only key tried to list or delete. Ask for a full-access key. |
| 413 `too_large` | Over 100 MB. Compress or trim it, or link the source instead. |
| 413 `storage_full` | The plan is full. Tell the user; they can delete files or move to Studio. |
| 404 `not_found` | No such file, or not theirs. |
| 429 `rate_limited` | Wait the `Retry-After` seconds, then retry. |
| 5xx `failed`, `fetch_failed` | Retry once, then tell the user. |

CLI exit codes: 1 failed (retry once), 2 bad request, too large or storage
full, 3 not found, 4 no key, unauthorised, forbidden or no plan, 5 rate
limited. With `--json`, stderr gets
`{"error": {"code", "status", "message", "retryable", "docs"}}`.

## Transforms

Add query params to any Stow URL. `stow url <url> w=800 f=avif` builds one,
or the `transform_url` tool. Results are cached, so the same URL is cheap the
second time. Unknown params are ignored.

A transform that can't be applied serves the original file instead. Before
handing over a thumbnail or poster, check with a GET (HEAD never transforms):
`curl -s -o /dev/null -D - '<url>' | grep -i x-stow-transform` gives `ok` for
a variant and `original` for a fallback.

Images:

| Param | Values |
| --- | --- |
| `w`, `h` | pixels, up to 4096 |
| `q` | 1-100, default 80 |
| `f` | `webp` (default), `avif`, `jpeg`, `png` |
| `fit` | `scale-down` (default), `contain`, `cover`, `crop`, `pad` |
| `gravity` | `auto` (subject-aware), `face`, `left`, `right`, `top`, `bottom`, `center` |
| `trim` | `border` removes flat borders; or `top;right;bottom;left` pixels |
| `trim.tolerance`, `trim.keep` | with `trim=border`: 1-255, and pixels of border to keep |

Videos (MP4 H.264, up to 100 MB and 10 minutes):

| Param | Values |
| --- | --- |
| `w`, `h` | pixels, 10-2000 |
| `fit` | `contain` (default), `cover`, `scale-down` |
| `t` | start time: `5`, `5s`, `500ms`, `1m` |
| `d` | duration, same format |
| `audio=false` | silent MP4 |
| `mode` | `video` (default), `frame` (still), `spritesheet`, `audio` (M4A) |
| `f` | `jpg` or `png` for `mode=frame` |
| `count` | frames in a spritesheet, up to 100 |

Common recipes:

- Thumbnail: `?w=400&h=400&fit=cover&gravity=auto`
- Poster frame for a video: `?mode=frame&t=1s&w=1280`
- Small preview clip: `?w=480&t=0&d=5s&audio=false`

For playback in a `<video>` tag, use the untransformed URL: it seeks
everywhere, while a transformed clip only does once cached. There is no HLS;
for long videos, link the original.

## List and delete

Delete only when the user asks for a file to go: it is permanent. The
`delete_file` tool needs `confirm: true`; `stow rm --dry-run` shows what would
go first.

```bash
stow ls                                # one URL per line, newest first
stow ls --json --limit 20              # one JSON object per line
stow rm https://stow.sh/{id}/{filename}
curl -sS -H "Authorization: Bearer $TOKEN" 'https://stow.sh/api/files?limit=100'
# => {"files":[...],"cursor":"..."}; pass ?cursor= for the next page, null on the last
curl -sS -X DELETE -H "Authorization: Bearer $TOKEN" \
  https://stow.sh/api/files/{id}/{filename}
```

Only the account that uploaded a file can delete it. Resized copies can keep
serving from caches for a while after a delete, so treat a shared link as
published.
