# cStar API — AI Context File

> Drop this file into your project root as `CLAUDE.md`, `.cursor/rules`, or your AI tool's context file.
> It gives your AI assistant complete knowledge of the cStar REST API, SDKs, webhooks, and CLI.
>
> Generated from: https://cstar.help/developers/cstar-ai-context.md
> Full docs: https://cstar.help/developers
> OpenAPI spec: https://cstar.help/openapi.yaml
> Full LLM context: https://cstar.help/llms-full.txt

---

## API Overview

**Base URL:** `https://www.cstar.help/api/v1/teams/{teamId}`

**Authentication:** Bearer token in Authorization header
```
Authorization: Bearer sk_live_xxxxxxxxxxxxx
```

**Key types:**
- Secret keys (`sk_live_*`, `sk_test_*`): Full CRUD, 1000 req/hour
- Publishable keys (`pk_live_*`, `pk_test_*`): Read-only, 100 req/hour

**Response format:** All responses return `{ success, data, meta: { requestId, timestamp } }`
**Pagination:** `?page=1&pageSize=20` (max 100)
**Errors:** `{ success: false, error: { type, code, message, field?, doc_url } }`

---

## API Reference

### Tickets

Base: `/api/v1/teams/{teamId}/tickets`

Object fields:
- `id` (string): Unique ticket identifier (tkt_ prefix)
- `title` (string): Ticket subject line
- `status` (string): Current status — values: new, open, pending, resolved, closed
- `priority` (string): Priority level — values: low, normal, high, urgent
- `customerId` (string): Associated customer ID (cus_ prefix)
- `assignedTo` (string): Assigned agent ID
- `tags` (string[]): Array of tag strings
- `notes` (string): Internal notes (not visible to customers)
- `messageCount` (integer): Number of messages on this ticket
- `createdAt` (datetime): When the ticket was created
- `updatedAt` (datetime): Last modification timestamp
- `resolvedAt` (datetime): When the ticket was resolved (if applicable)

Endpoints:
- `GET /` — List Tickets: Retrieve a paginated list of tickets with optional filtering by status, priority, customer, or search term.
- `GET /{ticketId}` — Get Ticket: Retrieve a single ticket by ID. Includes the full message thread.
- `POST /` — Create Ticket: Create a new support ticket. Optionally attach it to an existing customer or provide customer details inline.
- `PATCH /{ticketId}` — Update Ticket: Update one or more fields on an existing ticket. Only include the fields you want to change.
- `DELETE /{ticketId}` — Delete Ticket: Permanently delete a ticket and all its messages. This action cannot be undone.

### Customers

Base: `/api/v1/teams/{teamId}/customers`

Object fields:
- `id` (string): Unique customer identifier (cus_ prefix)
- `name` (string): Full name
- `email` (string): Email address
- `status` (string): Account status — values: active, inactive
- `sentiment` (string): Calculated sentiment based on interactions — values: positive, neutral, negative
- `tags` (string[]): Array of tag strings
- `notes` (string): Internal notes about this customer
- `ticketCount` (integer): Total number of tickets
- `createdAt` (datetime): When the customer was created
- `updatedAt` (datetime): Last modification timestamp

Endpoints:
- `GET /` — List Customers: Retrieve a paginated list of customers with optional filtering.
- `GET /{customerId}` — Get Customer: Retrieve a single customer by ID with their full profile and ticket history summary.
- `POST /` — Create Customer: Create a new customer record. Email must be unique within your team.
- `PATCH /{customerId}` — Update Customer: Update one or more fields on an existing customer.
- `DELETE /{customerId}` — Delete Customer: Permanently delete a customer. Associated tickets are preserved but unlinked.

### Customer Groups

Base: `/api/v1/teams/{teamId}/customer-groups`

Object fields:
- `id` (string): Unique group identifier
- `name` (string): Group name
- `slug` (string): URL-friendly slug (auto-generated from name if omitted)
- `description` (string): Optional description
- `externalId` (string): External platform ID (for import matching — e.g., Zendesk org ID)
- `customFields` (object): Arbitrary key-value metadata
- `customerCount` (integer): Number of customers in this group
- `createdAt` (datetime): When the group was created
- `updatedAt` (datetime): Last modification timestamp

