#CLI Usage with curl

A comprehensive guide to using this pastebin from the command line. For the full HTTP API reference, see api.md.

#Conventions

#Uploading

#Upload text content

$ curl -Fc='hello, world' https://shz.al
{
  "lastModifiedAt": "2026-11-10T03:08:13.000Z",
  "createdAt": "2026-11-10T03:08:13.000Z",
  "expireAt": "2026-11-17T03:08:13.000Z",
  "sizeBytes": 12,
  "location": "KV",
  "url": "https://shz.al/sCMi",
  "manageUrl": "https://shz.al/sCMi:x7wkFAHpyspi2PcxRaN7Shrh",
  "expirationSeconds": 604800
}

Save url for sharing and manageUrl for later updates or deletion. The other fields are the paste's metadata, the same as /m/<name> returns; a filename, highlightLanguage or encryptionScheme field shows up when the upload set one.

#Upload a file

$ curl -Fc=@panty.jpg https://shz.al
{
  "lastModifiedAt": "2026-11-10T03:08:13.000Z",
  "createdAt": "2026-11-10T03:08:13.000Z",
  "expireAt": "2026-11-17T03:08:13.000Z",
  "sizeBytes": 48812,
  "location": "R2",
  "filename": "panty.jpg",
  "url": "https://shz.al/Vk3d",
  "manageUrl": "https://shz.al/Vk3d:3EtywPhWs3MhtcEsiH338CmX",
  "expirationSeconds": 604800
}

The original filename will be sent back as the Content-Disposition header when the paste is fetched.

#Upload from stdin

$ echo 'hello' | curl -Fc=@- https://shz.al
$ cat panty.jpg | curl -Fc=@- https://shz.al

#Set an expiration

$ curl -Fc='kawaii' -Fe=300 https://shz.al      # 300 seconds
$ curl -Fc='kawaii' -Fe=2h  https://shz.al      # 2 hours
$ curl -Fc=@big.bin -Fe=30d https://shz.al      # 30 days

If e is not specified, the default expiration of the deployment is used. The maximum expiration is also enforced by the deployment.

#Use a custom name

$ curl -Fc='kawaii' -Fn=hitagi https://shz.al
{
  ...
  "url": "https://shz.al/~hitagi",
  "manageUrl": "https://shz.al/~hitagi:WRQfDZnR7GX5ZAJshs5cz84W",
  "expirationSeconds": 604800
}

The custom name is at least 3 characters long and may consist of letters, digits, and +_-[]*$@,;. Note the leading ~ in the returned URL. A name that is taken returns 409.

Because curl uses ; and , as field separators, names containing those characters need to be wrapped in extra quotes:

$ curl -Fc=@panty.jpg -Fn='"hi;hello,good"' https://shz.al

#Set a custom password

$ curl -Fc='kawaii' -Fs=12345678 https://shz.al

If s is omitted, a random password is generated and returned in manageUrl.

#Private mode (longer random name)

$ curl -Fc='secret' -Fp=1 https://shz.al

Without a custom name (n), p produces a 24-character random name, making the paste effectively unguessable.

#Mark a paste as syntax-highlighted

$ curl -Fc=@main.rs -Flang=rust https://shz.al
{
  ...
  "highlightLanguage": "rust",
  ...
}

The lang field is sent back as the X-PB-Highlight-Language header on fetching the paste, and is used by the display page (/d/<name>).

#Fetching

#Fetch raw content

$ curl https://shz.al/abcd
hello, world

#Save the response to a file

$ curl https://shz.al/~panty.jpg -o panty.jpg
$ curl -OJ https://shz.al/~panty               # use server-supplied filename

-J honors the Content-Disposition header set from the original filename. Headers of a paste look like this:

$ curl -I https://shz.al/~panty
HTTP/2 200
content-type: image/jpeg
content-length: 48812
content-disposition: inline; filename*=UTF-8''panty.jpg
last-modified: Tue, 10 Nov 2026 03:08:13 GMT
cache-control: public, max-age=600
x-content-type-options: nosniff
access-control-allow-origin: *
access-control-expose-headers: Content-Disposition

