Skip to content

API Reference

All endpoints accept and return raw text or JSON. No authentication required for public pastes.

Create Paste

POST /api/paste

Headers

Header Required Description
X-Slug No Custom slug (random if not provided)
X-Private No Set to true for private paste
X-Lang No Language for syntax highlighting

Body

Raw text content of the paste.

Response: 201 Created

{
  "url": "https://paste.semi.sh/abc123"
}

For private pastes:

{
  "url": "https://paste.semi.sh/private/abc123"
}

Response: 409 Conflict

{
  "error": "slug_exists"
}

Response: 403 Forbidden

{
  "error": "private_auth_not_configured"
}

Returned when X-Private: true is sent but the server has no PRIVATE_USER/PRIVATE_PASS configured.

Examples

# Create paste
curl -X POST https://paste.semi.sh/api/paste -d "hello world"

# With custom slug
curl -X POST https://paste.semi.sh/api/paste \
  -H "X-Slug: mycode" \
  -d "content here"

# Private paste
curl -X POST https://paste.semi.sh/api/paste \
  -H "X-Private: true" \
  -H "X-Lang: go" \
  -d "package main"

# From file
curl -X POST https://paste.semi.sh/api/paste \
  -H "X-Slug: deploy" \
  -H "X-Lang: bash" \
  --data-binary @deploy.sh

Overwrite Paste

PUT /api/paste/{slug}

Replaces the content of an existing paste. For private pastes, requires Basic Auth.

Response: 200 OK

{
  "status": "updated"
}

Response: 401 Unauthorized

WWW-Authenticate: Basic realm="Private Paste"

Examples

# Overwrite public paste
curl -X PUT https://paste.semi.sh/api/paste/mycode -d "updated content"

# Overwrite private paste (requires auth)
curl -X PUT -u admin:secret https://paste.semi.sh/api/paste/secrets -d "new secrets"

List Pastes

GET /api/pastes

Returns metadata for all public and private pastes. Requires admin auth (PRIVATE_USER/PRIVATE_PASS via HTTP Basic Auth).

Response: 200 OK

{
  "public": [
    {
      "slug": "abc123",
      "private": false,
      "lang": "go",
      "created_at": "2026-06-30T12:00:00Z",
      "size": 11,
      "ttl": "never"
    }
  ],
  "private": [
    {
      "slug": "secrets",
      "private": true,
      "lang": "",
      "created_at": "2026-06-30T12:01:00Z",
      "size": 7,
      "ttl": "never"
    }
  ]
}

Each entry mirrors the models.Paste fields. An empty scope returns [].

Response: 401 Unauthorized

WWW-Authenticate: Basic realm="Private Paste"

Response: 403 Forbidden

Returned when admin auth is not configured on the server. See private_auth_not_configured.

Examples

curl -u admin:secret https://paste.semi.sh/api/pastes

Delete Paste

DELETE /api/paste/{slug}

Removes a paste from the scope indicated by the X-Private header. Requires admin auth. A slug that exists in both scopes must be deleted twice (once per scope). Idempotent: deleting a missing paste returns 200.

Headers

Header Required Description
X-Private No Set to true to delete from the private scope (default: public)

Response: 200 OK

{
  "status": "deleted"
}

Response: 401 Unauthorized

WWW-Authenticate: Basic realm="Private Paste"

Examples

# Delete public paste
curl -X DELETE -u admin:secret https://paste.semi.sh/api/paste/mycode

# Delete private paste
curl -X DELETE -u admin:secret -H "X-Private: true" https://paste.semi.sh/api/paste/secrets

Get Public Paste

GET /{slug}

Browser (HTML)

Returns an HTML page with syntax highlighting (dark theme). The User-Agent header is checked to determine if the request is from a browser.

curl / tools (raw text)

Returns raw text with Content-Type: text/plain.

Force raw text

GET /{slug}?raw=1

Always returns raw text regardless of User-Agent.

Response: 200 OK

Browser: Content-Type: text/html curl: Content-Type: text/plain; charset=utf-8

Response: 404 Not Found

Paste does not exist or is private.

Examples

# Browser: HTML with syntax highlighting
curl -s https://paste.semi.sh/abc123 | head

# Force raw text
curl -s https://paste.semi.sh/abc123?raw=1

Get Private Paste

GET /private/{slug}

Returns HTML with syntax highlighting for browsers, raw text for curl/tools. Requires HTTP Basic Auth.

Browser (HTML)

Returns an HTML page with syntax highlighting (dark theme). The User-Agent header is checked to determine if the request is from a browser.

curl / tools (raw text)

Returns raw text with Content-Type: text/plain.

Force raw text

GET /private/{slug}?raw=1

Always returns raw text regardless of User-Agent.

Response: 200 OK

Browser: Content-Type: text/html curl: Content-Type: text/plain; charset=utf-8

Response: 401 Unauthorized

WWW-Authenticate: Basic realm="Private Paste"

Examples

# Browser: HTML with syntax highlighting (prompts for credentials)
curl -u admin:secret https://paste.semi.sh/private/secrets

# Force raw text
curl -u admin:secret https://paste.semi.sh/private/secrets?raw=1

Health Check

GET /health

Response: 200 OK

{
  "status": "ok"
}

Examples

curl -s https://paste.semi.sh/health

Landing Page

GET /

Returns a minimal HTML page with usage instructions and a link to the source repository.

Error Responses

All errors return JSON with an error field:

Status Error Cause
400 invalid_slug Slug contains invalid characters or is reserved
401 (empty) Missing or invalid admin auth (private paste access, list, delete)
403 private_auth_not_configured Private paste / admin action requested but server has no auth
404 (empty) Paste not found
409 slug_exists Slug already in use in the same scope (public or private)
413 (empty) Paste exceeds 10 MB limit
500 (empty) Server error

Slug Validation

Slugs must:

  • Be 1-64 characters long
  • Contain only [a-zA-Z0-9_-]
  • Not be a reserved word: private, api, health
  • Not contain path traversal sequences (.., /, \)