Endpoints:
- `GET /` — List Customer Groups: Retrieve a paginated list of customer groups.
- `POST /` — Create Customer Group: Create a new customer group.
- `GET /{groupId}` — Get Customer Group: Retrieve a single customer group by ID.
- `PATCH /{groupId}` — Update Customer Group: Update a customer group. Only provided fields are changed.
- `DELETE /{groupId}` — Delete Customer Group: Delete a customer group. Members are removed from the group but not deleted.
- `GET /{groupId}/members` — List Group Members: List customers that belong to a group.
- `POST /{groupId}/members` — Add Members to Group: Add one or more customers to a group. Duplicates are silently skipped.
- `DELETE /{groupId}/members` — Remove Member from Group: Remove a customer from a group.

### Articles

Base: `/api/v1/teams/{teamId}/articles`

Object fields:
- `id` (string): Unique article identifier (art_ prefix)
- `title` (string): Article title
- `content` (string): Article body (Markdown)
- `category` (string): Category name
- `status` (string): Publication status — values: draft, published
- `isPublic` (boolean): Whether visible in public knowledge base
- `tags` (string[]): Array of tag strings
- `viewCount` (integer): Number of times viewed
- `useCount` (integer): Number of times used in replies
- `createdAt` (datetime): When the article was created
- `updatedAt` (datetime): Last modification timestamp

Endpoints:
- `GET /` — List Articles: Retrieve a paginated list of knowledge base articles with optional filtering.
- `GET /{articleId}` — Get Article: Retrieve a single article by ID with full content.
- `POST /` — Create Article: Create a new knowledge base article. Articles start as drafts by default.
- `PATCH /{articleId}` — Update Article: Update one or more fields on an existing article.
- `DELETE /{articleId}` — Delete Article: Permanently delete an article from the knowledge base.

### Messages

Base: `/api/v1/teams/{teamId}/tickets/{ticketId}/messages`

Object fields:
- `id` (string): Unique message identifier (msg_ prefix)
- `ticketId` (string): Parent ticket ID (tkt_ prefix)
- `content` (string): Message body text
- `sender` (string): Who sent the message — values: agent, customer, system
- `senderName` (string): Display name of the sender
- `isInternal` (boolean): Whether this is an internal note (not visible to customers)
- `createdAt` (datetime): When the message was sent

Endpoints:
- `GET /` — List Messages: Get all messages for a ticket, ordered chronologically.
- `POST /` — Add Message: Add a new message to a ticket thread. Fires the `ticket.message_added` webhook event.

### Webhooks

Base: `/api/v1/teams/{teamId}/webhooks`

Object fields:
- `id` (string): Unique webhook identifier (whk_ prefix)
- `name` (string): Friendly name for the webhook
- `url` (string): Delivery URL (HTTPS)
- `events` (string[]): Array of subscribed event types
- `secret` (string): HMAC signing secret (whsec_ prefix, shown once at creation)
- `isActive` (boolean): Whether the webhook is currently active
- `createdAt` (datetime): When the webhook was created
- `updatedAt` (datetime): Last modification timestamp

Endpoints:
- `GET /` — List Webhooks: Retrieve all configured webhooks for your team.
- `GET /{webhookId}` — Get Webhook: Retrieve a single webhook by ID.
- `POST /` — Create Webhook: Create a new webhook subscription. The signing secret is returned once — save it immediately.
- `PATCH /{webhookId}` — Update Webhook: Update an existing webhook. Use this to change the URL, events, or toggle active status.
- `DELETE /{webhookId}` — Delete Webhook: Permanently delete a webhook subscription.
- `POST /trigger-test` — Trigger Test Event: Fire a test webhook event to all active webhooks and CLI listeners. Useful for testing your integration.

### Categories

Base: `/api/v1/teams/{teamId}/categories`

Object fields:
- `id` (string): Unique category identifier (UUID)
- `name` (string): Category display name
- `slug` (string): URL-safe slug (auto-generated from name)
- `description` (string): Category description
- `icon` (string): Icon identifier
- `color` (string): Color value
- `sortOrder` (integer): Display order (ascending)
- `isPublic` (boolean): Whether visible in the public knowledge base
- `createdAt` (datetime): When the category was created
- `updatedAt` (datetime): Last modification timestamp

