Skip to content

Pastepile API

A small, public REST API for creating, reading, listing, updating, and deleting pastes from scripts, CI jobs, webhooks, and your terminal.

  • No API key. No account. Anonymous by default.
  • CORS-open for every endpoint.
  • Editable via a one-shot edit key returned at creation.
  • Machine-readable OpenAPI 3.1 spec.

Base URL

https://pastepile.com

Endpoints at a glance

POST    /api/public/pastes            create a paste (returns edit_key, shown once)
GET     /api/public/pastes            list recent public pastes
GET     /api/public/pastes/{slug}     fetch one paste as JSON
PATCH   /api/public/pastes/{slug}     update title/files (auth: edit_key)
PUT     /api/public/pastes/{slug}     alias of PATCH
DELETE  /api/public/pastes/{slug}     delete the paste (auth: edit_key)
GET     /raw/{slug}                   fetch raw text (text/plain)
GET     /api/openapi.json             OpenAPI 3.1 spec

Limits & notes

  • Total content per paste: 400 KB across all files.
  • Files per paste: 1 to 10. Filenames: 1 to 80 chars.
  • Best-effort rate limit: ~30 create / 60 update / 20 delete requests per IP per hour.
  • The API creates non-encrypted pastes only. End-to-end encryption and time-capsule (drand timelock) pastes require the browser-held key and are not available over HTTP.
  • Password-protected, encrypted, and sealed time-capsule pastes are not returned by the read endpoint.
  • Errors are JSON: {"error":{"code":"...","message":"..."}}

Authentication (edit key)

Creating a paste returns an edit_key in the JSON response. It is shown once. The server only stores its SHA-256 hash; if you lose it you cannot recover it. Send it on update/delete one of three ways:

Authorization: Bearer <edit_key>
# or
X-Edit-Key: <edit_key>
# or in the JSON body
{ "edit_key": "<edit_key>", ... }

POST /api/public/pastes

Create a paste. Two content types are accepted.

JSON body

POST https://pastepile.com/api/public/pastes
Content-Type: application/json

{
  "title":       "Optional title (<= 120 chars)",
  "content":     "string  (single-file shortcut)",
  "language":    "plaintext | javascript | typescript | python | java | c | cpp | csharp | go | rust | ruby | php | html | css | sql | json | yaml | bash | markdown",
  "files":       [ { "name": "main.js", "language": "javascript", "content": "..." } ],
  "expiry":      "never | 10m | 1h | 1d | 1w | 1mo | burn",
  "visibility":  "public | unlisted",
  "password":    "optional server-side password",
  "custom_slug": "optional vanity URL: 3-40 chars, lowercase letters, digits, single hyphens"
}

Provide either content (single file) or a non-empty files array. Default expiry is 1w, default visibility is public.burn forces unlisted and deletes the paste on first read.

Plain-text body (shell-friendly)

POST https://pastepile.com/api/public/pastes
Content-Type: text/plain

<the paste content>

Response body is just the paste URL followed by a newline.

Response (JSON body)

200 OK
{
  "slug":             "ab12cd3",
  "url":              "https://pastepile.com/p/ab12cd3",
  "raw_url":          "https://pastepile.com/raw/ab12cd3",
  "edit_key":         "kK9...32-char-secret",
  "edit_key_notice":  "Save this edit_key now - it is shown once and is required to update or delete this paste."
}

Create with multiple files

curl -X POST "https://pastepile.com/api/public/pastes" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Two files",
    "expiry": "1d",
    "visibility": "public",
    "files": [
      { "name": "main.js",  "language": "javascript", "content": "console.log(1)" },
      { "name": "README.md","language": "markdown",   "content": "# hi"           }
    ]
  }'

GET /api/public/pastes

List recent listed pastes (no unlisted, encrypted, or sealed content).

GET https://pastepile.com/api/public/pastes?limit=20&offset=0&search=

200 OK
{
  "items": [
    { "slug": "ab12cd3", "title": "...", "language": "javascript",
      "preview": "...", "views": 4, "file_count": 1,
      "created_at": "...", "url": "https://pastepile.com/p/ab12cd3", "raw_url": "https://pastepile.com/raw/ab12cd3" }
  ],
  "total": 123, "limit": 20, "offset": 0
}

GET /api/public/pastes/{slug}

Fetch one paste as JSON. Increments the view counter and consumes burn-after-read pastes (same semantics as the website).

GET https://pastepile.com/api/public/pastes/{slug}

200 OK
{
  "slug": "ab12cd3",
  "title": "Optional title",
  "language": "javascript",
  "files": [ { "name": "main.js", "language": "javascript", "content": "console.log('hi')" } ],
  "views": 4,
  "created_at": "2026-06-14T12:34:56Z",
  "expires_at": "2026-06-21T12:34:56Z",
  "burn_after_read": false
}

Returns 404 for missing/expired/password-protected/encrypted pastes, and 403 for sealed time capsules. Password hashes and edit keys are never returned.

PATCH /api/public/pastes/{slug} (or PUT)

Update title/files of an existing paste. Requires the edit key.

curl -X PATCH "https://pastepile.com/api/public/pastes/<slug>" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <edit_key>" \
  -d '{
    "title": "New title",
    "files": [ { "name": "main.js", "language": "javascript", "content": "console.log(2)" } ]
  }'

# 200 OK
# { "ok": true, "version_no": 3 }

DELETE /api/public/pastes/{slug}

Permanently delete a paste. Requires the edit key.

curl -X DELETE "https://pastepile.com/api/public/pastes/<slug>" \
  -H "Authorization: Bearer <edit_key>"

# 200 OK
# { "ok": true }

GET /raw/{slug}

Fetch the raw text of a paste as text/plain; charset=utf-8 with X-Content-Type-Options: nosniff. Ideal for piping into shell tools.

curl "https://pastepile.com/raw/{slug}"
# or pipe straight into a file
curl -o file.txt "https://pastepile.com/raw/{slug}"

Shell one-liner: pipe stdin, get a URL

Drop into .bashrc / .zshrc:

pv() {
  curl -s --data-binary @- \
    -H "Content-Type: text/plain" \
    "https://pastepile.com/api/public/pastes"
}

cat error.log | pv
git diff   | pv

Embeds

Every non-encrypted paste has a bare embed page at /embed/{slug}:

<iframe
  src="https://pastepile.com/embed/<slug>"
  style="width:100%;height:420px;border:0;border-radius:12px;overflow:hidden"
  loading="lazy"
  title="Pastepile paste"
></iframe>

OpenAPI

Machine-readable spec for codegen, Postman, Insomnia, or your favorite client generator:

GET https://pastepile.com/api/openapi.json

Errors

Errors are JSON with a stable code and a human message: 400 bad input, 401 missing/invalid edit key, 403 sealed, 404 not found / protected, 409 custom_slug taken, 429 rate limited (with Retry-After), 500 server error.