Skip to content

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

createPaste.js
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.

readPaste.js
// 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

deletePaste.js
// 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 catch as 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 sets Access-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.

An API key is a secret. Do not ship one inside a public frontend bundle, where anyone can read it from the source. For an app whose users write pastes after the keyless window closes, either let each user paste their own key at runtime (stored client-side only), or route write calls through a minimal backend you control that holds the key.

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.

Read the full API docs

Related

Other developer guides