TypeScript SDK

Zero-dependency TypeScript client with typed methods, auto-retry on rate limits, and error handling.

Installation

npm install @liquichart/sdk

Usage

import { LiquiChart } from '@liquichart/sdk';

const lc = new LiquiChart({
  apiKey: process.env.LIQUICHART_API_KEY!,
  // baseUrl: 'https://www.liquichart.com' (default)
});

// Charts
const { data: chart } = await lc.charts.get('abc12345');
const { data: chartList } = await lc.charts.list({ limit: 20, status: 'published' });
await lc.charts.create({ title: 'Revenue', chartType: 'line', manualData: [...] });
await lc.charts.publish('abc12345');

// Batch fetch multiple charts in one request
const { data: batch } = await lc.charts.batch(['abc12345', 'def67890']);

// Polls
const { data: poll } = await lc.polls.get('xyz98765');
await lc.polls.create({ title: 'Survey', questions: [{ text: '...', options: ['A', 'B'] }] });
await lc.polls.close('xyz98765');

// Living Content (self-updating)
const { data: block } = await lc.livingContent.getUnified('my-block');
// block.mode is 'proactive' | 'reactive'
// block.content auto-updates when underlying data changes

// Workspace
const { data: ws } = await lc.workspace.get();
const { data: usage } = await lc.workspace.getUsage({ days: 30 });

// Experiments (read publicly-running experiments, follow for updates)
const { data: experiments } = await lc.experiments.list({ status: 'running' });
const { data: exp } = await lc.experiments.get('exp12345');

Webhook Verification

Verify incoming webhook payloads using HMAC-SHA256. Configure endpoints in Settings → Webhooks.

import { verifyWebhookSignature } from '@liquichart/sdk/webhooks';

// In your webhook handler (Next.js App Router example):
export async function POST(req: Request) {
  const rawBody = await req.text();
  const signature = req.headers.get('x-liquichart-signature') ?? '';

  const isValid = verifyWebhookSignature(
    rawBody,
    signature,
    process.env.LIQUICHART_WEBHOOK_SECRET!,
  );

  if (!isValid) return new Response('Unauthorized', { status: 401 });

  const event = JSON.parse(rawBody);
  // event.event_type, event.data, event.timestamp
}

Error Handling

import {
  LiquiChartNotFoundError,
  LiquiChartRateLimitError,
  LiquiChartAuthError,
  LiquiChartPlanRequiredError,
  LiquiChartScopeError,
} from '@liquichart/sdk';

try {
  const { data } = await lc.charts.get('nonexistent');
} catch (err) {
  if (err instanceof LiquiChartNotFoundError) {
    // Chart doesn't exist
  }
  if (err instanceof LiquiChartRateLimitError) {
    // Auto-retried twice already; err.retryAfter has seconds to wait
  }
  if (err instanceof LiquiChartAuthError) {
    // Invalid or expired API key
  }
  if (err instanceof LiquiChartPlanRequiredError) {
    // This endpoint requires a Pro or Visionary plan
  }
  if (err instanceof LiquiChartScopeError) {
    // API key is missing a required scope (e.g. charts:write)
  }
}

The SDK automatically retries on 429 (rate limit) up to 2 times with Retry-After backoff.

TypeScript Support

Full type definitions included. Every method returns typed responses:

import type { Chart, Poll, ChartDataPoint, LivingUnified, Experiment } from '@liquichart/sdk';

const { data: chart } = await lc.charts.get('abc12345');
// chart is typed as Chart — autocomplete works for:
// chart.title, chart.data, chart.config, chart.insight, chart._links, etc.

const { data: block } = await lc.livingContent.getUnified('my-slug');
// Narrow by mode for full type safety:
if (block.mode === 'proactive') {
  block.activeVariantName; // string | null
  block.evaluationCount;   // number
}