rafb.me API

Create and manage pastes and short links from scripts, CI jobs and apps. JSON over HTTPS, version 1. Machine-readable description: /api/v1/openapi.json (OpenAPI 3).

Authentication

Paste and link endpoints need an API key, which belongs to your account: anything you create through the API shows up under My pastes and My links. Sign in (or create an account) to create keys.

Send the key in the Authorization header:

Authorization: Bearer rafb_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keys act as your account, so keep them out of public repositories and client-side code you ship to others. Delete a key on the API keys page to revoke it immediately. Browser cookies are never accepted by the API. Some endpoints (marked open) need no key.

Conventions

  • Base URL: https://rafb.me/api/v1
  • Request and response bodies are JSON (Content-Type: application/json), with camelCase names.
  • Times are UTC, ISO 8601 (2026-10-29T13:45:00Z). null means "never" for expiry.
  • Expiry values: 10m, 1h, 1d, 1w, 1mo, never.
  • CORS is open, so you can call the API from any web page with fetch.
  • Breaking changes will go in a new version (/api/v2); v1 only gains fields and endpoints.

Errors

Errors use the HTTP status code plus a JSON body:

{ "error": "Expiry must be one of 10m, 1h, 1d, 1w, 1mo, never.", "code": "invalid_request", "field": "expiry" }
StatuscodeMeaning
400invalid_requestA field is missing or invalid; field says which.
401unauthorizedNo key, or the key is invalid or deleted.
404not_foundIt doesn't exist, has expired, or belongs to someone else.
409alias_takenThat custom short-link alias is in use.
422unsafe_urlThe URL is flagged as phishing or malware.
429Rate limited; retry after the Retry-After header's seconds.

Rate limits

Per account: 30 writes (POST, DELETE) and 300 reads per minute. Open endpoints are limited per IP address.

Pastes

POST /api/v1/pastes

Create a paste. Returns 201 with the paste, and its page URL in Location.

FieldType
contentstringRequired. Up to 512 KiB of text.
titlestringOptional, up to 200 characters.
languagestringSyntax highlighting id, e.g. csharp, plsql, json; see languages. Omit for plain text.
expirystringDefault 1w.
burnAfterReadingbooleanDelete after the first view. Default false.
curl -s https://rafb.me/api/v1/pastes \
  -H "Authorization: Bearer $RAFB_KEY" -H "Content-Type: application/json" \
  -d '{"title":"query.sql","language":"plsql","expiry":"1d","content":"SELECT * FROM dual;"}'
{
  "id": "Xk3mP9qa",
  "url": "https://rafb.me/p/Xk3mP9qa",
  "rawUrl": "https://rafb.me/p/Xk3mP9qa/raw",
  "title": "query.sql",
  "language": "plsql",
  "createdUtc": "2026-10-29T13:45:00Z",
  "expiresUtc": "2026-10-30T13:45:00Z",
  "burnAfterReading": false,
  "views": 0,
  "length": 19
}

Paste a file from the shell (needs jq):

jq -Rs '{content: ., language: "bash"}' deploy.sh | curl -s https://rafb.me/api/v1/pastes \
  -H "Authorization: Bearer $RAFB_KEY" -H "Content-Type: application/json" -d @- | jq -r .url

GET /api/v1/pastes

Your live pastes, newest first, without content.

GET /api/v1/pastes/{id}

One of your pastes, including content. This doesn't count a view or burn a burn-after-reading paste. To read anyone's paste, fetch its rawUrl (no key needed; that does count, and burns).

DELETE /api/v1/pastes/{id}

Delete one of your pastes. Returns 204.

POST /api/v1/links

Shorten a URL. Returns 201 with the link.

FieldType
urlstringRequired. An http(s) URL; a bare domain gets https://.
aliasstringOptional custom code: 3–32 letters, digits, - or _. Case-insensitive.
expirystringDefault never.

Not accepted: non-web schemes, private or local addresses, URLs containing a user name or password, links back to rafb.me, and URLs flagged by Google Safe Browsing.

curl -s https://rafb.me/api/v1/links \
  -H "Authorization: Bearer $RAFB_KEY" -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/a/very/long/path?with=query","alias":"my-link"}'
{
  "code": "my-link",
  "shortUrl": "https://rafb.me/s/my-link",
  "infoUrl": "https://rafb.me/s/my-link/info",
  "targetUrl": "https://example.com/a/very/long/path?with=query",
  "createdUtc": "2026-10-29T13:45:00Z",
  "expiresUtc": null,
  "clicks": 0,
  "lastClickUtc": null
}

From JavaScript:

const res = await fetch('https://rafb.me/api/v1/links', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${key}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ url: 'https://example.com/page' }),
});
if (!res.ok) throw new Error((await res.json()).error);
const { shortUrl } = await res.json();

GET /api/v1/links

Your live short links, newest first, with click counts.

GET /api/v1/links/{code}

One of your links, with its click count and last click time.

DELETE /api/v1/links/{code}

Delete one of your links; it stops redirecting immediately. Returns 204.

Other

GET /api/v1 open

API info. With a key, authenticated is true and user names the account, which makes it a handy key check:

curl -s https://rafb.me/api/v1 -H "Authorization: Bearer $RAFB_KEY"

GET /api/v1/languages open

The language ids pastes accept, with display names.

GET /api/v1/openapi.json open

OpenAPI 3 description, for generating clients or importing into Postman, Insomnia or Bruno.