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).nullmeans "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" }
| Status | code | Meaning |
|---|---|---|
| 400 | invalid_request | A field is missing or invalid; field says which. |
| 401 | unauthorized | No key, or the key is invalid or deleted. |
| 404 | not_found | It doesn't exist, has expired, or belongs to someone else. |
| 409 | alias_taken | That custom short-link alias is in use. |
| 422 | unsafe_url | The URL is flagged as phishing or malware. |
| 429 | Rate 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.
| Field | Type | |
|---|---|---|
content | string | Required. Up to 512 KiB of text. |
title | string | Optional, up to 200 characters. |
language | string | Syntax highlighting id, e.g. csharp, plsql, json; see languages. Omit for plain text. |
expiry | string | Default 1w. |
burnAfterReading | boolean | Delete 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.
Short links
POST /api/v1/links
Shorten a URL. Returns 201 with the link.
| Field | Type | |
|---|---|---|
url | string | Required. An http(s) URL; a bare domain gets https://. |
alias | string | Optional custom code: 3–32 letters, digits, - or _. Case-insensitive. |
expiry | string | Default 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.