` is still accepted by the verifier for back-compat but no longer emitted.
- `X-Event-Type`: Event type (e.g., `ticket.created`).
- `X-Event-ID`: Unique event ID — use as your idempotency key.
- `X-Webhook-ID`: Your webhook subscription ID.
- `X-Timestamp`: ISO 8601 delivery timestamp.
- `X-Delivery-Attempt`: Attempt number (starts at 1).
- `x-cstar-request-id`: Correlates the webhook back to the API call that triggered it.
#### Signature verification
```javascript
import { createHmac, timingSafeEqual } from 'node:crypto';
/**
* Verify a Stripe-style webhook signature.
* @param {string} body - Raw request body (string, not parsed JSON).
* @param {string} header - Value of the X-Signature header.
* @param {string} secret - Your webhook signing secret.
* @param {number} toleranceSeconds - Replay window (default 300s = 5 min).
*/
function verifyWebhook(body, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(
header.split(',').map((p) => p.split('='))
);
const ts = Number(parts.t);
const sig = parts.v1;
if (!ts || !sig) return false;
if (Math.abs(Date.now() / 1000 - ts) > toleranceSeconds) return false;
const expected = createHmac('sha256', secret)
.update(`${ts}.${body}`)
.digest('hex');
const a = Buffer.from(sig, 'hex');
const b = Buffer.from(expected, 'hex');
return a.length === b.length && timingSafeEqual(a, b);
}
```
Or use the helper exported by `@cstar.help/js/webhook`:
```javascript
import { verifySignature } from '@cstar.help/js/webhook';
if (!verifySignature(rawBody, req.headers['x-signature'], process.env.CSTAR_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
```
#### Retry policy
Failed deliveries (non-2xx response or timeout) retry with exponential backoff. The `X-Delivery-Attempt` header tells you which attempt this is.
---
## SDKs
### JavaScript — `@cstar.help/js` v0.15.1
Install: `npm install @cstar.help/js`
```javascript
import { CStarClient } from '@cstar.help/js';
const cstar = new CStarClient({
apiKey: process.env.CSTAR_SECRET_KEY, // sk_live_* or sk_test_*
teamId: process.env.CSTAR_TEAM_ID
});
// CRUD
const { data: tickets } = await cstar.tickets.list({ status: 'open' });
const { data: ticket } = await cstar.tickets.create({ title: 'Need help', priority: 'high' });
await cstar.tickets.update(ticket.id, { status: 'resolved' });
await cstar.tickets.delete(ticket.id);
// Last response metadata (request ID, timestamp, pagination)
console.log(cstar.lastMeta.requestId);
// Real-time event stream (SSE)
const off = cstar.realtime.on('ticket.*', (event) => {
console.log(event.type, event.data);
});
// off() to unsubscribe; cstar.destroy() to tear everything down
```
Available resource accessors on the client:
`tickets`, `customers`, `articles`, `webhooks`, `automations`, `categories`, `community.posts`, `community.topics`, `members`, `settings`, `notifications`, `mentions`, `attachments`, `customFields`, `sla`, `analytics`, `bulk`, `export`, `import`, `auditLog`, `search`, `tags`, `activity`, `customerGroups`, `game`, `ai`, `views`, `billing`. Plus `realtime` and (when `offline: true`) `offlineQueue`.
### JS — Customer auth (`@cstar.help/js/auth`)
```javascript
import { AuthClient } from '@cstar.help/js/auth';
const auth = new AuthClient({ teamSlug: 'acme' });
await auth.signup({ email: 'jane@example.com', password: 'securepass', name: 'Jane' });
await auth.login({ email: 'jane@example.com', password: 'securepass' });
auth.isAuthenticated; // true
auth.accessToken; // JWT
auth.getCustomer(); // { id, email, name }
auth.logout();
```
### JS — Public knowledge base (`@cstar.help/js/library`)
```javascript
import { LibraryClient } from '@cstar.help/js/library';
const library = new LibraryClient({ teamSlug: 'acme' });
const categories = await library.categories();
const articles = await library.articles({ categorySlug: 'billing' });
const article = await library.article('reset-password');
const results = await library.search('reset password');
const popular = await library.popularArticles(5);
const stats = await library.stats();
```
### React — `@cstar.help/react` v0.10.0
Install: `npm install @cstar.help/react`
```jsx
import {
CStarProvider,
useTickets,
useCustomers,
useArticles,
useCStarClient,
useSubscription
} from '@cstar.help/react';
function App() {
return (
);
}
function TicketList() {
const { tickets, loading, error, refetch, pagination } = useTickets({ status: 'open' });
const client = useCStarClient();
useSubscription('ticket.created', (event) => refetch());
if (loading) return Loading...
;
return tickets.map((t) => {t.title}
);
}
```
### Svelte 5 — `@cstar.help/svelte` v0.9.0
Install: `npm install @cstar.help/svelte`
```svelte
{#if tickets.loading}
Summoning tickets…
{:else if tickets.error}
Couldn't load — try again?
{:else}
{#each tickets.data as t (t.id)}
{t.title} — {t.status}
{/each}
{/if}
```
---
## CLI — `@cstar.help/cli` v0.8.2
Install: `npm install -g @cstar.help/cli`
### Commands
- `cstar login --api-key sk_live_...`: Authenticate and store credentials in your OS keychain.
- `cstar logout`: Remove stored credentials.
- `cstar status`: Team info, environment, rate-limit usage.
- `cstar events [--category tickets]`: List webhook event types.
- `cstar keys list / create / revoke`: Manage API keys.
- `cstar listen --forward-to http://localhost:3000/webhooks`: Forward webhook events to your local server.
- `cstar trigger ticket.created`: Fire a test webhook event.
- `cstar logs [--method POST] [--status 4xx] [--tail]`: Tail API request logs.
- `cstar mcp-server`: Run as an MCP server for AI agents (Claude Code, Cursor, etc.).
### Global flags
- `--json`: Output as JSON (for piping to `jq`).
- `--api-key `: Override stored API key.
- `--base-url `: Override API base URL.
- `--no-color`: Disable colored output.
### MCP server config (Claude Code, Cursor, Continue)
```json
{
"mcpServers": {
"cstar": {
"command": "npx",
"args": ["-y", "@cstar.help/cli", "mcp-server", "--api-key", "sk_live_..."]
}
}
}
```
MCP tools: `cstar_list_tickets`, `cstar_get_ticket`, `cstar_create_ticket`, `cstar_list_customers`, `cstar_get_customer`, `cstar_list_articles`, `cstar_trigger_webhook`, `cstar_get_status`, `cstar_list_events`.
---
## Cheat Sheets
Single-page reference tomes per surface, printable. AI assistants can link users straight to the right one:
- https://cstar.help/developers/cheatsheets — index ("the tome shelf")
- https://cstar.help/developers/cheatsheets/js — JS SDK
- https://cstar.help/developers/cheatsheets/react — React SDK
- https://cstar.help/developers/cheatsheets/svelte — Svelte SDK
- https://cstar.help/developers/cheatsheets/cli — CLI
- https://cstar.help/developers/cheatsheets/webhooks — Webhooks (signature verification + headers)
---
## Quick patterns
### Create a ticket from a form submission
```javascript
const { data } = await cstar.tickets.create({
title: formData.subject,
priority: 'normal',
customerName: formData.name,
tags: ['web-form']
});
```
### Sync ticket updates to your DB via webhook
```javascript
// Local dev: cstar listen --forward-to http://localhost:3000/webhooks
import { verifySignature } from '@cstar.help/js/webhook';
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
const ok = verifySignature(req.body.toString(), req.headers['x-signature'], SECRET);
if (!ok) return res.status(401).send('Invalid signature');
const { type, data } = JSON.parse(req.body.toString());
if (type === 'ticket.updated') db.tickets.upsert(data.ticket);
res.status(200).end();
});
```
### Search across resources
```javascript
const urgent = await cstar.tickets.list({ status: 'open', priority: 'urgent' });
const matches = await cstar.tickets.list({ search: 'billing issue' });
const customer = await cstar.customers.list({ search: 'jane@example.com' });
```
---
Generated: 2026-05-07T21:29:46.233Z