Call the paste API with plain JavaScript fetch
Framework-neutral fetch code for the Pastepile API: create, read, and delete pastes from the browser, handle the error envelope and 429s, and debug CORS.
Updated
Everything on this page is plain fetch and works unchanged in vanilla JavaScript, Vue, Svelte, Solid, or anywhere else a browser runs. Those frameworks need nothing framework-specific to call an HTTP API, which is why there is no separate Vue or Svelte guide: this is that guide. Angular and React get their own pages only because HttpClient and hook lifecycles genuinely change the code.
Create a paste
async function createPaste(content) {
const res = await fetch("https://www.pastepile.com/api/public/pastes", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
content,
expiry: "1w", // 10m | 1h | 1d | 1w | 1mo | burn | never
visibility: "unlisted" // or "public"
}),
});
const body = await res.json();
if (!res.ok) {
if (res.status === 429) {
const wait = res.headers.get("Retry-After") ?? body.error?.retry_after ?? 60;
throw new Error("Rate limited. Retry in " + wait + " seconds.");
}
throw new Error(body.error?.message ?? "Request failed (" + res.status + ")");
}
// body.url is the share link; body.edit_key is shown once and
// is the only way to update or delete this paste later.
return body;
}Read a paste
Reads are keyless, permanently. There are two shapes: structured JSON, or the raw text body.
// Structured: title, files, language, timestamps.
const paste = await fetch("https://www.pastepile.com/api/public/pastes/" + slug)
.then((r) => {
if (!r.ok) throw new Error("Paste not found or not readable");
return r.json();
});
// Raw: exactly the paste text, nothing else.
const text = await fetch("https://www.pastepile.com/raw/" + slug)
.then((r) => {
if (!r.ok) throw new Error("Paste not found or not readable");
return r.text();
});Delete a paste
// The edit key came back once, in the create response.
await fetch("https://www.pastepile.com/api/public/pastes/" + slug, {
method: "DELETE",
headers: { "X-Edit-Key": editKey },
});Debugging: is it CORS or is it the API?
Every response from the API carries Access-Control-Allow-Origin: *, including errors, 404s, and rate-limit responses, so a failed request is a readable failure instead of an opaque CORS error in the console. Preflight (OPTIONS) requests are answered even for unknown paths. Authentication is header-based; there are no cookies, so do not set credentials: "include" on your requests. The rate-limit headers (Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) and X-Request-Id are exposed cross-origin, so browser code can read them.
- Because errors carry CORS headers too, a 404 or 429 from this API reaches your
catchas a readable response with a JSON body. If the browser console shows an actual CORS error against this API, the usual cause is in the request, not the server. credentials: "include"breaks it. The API never setsAccess-Control-Allow-Credentials, and the CORS spec forbids combining credentialed requests with a wildcard origin. The API uses header auth, so there is nothing to gain from cookies; remove the option.- Only these request headers are allowed cross-origin:
Content-Type,Authorization,X-API-Key,X-Edit-Key,X-Pastepile-Intent,X-Pro-Key. A custom header outside that list fails the preflight. - A blocked network request (an ad blocker, a corporate proxy) produces the same console message as a CORS failure. Check the network tab for whether the request left the browser at all.
Keys, limits, and what stays free
Creating pastes through the API without a key works until September 8, 2026. From that date, API writes need an active subscription and an API key. Reads stay free and keyless, and pasting in the browser at pastepile.com stays free; only programmatic writes are affected.
Limits that matter from a browser app: keyless creates are limited to 30 per hour per IP address, with a burst cap of 30 per minute. Keyless reads allow 120 per minute per IP. The maximum paste size is 2 MB without a key and 25 MB with a Pro key. The full table lives in the API docs.