npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@damianhodgkiss/helpscout-docs-api

v1.1.0

Published

TypeScript client for Help Scout Docs API

Downloads

18

Readme

@damianhodgkiss/helpscout-docs-api

TypeScript SDK for the Help Scout Docs API with full type safety and a clean, modern API.

Features

  • 🎯 Client-based API - Initialize once with API key, use everywhere
  • 📦 Modular exports - Import only what you need for better tree-shaking
  • 🔒 Type-safe - Full TypeScript support with strict typing
  • 🚀 Zero dependencies - Uses native fetch
  • Clean API - No repetitive API key passing
  • 🌳 Tree-shakeable - Optimized bundle size

Installation

npm install @damianhodgkiss/helpscout-docs-api

Quick Start

Client-Based API (Recommended)

Initialize the client once with your API key, then use it throughout your application:

import { createDocsApiClient } from '@damianhodgkiss/helpscout-docs-api';

const client = createDocsApiClient(process.env.HELPSCOUT_API_KEY!);

// Articles
const { article } = await client.articles.createArticle({
  collectionId: 'abc123',
  name: 'Getting Started',
  text: '<p>Welcome to our documentation!</p>',
  status: 'published'
});

// Categories
const { categories } = await client.categories.listCategories({
  collectionId: 'abc123'
});

// Collections
const { collections } = await client.collections.listCollections();

// Assets
const asset = await client.assets.createArticleAsset({
  articleId: article.id,
  assetType: 'image',
  file: imageBuffer,
  fileName: 'screenshot.png'
});

Modular Imports (Advanced)

For even better tree-shaking, import only the modules you need:

import { createArticlesClient } from '@damianhodgkiss/helpscout-docs-api/articles';
import { createCategoriesClient } from '@damianhodgkiss/helpscout-docs-api/categories';

const articlesClient = createArticlesClient(apiKey);
const categoriesClient = createCategoriesClient(apiKey);

await articlesClient.createArticle({ ... });
await categoriesClient.listCategories({ ... });

Functional API (Alternative)

You can also use the functional API if you prefer:

import { createArticle } from '@damianhodgkiss/helpscout-docs-api/articles';

const result = await createArticle(apiKey, {
  collectionId: 'abc123',
  name: 'Getting Started',
  text: '<p>Welcome!</p>'
});

API Reference

Articles Client

createArticle

Create a new article.

const { article } = await client.articles.createArticle({
  collectionId: string;      // Required: Collection ID
  name: string;              // Required: Article title
  text: string;              // Required: Article content (HTML or plain text)
  status?: 'published' | 'notpublished';  // Optional: Publication status
  slug?: string;             // Optional: SEO-friendly URL slug
  categories?: string[];     // Optional: Category IDs
  related?: string[];        // Optional: Related article IDs
  keywords?: string[];       // Optional: Search keywords
  reload?: boolean;          // Optional: Return created article in response
});

getArticle

Get an article by ID or number.

const { article } = await client.articles.getArticle({
  articleIdOrNumber: string | number;  // Required: Article ID or number
  draft?: boolean;                     // Optional: Get draft version
});

listArticles

List articles in a collection or category.

const { articles } = await client.articles.listArticles({
  collectionId?: string;     // Required if categoryId not provided
  categoryId?: string;       // Required if collectionId not provided
  page?: number;             // Optional: Page number (default: 1)
  status?: 'all' | 'published' | 'notpublished';  // Optional: Filter by status
  sort?: 'number' | 'status' | 'name' | 'popularity' | 'createdAt' | 'updatedAt';
  order?: 'asc' | 'desc';    // Optional: Sort order
  pageSize?: number;         // Optional: Results per page (max 100)
});

updateArticle

Update an existing article.

const { article } = await client.articles.updateArticle({
  articleId: string;         // Required: Article ID
  status?: 'published' | 'notpublished';
  slug?: string;
  name?: string;
  text?: string;
  categories?: string[] | null;  // null removes all categories
  related?: string[] | null;     // null removes all related articles
  keywords?: string[] | null;    // null removes all keywords
  reload?: boolean;
});

deleteArticle

Delete an article permanently.

await client.articles.deleteArticle({
  articleId: string;  // Required: Article ID
});

searchArticles

Search for articles.

const { articles } = await client.articles.searchArticles({
  query: string;             // Required: Search query
  page?: number;
  collectionId?: string;     // Optional: Filter to specific collection
  siteId?: string;           // Optional: Filter to specific site
  status?: 'all' | 'published' | 'notpublished';
  visibility?: 'all' | 'public' | 'private';
});

saveArticleDraft

Save a draft version of an article.

await client.articles.saveArticleDraft({
  articleId: string;  // Required: Article ID
  text: string;       // Required: Draft content
});

deleteArticleDraft

Delete an article draft.

await client.articles.deleteArticleDraft({
  articleId: string;  // Required: Article ID
});

Categories Client

createCategory

Create a new category.

const { category } = await client.categories.createCategory({
  collectionId: string;      // Required: Collection ID
  name: string;              // Required: Category name
  slug?: string;
  visibility?: 'public' | 'private';
  order?: number;
  defaultSort?: 'popularity' | 'name';
  reload?: boolean;
});

getCategory

