# Pastebox HTTP API English | [Korean](./API_ko.md) This document describes the public HTTP interface implemented by Pastebox. Replace `https://paste.example.com` with the base URL of your deployment. ## Overview | Operation | Method and path | Authentication | |---|---|---| | Upload | `POST /` or `PUT /` | None | | Read a paste | `GET /` or `HEAD /` | `paste-password` when protected | | Clone a paste | `POST /` | `paste-password` when the source is protected | | Read management metadata | `GET /api/v1/pastes/` | `paste-manage-token` | | Update a paste | `PATCH /api/v1/pastes/` | `paste-manage-token` | | Delete a paste | `DELETE /api/v1/pastes/` | `paste-manage-token` | Paste content is text-only and uploads are limited to 1 GiB. API clients should treat generated passwords and private manage URLs as secrets. Do not put them in logs. ## Upload Use a streaming raw request body for stdin. For a direct file upload, send its basename in the `filename` header (or the standard `Content-Disposition` filename parameter) so Pastebox preserves the extension and selects syntax highlighting. Multipart `file` uploads preserve the original filename automatically. ```bash # Raw text printf 'hello\n' | curl -X POST --data-binary @- https://paste.example.com/ # Direct file upload with original filename and syntax highlighting curl -X POST --data-binary @server.go -H "filename: server.go" https://paste.example.com/ # Multipart file upload with original filename curl -F "file=@server.log" https://paste.example.com/ ``` ### Upload headers | Header | Value | |---|---| | `data-policy` | `temporary` (default), `permanent`, `once`, or a duration such as `30m`, `12h`, or `7d`, up to 30 days | | `usepassword` | `true` to generate an 8-character password | | `password` | A custom password containing 8–128 characters and no control characters | | `code` | A custom code of 1–10 characters using only `A-Z`, `a-z`, `0-9`, `_`, and `-` | | `label` | An optional label of up to 100 characters without control characters | | `filename` | Optional basename for a raw request body; used for stored filename and syntax highlighting | | `language` | Optional syntax-highlighting override, such as `go`, `javascript`, `json`, `python`, or `yaml` | `usepassword: true` and the `password` header are mutually exclusive. The default response is plain text: ```text url: https://paste.example.com/AbC12 expires: 2026-07-24T12:00:00+09:00 password: GENERATED_PASSWORD manage: https://paste.example.com/AbC12?manage=MANAGE_TOKEN ``` `expires` is omitted for permanent pastes. `password` is returned only when Pastebox generated it. A client-supplied password is never echoed. Append `?format=json` for JSON: ```bash curl -F "file=@server.log" "https://paste.example.com/?format=json" ``` ```json { "url": "https://paste.example.com/AbC12", "expires": "2026-07-24T12:00:00+09:00", "manage": "https://paste.example.com/AbC12?manage=MANAGE_TOKEN", "password_protected": false } ``` The upload response does not include a separate delete URL. Delete the paste from its private manage page or with the management API. Common upload errors include `400 Bad Request` for invalid headers or multipart input, `409 Conflict` for a duplicate custom code, `413 Payload Too Large`, `415 Unsupported Media Type`, and `503 Service Unavailable` when uploads are disabled. With `?format=json`, errors use `{"error":"message"}`. ## Read a paste Request the original content with `?raw=1`. Send protected-paste passwords in the `paste-password` header so they do not appear in URLs or access logs. ```bash curl "https://paste.example.com/AbC12?raw=1" curl -H "paste-password: PASTE_PASSWORD" "https://paste.example.com/AbC12?raw=1" ``` `HEAD /` checks access and returns headers without consuming a one-time paste. A successful `GET` of a one-time paste deletes it after that view. Missing, expired, or already consumed pastes return `404 Not Found`; an invalid or missing password returns `401 Unauthorized` for non-browser clients. ## Clone a paste Clone with `POST /`. The clone preserves the source filename and label. Upload options such as `data-policy`, `usepassword`, `password`, and `code` apply to the new paste. ```bash curl -X POST \ -H "paste-password: SOURCE_PASSWORD" \ -H "data-policy: 12h" \ "https://paste.example.com/AbC12?format=json" ``` The clone response uses the same plain-text or JSON schema as upload and returns a new private manage URL. Cloning returns `503 Service Unavailable` when uploads are disabled. ## Management API The versioned management endpoint is: ```text /api/v1/pastes/ ``` Extract the `manage` query value from the private manage URL returned at upload or clone time, then send it in the `paste-manage-token` header. Management API responses are JSON and use `Cache-Control: no-store`. ```bash MANAGE_TOKEN='token-from-the-manage-url' ``` ### Get metadata ```bash curl -H "paste-manage-token: $MANAGE_TOKEN" \ https://paste.example.com/api/v1/pastes/AbC12 ``` ```json { "id": "AbC12", "filename": "server.log", "label": "production", "url": "https://paste.example.com/AbC12", "created_at": "2026-07-23T10:00:00+09:00", "expires": "2026-07-24T10:00:00+09:00", "data_policy": "temporary", "size": 1234, "content_type": "text/x-log; charset=utf-8", "password_protected": false } ``` `filename`, `label`, and `expires` are omitted when they have no value. Token hashes and other private storage metadata are never returned. ### Update metadata or protection Send one JSON object with an `action`. Unknown fields, malformed JSON, trailing JSON values, and bodies larger than 64 KiB are rejected. Set a label: ```bash curl -X PATCH \ -H "Content-Type: application/json" \ -H "paste-manage-token: $MANAGE_TOKEN" \ --data '{"action":"set_label","label":"production"}' \ https://paste.example.com/api/v1/pastes/AbC12 ``` Set a retention policy: ```json {"action":"set_policy","data_policy":"12h"} ``` Enable protection with a generated password: ```json {"action":"enable_password"} ``` The generated password is returned once in the successful response as `password`. Enable protection with a client-supplied password: ```json {"action":"enable_password","new_password":"a-custom-password"} ``` The supplied password is stored as a hash and is not returned. Disable protection by proving knowledge of the current password: ```json {"action":"disable_password","password":"current-password"} ``` Every successful PATCH returns the current metadata using the same schema as GET. ### Delete ```bash curl -X DELETE \ -H "paste-manage-token: $MANAGE_TOKEN" \ https://paste.example.com/api/v1/pastes/AbC12 ``` ```json { "deleted": true, "id": "AbC12" } ``` The browser manage page uses this same DELETE request. For backward compatibility, DELETE also accepts a previously issued token in `paste-delete-token`. Send exactly one of `paste-manage-token` or `paste-delete-token`. New upload and clone responses no longer issue delete URLs, so new clients should use the manage token. ### Management API errors Errors always use this JSON shape: ```json {"error":"message"} ``` | Status | Meaning | |---|---| | `400 Bad Request` | Invalid JSON, action, label, policy, password, or token-header combination | | `401 Unauthorized` | The current paste password is missing or incorrect when disabling protection | | `404 Not Found` | The paste does not exist, has expired, or the private token is invalid | | `409 Conflict` | Password protection is already enabled | | `405 Method Not Allowed` | Unsupported method; the endpoint allows `GET`, `PATCH`, and `DELETE` | | `500 Internal Server Error` | The request could not be completed | ## Health check `GET /healthz` and `HEAD /healthz` return `200 OK` with `ok` while required storage is healthy, or `503 Service Unavailable` when it is not.