UNPKG

@proveanything/smartlinks

Version:

Official JavaScript/TypeScript SDK for the Smartlinks API

1,940 lines (1,748 loc) 196 kB
# Smartlinks API Summary Version: 1.6.4 | Generated: 2026-02-26T12:33:27.813Z This is a concise summary of all available API functions and types. ## Documentation For detailed guides on specific features: - **[AI & Chat Completions](ai.md)** - Chat completions, RAG (document-grounded Q&A), voice integration, streaming, tool calling, podcast generation - **[Widgets](widgets.md)** - Embeddable React components for parent applications - **[Containers](containers.md)** - Building full-app embeddable containers (lazy-loaded) - **[Realtime](realtime.md)** - Real-time data updates and WebSocket connections - **[iframe Responder](iframe-responder.md)** - iframe integration and cross-origin communication - **[i18n](i18n.md)** - Internationalization and localization - **[Liquid Templates](liquid-templates.md)** - Dynamic templating for content generation - **[Theme System](theme.system.md)** - Theme configuration and customization - **[Theme Defaults](theme-defaults.md)** - Default theme values and presets - **[Proof Claiming Methods](proof-claiming-methods.md)** - All methods for claiming/registering product ownership (NFC tags, serial numbers, auto-generated claims) - **[App Data Storage](app-data-storage.md)** - User-specific and collection-scoped app data storage - **[App Objects: Cases, Threads & Records](app-objects.md)** - Generic app-scoped building blocks for support cases, discussions, bookings, registrations, and more - **[Communications](comms.md)** - Transactional sends, multi-channel broadcasts, consent management, push registration, and analytics - **[AI Guide Template](ai-guide-template.md)** - A sample for an app on how to build an AI setup guide ## API Namespaces The Smartlinks SDK is organized into the following namespaces: — Core Data & Configuration — - **collection** - Manage collections, settings, and identifiers for your workspace. - **product** - Create and manage products within a collection; metadata, tags, media. - **variant** - Manage product variants per product; includes serial number helpers. - **asset** - Upload and manage media assets for collections, products, and proofs. - **batch** - Group products into batches; manage serial number ranges and lookups. - **crate** - Organize products in containers/crates for logistics and grouping. - **form** - Build and manage dynamic forms used by apps and workflows. - **appConfiguration** - Read/write app configuration and scoped data (collection/product/proof). — Identity & Access — - **auth** - Admin authentication and account ops: login/logout, tokens, account info. - **authKit** - End‑user auth flows (email/password, OAuth, phone); profiles and verification. - **contact** - Manage customer contacts; CRUD, lookup, upsert, erase. — Messaging & Audience — - **comms** - Send notifications (push, email, wallet); templating, severity, delivery status. → [Guide](comms.md) - **broadcasts** - Define broadcast campaigns; append recipients/events; analytics and CRUD. - **segments** - Define dynamic/static audience segments; estimate and list recipients; schedule calculations. — Analytics & Events — - **interactions** - Log and analyze interactions/outcomes; aggregates and actor lists; interaction definition CRUD. — Automation — - **journeys** - Configure automated flows triggered by events or schedules; steps, rules; full CRUD. — NFC, Proofs & Claims — - **nfc** - Claim and validate NFC tags; perform tag lookups. - **proof** - Create, update, claim, and list product proofs (digital certificates). - **claimSet** - Manage claim sets and tag assignments; queries, reports, and updates. - **qr** - Lookup short codes to resolve collection/product/proof context. — AI & Utilities — - **ai** - Chat completions, RAG (document Q&A), podcast generation, TTS, content/image generation, voice integration. - **serialNumber** - Assign, lookup, and manage serial numbers across scopes. — Other — - **appObjects** - Functions for appObjects operations - **async** - Functions for async operations - **attestation** - Functions for attestation operations - **jobs** - Functions for jobs operations - **journeysAnalytics** - Functions for journeysAnalytics operations - **location** - Functions for location operations - **order** - Functions for order operations - **realtime** - Functions for realtime operations - **tags** - Functions for tags operations - **template** - Functions for template operations ## HTTP Utilities Core HTTP functions for API configuration and communication: **isProxyEnabled**() → `boolean` Return whether proxy mode is currently enabled. **initializeApi**(options: { baseURL: string apiKey?: string bearerToken?: string proxyMode?: boolean ngrokSkipBrowserWarning?: boolean extraHeaders?: Record<string, string> iframeAutoResize?: boolean // default true when in iframe logger?: Logger // optional console-like or function to enable verbose logging /** * When true, bypasses the idempotency guard and forces a full re-initialization. * Use only when you intentionally need to reset all SDK state (e.g. in tests or * when switching accounts) → `void` Call this once (e.g. at app startup) to configure baseURL/auth. **setNgrokSkipBrowserWarning**(flag: boolean) → `void` Enable/disable automatic "ngrok-skip-browser-warning" header. **setExtraHeaders**(headers: Record<string, string>) → `void` Replace or augment globally applied custom headers. **setBearerToken**(token: string | undefined) → `void` Allows setting the bearerToken at runtime (e.g. after login/logout). **getBaseURL**() → `string | null` Get the currently configured API base URL. Returns null if initializeApi() has not been called yet. **isInitialized**() → `boolean` Returns true if initializeApi() has been called at least once. Useful for guards in widgets or shared modules that want to skip initialization when another module has already done it. ```ts if (!isInitialized()) { initializeApi({ baseURL: 'https://smartlinks.app/api/v1' }) } ``` **hasAuthCredentials**() → `boolean` Returns true if the SDK currently has any auth credential set (bearer token or API key). Use this as a cheap pre-flight check before calling endpoints that require authentication, to avoid issuing a network request that you already know will return a 401. ```ts if (hasAuthCredentials()) { const account = await auth.getAccount() } ``` **configureSdkCache**(options: { enabled?: boolean ttlMs?: number maxEntries?: number persistence?: 'none' | 'indexeddb' persistenceTtlMs?: number serveStaleOnOffline?: boolean clearOnPageLoad?: boolean }) → `void` Configure the SDK's built-in in-memory GET cache. The cache is transparent — it sits inside the HTTP layer and requires no changes to your existing API calls. All GET requests benefit automatically. Per-resource rules (collections/products → 1 h, proofs → 30 s, etc.) override this value. in-memory only (`'none'`, default). Ignored in Node.js. fallback, from the original fetch time (default: 7 days). `SmartlinksOfflineError` with stale data instead of propagating the network error. caches on page load/refresh. IndexedDB persists for offline. ```ts // Enable IndexedDB persistence for offline support configureSdkCache({ persistence: 'indexeddb' }) // Disable cache entirely in test environments configureSdkCache({ enabled: false }) // Keep caches across page refreshes (not recommended for production) configureSdkCache({ clearOnPageLoad: false }) ``` **invalidateCache**(urlPattern?: string) → `void` Manually invalidate entries in the SDK's GET cache. *contains* this string is removed. Omit (or pass `undefined`) to wipe the entire cache. ```ts invalidateCache() // clear everything invalidateCache('/collection/abc123') // one specific collection invalidateCache('/product/') // all product responses ``` **proxyUploadFormData**(path: string, formData: FormData, onProgress?: (percent: number) → `void` Upload a FormData payload via proxy with progress events using chunked postMessage. Parent is expected to implement the counterpart protocol. **request**(path: string) → `Promise<T>` Internal helper that performs a GET request to `${baseURL}${path}`, injecting headers for apiKey or bearerToken if present. Cache pipeline (when caching is not skipped): L1 hit → return from memory (no I/O) L2 hit → return from IndexedDB, promote to L1 (no network) Miss → fetch from network, store in L1 + L2 Offline → serve stale L2 entry via SmartlinksOfflineError (if persistence enabled) Concurrent identical GETs share one in-flight promise (deduplication). Node-safe: IndexedDB calls are no-ops when IDB is unavailable. **post**(path: string, body: any, extraHeaders?: Record<string, string>) → `Promise<T>` Internal helper that performs a POST request to `${baseURL}${path}`, injecting headers for apiKey or bearerToken if present. If body is FormData, Content-Type is not set. Returns the parsed JSON as T, or throws an Error. **put**(path: string, body: any, extraHeaders?: Record<string, string>) → `Promise<T>` Internal helper that performs a PUT request to `${baseURL}${path}`, injecting headers for apiKey or bearerToken if present. If body is FormData, Content-Type is not set. Returns the parsed JSON as T, or throws an Error. **patch**(path: string, body: any, extraHeaders?: Record<string, string>) → `Promise<T>` Internal helper that performs a PATCH request to `${baseURL}${path}`, injecting headers for apiKey or bearerToken if present. If body is FormData, Content-Type is not set. Returns the parsed JSON as T, or throws an Error. **requestWithOptions**(path: string, options: RequestInit) → `Promise<T>` Internal helper that performs a request to `${baseURL}${path}` with custom options, injecting headers for apiKey or bearerToken if present. Returns the parsed JSON as T, or throws an Error. **del**(path: string, extraHeaders?: Record<string, string>) → `Promise<T>` Internal helper that performs a DELETE request to `${baseURL}${path}`, injecting headers for apiKey or bearerToken if present. Returns the parsed JSON as T, or throws an Error. **getApiHeaders**() → `Record<string, string>` Returns the common headers used for API requests, including apiKey and bearerToken if set. **sendCustomProxyMessage**(request: string, params: any) → `Promise<T>` Sends a custom proxy message to the parent Smartlinks application when running in an iframe. This function is used to communicate with the parent window when the SDK is embedded in an iframe and proxyMode is enabled. It sends a message to the parent and waits for a response. ## Error Handling All API functions throw `SmartlinksApiError` when requests fail. This error class provides structured access to HTTP status codes, server error codes, and additional context. ### SmartlinksApiError **Properties:** - **message** `string` - Human-readable error message in English (e.g., "Error 400: Not Authorized") - **statusCode** `number` - HTTP status code (400, 401, 404, 500, etc.) - **code** `number` - Numeric error code (same as statusCode) - **details** `Record<string, any> | undefined` - Additional server response data, including string error codes - **url** `string | undefined` - The URL that was requested **Helper Methods:** - **isAuthError()** `boolean` - Returns true for 401 or 403 status codes - **isNotFound()** `boolean` - Returns true for 404 status code - **isRateLimited()** `boolean` - Returns true for 429 status code - **isClientError()** `boolean` - Returns true for 4xx status codes - **isServerError()** `boolean` - Returns true for 5xx status codes - **toJSON()** `object` - Returns a serializable object for logging ### Error Format Normalization The SDK automatically normalizes various server error response formats into a consistent structure. The server may return errors in different formats, but they are all accessible through the same properties. **Server String Error Codes:** Server-specific error identifiers are preserved in `error.details`: - Access via: `error.details?.errorCode` or `error.details?.error` - Format examples: `"NOT_AUTHORIZED"`, `"broadcasts.topic.invalid"`, `"sendgrid.provision.failed"` - Use these for programmatic error handling (switch statements, conditional logic) ### Usage Examples **Basic Error Handling:** ```typescript import { SmartlinksApiError, product } from '@proveanything/smartlinks' try { const item = await product.get('collectionId', 'productId') } catch (error) { if (error instanceof SmartlinksApiError) { console.error('Status:', error.statusCode) // 404 console.error('Message:', error.message) // "Error 404: Not found" console.error('URL:', error.url) // "/public/collection/..." } } ``` **Using Helper Methods:** ```typescript try { await product.create('collectionId', data) } catch (error) { if (error instanceof SmartlinksApiError) { if (error.isAuthError()) { // Handle 401/403 - redirect to login redirectToLogin() } else if (error.isNotFound()) { // Handle 404 showNotFound() } else if (error.isRateLimited()) { // Handle 429 - implement retry with backoff await retryAfterDelay() } else if (error.isServerError()) { // Handle 5xx showMaintenanceMessage() } } } ``` **Accessing Server Error Codes:** ```typescript try { await broadcasts.send('collectionId', 'broadcastId', options) } catch (error) { if (error instanceof SmartlinksApiError) { // Extract server-defined string error code const serverCode = error.details?.errorCode || error.details?.error switch (serverCode) { case 'NOT_AUTHORIZED': redirectToLogin() break case 'broadcasts.topic.invalid': showTopicSelector() break case 'sendgrid.provision.failed': alertAdmin('Email service error') break default: showError(error.message) } } } ``` **Error Logging for Monitoring:** ```typescript try { await api.someMethod() } catch (error) { if (error instanceof SmartlinksApiError) { // Log structured error data logger.error('API Error', error.toJSON()) // Send to monitoring service Sentry.captureException(error, { extra: error.toJSON(), tags: { statusCode: error.statusCode, serverErrorCode: error.details?.errorCode || error.details?.error, } }) } } ``` **Handling Validation Errors:** ```typescript try { await product.create('collectionId', formData) } catch (error) { if (error instanceof SmartlinksApiError && error.statusCode === 400) { // Access field-specific validation errors if available if (error.details?.fields) { Object.entries(error.details.fields).forEach(([field, message]) => { showFieldError(field, String(message)) }) } else { showError(error.message) } } } ``` **Retry Logic for Transient Errors:** ```typescript async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> { for (let attempt = 0; attempt < maxRetries; attempt++) { try { return await fn() } catch (error) { if (error instanceof SmartlinksApiError) { // Only retry server errors and rate limiting const shouldRetry = error.isServerError() || error.isRateLimited() if (!shouldRetry || attempt === maxRetries - 1) { throw error } // Exponential backoff const delay = 1000 * Math.pow(2, attempt) await new Promise(resolve => setTimeout(resolve, delay)) } else { throw error } } } throw new Error('Max retries exceeded') } // Usage const collections = await withRetry(() => collection.list()) ``` ### Error Code Reference **HTTP Status Codes (numeric):** - `400` - Bad Request (invalid input) - `401` - Unauthorized (authentication required) - `403` - Forbidden (insufficient permissions) - `404` - Not Found (resource doesn't exist) - `429` - Too Many Requests (rate limited) - `500` - Internal Server Error - `502` - Bad Gateway - `503` - Service Unavailable **Server Error Codes (strings in `details.errorCode` or `details.error`):** Examples include: - `"NOT_AUTHORIZED"` - Not authorized for this action - `"broadcasts.topic.invalid"` - Invalid communication topic - `"broadcasts.manual.segment.missing"` - Missing required segment - `"sendgrid.provision.failed"` - Email service provisioning failed - `"validation.failed"` - Request validation failed *Note: Server error codes use either `UPPERCASE_UNDERSCORE` or `dotted.notation` format. Both are supported.* ## Types ### ai **ContentPart** (interface) ```typescript interface ContentPart { type: 'text' | 'image_url' text?: string image_url?: { url: string detail?: 'auto' | 'low' | 'high' } } ``` **FunctionCall** (interface) ```typescript interface FunctionCall { name: string arguments: string } ``` **ToolCall** (interface) ```typescript interface ToolCall { id: string type: 'function' function: { name: string arguments: string } } ``` **ChatMessage** (interface) ```typescript interface ChatMessage { role: 'system' | 'user' | 'assistant' | 'function' | 'tool' content: string | ContentPart[] name?: string function_call?: FunctionCall tool_calls?: ToolCall[] tool_call_id?: string } ``` **ToolDefinition** (interface) ```typescript interface ToolDefinition { type: 'function' function: { name: string description: string parameters: { type: 'object' properties: Record<string, { type: string description?: string enum?: string[] }> required?: string[] } } } ``` **ChatCompletionRequest** (interface) ```typescript interface ChatCompletionRequest { messages: ChatMessage[] model?: string stream?: boolean tools?: ToolDefinition[] tool_choice?: 'none' | 'auto' | 'required' | { type: 'function'; function: { name: string } } temperature?: number max_tokens?: number top_p?: number frequency_penalty?: number presence_penalty?: number response_format?: { type: 'text' | 'json_object' } user?: string } ``` **ChatCompletionChoice** (interface) ```typescript interface ChatCompletionChoice { index: number message: ChatMessage finish_reason: 'stop' | 'length' | 'function_call' | 'tool_calls' | 'content_filter' | null } ``` **ChatCompletionResponse** (interface) ```typescript interface ChatCompletionResponse { id: string object: 'chat.completion' created: number model: string choices: ChatCompletionChoice[] usage: { prompt_tokens: number completion_tokens: number total_tokens: number } } ``` **ChatCompletionChunk** (interface) ```typescript interface ChatCompletionChunk { id: string object: 'chat.completion.chunk' created: number model: string choices: Array<{ index: number delta: Partial<ChatMessage> finish_reason: string | null }> } ``` **AIModel** (interface) ```typescript interface AIModel { id: string provider: 'gemini' | 'openai' modelId: string name: string description: string capabilities: Array<'text' | 'vision' | 'audio' | 'code'> contextWindow: number pricing: { input: number output: number cached?: number } features: string[] recommended?: string } ``` **DocumentChunk** (interface) ```typescript interface DocumentChunk { text: string embedding: number[] metadata: { chunkIndex: number documentId: string [key: string]: any } } ``` **IndexDocumentRequest** (interface) ```typescript interface IndexDocumentRequest { productId: string text?: string documentUrl?: string metadata?: Record<string, any> chunkSize?: number overlap?: number provider?: 'openai' | 'gemini' } ``` **IndexDocumentResponse** (interface) ```typescript interface IndexDocumentResponse { success: boolean productId: string documentId: string chunks: number metadata: { textLength: number chunkSize: number overlap: number embeddingDimensions: number } sample?: { text: string chunkIndex: number } } ``` **ConfigureAssistantRequest** (interface) ```typescript interface ConfigureAssistantRequest { productId: string systemPrompt?: string model?: string maxTokensPerResponse?: number temperature?: number rateLimitPerUser?: number allowedTopics?: string[] customInstructions?: { tone?: string additionalRules?: string [key: string]: any } } ``` **ConfigureAssistantResponse** (interface) ```typescript interface ConfigureAssistantResponse { success: boolean configuration: { productId: string systemPrompt: string model: string maxTokensPerResponse: number temperature: number rateLimitPerUser: number allowedTopics: string[] customInstructions?: Record<string, any> updatedAt: string } } ``` **PublicChatRequest** (interface) ```typescript interface PublicChatRequest { productId: string userId: string message: string sessionId?: string stream?: boolean } ``` **PublicChatResponse** (interface) ```typescript interface PublicChatResponse { message: string sessionId: string usage: { prompt_tokens: number completion_tokens: number total_tokens: number } context?: { chunksUsed: number topSimilarity: number } } ``` **Session** (interface) ```typescript interface Session { sessionId: string productId: string userId: string messageCount: number createdAt: string lastActivityAt: string messages: ChatMessage[] } ``` **RateLimitStatus** (interface) ```typescript interface RateLimitStatus { used: number remaining: number resetAt: string } ``` **SessionStatistics** (interface) ```typescript interface SessionStatistics { totalSessions: number activeSessions: number totalMessages: number rateLimitedUsers: number } ``` **VoiceSessionRequest** (interface) ```typescript interface VoiceSessionRequest { productId: string userId: string collectionId: string settings?: { voice?: string language?: string model?: string } } ``` **VoiceSessionResponse** (interface) ```typescript interface VoiceSessionResponse { token: string systemInstruction: string expiresAt: string productName: string } ``` **EphemeralTokenRequest** (interface) ```typescript interface EphemeralTokenRequest { settings?: { ttl?: number voice?: string language?: string model?: string } } ``` **EphemeralTokenResponse** (interface) ```typescript interface EphemeralTokenResponse { token: string expiresAt: string } ``` **TranscriptionResponse** (interface) ```typescript interface TranscriptionResponse { text: string } ``` **TTSRequest** (interface) ```typescript interface TTSRequest { text: string voice?: 'alloy' | 'echo' | 'fable' | 'onyx' | 'nova' | 'shimmer' speed?: number format?: 'mp3' | 'opus' | 'aac' | 'flac' } ``` **GeneratePodcastRequest** (interface) ```typescript interface GeneratePodcastRequest { productId: string documentText?: string duration?: number style?: 'casual' | 'professional' | 'educational' | 'entertaining' voices?: { host1?: string host2?: string } includeAudio?: boolean language?: string customInstructions?: string } ``` **PodcastScript** (interface) ```typescript interface PodcastScript { title: string description: string segments: Array<{ speaker: 'host1' | 'host2' text: string timestamp?: number duration?: number }> } ``` **GeneratePodcastResponse** (interface) ```typescript interface GeneratePodcastResponse { success: boolean podcastId: string script: PodcastScript audio?: { host1Url?: string host2Url?: string mixedUrl?: string } metadata: { duration: number wordCount: number generatedAt: string } } ``` **PodcastStatus** (interface) ```typescript interface PodcastStatus { podcastId: string status: 'generating_script' | 'generating_audio' | 'mixing' | 'completed' | 'failed' progress: number estimatedTimeRemaining?: number error?: string result?: GeneratePodcastResponse } ``` **AIGenerateContentRequest** (interface) ```typescript interface AIGenerateContentRequest { contents: string | any responseMimeType?: string systemInstruction?: string provider?: string model?: string [key: string]: any } ``` **AIGenerateImageRequest** (interface) ```typescript interface AIGenerateImageRequest { prompt: string provider?: string model?: string * Requested image size. * OpenAI supported values: '1024x1024', '1024x1792', '1792x1024' * Other providers may support different sizes. size?: string [key: string]: any } ``` **AISearchPhotosRequest** (interface) ```typescript interface AISearchPhotosRequest { query: string per_page?: number orientation?: 'landscape' | 'portrait' | 'squarish' [key: string]: any } ``` **AISearchPhotosPhoto** (interface) ```typescript interface AISearchPhotosPhoto { url: string alt?: string photographer?: string photographerUrl?: string [key: string]: any } ``` ### appConfiguration **AppConfigurationResponse** (interface) ```typescript interface AppConfigurationResponse { id: string name: string settings?: Record<string, any> } ``` ### appManifest **AppBundle** (interface) ```typescript interface AppBundle { js: string | null; css: string | null; source?: string; styles?: string; } ``` **AppManifestFiles** (interface) ```typescript interface AppManifestFiles { js: { umd: string; esm?: string; }; css?: string; } ``` **AppWidgetComponent** (interface) ```typescript interface AppWidgetComponent { name: string; description?: string; sizes?: Array<'compact' | 'standard' | 'large' | string>; props?: { required?: string[]; optional?: string[]; }; settings?: Record<string, any>; } ``` **AppContainerComponent** (interface) ```typescript interface AppContainerComponent { name: string; description?: string; props?: { required?: string[]; optional?: string[]; }; } ``` **AppAdminConfig** (interface) ```typescript interface AppAdminConfig { $schema?: string; * Path (relative to the app's public root) to an AI guide markdown file. * Provides natural-language context for AI-assisted configuration. * @example "ai-guide.md" aiGuide?: string; setup?: { description?: string; questions?: Array<{ id: string; prompt: string; type: string; default?: any; required?: boolean; options?: Array<{ value: string; label: string }>; }>; configSchema?: Record<string, any>; saveWith?: { method: string; scope: 'collection' | 'product' | string; admin?: boolean; note?: string; }; contentHints?: Record<string, { aiGenerate?: boolean; prompt?: string; }>; }; import?: { description?: string; scope?: string; fields?: Array<{ name: string; type: string; required?: boolean; default?: any; description?: string; }>; csvExample?: string; saveWith?: { method: string; scope: string; admin?: boolean; note?: string; }; }; tunable?: { description?: string; fields?: Array<{ name: string; description?: string; type: string; options?: string[]; }>; }; metrics?: { interactions?: Array<{ id: string; description?: string }>; kpis?: Array<{ name: string; compute?: string }>; }; } ``` **AppManifest** (interface) ```typescript interface AppManifest { $schema?: string; meta?: { name: string; description?: string; version: string; platformRevision?: string; appId: string; }; * Relative path to the admin configuration file (e.g. `"app.admin.json"`). * When present, fetch this file to get the full {@link AppAdminConfig} * (setup questions, import schema, tunable fields, metrics definitions). * Absent when the app has no admin UI. admin?: string; widgets?: { files: AppManifestFiles; components: AppWidgetComponent[]; }; containers?: { files: AppManifestFiles; components: AppContainerComponent[]; }; [key: string]: any; } ``` **CollectionAppWidget** (interface) ```typescript interface CollectionAppWidget { appId: string; manifest: AppManifest; widget: AppBundle; container: AppBundle | null; admin: string | null; } ``` **CollectionWidgetsResponse** (interface) ```typescript interface CollectionWidgetsResponse { apps: CollectionAppWidget[]; } ``` **GetCollectionWidgetsOptions** (interface) ```typescript interface GetCollectionWidgetsOptions { force?: boolean; } ``` ### appObjects **PaginatedResponse<T>** (interface) ```typescript interface PaginatedResponse<T> { data: T[] pagination: { total: number limit: number offset: number hasMore: boolean } } ``` **AggregateRequest** (interface) ```typescript interface AggregateRequest { filters?: { status?: string category?: string // cases only record_type?: string // records only product_id?: string created_at?: { gte?: string; lte?: string } closed_at?: '__notnull__' | { gte?: string; lte?: string } // cases only expires_at?: { lte?: string } // records only } groupBy?: string[] // see per-resource allowed values metrics?: string[] // see per-resource allowed values below timeSeriesField?: string // e.g. 'created_at' timeSeriesInterval?: 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year' } ``` **AggregateResponse** (interface) ```typescript interface AggregateResponse { groups?: ({ count: number } & Record<string, unknown>)[] timeSeries?: ({ bucket: string; count: number } & Record<string, unknown>)[] count?: number avg_close_time_seconds?: number p50_close_time_seconds?: number p95_close_time_seconds?: number total_replies?: number avg_replies?: number } ``` **ListQueryParams** (interface) ```typescript interface ListQueryParams { limit?: number // default 50, max 500 offset?: number // default 0 sort?: string // field:asc or field:desc includeDeleted?: boolean // admin only status?: string // exact or in:a,b,c productId?: string createdAt?: string // gte:2024-01-01, lte:2024-12-31, or ISO date string updatedAt?: string // same format } ``` **AppCase** (interface) ```typescript interface AppCase { id: string orgId: string collectionId: string appId: string visibility: Visibility ref: string | null status: string // 'open' | 'resolved' | 'closed' | custom priority: number | null category: string | null assignedTo: string | null // admin zone / admin callers only productId: string | null proofId: string | null contactId: string | null createdAt: string // ISO 8601 updatedAt: string closedAt: string | null deletedAt: string | null // admin callers only data: Record<string, unknown> // visible to all roles owner: Record<string, unknown> // visible to owner + admin admin: Record<string, unknown> // visible to admin only } ``` **CreateCaseInput** (interface) ```typescript interface CreateCaseInput { visibility?: Visibility // default 'owner' ref?: string status?: string // default 'open' priority?: number category?: string assignedTo?: string // admin only productId?: string proofId?: string contactId?: string data?: Record<string, unknown> owner?: Record<string, unknown> admin?: Record<string, unknown> // admin only } ``` **UpdateCaseInput** (interface) ```typescript interface UpdateCaseInput { data?: Record<string, unknown> owner?: Record<string, unknown> admin?: Record<string, unknown> status?: string priority?: number category?: string assignedTo?: string ref?: string } ``` **AppendHistoryInput** (interface) ```typescript interface AppendHistoryInput { entry?: Record<string, unknown> // free-form entry object; 'at' is auto-set historyTarget?: 'owner' | 'admin' // which zone receives the entry (default 'admin') status?: string // optionally update status atomically priority?: number assignedTo?: string } ``` **CaseSummaryRequest** (interface) ```typescript interface CaseSummaryRequest { period?: { from: string; to: string } // ISO 8601 date range } ``` **CaseSummaryResponse** (interface) ```typescript interface CaseSummaryResponse { total: number byStatus: Record<string, number> byPriority: Record<string, number> trend: { week: string; count: number }[] } ``` **ReplyEntry** (interface) ```typescript interface ReplyEntry { at: string // ISO 8601, auto-set authorId?: string authorType?: string [key: string]: unknown } ``` **AppThread** (interface) ```typescript interface AppThread { id: string orgId: string collectionId: string appId: string visibility: Visibility slug: string | null title: string | null status: string // 'open' | 'closed' | custom authorId: string | null authorType: string // default 'user' productId: string | null proofId: string | null contactId: string | null parentType: string | null parentId: string | null replyCount: number lastReplyAt: string | null createdAt: string updatedAt: string deletedAt: string | null // admin only body: Record<string, unknown> replies: ReplyEntry[] tags: string[] data: Record<string, unknown> owner: Record<string, unknown> admin: Record<string, unknown> // admin only } ``` **CreateThreadInput** (interface) ```typescript interface CreateThreadInput { visibility?: Visibility // default 'owner' slug?: string title?: string status?: string // default 'open' authorId?: string authorType?: string productId?: string proofId?: string contactId?: string parentType?: string parentId?: string body?: Record<string, unknown> tags?: string[] data?: Record<string, unknown> owner?: Record<string, unknown> admin?: Record<string, unknown> // admin only } ``` **UpdateThreadInput** (interface) ```typescript interface UpdateThreadInput { body?: Record<string, unknown> tags?: string[] data?: Record<string, unknown> owner?: Record<string, unknown> admin?: Record<string, unknown> title?: string slug?: string status?: string visibility?: Visibility } ``` **ReplyInput** (interface) ```typescript interface ReplyInput { authorId?: string authorType?: string [key: string]: unknown // any extra fields stored on the reply object } ``` **AppRecord** (interface) ```typescript interface AppRecord { id: string orgId: string collectionId: string appId: string visibility: Visibility recordType: string ref: string | null status: string // default 'active' productId: string | null proofId: string | null contactId: string | null authorId: string | null authorType: string parentType: string | null parentId: string | null createdAt: string updatedAt: string startsAt: string | null expiresAt: string | null deletedAt: string | null // admin only data: Record<string, unknown> owner: Record<string, unknown> admin: Record<string, unknown> // admin only } ``` **CreateRecordInput** (interface) ```typescript interface CreateRecordInput { recordType: string visibility?: Visibility // default 'owner' ref?: string status?: string // default 'active' productId?: string proofId?: string contactId?: string authorId?: string authorType?: string parentType?: string parentId?: string startsAt?: string // ISO 8601 expiresAt?: string data?: Record<string, unknown> owner?: Record<string, unknown> admin?: Record<string, unknown> // admin only } ``` **UpdateRecordInput** (interface) ```typescript interface UpdateRecordInput { data?: Record<string, unknown> owner?: Record<string, unknown> admin?: Record<string, unknown> status?: string visibility?: Visibility ref?: string recordType?: string startsAt?: string expiresAt?: string } ``` **RelatedResponse** (interface) ```typescript interface RelatedResponse { threads: AppThread[] records: AppRecord[] } ``` **PublicCreatePolicy** (interface) ```typescript interface PublicCreatePolicy { cases?: PublicCreateRule threads?: PublicCreateRule records?: PublicCreateRule } ``` **PublicCreateRule** (interface) ```typescript interface PublicCreateRule { allow: { anonymous?: boolean authenticated?: boolean } enforce?: { anonymous?: Partial<CreateCaseInput | CreateThreadInput | CreateRecordInput> authenticated?: Partial<CreateCaseInput | CreateThreadInput | CreateRecordInput> } } ``` **Visibility** = `'public' | 'owner' | 'admin'` **CallerRole** = `'admin' | 'owner' | 'public'` ### asset **Asset** (interface) ```typescript interface Asset { id: string url: string name: string mimeType?: string size?: number createdAt?: string metadata?: Record<string, any> assetType?: string type?: string collectionId?: string hash?: string thumbnails?: { x100?: string x200?: string x512?: string [key: string]: string | undefined } site?: string cleanName?: string } ``` **UploadAssetOptions** (interface) ```typescript interface UploadAssetOptions { file: File scope: | { type: 'collection'; collectionId: string } | { type: 'product'; collectionId: string; productId: string } | { type: 'proof'; collectionId: string; productId: string; proofId: string } name?: string metadata?: Record<string, any> onProgress?: (percent: number) => void appId?: string admin?: boolean } ``` **UploadFromUrlOptions** (interface) ```typescript interface UploadFromUrlOptions { url: string scope: | { type: 'collection'; collectionId: string } | { type: 'product'; collectionId: string; productId: string } | { type: 'proof'; collectionId: string; productId: string; proofId: string } folder?: 'images' | 'videos' | 'documents' metadata?: Record<string, any> appId?: string admin?: boolean } ``` **ListAssetsOptions** (interface) ```typescript interface ListAssetsOptions { scope: | { type: 'collection'; collectionId: string } | { type: 'product'; collectionId: string; productId: string } | { type: 'proof'; collectionId: string; productId: string; proofId: string } appId?: string mimeTypePrefix?: string limit?: number offset?: number } ``` **GetAssetOptions** (interface) ```typescript interface GetAssetOptions { assetId: string scope: | { type: 'collection'; collectionId: string } | { type: 'product'; collectionId: string; productId: string } | { type: 'proof'; collectionId: string; productId: string; proofId: string } } ``` **RemoveAssetOptions** (interface) ```typescript interface RemoveAssetOptions { assetId: string scope: | { type: 'collection'; collectionId: string } | { type: 'product'; collectionId: string; productId: string } | { type: 'proof'; collectionId: string; productId: string; proofId: string } } ``` **AssetResponse** = `Asset` ### attestation **AttestationResponse** (interface) ```typescript interface AttestationResponse { id: string createdAt: string updatedAt: string public: Record<string, any> private: Record<string, any> proof: Record<string, any> } ``` **AttestationCreateRequest** (interface) ```typescript interface AttestationCreateRequest { public: Record<string, any> private: Record<string, any> proof: Record<string, any> } ``` **AttestationUpdateRequest** (interface) ```typescript interface AttestationUpdateRequest { type?: string data?: Record<string, any> } ``` ### auth **UserAccountRegistrationRequest** (interface) ```typescript interface UserAccountRegistrationRequest { name: string email?: string phone?: string password?: string sendAccountConfirmation?: boolean collectionId?: string, tokenType?: 'bearer' | 'firebase' } ``` ### authKit **AuthKitUser** (interface) ```typescript interface AuthKitUser { uid: string email?: string displayName?: string | null photoURL?: string | null phoneNumber?: string | null emailVerified?: boolean accountData?: Record<string, any> } ``` **UserProfile** (interface) ```typescript interface UserProfile { uid: string email?: string displayName?: string | null phoneNumber?: string | null photoURL?: string | null emailVerified?: boolean accountData?: Record<string, any> } ``` **ProfileUpdateData** (interface) ```typescript interface ProfileUpdateData { displayName?: string photoURL?: string accountData?: Record<string, any> } ``` **SuccessResponse** (interface) ```typescript interface SuccessResponse { success: boolean message?: string token?: string // some flows may return a refreshed token } ``` **AuthLoginResponse** (interface) ```typescript interface AuthLoginResponse { token?: string user: AuthKitUser accountData?: Record<string, any> emailVerificationMode?: 'immediate' | 'verify-auto-login' | 'verify-manual-login' requiresEmailVerification?: boolean // True if email verification is required but not yet completed emailVerificationDeadline?: number // Unix timestamp - for 'immediate' mode grace period deadline accountLocked?: boolean // True if account is locked due to expired verification deadline } ``` **MagicLinkSendResponse** (interface) ```typescript interface MagicLinkSendResponse { success: boolean message: string } ``` **PhoneSendCodeResponse** (interface) ```typescript interface PhoneSendCodeResponse { verificationId: string message: string } ``` **PhoneVerifyResponse** (interface) ```typescript interface PhoneVerifyResponse { token: string user: AuthKitUser } ``` **PasswordResetRequestResponse** (interface) ```typescript interface PasswordResetRequestResponse { success: boolean message: string } ``` **VerifyResetTokenResponse** (interface) ```typescript interface VerifyResetTokenResponse { valid: boolean email?: string expiresAt?: number message?: string } ``` **PasswordResetCompleteResponse** (interface) ```typescript interface PasswordResetCompleteResponse { success: boolean message: string } ``` **EmailVerificationActionResponse** (interface) ```typescript interface EmailVerificationActionResponse { success: boolean message: string } ``` **EmailVerifyTokenResponse** (interface) ```typescript interface EmailVerifyTokenResponse { success: boolean message: string token?: string user?: AuthKitUser accountData?: Record<string, any> emailVerificationMode?: 'immediate' | 'verify-auto-login' | 'verify-manual-login' } ``` **AuthKitBrandingConfig** (interface) ```typescript interface AuthKitBrandingConfig { logoUrl?: string title?: string subtitle?: string primaryColor?: string secondaryColor?: string backgroundColor?: string buttonStyle?: string fontFamily?: string } ``` **AuthKitConfig** (interface) ```typescript interface AuthKitConfig { id: string branding?: AuthKitBrandingConfig enabledProviders?: string[] customCss?: string termsUrl?: string privacyUrl?: string supportEmail?: string redirectUrl?: string updatedAt?: string } ``` ### batch **FirebaseTimestamp** (interface) ```typescript interface FirebaseTimestamp { seconds: number // Unix timestamp in seconds nanoseconds?: number // Nanoseconds component } ``` **BatchResponse** (interface) ```typescript interface BatchResponse { id: string // Batch ID name?: string // Batch name expiryDate?: FirebaseTimestamp | string // Firebase timestamp or ISO 8601 date productId?: string // Product ID (for collection-level searches) collectionId?: string // Collection ID [key: string]: any // Additional batch fields } ``` **BatchCreateRequest** (interface) ```typescript interface BatchCreateRequest { id: string // Batch ID name?: string // Batch name expiryDate?: FirebaseTimestamp | string // Firebase timestamp or ISO 8601 date [key: string]: any // Additional batch fields } ``` **BatchUpdateRequest** (interface) ```typescript interface BatchUpdateRequest { name?: string // Batch name expiryDate?: FirebaseTimestamp | string // Firebase timestamp or ISO 8601 date [key: string]: any // Additional batch fields } ``` **SearchBatchesRequest** (interface) ```typescript interface SearchBatchesRequest { search?: string // Search term (batch ID or name) productId?: string // Filter by specific product limit?: number // Max results (default: 100) } ``` **BatchTag** (interface) ```typescript interface BatchTag { code: string // Code/tag ID claimSetId: string // Claim set ID collectionId?: string // Collection ID productId?: string // Associated product ID batchId?: string // Batch ID tagId?: string // Tag identifier index?: number // Position in claim set } ``` ### broadcasts **ListBroadcastsQuery** (interface) ```typescript interface ListBroadcastsQuery { limit?: number offset?: number appId?: string } ``` **BroadcastRecord** (interface) ```typescript interface BroadcastRecord { id: string collectionId: string appId: string templateId?: string | null segmentId?: string | null status?: string | null scheduledAt?: string | null sentAt?: string | null data?: { display?: { title?: string description?: string icon?: string color?: string } broadcastType?: string topic: string templateParams?: Record<string, unknown>; channelSettings?: { mode?: 'preferred' | 'channels' | 'all' channels?: Array<{ channel: BroadcastChannel enabled?: boolean priority?: number }> } [key: string]: unknown } createdAt: string } ``` **BroadcastList** (interface) ```typescript interface BroadcastList { items: BroadcastRecord[] limit: number offset: number } ``` **BroadcastRecipientsResponse** (interface) ```typescript interface BroadcastRecipientsResponse { items: import('./comms').Recipient[] total: number limit: number offset: number note?: string } ``` **BroadcastPreviewRequest** (interface) ```typescript interface BroadcastPreviewRequest { contactId?: string email?: string phone?: string props?: Record<string, any> channelOverride?: BroadcastChannel hydrate?: boolean include?: { product?: boolean; proof?: boolean; user?: boolean; [k: string]: boolean | undefined } } ``` **BroadcastSendTestRequest** (interface) ```typescript interface BroadcastSendTestRequest { contactId?: string email?: string phone?: string props?: Record<string, any> channelOverride?: BroadcastChannel hydrate?: boolean include?: { product?: boolean; proof?: boolean; user?: boolean; [k: string]: boolean | undefined } } ``` **BroadcastSendTestResponse** (interface) ```typescript interface BroadcastSendTestResponse { ok: boolean; id?: string; channel?: BroadcastChannel } ``` **BroadcastSendManualRequest** (interface) ```typescript interface BroadcastSendManualRequest { limit?: number offset?: number dryRun?: boolean sharedContext?: Record<string, any> } ``` **BroadcastSendManualResponse** (interface) ```typescript interface BroadcastSendManualResponse { ok: boolean counts: { sent: number; failed: number; skipped: number } page: { limit: number; offset: number; total: number } results: Array<{ contactId: string status: 'sent' | 'failed' | 'skipped' | 'dry_run' id?: string error?: string message?: string }> } ``` **BroadcastSendRequest** (interface) ```typescript interface BroadcastSendRequest { pageSize?: number maxPages?: number sharedContext?: Record<string, any> channel?: BroadcastChannel hydrate?: boolean include?: { product?: boolean; proof?: boolean; user?: boolean; [k: string]: boolean | undefined } } ``` **BroadcastAppendEventBody** (interface) ```typescript interface BroadcastAppendEventBody { broadcastId: string contactId?: string channel?: BroadcastChannel templateId?: string eventType: string outcome?: 'success' | 'failed' failureReason?: string metadata?: Record<string, any> } ``` **BroadcastAppendBulkBody** (interface) ```typescript interface BroadcastAppendBulkBody { ids: string[] idField?: string params: Record<string, any> // merged with collectionId server-side } ``` **BroadcastChannel** = `'email' | 'push' | 'sms' | 'wallet'` **BroadcastPreviewResponse** = `` ### claimSet **ClaimCodeRef** (interface) ```typescript interface ClaimCodeRef { codeId: string claimId: string } ``` **UpdateClaimDataRequest** (interface) ```typescript interface UpdateClaimDataRequest { data: Record<string, any> codes: ClaimCodeRef[] } ``` **AssignClaimsRequest** (interface) ```typescript interface AssignClaimsRequest { id: string collectionId: string productId: string batchId?: string start?: number end?: number codeId?: string data?: Record<string, any> } ``` ### collection **Collection** (interface) ```typescript interface Collection { id: string title: string description: string headerImage?: { url: string thumbnails: { x100: string x200: string x512: string } } logoImage?: { url: string thumbnails: { x100: string x200: string x512: string } } loaderImage?: { overwriteName: string name: string type: string url: string } languages?: { code: string lang: string supported: boolean }[], roles: { [userId: string]: string } // User roles mapping with user IDs as keys and role names as values groupTags?: string[] // Array of group tag names redirectUrl?: string // Whether the collection has a custom domain shortId: string, // The shortId of this collection dark?: boolean // if dark mode is enabled for this collection primaryColor?: string secondaryColor?: string portalUrl?: string // URL for the collection's portal (if applicable) allowAutoGenerateClaims?: boolean defaultAuthKitId: string // default auth kit for this collection, used for auth } ``` **AppConfig** (interface) ```typescript interface AppCo