Get a category by ID or number.

const { category } = await client.categories.getCategory({
  categoryIdOrNumber: string | number;  // Required: Category ID or number
});

listCategories

List categories in a collection.

const { categories } = await client.categories.listCategories({
  collectionId: string;      // Required: Collection ID
  page?: number;
  sort?: 'number' | 'order' | 'name' | 'articleCount' | 'createdAt' | 'updatedAt';
  order?: 'asc' | 'desc';
});

updateCategory

Update an existing category.

const { category } = await client.categories.updateCategory({
  categoryId: string;        // Required: Category ID
  name: string;              // Required: Category name
  slug?: string;
  visibility?: 'public' | 'private';
  order?: number;
  defaultSort?: 'popularity' | 'name';
  reload?: boolean;
});

deleteCategory

Delete a category.

await client.categories.deleteCategory({
  categoryId: string;  // Required: Category ID
});

Collections Client

createCollection

Create a new collection.

const { collection } = await client.collections.createCollection({
  siteId: string;            // Required: Site ID
  name: string;              // Required: Collection name
  visibility?: 'public' | 'private';
  order?: number;
  description?: string;      // Optional: Max 45 characters
  reload?: boolean;
});

getCollection

Get a collection by ID or number.

const { collection } = await client.collections.getCollection({
  collectionIdOrNumber: string | number;  // Required: Collection ID or number
});

listCollections

List all collections.

const { collections } = await client.collections.listCollections({
  page?: number;
  siteId?: string;           // Optional: Filter to specific site
  visibility?: 'all' | 'public' | 'private';
  sort?: 'number' | 'visibility' | 'order' | 'name' | 'createdAt' | 'updatedAt';
  order?: 'asc' | 'desc';
});

updateCollection

Update an existing collection.

const { collection } = await client.collections.updateCollection({
  collectionId: string;      // Required: Collection ID
  name: string;              // Required: Collection name
  visibility?: 'public' | 'private';
  order?: number;
  description?: string;
  siteId?: string;           // Optional: Move to different site
  reload?: boolean;
});

deleteCollection

Delete a collection.

await client.collections.deleteCollection({
  collectionId: string;  // Required: Collection ID
});

Assets Client

createArticleAsset

Upload an image or attachment for an article.

const asset = await client.assets.createArticleAsset({
  articleId: string;         // Required: Article ID
  assetType: 'image' | 'attachment';  // Required: Asset type
  file: Buffer | Blob;       // Required: File content
  fileName?: string;         // Optional: File name
});

Sites Client

listSites

List all sites.

const { sites } = await client.sites.listSites({
  page?: number;  // Optional: Page number (default: 1)
});

getSite

Get a site by ID.

const { site } = await client.sites.getSite({
  siteId: string;  // Required: Site ID
});

updateSite

Update an existing site.

const { site } = await client.sites.updateSite({
  siteId: string;            // Required: Site ID
  subDomain?: string;        // Optional: Subdomain (must be unique if provided)
  title?: string;            // Optional: Site title
  status?: string;           // Optional: Site status
  cname?: string;            // Optional: Custom domain
  hasPublicSite?: boolean;   // Optional: Public availability
  logoUrl?: string;          // Optional: Logo URL
  logoWidth?: number;        // Optional: Logo width in pixels
  logoHeight?: number;       // Optional: Logo height in pixels
  favIconUrl?: string;       // Optional: Favicon URL
  touchIconUrl?: string;     // Optional: Touch icon URL
  homeUrl?: string;          // Optional: Company website URL
  homeLinkText?: string;     // Optional: Navigation link text
  bgColor?: string;          // Optional: Background color (hex)
  description?: string;      // Optional: Meta description
  hasContactForm?: boolean;  // Optional: Contact form display
  mailboxId?: number;        // Optional: Help Scout mailbox ID
  contactEmail?: string;     // Optional: Contact form email
  styleSheetUrl?: string;    // Optional: Custom stylesheet URL
  headerCode?: string;       // Optional: Custom HTML/JavaScript
  reload?: boolean;          // Optional: Return updated site in response
});

TypeScript Support

All methods are fully typed with TypeScript. The SDK exports all request and response types:

import type {
  Article,
  ArticleRef,
  Category,
  Collection,
  CreateArticleRequest,
  CreateArticleResponse,
  // ... and many more
} from '@damianhodgkiss/helpscout-docs-api/articles';

Error Handling

All methods throw standard errors for HTTP failures:

try {
  await client.articles.createArticle({ ... });
} catch (error) {
  if (error instanceof Error) {
    console.error('API error:', error.message);
  }
}

Common HTTP status codes:

  • 400 - Bad Request: Invalid parameters
  • 401 - Unauthorized: Invalid API key
  • 403 - Forbidden: Access denied
  • 404 - Not Found: Resource doesn't exist
  • 500 - Internal Server Error

Rate Limiting

Help Scout Docs API has rate limits based on the number of sites:

  • 1 site: 2,000 requests per 10 minutes
  • 2 sites: 3,000 requests per 10 minutes
  • 3+ sites: 4,000 requests per 10 minutes

Requirements

  • Node.js 18.0.0 or higher (for native fetch support)
  • TypeScript 5.0+ (for best type experience)

License

MIT

Resources