thefaqapp
Skip to main content

TypeScript SDK — Universal API Client

Official TypeScript SDK for TheFAQApp. Universal API client for Node.js, Deno, Bun, and the browser with full type safety and IntelliSense.

@faqapp/core

Universal TypeScript client for the TheFAQApp API. Works in Node.js, Deno, Bun, and the browser.

View on npm →

Install

npm install @faqapp/core

Setup

import { FAQClient } from '@faqapp/core';

const client = new FAQClient({
  apiKey: process.env.FAQ_API_KEY!,
  organizationSlug: 'your-org',
});

You can also use the factory function:

import { createFAQClient } from '@faqapp/core';

const client = createFAQClient({
  apiKey: process.env.FAQ_API_KEY!,
  organizationSlug: 'your-org',
});

Resources

The SDK uses a resource-based pattern. All resources are accessed as properties on the client instance.

Questions

client.questions.list(params?)

List questions with pagination and optional filters.

const page = await client.questions.list({
  limit: 10,
  category: 'billing',
  sortBy: 'views',
  status: 'published',
});

console.log(page.data);        // Question[]
console.log(page.pagination);  // { page, limit, total, pages }

Parameters:

ParamTypeDescription
pagenumberPage number (1-indexed)
limitnumberItems per page
categorystringFilter by category slug
searchstringFull-text search query
status"published" | "draft"Filter by status
featured"true" | "false"Filter by featured flag
tagsstringComma-separated tag filter
sortBystringcreated, updated, views, alphabetical, order, helpful
sortOrder"asc" | "desc"Sort direction

Auto-pagination

Iterate over all items across pages automatically:

for await (const question of client.questions.list().iter()) {
  console.log(question.question);
}

// Or iterate page by page
for await (const page of client.questions.list().iterPages()) {
  console.log(`Page ${page.pagination.page}:`, page.data.length, 'items');
}

client.questions.get(slug)

Get a single question by slug.

const { data: question } = await client.questions.get('how-to-cancel');
console.log(question.question, question.stats);

client.questions.create(params)

Create a new question. Requires write scope.

const { data } = await client.questions.create({
  question: 'What are your business hours?',
  answer: '<p>Monday–Friday, 9am–5pm EST.</p>',
  categorySlug: 'general',
  published: true,
  tags: ['hours', 'contact'],
});

client.questions.update(slug, params)

Partial update — only provided fields are changed.

const { data } = await client.questions.update('business-hours', {
  answer: '<p>Monday–Friday, 9am–6pm EST.</p>',
  featured: true,
});

client.questions.delete(slug)

Delete a question by slug.

const { data } = await client.questions.delete('old-question');
console.log(data.deleted); // true

client.questions.bulk(params)

Bulk-create multiple questions in a single request.

const { data } = await client.questions.bulk({
  questions: [
    { question: 'Q1?', answer: 'A1' },
    { question: 'Q2?', answer: 'A2', categorySlug: 'general' },
  ],
});

console.log(`Created: ${data.created}, Updated: ${data.updated}`);

client.questions.export()

Export all questions (non-paginated).

const { data: allQuestions } = await client.questions.export();

Categories

client.categories.list(params?)

const page = await client.categories.list({ limit: 50 });
console.log(page.data); // Category[]

client.categories.get(slug)

const { data: category } = await client.categories.get('billing');

client.categories.create(params)

const { data } = await client.categories.create({
  name: 'Billing',
  icon: '💳',
  description: 'Payment and subscription questions',
});

client.categories.update(slug, params)

const { data } = await client.categories.update('billing', {
  description: 'Updated description',
});

client.categories.delete(slug)

await client.categories.delete('old-category');

client.search.query(params)

Search questions by query string. Accepts a string or an options object.

// Simple string search
const { data } = await client.search.query('how do I reset');

// With options
const { data } = await client.search.query({
  q: 'billing',
  category: 'payments',
  limit: 5,
});

console.log(data.results); // SearchResult[]
console.log(data.total);   // number

Feedback

client.feedback.submit(questionSlug, params)

Submit feedback for a question.

await client.feedback.submit('how-to-cancel', {
  helpful: true,
  comment: 'This solved my issue!',
});

client.feedback.stats(questionSlug)

Get aggregated feedback statistics.

const { data } = await client.feedback.stats('how-to-cancel');
console.log(data.helpfulPercentage); // e.g. 85

Other Resources

The client also provides access to:

  • client.translations — Manage translations for questions and categories
  • client.webhooks — Manage webhook subscriptions
  • client.domains — Manage custom domains
  • client.apiKeys — Manage API keys
  • client.organization — Retrieve organization info

Configuration

new FAQClient({
  apiKey: 'faq_...',                    // Required
  organizationSlug: 'my-org',           // Required
  baseUrl: 'https://api.faq.money',     // Default
  timeout: 30000,                       // Default: 30s
  maxRetries: 2,                        // Default: 2 (retries on 429 & 5xx)
});

Error Handling

The SDK provides a typed error hierarchy for precise error handling:

import {
  FAQAPIError,
  FAQValidationError,
  FAQNotFoundError,
  FAQRateLimitError,
  FAQNetworkError,
  FAQTimeoutError,
} from '@faqapp/core';

try {
  await client.questions.create({ question: '', answer: '' });
} catch (error) {
  if (error instanceof FAQNotFoundError) {
    console.error('Not found:', error.message);
  }

  if (error instanceof FAQValidationError) {
    console.error('Validation errors:', error.errors);
    // error.errors is ValidationIssue[] with field-level details
  }

  if (error instanceof FAQRateLimitError) {
    console.error(`Rate limited. Retry after ${error.retryAfter}s`);
  }

  if (error instanceof FAQNetworkError) {
    console.error('Network error:', error.message);
  }

  if (error instanceof FAQTimeoutError) {
    console.error(`Timed out after ${error.timeoutMs}ms`);
  }

  if (error instanceof FAQAPIError) {
    // Catch-all for any API error (4xx/5xx)
    console.error(`${error.status}: ${error.message}`);
    console.error('Request ID:', error.requestId);
  }
}

All errors extend FAQError and carry an optional requestId for traceability.

Pagination

List methods return a PagePromise that resolves to a Page object:

const page = await client.questions.list({ limit: 10 });

page.data;           // Question[] — items on this page
page.pagination;     // { page, limit, total, pages }
page.hasNextPage();  // boolean
page.getNextPage();  // Promise<Page<Question>>

For automatic iteration across all pages:

// All items
for await (const q of client.questions.list().iter()) {
  console.log(q.question);
}

// All pages
for await (const page of client.questions.list().iterPages()) {
  console.log(page.data);
}