Endpoints:
- `GET /` — List Categories: Retrieve all categories for a team, ordered by sort order then name.
- `POST /` — Create Category: Create a new article category. Slug is auto-generated from the name.
- `PATCH /{categoryId}` — Update Category: Update one or more fields on an existing category. Only include the fields you want to change.
- `DELETE /{categoryId}` — Delete Category: Permanently delete a category. Articles in this category will become uncategorized.

### Community

Base: `/api/v1/teams/{teamId}/community`

Object fields:
- `id` (uuid): Unique post identifier
- `title` (string): Post title
- `slug` (string): URL-friendly slug
- `body` (string): Post body text
- `topic_id` (uuid): Topic category ID
- `status` (string): Post status — values: open, answered, officially_answered, planned, not_planned, completed, under_review
- `visibility` (string): Post visibility — values: public, members_only
- `vote_count` (integer): Number of upvotes
- `comment_count` (integer): Number of comments
- `is_pinned` (boolean): Whether post is pinned to top
- `is_locked` (boolean): Whether new comments are disabled
- `custom_fields` (object): Custom field values as key-value pairs (field definition ID → value). Only fields assigned to the post's topic are accepted. Internal only — not returned by public API.
- `attachments` (array): Image attachments (max 10 per post, 5 per comment). Each object: {filename, content_type, size_bytes, storage_path}. Images only (JPEG, PNG, GIF, WebP), 5MB max per file.
- `created_at` (datetime): When the post was created

Endpoints:
- `GET /posts` — List posts: Get all community posts for the team with optional filters.
- `POST /posts` — Create post: Create a new community post.
- `PATCH /posts/{postId}` — Update post status: Update a community post status or properties.
- `GET /topics` — List topics: Get all community topics for the team. Each topic includes a customFieldConfig array specifying which custom fields appear on posts in that topic.

### Members

Base: `/api/v1/teams/{teamId}/members`

Object fields:
- `id` (string): Membership ID
- `userId` (string): User account ID
- `name` (string): Display name
- `email` (string): Email address
- `avatarUrl` (string): Avatar image URL
- `role` (string): Team role — values: owner, admin, manager, librarian, agent, spectator
- `roleDisplayName` (string): Game title for role (e.g., The Hero)
- `permissions` (string[]): Array of permission keys
- `level` (integer): Player level
- `xp` (integer): Current XP
- `joinedAt` (datetime): When the member joined

Endpoints:
- `GET /` — List Members: List all team members with their roles, levels, and permissions.
- `GET /{memberId}` — Get Member: Get a single team member by membership ID.
- `PATCH /{memberId}` — Update Member Role: Update a member's role. Cannot change the owner role.
- `DELETE /{memberId}` — Remove Member: Remove a member from the team. Cannot remove the team owner.
- `GET /../invites` — List Invites: List pending team invites.
- `POST /../invites` — Send Invite: Send a team invitation email.

### Settings

Base: `/api/v1/teams/{teamId}/settings`

Object fields:
- `object` (string): Always "settings"
- `teamName` (string): Team display name
- `teamSlug` (string): URL-safe team identifier

Endpoints:
- `GET /` — Get Settings: Get all team settings.
- `PATCH /` — Update Settings: Update team settings. Only provided fields are changed.
- `GET /statuses` — List Statuses: List all ticket status configurations.
- `GET /business-hours` — Get Business Hours: Get business hours configuration including timezone and weekly schedule.
- `GET /widget` — Get Widget Settings: Get widget appearance and behavior settings.

### Notifications

Base: `/api/v1/teams/{teamId}/notifications`

Object fields:
- `id` (string): Notification ID
- `type` (string): Notification type
- `title` (string): Notification title
- `body` (string): Notification body
- `read` (boolean): Whether the notification has been read
- `createdAt` (datetime): When the notification was created

Endpoints:
- `GET /` — List Notifications: List notifications for the authenticated user.
- `GET /unread-count` — Get Unread Count: Get the number of unread notifications.
- `POST /mark-all-read` — Mark All Read: Mark all notifications as read.

### Custom Fields

Base: `/api/v1/teams/{teamId}/custom-fields`

