Files
palette/docs/API.md
T
poslop 91568c0598
CI / test (pull_request) Successful in 24s
CI / docker (pull_request) Skipped
fix #63: require deletion token on DELETE /api/pastes/{id}
- DELETE now demands the create-time deletion token (Authorization
  header: Bearer/Token/bare, or ?token= query param), compared with
  the constant-time store.DeletionTokenEqual. 403 otherwise.
- Creator-browser deletes via the /mine button (matching vwr cookie,
  #37) remain allowed; other browsers and plain API clients get 403.
- Regression tests: no token, wrong token (header+query), correct
  token (header+query), creator-cookie path, token extraction.
- Adapted TestSoftDelete to pass the deletion token.
- docs/API.md delete section updated.
- Based on #58's SoftDelete (bool, error) signature.
2026-09-09 09:21:28 -05:00

3.2 KiB

Palette API

All endpoints are JSON unless noted. The web UI is served from the same port.

Create paste

curl -X POST http://localhost:8080/api/pastes \
  -H "Content-Type: application/json" \
  -d '{
    "content": "print(hello)",
    "title": "my snippet",
    "language": "python",
    "expires_in": "168h",
    "password": "optional",
    "custom_slug": "optional",
    "burn_after_read": false,
    "burn_after_reads": 1,
    "visibility": "public"
  }'
  • expires_in is a Go duration string (90m, 6h, 336h). Omit for no expiry.
  • visibility is public or unlisted.
  • burn_after_reads sets how many reads the paste survives (default 1 when burn_after_read is true). A read is counted per unique viewer session; the same viewer returning within 15 minutes does not count again.
  • Response includes id, url, raw_url, api_url, expires_at, created_at, and a one-time deletion_token.

Errors: 400 invalid body/content too large/duplicate slug, 401 password required, 404 paste expired/burned/gone, 413 content exceeds max bytes, 429 rate limited.

Get paste

curl http://localhost:8080/api/pastes/{id}
# password-protected pastes:
curl "http://localhost:8080/api/pastes/{id}?password=secret"
# or via header: X-Paste-Password: secret

The response includes reads_remaining (null when no read budget is set).

Raw content

curl http://localhost:8080/raw/{id}

Raw reads count against a burn-after-read budget, same as page views.

Delete

# soft delete (requires the deletion token from the create response)
curl -X DELETE -H "Authorization: Bearer TOKEN" http://localhost:8080/api/pastes/{id}
# ...or via query param; the creator browser (viewer cookie) may also delete without a token
curl -X DELETE "http://localhost:8080/api/pastes/{id}?token=TOKEN"

# hard delete immediately (requires the one-time deletion token)
curl -X DELETE "http://localhost:8080/api/pastes/{id}/redeem?token=TOKEN"

Lists

curl "http://localhost:8080/api/public?limit=25&offset=0"   # public history
curl http://localhost:8080/api/mine                          # this browser's pastes (viewer cookie)

Language detection

curl -X POST http://localhost:8080/api/guess-language \
  -H "Content-Type: application/json" \
  -d '{"content": "package main"}'

Cans (bundles of items)

curl -X POST http://localhost:8080/api/pastes/can \
  -F "title=My bundle" \
  -F "expires_in=48h" \
  -F 'json_items=[{"title":"notes.txt","content":"some notes"}]' \
  -F "files=@screenshot.png" \
  -F "files=@log.txt"

curl http://localhost:8080/api/cans/{id}
curl http://localhost:8080/api/cans/{id}/items/{item_id}

Web pages

  • /new — create a paste
  • /history — public paste history
  • /mine — pastes created from this browser
  • /{id} — view a paste
  • /unlock/{id} — password gate for protected pastes
  • /raw/{id} — raw content with original content type

Expiry and deletion

  • Expired pastes are soft-deleted by a background sweeper (runs every minute).
  • Soft-deleted pastes are hard-deleted after a 7-day grace period.
  • Deletion tokens allow immediate hard delete.
  • Burn-after-read pastes are soft-deleted once the read budget is exhausted.