Official typed JavaScript/TypeScript SDK for the DOOMSCROLLR REST API.
Use it when your app, automation, or AI workflow needs owned-audience primitives: posts, pages, products, subscribers, capture widgets, domains, analytics, and replacement flows. For public inspiration, see doomscrollr.com/featured.
Use it from Node.js, serverless functions, workers, and modern runtimes that provide fetch. If you are connecting an AI agent over MCP, use @doomscrollr/mcp-server instead.
npm install @doomscrollr/apiRequirements: Node.js 18+ or any runtime with a compatible fetch implementation.
Create an API key in the DOOMSCROLLR dashboard and pass it as a Bearer token through the client:
import { DoomscrollrApi } from "@doomscrollr/api";
const doomscrollr = new DoomscrollrApi({
apiKey: process.env.DOOMSCROLLR_API_KEY,
});You can also read configuration from environment variables:
const doomscrollr = DoomscrollrApi.fromEnv();Supported variables:
DOOMSCROLLR_API_KEY— dashboard API keyDOOMSCROLLR_API_BASE— optional API base URL override; defaults tohttps://doomscrollr.com/api/v1
The SDK sends authenticated requests as:
Authorization: Bearer <DOOMSCROLLR_API_KEY>register() is the only method that does not require an existing API key.
import { DoomscrollrApi } from "@doomscrollr/api";
const doomscrollr = DoomscrollrApi.fromEnv();
const profile = await doomscrollr.getProfile();
console.log(`Connected to @${profile.username}`);
await doomscrollr.createLinkPost({
url: "https://example.com/article",
title: "Useful read",
tags: "links,research",
status: "draft",
});const page = await doomscrollr.listPosts({
page: 1,
per_page: 20,
status: "published",
tag: "research",
q: "porsche",
});
for (const post of page.data) {
console.log(post.id, post.title);
}
console.log(`Page ${page.current_page} of ${page.last_page ?? "?"}`);List methods return API pagination metadata when available:
datacurrent_pagelast_pageper_pagetotal
Supported filters include:
listPosts({ page, per_page, q, status, tag })listAudience({ page, per_page, q, tag, bounced })listProducts({ page, per_page, q, type, min_price, max_price })
await doomscrollr.createImagePost({
image: "https://example.com/photo.jpg",
title: "New drop",
description: "Behind the scenes.",
tags: "drop,bts",
status: "scheduled",
publish_at: "2026-05-01T17:00:00Z",
});await doomscrollr.addSubscriber({
email: "subscriber@example.com",
first_name: "Ada",
tags: ["launch", "vip"],
source: "website",
});
const csv = await doomscrollr.exportAudience({ tag: "launch" });
console.log(csv);await doomscrollr.createProduct({
title: "Tie Dye Pants",
price: 50,
type: "physical",
cover_photo_url: "https://example.com/tie-dye-pants.jpg",
inventory_count: 10,
shipping_required: true,
});await doomscrollr.buildLinktree({
title: "Links",
intro: "Everything in one owned place.",
style_preset: "brutalist",
add_to_navigation: true,
links: [
{ label: "Shop", url: "https://example.com/shop" },
{ label: "Newsletter", url: "https://example.com/newsletter" },
],
});
await doomscrollr.buildSocialFeed({
title: "Moodboard",
source_query: "air cooled Porsche",
limit: 6,
});Available flow helpers:
buildLinktree()buildKomi()buildShopify()buildEcommerce()buildSubstack()buildNewsletter()buildWebsite()buildSocialFeed()buildMembership()
await doomscrollr.postShopmyProducts({
collection_title: "Holiday gifts under $100",
use_case: "gift guide",
status: "draft",
products: [
{
url: "https://shopmy.us/example-product",
note: "Great texture, easy gift.",
},
],
});const embed = await doomscrollr.getEmbedCode();
await doomscrollr.updateCaptureSettings({
headline: "Join the list",
enabled: true,
});Failed responses throw DoomscrollrApiError with the HTTP status, response payload, and rate-limit metadata when the API provides it.
import { DoomscrollrApiError } from "@doomscrollr/api";
try {
await doomscrollr.getProfile();
} catch (error) {
if (error instanceof DoomscrollrApiError) {
console.error(error.status);
console.error(error.data);
if (error.status === 429) {
console.error(`Rate limit resets at ${error.rateLimit?.reset}`);
}
} else {
throw error;
}
}The API returns X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers on rate-limited responses; the SDK exposes them as error.rateLimit.
Every method accepts an optional { signal } request option:
const controller = new AbortController();
const posts = await doomscrollr.listPosts({ per_page: 10 }, { signal: controller.signal });For new API endpoints that are not yet wrapped by a helper, use request() directly:
const result = await doomscrollr.request("GET", "/profile");textRequest() is available for text responses such as CSV exports.
The SDK covers the DOOMSCROLLR API v1 surfaces for:
- account registration
- profile and settings
- posts, image posts, and bulk post operations
- audience/subscribers, bulk operations, and CSV export
- products, variants, inventory, and bulk product operations
- domains
- Pinterest, Instagram, and RSS integrations
- embed code and capture widget settings
- pages/contact pages/navigation
- top-liked-post analytics
- curation theme
- owned replacement flows
- ShopMy affiliate recommendations
MIT