Surflet

TypeScript SDK

TypeScript SDK installation and usage guide

Installation

pnpm add @surflet/sdk
# or
npm install @surflet/sdk

Initialize the Client

import { Surflet } from '@surflet/sdk';

const client = new Surflet({
  apiKey: 'sk_live_...',
  baseUrl: 'https://api.surflet.app',  // optional, defaults to production
  timeout: 30000,                       // optional, timeout in milliseconds
});

Via environment variables:

export SURFLET_API_KEY=sk_live_...
export SURFLET_API_URL=https://api.surflet.app
const client = new Surflet();  // automatically reads environment variables

Quick Publish

const page = await client.publish({
  title: 'Daily Briefing',
  content: '## Summary\n\nAll systems operational.',
});

console.log(page.pageUrl);

Structured Publish

Use builder functions to create structured content:

import {
  Surflet,
  keyValue,
  callout,
  table,
  action,
  access,
} from '@surflet/sdk';

const client = new Surflet({
  apiKey: 'sk_test_surflet123',
  baseUrl: 'http://localhost:3001',
});

const page = await client.publish({
  pageType: 'approval',
  title: 'Server Purchase Request',
  blocks: [
    keyValue('Details', [
      { key: 'Vendor', value: 'Dell' },
      { key: 'Model', value: 'PowerEdge R760' },
      { key: 'Quantity', value: '5' },
      { key: 'Amount', value: '$15,000' },
    ]),
    callout('Within Q1 budget allocation', 'info'),
    table({
      title: 'Cost Breakdown',
      columns: [
        { key: 'item', label: 'Item' },
        { key: 'qty', label: 'Quantity' },
        { key: 'price', label: 'Unit Price' },
        { key: 'total', label: 'Total' },
      ],
      rows: [
        { item: 'Server', qty: '5', price: '$2,500', total: '$12,500' },
        { item: 'RAM Upgrade', qty: '5', price: '$300', total: '$1,500' },
        { item: 'Setup Fee', qty: '1', price: '$1,000', total: '$1,000' },
      ],
    }),
  ],
  actions: [
    action('approve', 'Approve Purchase', { style: 'primary' }),
    action('reject', 'Reject', { style: 'danger', requiresComment: true }),
  ],
  access: access.authenticated({ emails: ['[email protected]'] }),
  onAction: {
    defaultUrl: 'https://your-agent.example.com/webhook/surflet',
  },
});

Block Builders

keyValue — Key-Value Pairs

keyValue('User Profile', [
  { key: 'Name', value: 'Alice Wang' },
  { key: 'Email', value: '[email protected]' },
  { key: 'Role', value: 'Engineering Manager' },
]);

text — Markdown Rich Text

import { text } from '@surflet/sdk';

text('## Analysis Report\n\nDetailed findings...', { title: 'Report' });

table — Data Table

table({
  title: 'Team Members',
  columns: [
    { key: 'name', label: 'Name' },
    { key: 'role', label: 'Role' },
  ],
  rows: [
    { name: 'Alice', role: 'Manager' },
    { name: 'Bob', role: 'Engineer' },
  ],
});

callout — Callout Box

callout('This is an important notice', 'warning');
// Supported styles: 'info' | 'warning' | 'error' | 'success'

code — Code Block

import { code } from '@surflet/sdk';

code("console.log('hello')", {
  language: 'javascript',
  title: 'Example',
});

timeline — Timeline

import { timeline } from '@surflet/sdk';

timeline([
  { time: '2026-03-20 10:00', event: 'Created', detail: 'User submitted ticket' },
  { time: '2026-03-20 11:30', event: 'Analyzed', detail: 'AI recommended refund' },
], { title: 'Event History' });

chart — Chart

import { chart } from '@surflet/sdk';

chart({
  chartType: 'bar',
  data: {
    labels: ['Q1', 'Q2', 'Q3', 'Q4'],
    datasets: [{ label: 'Revenue', data: [100, 200, 150, 300] }],
  },
  title: 'Quarterly Revenue',
});