Object fields:
- `id` (string): Field ID
- `name` (string): Display name
- `key` (string): Machine-readable key
- `type` (string): Field type — values: text, number, select, multiselect, date, boolean
- `entityType` (string): Which entity this field belongs to — values: tickets, customers
- `required` (boolean): Whether the field is required
- `options` (string[]): Options for select/multiselect fields
- `position` (integer): Display order

Endpoints:
- `GET /` — List Custom Fields: List all custom field definitions.
- `POST /` — Create Custom Field: Create a new custom field definition.

### SLA Rules

Base: `/api/v1/teams/{teamId}/sla/rules`

Object fields:
- `id` (string): Rule ID
- `name` (string): Rule name
- `priority` (string): Ticket priority this rule applies to
- `responseTarget` (integer): Response time target in minutes
- `resolutionTarget` (integer): Resolution time target in minutes
- `businessHoursOnly` (boolean): Only count business hours
- `enabled` (boolean): Whether the rule is active

Endpoints:
- `GET /` — List SLA Rules: List all SLA rules.
- `POST /` — Create SLA Rule: Create a new SLA rule.

### Analytics

Base: `/api/v1/teams/{teamId}/analytics`

Object fields:
- `period` (string): Time period for the data
- `tickets.total` (integer): Total tickets in period
- `tickets.open` (integer): Currently open tickets
- `tickets.resolved` (integer): Tickets resolved in period
- `customers.total` (integer): Total customers
- `csat.average` (number): Average CSAT score

Endpoints:
- `GET /overview` — Get Overview: Get a summary of ticket, customer, and CSAT metrics for a time period.
- `GET /agents` — Get Agent Stats: Get per-agent performance metrics.

### Bulk Operations

Base: `/api/v1/teams/{teamId}/bulk`

Object fields:
- `action` (string): Operation type — values: update, delete
- `resource` (string): Resource type — values: tickets, customers, articles
- `total` (integer): Total items processed
- `succeeded` (integer): Items successfully processed
- `failed` (integer): Items that failed

Endpoints:
- `POST /` — Bulk Operation: Perform a bulk update or delete on up to 100 resources at once.

### Export

Base: `/api/v1/teams/{teamId}/export`

Object fields:
- `format` (string): Export format (json or csv)
- `totalRows` (integer): Total rows exported

Endpoints:
- `POST /` — Create Export: Export data synchronously. Supports multi-resource JSON or single-resource CSV.

### Import

Base: `/api/v1/teams/{teamId}/import`

Object fields:
- `resource` (string): Resource type imported
- `total` (integer): Total records processed
- `created` (integer): Records created
- `updated` (integer): Records updated
- `skipped` (integer): Records skipped

Endpoints:
- `POST /` — Run Import: Import records synchronously. Max 500 per request.
- `GET /` — List Import Logs: List import history logs.

### Audit Log

Base: `/api/v1/teams/{teamId}/audit-log`

Object fields:
- `id` (string): Log entry ID
- `action` (string): Action performed (e.g., ticket.created)
- `resourceType` (string): Type of resource affected
- `resourceId` (string): ID of the affected resource
- `actorName` (string): Name of who performed the action
- `details` (object): Additional details about the action
- `createdAt` (datetime): When the action occurred

Endpoints:
- `GET /` — List Audit Log: List audit log entries with optional filtering.

### Search

Base: `/api/v1/teams/{teamId}/search`

Object fields:
- `type` (string): Resource type (ticket, customer, article)
- `id` (string): Resource ID
- `title` (string): Title or name
- `snippet` (string): Matching text excerpt

Endpoints:
- `GET /` — Search: Perform a cross-resource search.

### Tags

Base: `/api/v1/teams/{teamId}/tags`

Object fields:
- `name` (string): Tag name
- `count` (integer): Number of tickets using this tag

Endpoints:
- `GET /` — List Tags: List all tags with usage counts.
- `POST /` — Create Tag: Create a new tag.

### Game

Base: `/api/v1/teams/{teamId}/game`

Object fields:
- `level` (integer): Player level (resets each season)
- `xp` (integer): Current XP within the season
- `gold` (integer): Gold balance (earned from tickets and bosses)
- `skills` (object): Skill tree allocations (4 skills, max 5 each)

