Create a paste
POST a paste to paste.hep.gg with a bearer API key. Request body, JSON envelope, and error codes.
Create a paste over HTTP. This is the endpoint behind the CLI, ShareX, and any script you write. Authenticate with a bearer API key minted at dashboard/snippets/keys.
https://paste.hep.gg/api/pasteAuth requiredAuthentication
Send your key as a bearer token:
Authorization: Bearer hepgg_pst_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
The key resolves to your account, so the paste is attributed to you and counts
against your plan's size cap and (for Free accounts) total paste count. A
disabled or unknown key returns 401.
Request body
Content type is application/json.
content413.titlenulllanguageautopython, json, bash). Omit it to let the server auto-detect from the content. See Language detection.visibilitypublicpublic, unlisted, or private. private requires a signed-in owner, so a key-only call cannot create one (returns 400). See Visibility.isPermanentfalseResponse
A 200 with the standard JSON envelope.
idurlhttps://paste.hep.gg/<id>.expiresAtnull if it never expires (Prime, or a paste explicitly marked permanent).anonymousfalse for key-authed and session pastes; true only for captcha-authed anonymous web posts.{
"ok": true,
"data": {
"id": "aB3dE6kp",
"url": "https://paste.hep.gg/aB3dE6kp",
"expiresAt": "2026-08-27T00:00:00.000Z",
"anonymous": false
}
}Examples
curl https://paste.hep.gg/api/paste \
-H "Authorization: Bearer hepgg_pst_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"title": "deploy log",
"content": "==> building\n==> done in 4.2s",
"language": "bash",
"visibility": "unlisted"
}'const res = await fetch("https://paste.hep.gg/api/paste", {
method: "POST",
headers: {
Authorization: "Bearer hepgg_pst_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "deploy log",
content: "==> building\n==> done in 4.2s",
language: "bash",
visibility: "unlisted",
}),
});
const json = await res.json();
if (!json.ok) throw new Error(json.error);
console.log(json.data.url);Pipe a file straight in from the shell:
jq -Rs '{content: ., language: "python"}' main.py | \
curl https://paste.hep.gg/api/paste \
-H "Authorization: Bearer hepgg_pst_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
--data-binary @-Visibility
| Value | Who can read it | Notes |
|---|---|---|
public | Anyone with the link | Default for /api/paste. Cacheable raw reads (see Read). |
unlisted | Anyone with the link | Not surfaced in any public listing. |
private | The owner only | Requires a signed-in session; a key-only call returns 400. |
The default on paste.hep.gg/api/paste is public. (The dashboard's own
/api/v1/snippets create path defaults to unlisted instead, so set
visibility explicitly if you care.)
Language detection
If you omit language, the server runs auto-detection on the content. To keep
the rendered page honest, detection only applies when:
- the content has at least 20 non-whitespace characters, and
- the detector is confident, and
- the detected language is one of a curated common set (JavaScript, TypeScript, Python, Go, Rust, Java, C/C++, C#, Kotlin, Swift, Ruby, PHP, Bash, PowerShell, HTML, CSS, SCSS, JSON, YAML, XML, Markdown, SQL, GraphQL, Dockerfile, diff, Lua, Scala).
Short or ambiguous blobs stay plaintext. Pass language explicitly when you
already know it, especially for languages outside that set.
Errors
Errors use { "ok": false, "error": "...", "code"?: "..." } with a matching
HTTP status.
| Status | When | Message / code |
|---|---|---|
400 | Empty content | Paste content is required |
400 | visibility: "private" with a key-only call | Sign in to create private pastes |
400 | Anonymous web post with a bad captcha | Captcha failed. Try again. |
401 | Unknown bearer key | Invalid API key |
401 | Disabled bearer key | API key disabled |
403 | Signed-in but suspended/unapproved account | Your account is not approved for paste creation |
413 | Content over the plan cap | Paste too large. Max 1 MB. (or 8 MB on Prime) |
429 | Free account at its total paste cap | code PASTE_TOTAL_CAP |
{
"ok": false,
"error": "Paste too large. Max 1 MB."
}{
"ok": false,
"error": "You've reached your snippet limit. Delete a few or upgrade to Prime.",
"code": "PASTE_TOTAL_CAP"
}