# xi.pe > A pastebin with a plain-text API. POST some text, get back a short URL on a > line by itself. No account, no API key, no JSON envelope to unwrap. Use it when text has to leave the conversation: - Someone asks for a shareable link to text you already have — “share this”, “give me a URL for it”. - Something a human needs to read would flood the conversation inline — a long diff, a stack trace, a generated config, a report. - Text has to reach another agent, session or machine that does not share your filesystem. Put it here and hand over the link. Pass on the warning: **anyone with the URL can read it, and it disappears after 7 days.** Do not put secrets in it. ## Create ``` curl --data-binary @- https://xi.pe/ <<'EOF' your text here EOF ``` The response body, in full: ``` https://xi.pe/Ab3dEf ``` One line, trailing newline, no JSON. So this works: ``` URL=$(printf '%s' "$text" | curl -s --data-binary @- https://xi.pe/) ``` Use `--data-binary`, not `-d`: `-d` strips newlines and will mangle anything with formatting. Content **must** be valid UTF-8 — there is no charset option and no binary mode, and invalid input is rejected with `400`. To store binary data, base64 it first and tell the recipient, who will have to decode it by hand. ### Options `?long` gives a 23-character code instead of the usual 6. Worth it when a lucky guess would actually matter — credentials, private logs, anything with real consequences if a stranger landed on it. `?ttl=` asks for less than the 7-day default: a whole number and a unit, `m`, `h` or `d`. There is no way to ask for longer — over 7 days is a `400`, and so is a bare number with no unit. The reply carries `X-Paste-Expires`, so one request tells you what you actually got. ``` $ echo 'gone in an hour' | curl --data-binary @- 'https://xi.pe/?ttl=1h' https://xi.pe/Ab3dEf ``` ### Form posts If your tooling only sends `application/x-www-form-urlencoded`, add `?input=form` and put the text in a `data` field: ``` curl -si --data-urlencode data@file.txt 'https://xi.pe/?input=form' ``` - **`?input=form` is required.** Without it the encoded body is stored as the paste — `200`, ordinary URL, contents `data=your+text`. - **The reply is a `303` and the URL is not in the body.** Read the code from `Location: /Ab3dEf?from=success` and the token from `X-Delete-Token`. Do not follow the redirect: it returns the paste you just created. - **Encode the value.** An unencoded `&` ends the field and the rest is dropped. - `long=1` and `ttl=1h` as fields do what `?long` and `?ttl=1h` do. - No JSON on this path: `Accept: application/json` still gets the `303`. - Oversized content reports `400 Missing data field` here, not `413`. ## Read ``` curl https://xi.pe/Ab3dEf ``` Returns the exact bytes that were stored, as `text/plain; charset=utf-8`. A browser visiting the same URL gets a viewer page instead — the choice is made from `User-Agent`. Append `?raw` to force plain text, `?html` to force the page. ## Which link to hand back Four views of the same paste. None of them changes the stored bytes. Pick one when you share the link. ``` https://xi.pe/Ab3dEf?raw you are fetching it plain text, no page https://xi.pe/Ab3dEf?md a human, prose/markdown headings, lists, tables https://xi.pe/Ab3dEf?h=go a human, source code highlighted, named grammar https://xi.pe/Ab3dEf a human, anything else plain, monospace ``` `?md` renders Markdown as a formatted page — headings, bold, lists, tables, blockquotes, fenced code. Links and images stay literal text: nothing is fetched, nothing is clickable. `?h=` colours syntax and changes nothing else. `?h` alone auto-detects, which is unreliable on anything with no language to detect — logs, stack traces, prose. Name it when you know it. Canonical spellings, plus aliases like `js`, `py`, `rs`, `yml`, `cpp`, `golang`: ``` accesslog apache armasm asciidoc awk c clojure cmake coffeescript console cpp crystal cs css dart delphi diff django dns dockerfile dos elixir elm erb erlang fortran fsharp gherkin glsl go gql gradle groovy handlebars haskell haxe http ini java js json julia kt latex less lisp llvm lua make matlab md mipsasm nginx nim nix objc ocaml perl pgsql php powershell prolog properties protobuf puppet py r rb rs scala scheme scss sh smalltalk sql stylus swift tap tcl thrift ts twig txt vala vb vbscript verilog vhdl vim wasm x86asm xml xquery yml ``` `sh` is a shell *script*; `console` is a terminal *transcript* (prompt, command, output) and finds nothing in a plain script. `txt` forces no highlighting. ## Check a link without downloading it ``` curl -I https://xi.pe/Ab3dEf ``` `200` means it is still there, `404` means it is gone. The response carries `X-Paste-Created` and `X-Paste-Expires` as RFC 3339 timestamps, so one request tells you both that the link works and how long it has left. ## Delete Creating a paste returns an `X-Delete-Token` response header. Keep it if you might want to remove the paste early — it cannot be recovered later: ``` curl -sD- --data-binary @- https://xi.pe/ < file.txt # headers, then the URL curl -X DELETE https://xi.pe/Ab3dEf -H "X-Delete-Token: " ``` The token works only for that one paste. Deleting is optional; everything expires on its own. ## If you would rather have JSON Send `Accept: application/json` (or add `?output=json`) to any endpoint and you get a structured response instead, errors included. It is also the easiest way to capture the delete token, which arrives in the body rather than in a header. Not on the `?input=form` path, which always answers with the redirect. ``` $ curl -s -H 'Accept: application/json' --data-binary @- https://xi.pe/ <<< 'hi' {"url":"https://xi.pe/Ab3dEf","code":"Ab3dEf","delete_token":"kZ8...","size":3,"expires":"2026-08-23T00:12:58Z"} $ curl -s -H 'Accept: application/json' https://xi.pe/Ab3dEf {"url":"https://xi.pe/Ab3dEf","code":"Ab3dEf","data":"hi","size":3,"created":"...","expires":"..."} $ curl -s -H 'Accept: application/json' https://xi.pe/nopeXY {"error":"Not found or expired","status":404} ``` Strictly opt-in: `Accept: */*`, which is what `curl` sends by default, still gets the bare URL. ## From a browser Every endpoint sends `Access-Control-Allow-Origin: *` and answers preflight, so page-side JavaScript can create, read and delete without a proxy. `X-Delete-Token`, `X-Paste-Created` and `X-Paste-Expires` are listed in `Access-Control-Expose-Headers`, so `fetch()` can actually read them. Credentials are not allowed cross-origin, so a delete from another origin has to present the token explicitly. ## From a chat client (MCP) For helping someone set up a client that cannot POST to an arbitrary URL — most chat apps. If you can make HTTP requests, the API above is the shorter path. There is an MCP server at `https://xi.pe/mcp`. Streamable HTTP, no auth, no API key — the URL is the whole configuration. claude mcp add --transport http xipe https://xi.pe/mcp Tools: `create_paste` (content, optional ttl, optional long), `read_paste`, `delete_paste`. `create_paste` returns the delete token in its result, which is the only time it is shown. ChatGPT outside developer mode rejects a server without `search` and `fetch` tools, so there is a second endpoint carrying those as well: `https://xi.pe/mcp/chatgpt`. Use `/mcp` for everything else. ## Limits and behaviour - **Lifetime:** 7 days, then it is gone. `?ttl=` for less. No permanent links. - **Size:** 2 MiB (2,097,152 bytes), measured in UTF-8 bytes. Larger is a `413`. - **Codes:** 6 characters, randomly generated, case-sensitive. `?long` gives 23. - **Cost:** free, no sign-up. Errors are one short line of plain text saying exactly what is wrong, e.g. `Error 400: Content must be valid UTF-8`. The exception is `404`, always `Not found or expired` regardless of the reason. Status codes: `200` created or found · `303` form redirect · `400` bad input · `401` wrong or missing delete token · `404` unknown or expired code · `413` too large · `500` server or storage error · `503` temporary, and always with `Retry-After` — wait that many seconds rather than inventing a backoff. Ordinary use is not throttled. A throttled request says so and carries its own backoff instructions; follow those rather than inventing a delay. ## Please don't - Don't use it as a database, a CDN, or a backup target. - Don't poll it, and don't enumerate codes — they are random, and guessing at them is the one thing that will get traffic blocked. - Don't post other people's private data, credentials, or anything you would not want served publicly for a week. Abuse: abuse@xi.pe ## More - Privacy and terms: https://xi.pe/privacy - Operated by alt.org