Endpoints:
- `GET /player` — Get Player Stats: Get a player's game stats including level, XP, gold, skills, streaks, and season info.
- `GET /player/{memberId}` — Get Player by Member ID: Get game stats for a specific team member by their membership ID.
- `GET /boss` — Get Boss State: Get the current boss battle state including health, phase, abilities, participants, and battle duration.
- `GET /boss/active` — Is Boss Active: Lightweight check if a boss battle is currently active.
- `POST /boss/damage` — Deal Boss Damage: Deal damage to the current boss. Damage is calculated server-side based on ticket priority, skills, and combo state. Clients cannot specify damage values.
- `POST /boss/spawn` — Spawn Boss: Spawn a new boss battle. Fails if a boss is already active.
- `GET /boss/defeats` — Boss Defeat History: Get the history of defeated bosses with participants and rewards.
- `GET /boss/defeats/{defeatId}` — Get Single Defeat: Get full details for a specific boss defeat.
- `GET /leaderboard` — Get Leaderboard: Get team leaderboard rankings for a given period.
- `GET /leaderboard/me` — Get My Rank: Get the current user's rank on the leaderboard.
- `GET /achievements` — List Achievements: List all achievements with rarity, progress, and summary stats.
- `GET /achievements/{achievementId}` — Get Single Achievement: Get details and progress for a specific achievement.
- `GET /achievements/recent` — Recent Achievements: Get recently unlocked achievements across the team.
- `GET /quests/today` — Today's Quests: Get today's daily quests with progress. Quests reset at midnight UTC.
- `GET /quests/history` — Quest History: Get past quest completions grouped by date.
- `GET /skills` — Get Skill Tree: Get the skill tree with current allocations and available points. 4 skills: Quick Learner (+XP), Treasure Hunter (+Gold), Boss Slayer (+Damage), Social Butterfly (+1-Ups).
- `POST /skills/allocate` — Allocate Skill Point: Spend an available skill point. Earn 1 point every 5 levels.
- `POST /skills/reset` — Reset Skills: Reset all skill allocations, returning points to the available pool.
- `GET /seasons/current` — Get Current Season: Get the current active season with badge thresholds and days remaining.
- `GET /seasons` — List Seasons: Get all seasons (current and past).
- `GET /seasons/{seasonId}/stats` — Season Stats: Get a user's stats for a specific season (current or past).
- `GET /one-ups` — List One-Ups: Get recent one-ups on the team.
- `POST /one-ups` — Send One-Up: Send a one-up to a teammate. 3 free per day (+ social_butterfly skill bonus). Gold one-ups deduct from sender balance. Max 140 char message, max 100 gold.
- `GET /one-ups/remaining` — One-Ups Remaining: Check how many free one-ups remain today.
- `GET /high-fives` — List High Fives: Get recent high fives sent to or from this team.
- `POST /high-fives` — Send High Five: Send a high five to another team. Limited to 1 per team per day. Max 80 char message.
- `GET /high-fives/can-send/{recipientTeamId}` — Can Send High Five: Check if you can send a high five to a specific team today.
- `GET /cosmetics` — List Cosmetics: Get all cosmetic items with unlock status.
- `GET /cosmetics/preferences` — Get Cosmetic Preferences: Get the user's currently equipped cosmetics.
- `PATCH /cosmetics/preferences` — Update Cosmetic Preferences: Equip a cosmetic. Can only equip unlocked items. Victory message max 200 chars.
- `GET /puzzles/today` — Today's Puzzle: Get today's daily warm-up puzzle.
- `POST /puzzles/complete` — Complete Puzzle: Record a puzzle completion. Awards XP based on time and mistakes.
- `GET /puzzles/leaderboard` — Puzzle Leaderboard: Get puzzle leaderboard — by scores (for a specific puzzle) or by streaks.
- `GET /puzzles/streak` — Puzzle Streak: Get a user's puzzle streak stats.
- `GET /activity` — Team Activity Feed: Get the team-wide game activity feed. Supports cursor-based pagination.
- `GET /activity/member/{memberId}` — Member Activity: Get activity feed for a specific team member.
- `GET /config` — Game Config: Get game balance constants (XP per level, boss difficulties, reward tables, etc). Read-only, no database calls. Any API key can access.

### AI Actions

Base: `/api/v1/teams/{teamId}/ai`

Object fields:
- `action` (string): AI action type — values: auto-tag, suggest-reply, summarize, improve
- `result` (object): Action-specific result data