A text paste also carries content-security-policy: sandbox ..., so that a browser opening it directly cannot touch the site's data; see api.md.

#Force download (attachment)

$ curl 'https://shz.al/abcd?a' -OJ

The ?a query string sets Content-Disposition: attachment.

#Override mime type

$ curl 'https://shz.al/~panty.jpg?mime=image/png' \
    -w '%{content_type}\n' -o /dev/null -sS
image/png

Or via path extension:

$ curl 'https://shz.al/abcd.json' -i

#Pipe to another tool

$ curl https://shz.al/~panty.jpg | feh -
$ curl https://shz.al/~config | jq .

#Conditional fetch with If-Modified-Since

$ curl -I -H 'If-Modified-Since: Wed, 11 Nov 2026 00:00:00 GMT' \
    https://shz.al/~hitagi
HTTP/2 304

#Inspecting metadata

$ curl https://shz.al/m/~panty
{
  "lastModifiedAt": "2026-11-10T03:08:13.000Z",
  "createdAt": "2026-11-10T03:08:13.000Z",
  "expireAt": "2026-11-17T03:08:13.000Z",
  "sizeBytes": 48812,
  "location": "R2",
  "filename": "panty.jpg"
}

filename, highlightLanguage and encryptionScheme are present only when the upload set them. location tells whether the content lives in KV (small pastes) or R2 (large ones).

A HEAD request returns the same headers as GET without the body, useful for quickly checking size and Content-Type:

$ curl -I https://shz.al/abcd

#URL shortener

Upload a short URL, then redirect through /u/<name>:

$ curl -Fc='https://example.com/very/long/path' -Fn=ex https://shz.al
$ curl -L https://shz.al/u/~ex

#Markdown rendering

Upload a markdown file and render it as HTML via /a/<name>:

$ curl -Fc=@README.md -Fn=readme https://shz.al
$ firefox https://shz.al/a/~readme

GitHub-flavored Markdown is supported, along with syntax highlighting and LaTeX math via MathJax.

#Updating an existing paste

Use the manageUrl returned at upload time:

$ curl -X PUT -Fc='kawaii~' \
    https://shz.al/~hitagi:WRQfDZnR7GX5ZAJshs5cz84W
{
  "lastModifiedAt": "2026-11-10T03:09:02.000Z",
  "createdAt": "2026-11-10T03:08:13.000Z",
  "expireAt": "2026-11-17T03:08:13.000Z",
  "sizeBytes": 7,
  "location": "KV",
  "url": "https://shz.al/~hitagi",
  "manageUrl": "https://shz.al/~hitagi:WRQfDZnR7GX5ZAJshs5cz84W",
  "expirationSeconds": 604800
}

PUT accepts the same fields as POST (c, e, s, lang, encryption-scheme) except n, and answers like POST. Note that e recalculates the expiration starting from the update time; without it the expiration is kept.

#Deleting a paste

$ curl -X DELETE https://shz.al/~hitagi:WRQfDZnR7GX5ZAJshs5cz84W
the paste will be deleted in seconds

Deletion may take a few seconds to propagate globally.

With a wrong password, both PUT and DELETE answer 403:

$ curl -X DELETE https://shz.al/~hitagi:wrongpassword
Error 403: incorrect password for paste '~hitagi'

#Tips

#Common errors

Errors come as plain text, Error <status>: <message>, for example Error 404: paste of name 'zzzz' not found or Error 400: Name should have at least 3 characters.

Status Meaning
400 Malformed request (bad field, illegal name, bad expire).
403 Wrong password when updating or deleting.
404 Paste not found, or already expired.
409 Custom name is already in use.
413 Request body exceeds 100 MB (platform cap, intercepted by Cloudflare before reaching the worker), or content exceeds the deployment's R2_MAX_ALLOWED.
500 Unexpected server error — please report it.

For the full HTTP API including HEAD, OPTIONS, response headers, and edge cases, see api.md.