@damianhodgkiss/helpscout-docs-api
v1.1.0
Published
TypeScript client for Help Scout Docs API
Downloads
18
Maintainers
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-apiQuick 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 parameters401- Unauthorized: Invalid API key403- Forbidden: Access denied404- Not Found: Resource doesn't exist500- 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