Endpoints:
- `POST /` — Run AI Action: Run an AI action. Available actions: auto-tag (tag a ticket), suggest-reply (generate a response), summarize (summarize a conversation), improve (refine draft text).

### Automations

Base: `/api/v1/teams/{teamId}/automations`

Object fields:
- `id` (string): Rule ID
- `name` (string): Rule name
- `triggerEvent` (string): Event that triggers this rule
- `conditions` (object): Conditions that must match (all/any)
- `actions` (array): Actions to execute when triggered
- `enabled` (boolean): Whether the rule is active
- `executionCount` (integer): Total times this rule has fired

Endpoints:
- `GET /` — List Automations: List all automation rules.
- `POST /` — Create Automation: Create a new automation rule.
- `POST /{ruleId}/test` — Test Automation (Dry Run): Dry-run a rule against a specific resource. No actions are executed — just shows what would happen.

### Saved Views

Base: `/api/v1/teams/{teamId}/views`

Object fields:
- `id` (string): View ID
- `name` (string): View name
- `entityType` (string): Entity type — values: tickets, customers, articles, community_posts
- `filters` (object): Saved filter configuration
- `sortField` (string): Sort field
- `sortDirection` (string): Sort direction — values: asc, desc
- `visibility` (string): Who can see this view — values: private, team

Endpoints:
- `GET /` — List Views: List saved views, optionally filtered by entity type.
- `POST /` — Create View: Create a saved view.
- `GET /{viewId}/tickets` — Execute View: Execute a saved view — returns the filtered and sorted results.

### Billing

Base: `/api/v1/teams/{teamId}/billing`

Object fields:
- `status` (string): Subscription status
- `plan` (string): Current plan
- `memberCount` (integer): Number of team members
- `currentPeriodEnd` (datetime): When the current billing period ends

Endpoints:
- `GET /subscription` — Get Subscription: Get the current subscription status and plan details.
- `POST /portal` — Create Billing Portal: Create a Stripe billing portal session. Returns a URL where the team admin can manage their subscription.



---

## Webhook Events

Events follow the pattern `resource.action`. Subscribe via the API or CLI.

- `ticket.created`: Fired when a new ticket is created via app, widget, API, or email
- `ticket.updated`: Fired when a ticket status, priority, or assignment changes
- `ticket.closed`: Fired when a ticket is resolved or closed
- `ticket.message_added`: Fired when a new message is added to a ticket
- `ticket.deleted`: Fired when a ticket is deleted via app or API
- `customer.created`: Fired when a new customer is created
- `customer.updated`: Fired when customer details are modified
- `customer.deleted`: Fired when a customer is deleted via app or API
- `article.created`: Fired when a new Library article is created
- `article.published`: Fired when an article is published to the Public Library
- `article.updated`: Fired when an article content or metadata is modified
- `article.deleted`: Fired when an article is deleted via app or API
- `boss.spawned`: Fired when a boss appears for the team
- `boss.damaged`: Fired when a boss takes damage from a ticket close
- `boss.defeated`: Fired when a boss is defeated by the team
- `player.level_up`: Fired when a player reaches a new level
- `player.achievement_unlocked`: Fired when a player unlocks an achievement
- `player.xp_gained`: Fired when a player earns XP from closing a ticket or quest
- `player.quest_completed`: Fired when a player completes a daily quest
- `player.streak_milestone`: Fired when a player hits a streak milestone (3, 5, 10, or 25 days)
- `social.one_up_sent`: Fired when a teammate sends a one-up recognition
- `social.high_five_sent`: Fired when a team sends a high five to another team
- `community_post.created`: Fired when a new community post is created
- `community_post.updated`: Fired when a community post is updated
- `community_post.status_changed`: Fired when a community post status is changed (e.g., Planned, Completed)
- `community_post.commented`: Fired when a new comment is added to a community post
- `community_post.deleted`: Fired when a community post is deleted
- `community_post.voted`: Fired when a community post receives a vote
- `survey.submitted`: Fired when a customer submits a CSAT survey response

### Payload format
```json
{
  "id": "evt_abc123",
  "type": "ticket.created",
  "created_at": "2025-12-10T14:30:00Z",
  "team_id": "your-team-id",
  "data": { "id": "tkt_abc123", "title": "...", "status": "new" }
}
```