diff — Diff View

import { diff } from '@surflet/sdk';

diff({
  oldText: 'old version content',
  newText: 'new version content',
  language: 'python',
  title: 'Config Changes',
});
import { gallery } from '@surflet/sdk';

gallery([
  { url: 'https://example.com/img1.png', caption: 'Damage photo' },
  { url: 'https://example.com/img2.png', caption: 'Packaging' },
], { title: 'Evidence' });

form — Interactive Form

import { form } from '@surflet/sdk';

form([
  { fieldId: 'amount', type: 'number', label: 'Refund Amount', required: true },
  { fieldId: 'reason', type: 'textarea', label: 'Reason' },
], { title: 'Refund Details' });

divider — Divider

import { divider } from '@surflet/sdk';

divider();

Action Builder

action('approve', 'Approve', {
  style: 'primary',            // 'primary' | 'secondary' | 'danger'
  requiresComment: false,
  confirmMessage: 'Are you sure you want to approve?',
});

Access Builder

// Public access
access.public();

// Specific identities
access.authenticated({ emails: ['[email protected]'] });

// Single-use link
access.oneTime({ burnAfter: 300 });

// Time-limited
access.timeLimited({ expiresAt: '2026-04-01T00:00:00Z' });

// Password protection
access.password({ passwordHash: 'sha256:...' });

Publish from Template

// List available templates
const templates = await client.listTemplates();
templates.templates.forEach((t) => console.log(`${t.name}: ${t.description}`));

// Publish from template
const page = await client.publishTemplate('refund_approval', {
  customer: 'Alice Wang',
  order_id: '#ORD-7891',
  amount: 127.50,
  reason: 'Product damaged on arrival',
  risk_score: 15,
});
console.log(page.pageUrl);

Append Blocks (Streaming Publish)

import { Surflet, callout, keyValue, chart, text } from '@surflet/sdk';

const client = new Surflet({ apiKey: 'sk_live_...' });

// Create the initial page
const page = await client.publish({
  title: 'Analysis Report',
  blocks: [callout('Analyzing data...', 'info')],
});

// Append analysis results
await client.appendBlocks(page.pageId, [
  keyValue('Key Metrics', [
    { key: 'Total Tickets', value: '156' },
    { key: 'Resolution Rate', value: '94%' },
  ]),
  chart({
    chartType: 'line',
    data: {
      labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
      datasets: [{ label: 'Tickets', data: [28, 35, 22, 41, 30] }],
    },
    title: 'Daily Tickets',
  }),
]);

// Continue appending
await client.appendBlocks(page.pageId, [
  text('## Summary\n\nTicket resolution improved by 12% this week.', { title: 'Summary' }),
]);

Analytics & Quality Score

// Get page view analytics
const analytics = await client.getAnalytics('pg_xxx');
console.log(`Total views: ${analytics.totalViews}`);
console.log(`Unique viewers: ${analytics.uniqueViewers}`);

// Get agent quality score
const score = await client.getQualityScore();
console.log(`Quality Score: ${score.score}/100`);
console.log(`Acceptance Rate: ${score.acceptanceRate}%`);

Query and Actions

// Get a page
const page = await client.getPage('pg_xxx');
console.log(page.status);

// Revoke a page
await client.revokePage('pg_xxx');

// Inbox
const inbox = await client.getInbox({ status: 'pending' });
for (const item of inbox.items) {
  console.log(`${item.title} - ${item.priority}`);
}

// Approval actions
await client.approve('pg_xxx', { comment: 'Looks good' });
await client.reject('pg_xxx', { comment: 'Need more details' });

Type Definitions

The TypeScript SDK provides complete type definitions:

import type {
  PublishOptions,
  Page,
  Block,
  Action,
  AccessConfig,
  ApprovalChain,
  OnActionConfig,
  InboxResponse,
} from '@surflet/sdk';