### Headers sent with each delivery
- `X-Signature`: HMAC-SHA256 signature for verification
- `X-Event-Type`: Event type (e.g., `ticket.created`)
- `X-Event-ID`: Unique event ID (idempotency key)
- `X-Webhook-ID`: Webhook subscription ID
- `X-Timestamp`: ISO 8601 delivery timestamp
- `X-Delivery-Attempt`: Attempt number (starting at 1)

### Signature verification (X-Signature header)
```javascript
const crypto = require('crypto');
function verifyWebhook(rawBody, signature, secret) {
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
```

---

## SDKs

### JavaScript (@cstar.help/js)
```bash
npm install @cstar.help/js
```
```javascript
import { CStarClient } from '@cstar.help/js';
const cstar = new CStarClient({ apiKey: 'sk_live_xxxxx', teamId: 'your-team-id' });

// CRUD
const { data: tickets } = await cstar.tickets.list({ status: 'open' });
const { data: ticket } = await cstar.tickets.create({ title: 'Help needed', priority: 'high' });
await cstar.tickets.update(ticket.id, { status: 'resolved' });
await cstar.tickets.delete(ticket.id);
```

### 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@co.com', password: 'securepass', name: 'Jane' });
await auth.login({ email: 'jane@co.com', password: 'securepass' });
auth.isAuthenticated;   // true
auth.accessToken;       // JWT token
auth.getCustomer();     // { id, email, name }
auth.logout();
```

### 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(); // { totalArticles, totalCategories, totalViews }
```

### React (@cstar.help/react)
```bash
npm install @cstar.help/react
```
```jsx
import { CStarProvider, useTickets, useCustomers, useCStarClient, useSubscription } from '@cstar.help/react';

// Wrap app: <CStarProvider apiKey="..." teamId="...">
// Hooks return: { data, loading, error, refetch, pagination }
const { tickets, loading } = useTickets({ status: 'open' });
const client = useCStarClient(); // For mutations
useSubscription('ticket.created', (event) => { /* handle */ });
```

### Svelte 5 (@cstar.help/svelte)
```bash
npm install @cstar.help/svelte
```
```svelte
<script>
  import { setCStarClient, Tickets, Customers, getCStarClient } from '@cstar.help/svelte';
  setCStarClient({ apiKey: 'sk_live_xxxxx', teamId: 'your-team-id' }); // in +layout.svelte

  const tickets = new Tickets({ status: 'open' }); // Reactive via $state/$derived
  // tickets.data, tickets.loading, tickets.error
</script>
```

---

## CLI

```bash
npm install -g @cstar.help/cli
```

| Command | Description |
|---------|-------------|
| `cstar login --api-key sk_live_xxx` | Authenticate |
| `cstar status` | Show team info and rate limits |
| `cstar keys list/create/revoke` | Manage API keys |
| `cstar listen --forward-to http://localhost:3000/webhooks` | Forward webhooks locally |
| `cstar trigger ticket.created` | Fire test webhook event |
| `cstar logs [--tail] [--status 4xx]` | View API request logs |
| `cstar mcp-server` | Run as MCP server for AI agents |

### MCP Server Config (Claude Code, Cursor, etc.)
```json
{
  "mcpServers": {
    "cstar": {
      "command": "npx",
      "args": ["-y", "@cstar.help/cli", "mcp-server", "--api-key", "sk_live_xxxxx"]
    }
  }
}
```

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

---

## 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']
});
```

### Listen for ticket updates and sync to your database
```javascript
// Using CLI: cstar listen --forward-to http://localhost:3000/webhooks
// In your server:
app.post('/webhooks', (req, res) => {
  if (!verifyWebhook(req.rawBody, req.headers['x-signature'], WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  const { type, data } = req.body;
  if (type === 'ticket.updated') {
    db.tickets.upsert(data); // Sync to your DB
  }
  res.status(200).send('OK');
});
```

### Search and filter across resources
```javascript
// Tickets by status and priority
const urgent = await cstar.tickets.list({ status: 'open', priority: 'urgent' });

// Full-text search
const results = await cstar.tickets.list({ search: 'billing issue' });

// Customer lookup
const customer = await cstar.customers.list({ search: 'jane@example.com' });
```
