.do

api - HTTP Client

Complete guide to HTTP operations and service proxy in MCP.do - external API calls, webhook handling, integration with Stripe, GitHub, Email, Composio, and Zapier

api - HTTP Client & Service Proxy

The api primitive provides a powerful HTTP client for external API calls and a service proxy for seamless integration with third-party services. It handles authentication, error handling, retries, and provides type-safe methods for popular integrations.

Overview

The API client is designed for:

  • External API Calls: Make HTTP requests to any external service
  • Service Proxy: Access integrated services (Stripe, GitHub, Email)
  • Auto-Routing: Intelligent tier-based routing (Tier 1 → 2 → 3)
  • Type Safety: Full TypeScript support with typed responses
  • Error Handling: Comprehensive error handling with retry logic
  • Authentication: Automatic credential management
  • Rate Limiting: Built-in rate limit handling

Architecture

graph TB API[api Primitive] CLIENT[ApiClient] PROXY[Service Proxy] EXTERNAL[External APIs] TIER1[Tier 1: Native Workers] TIER2[Tier 2: Composio] TIER3[Tier 3: Zapier] API --> CLIENT API --> PROXY CLIENT --> EXTERNAL PROXY --> TIER1 PROXY --> TIER2 PROXY --> TIER3 TIER1 --> STRIPE[Stripe] TIER1 --> GITHUB[GitHub] TIER1 --> EMAIL[Email] TIER2 --> APPS2[200+ Apps] TIER3 --> APPS3[6000+ Apps]

Type Signatures

interface ApiClient {
  // Core HTTP methods
  fetch(
    url: string,
    options?: {
      method?: string
      headers?: Record<string, string>
      body?: string | object
    }
  ): Promise<Response>

  // Service proxy
  proxy(
    service: string,
    path: string,
    options?: {
      method?: string
      headers?: Record<string, string>
      body?: string | object
    }
  ): Promise<any>

  // Health check
  health(): Promise<ApiRootResponse>
  isHealthy(options?: { throwOnError?: boolean }): Promise<boolean>

  // User info
  user(): Promise<UserInfo>

  // Webhooks
  sendWebhook(provider: string, payload: WebhookPayload, headers?: Record<string, string>): Promise<unknown>
}

// Extended with integrations
interface ApiClientWithIntegrations extends ApiClient {
  stripe: StripeAPI
  github: GitHubAPI
  email: EmailAPI
  composio: ComposioAPI
  zapier: ZapierAPI
  apps: AppsAPI
}

Basic HTTP Operations

Simple GET Request

import { api } from 'sdk.do'

// Fetch external data
const response = await api.fetch('https://api.example.com/data', {
  method: 'GET',
  headers: {
    Accept: 'application/json',
  },
})

const data = await response.json()
console.log(data)

POST Request with JSON Body

const response = await api.fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Accept: 'application/json',
  },
  body: JSON.stringify({
    name: 'Alice Smith',
    email: '[email protected]',
  }),
})

const user = await response.json()
console.log('Created user:', user.id)

Handling Different Response Types

// JSON response
const jsonResponse = await api.fetch('https://api.example.com/json')
const jsonData = await jsonResponse.json()

// Text response
const textResponse = await api.fetch('https://api.example.com/text')
const textData = await textResponse.text()

// Blob response (file download)
const blobResponse = await api.fetch('https://api.example.com/file.pdf')
const blob = await blobResponse.blob()

// Array buffer
const bufferResponse = await api.fetch('https://api.example.com/binary')
const buffer = await bufferResponse.arrayBuffer()

Custom Headers and Authentication

// API key authentication
const response = await api.fetch('https://api.example.com/protected', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_API_KEY',
    'X-API-Version': '2024-01',
    Accept: 'application/json',
  },
})

// Basic authentication
const credentials = btoa('username:password')
const response2 = await api.fetch('https://api.example.com/protected', {
  headers: {
    Authorization: `Basic ${credentials}`,
  },
})

Service Proxy

Proxy to Integrated Services

The service proxy automatically handles authentication and routing:

// Proxy to Stripe
const customer = await api.proxy('stripe', '/v1/customers/cus_123')
console.log(customer)

// Proxy to GitHub
const repo = await api.proxy('github', '/repos/dot-do/platform')
console.log(repo)

// Proxy to Email service
const result = await api.proxy('email', '/send', {
  method: 'POST',
  body: {
    to: '[email protected]',
    subject: 'Hello',
    body: 'Welcome!',
  },
})

Auto-Routing Across Tiers

The proxy automatically tries Tier 1 → Tier 2 → Tier 3:

// Try native integration first, fall back to Composio, then Zapier
const result = await api.apps.execute({
  app: 'notion',
  action: 'createPage',
  params: {
    database_id: 'db_123',
    title: 'New Page',
  },
})

// Automatically routes to:
// 1. Native worker (if exists)
// 2. Composio (if connected)
// 3. Zapier (if configured)

Tier 1: Native Integrations

Stripe Integration

Full Stripe API access with type safety:

import { api } from 'sdk.do'

// Create customer
const customer = await api.stripe.customers.create({
  email: '[email protected]',
  name: 'Alice Smith',
  metadata: {
    userId: 'usr_123',
  },
})

// Get customer
const retrieved = await api.stripe.customers.get(customer.id)

// Update customer
const updated = await api.stripe.customers.update(customer.id, {
  name: 'Alice Johnson',
  metadata: {
    plan: 'premium',
  },
})

// List customers
const customers = await api.stripe.customers.list({
  limit: 10,
  starting_after: 'cus_123',
})

// Delete customer
await api.stripe.customers.delete(customer.id)

Stripe Subscriptions

// Create subscription
const subscription = await api.stripe.subscriptions.create({
  customer: 'cus_123',
  items: [{ price: 'price_monthly' }, { price: 'price_addon', quantity: 2 }],
  trial_period_days: 14,
})

// Get subscription
const sub = await api.stripe.subscriptions.get('sub_123')

// Cancel subscription
await api.stripe.subscriptions.cancel('sub_123')

Stripe Payment Intents

// Create payment intent
const intent = await api.stripe.paymentIntents.create({
  amount: 2000, // $20.00
  currency: 'usd',
  customer: 'cus_123',
  payment_method: 'pm_card_visa',
  confirm: true,
})

// Confirm payment intent
await api.stripe.paymentIntents.confirm(intent.id)

// Cancel payment intent
await api.stripe.paymentIntents.cancel(intent.id)

Stripe Invoices

// Get invoice
const invoice = await api.stripe.invoices.get('in_123')

// List customer invoices
const invoices = await api.stripe.invoices.list({
  customer: 'cus_123',
  limit: 20,
})

GitHub Integration

Complete GitHub API access:

import { api } from 'sdk.do'

// Get repository
const repo = await api.github.repos.get({
  owner: 'dot-do',
  repo: 'platform',
})

// List repositories
const repos = await api.github.repos.list({
  type: 'owner',
  sort: 'updated',
  direction: 'desc',
})

// Create repository
const newRepo = await api.github.repos.create({
  name: 'my-new-repo',
  description: 'A new repository',
  private: false,
  auto_init: true,
})

GitHub Issues

// Create issue
const issue = await api.github.issues.create({
  owner: 'dot-do',
  repo: 'platform',
  title: 'Bug: Login not working',
  body: 'Description of the bug...',
  labels: ['bug', 'priority-high'],
  assignees: ['alice'],
})

// Get issue
const retrieved = await api.github.issues.get({
  owner: 'dot-do',
  repo: 'platform',
  issue_number: 123,
})

// List issues
const issues = await api.github.issues.list({
  owner: 'dot-do',
  repo: 'platform',
  state: 'open',
})

// Update issue
const updated = await api.github.issues.update({
  owner: 'dot-do',
  repo: 'platform',
  issue_number: 123,
  state: 'closed',
  body: 'Fixed in PR #456',
})

GitHub Pull Requests

// Create pull request
const pr = await api.github.pulls.create({
  owner: 'dot-do',
  repo: 'platform',
  title: 'Add new feature',
  body: 'This PR adds...',
  head: 'feature-branch',
  base: 'main',
})

// Get pull request
const retrieved = await api.github.pulls.get({
  owner: 'dot-do',
  repo: 'platform',
  pull_number: 456,
})

// List pull requests
const prs = await api.github.pulls.list({
  owner: 'dot-do',
  repo: 'platform',
  state: 'open',
})

// Merge pull request
const merged = await api.github.pulls.merge({
  owner: 'dot-do',
  repo: 'platform',
  pull_number: 456,
  commit_message: 'Merge: Add new feature',
})

GitHub Files

// Get file
const file = await api.github.files.get({
  owner: 'dot-do',
  repo: 'platform',
  path: 'README.md',
  ref: 'main',
})

console.log(atob(file.content)) // Decode base64 content

// Create file
await api.github.files.create({
  owner: 'dot-do',
  repo: 'platform',
  path: 'docs/new-file.md',
  message: 'Add new documentation',
  content: btoa('# New Documentation\n\nContent here...'),
})

// Update file
await api.github.files.update({
  owner: 'dot-do',
  repo: 'platform',
  path: 'docs/new-file.md',
  message: 'Update documentation',
  content: btoa('# Updated Documentation\n\nNew content...'),
  sha: file.sha, // Required for updates
})

// Delete file
await api.github.files.delete({
  owner: 'dot-do',
  repo: 'platform',
  path: 'docs/old-file.md',
  message: 'Remove old documentation',
  sha: file.sha,
})

Email Integration

Send emails via multiple providers:

import { api } from 'sdk.do'

// Send text email
const result = await api.email.send({
  to: '[email protected]',
  subject: 'Welcome to our platform',
  body: 'Thank you for signing up!',
  from: '[email protected]',
})

// Send HTML email
const htmlResult = await api.email.send({
  to: ['[email protected]', '[email protected]'],
  subject: 'Newsletter',
  body: 'Plain text fallback',
  html: '<h1>Newsletter</h1><p>HTML content here...</p>',
  from: '[email protected]',
})

// Send with attachments
const withAttachments = await api.email.sendWithAttachments({
  to: '[email protected]',
  subject: 'Invoice',
  body: 'Please find your invoice attached',
  attachments: [
    {
      filename: 'invoice.pdf',
      content: pdfBuffer,
      contentType: 'application/pdf',
    },
  ],
})

Email Templates

// Send template email
const result = await api.email.sendTemplate({
  to: '[email protected]',
  template: 'welcome-email',
  variables: {
    name: 'Alice',
    confirmUrl: 'https://example.com/confirm/abc123',
  },
})

Queued Emails

// Queue email for later delivery
const queued = await api.email.sendQueued({
  to: '[email protected]',
  subject: 'Scheduled Newsletter',
  body: 'Content...',
  scheduledFor: new Date(Date.now() + 3600000), // Send in 1 hour
})

console.log(queued.id) // Queue ID for tracking

Helper Methods

// Send text-only email
await api.email.sendText('[email protected]', 'Subject', 'Plain text body')

// Send HTML email
await api.email.sendHtml('[email protected]', 'Subject', '<p>HTML body</p>')

Tier 2: Composio Integration

Access 200+ apps through Composio:

import { api } from 'sdk.do'

// Execute any Composio action
const result = await api.composio.execute({
  app: 'slack',
  action: 'sendMessage',
  parameters: {
    channel: '#general',
    text: 'Hello from MCP.do!',
  },
})

// List available apps
const apps = await api.composio.listApps()
console.log(apps.map((a) => a.name))

// Get app details
const slack = await api.composio.getApp('slack')
console.log(slack)

// List actions for an app
const actions = await api.composio.listActions('slack')
console.log(actions)

// List connections
const connections = await api.composio.listConnections()
console.log(connections)

Composio Convenience Methods

Slack

// Send Slack message
await api.composio.slack.sendMessage({
  channel: '#general',
  text: 'Hello team!',
  username: 'Bot',
  icon_emoji: ':robot_face:',
})

Notion

// Create Notion page
await api.composio.notion.createPage({
  database_id: 'db_123',
  properties: {
    Name: { title: [{ text: { content: 'New Page' } }] },
    Status: { select: { name: 'In Progress' } },
  },
})

Linear

// Create Linear issue
await api.composio.linear.createIssue({
  title: 'Bug: Login error',
  description: 'Users cannot log in',
  teamId: 'team_123',
  priority: 1,
  labels: ['bug', 'high-priority'],
})

Tier 3: Zapier Integration

Access 6000+ apps through Zapier:

import { api } from 'sdk.do'

// Execute Zapier action
const result = await api.zapier.execute({
  app: 'airtable',
  action: 'createRecord',
  params: {
    baseId: 'app123',
    tableId: 'tbl456',
    fields: {
      Name: 'New Record',
      Status: 'Active',
    },
  },
})

// List available actions
const actions = await api.zapier.listActions({
  app: 'airtable',
})

// List configured Zaps
const zaps = await api.zapier.listZaps()

// Get Zap details
const zap = await api.zapier.getZap('zap_123')

Auto-Routing Example

The apps proxy automatically tries all tiers:

import { api } from 'sdk.do'

// This will try:
// 1. Native Notion worker (if exists)
// 2. Composio Notion integration (if connected)
// 3. Zapier Notion integration (if configured)
const result = await api.apps.execute({
  app: 'notion',
  action: 'createDatabase',
  params: {
    parent: { page_id: 'page_123' },
    title: [{ text: { content: 'My Database' } }],
  },
})

Integration with Other Primitives

With Database Operations

import { api, db, $ } from 'sdk.do'

// Sync external data to database
async function syncStripeCustomers() {
  const customers = await api.stripe.customers.list({ limit: 100 })

  for (const customer of customers.data) {
    await db.create('Customer', {
      externalId: customer.id,
      email: customer.email,
      name: customer.name,
      metadata: customer.metadata,
    })
  }
}

// Create webhook handler
on($.Stripe.customer.created, async (data) => {
  await db.create('Customer', {
    externalId: data.id,
    email: data.email,
    name: data.name,
  })
})

With AI Operations

import { api, ai } from 'sdk.do'

// Fetch data and analyze with AI
async function analyzeGitHubRepo(owner: string, repo: string) {
  // Get repository data
  const repoData = await api.github.repos.get({ owner, repo })
  const issues = await api.github.issues.list({ owner, repo, state: 'open' })

  // Analyze with AI
  const analysis = await ai.generate({
    prompt: `Analyze this GitHub repository:
Repository: ${repoData.name}
Stars: ${repoData.stargazers_count}
Issues: ${issues.length}
Description: ${repoData.description}

Provide insights about the project health and recommendations.`,
    model: 'gpt-5',
  })

  return analysis.text
}

With Event System

import { api, on, send, $ } from 'sdk.do'

// Send notification on new order
on($.Order.created, async (order) => {
  // Send email
  await api.email.send({
    to: order.customer.email,
    subject: 'Order Confirmation',
    body: `Your order #${order.id} has been confirmed!`,
  })

  // Send Slack notification
  await api.composio.slack.sendMessage({
    channel: '#orders',
    text: `New order: ${order.id} - $${order.total}`,
  })

  // Create GitHub issue for high-value orders
  if (order.total > 1000) {
    await api.github.issues.create({
      owner: 'dot-do',
      repo: 'operations',
      title: `High-value order: ${order.id}`,
      body: `Order ID: ${order.id}\nCustomer: ${order.customer.name}\nTotal: $${order.total}`,
      labels: ['high-value', 'needs-review'],
    })
  }
})

Webhook Handling

Sending Webhooks

// Send webhook to external service
const result = await api.sendWebhook(
  'stripe',
  {
    event: 'order.created',
    data: {
      orderId: 'ord_123',
      amount: 2000,
      currency: 'usd',
    },
  },
  {
    'X-Custom-Header': 'value',
  }
)

Receiving Webhooks

import { api, db, on, $ } from 'sdk.do'

// Handle incoming webhooks
on($.Webhook.received.stripe, async (payload) => {
  if (payload.type === 'payment_intent.succeeded') {
    // Update order status
    await db.update('Order', payload.data.object.metadata.orderId, {
      status: 'paid',
      paidAt: new Date(),
    })

    // Send confirmation email
    await api.email.send({
      to: payload.data.object.receipt_email,
      subject: 'Payment Received',
      body: 'Thank you for your payment!',
    })
  }
})

Error Handling

Basic Error Handling

import { api, isApiError } from 'sdk.do'

try {
  const data = await api.fetch('https://api.example.com/data')
} catch (error) {
  if (isApiError(error)) {
    console.error(`API Error: ${error.status} - ${error.message}`)
    console.error('Response body:', error.body)
  } else {
    console.error('Unknown error:', error)
  }
}

Retry Logic

async function fetchWithRetry(url: string, maxRetries: number = 3): Promise<any> {
  let lastError: Error

  for (let i = 0; i < maxRetries; i++) {
    try {
      return await api.fetch(url)
    } catch (error) {
      lastError = error as Error

      if (isApiError(error) && error.status >= 400 && error.status < 500) {
        // Don't retry client errors
        throw error
      }

      // Wait before retry with exponential backoff
      if (i < maxRetries - 1) {
        await new Promise((resolve) => setTimeout(resolve, Math.pow(2, i) * 1000))
      }
    }
  }

  throw lastError!
}

Rate Limit Handling

import { api, isApiError } from 'sdk.do'

async function handleRateLimits(url: string) {
  try {
    return await api.fetch(url)
  } catch (error) {
    if (isApiError(error) && error.status === 429) {
      // Rate limited - wait and retry
      const retryAfter = error.body?.retry_after || 60
      console.log(`Rate limited. Retrying after ${retryAfter}s`)

      await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000))
      return await api.fetch(url)
    }
    throw error
  }
}

Integration-Specific Errors

// Stripe error handling
try {
  const customer = await api.stripe.customers.create({
    email: 'invalid-email',
  })
} catch (error) {
  if (isApiError(error)) {
    if (error.status === 400) {
      console.error('Invalid customer data:', error.body)
    } else if (error.status === 402) {
      console.error('Payment required')
    }
  }
}

// GitHub error handling
try {
  const issue = await api.github.issues.create({
    owner: 'dot-do',
    repo: 'nonexistent',
    title: 'Test',
  })
} catch (error) {
  if (isApiError(error)) {
    if (error.status === 404) {
      console.error('Repository not found')
    } else if (error.status === 403) {
      console.error('Permission denied - check GitHub token')
    }
  }
}

Authentication Patterns

API Key Authentication

import { configure, api } from 'sdk.do'

// Configure SDK with API key
configure({
  apiKey: process.env.DO_API_KEY,
})

// All API calls now include authentication
const data = await api.fetch('https://api.do/protected')

Service-Specific Credentials

// Stripe uses separate API key
configure({
  apiKey: process.env.DO_API_KEY,
  stripeWorkerUrl: 'https://stripe.do',
})

// Stripe calls use Stripe credentials configured on server
const customer = await api.stripe.customers.create({
  email: '[email protected]',
})

// GitHub uses GitHub token configured on server
const repo = await api.github.repos.get({
  owner: 'dot-do',
  repo: 'platform',
})

OAuth Integration

// OAuth flow for user-specific integrations
async function connectGitHub(userId: string) {
  // Initiate OAuth flow
  const authUrl = await api.fetch('https://api.do/oauth/github/authorize', {
    method: 'POST',
    body: JSON.stringify({
      userId,
      scopes: ['repo', 'user'],
      redirectUri: 'https://example.com/callback',
    }),
  })

  // Redirect user to authUrl
  return authUrl
}

// Handle OAuth callback
async function handleOAuthCallback(code: string, userId: string) {
  // Exchange code for token
  const result = await api.fetch('https://api.do/oauth/github/callback', {
    method: 'POST',
    body: JSON.stringify({
      code,
      userId,
    }),
  })

  // Token is now stored for user-specific GitHub calls
  return result
}

Readonly vs Authenticated Mode

Readonly Operations (Anonymous)

Anonymous users can only make GET requests:

// ✅ Works without authentication
const data = await api.fetch('https://api.example.com/public-data', {
  method: 'GET',
})

// ❌ Fails without authentication
const result = await api.fetch('https://api.example.com/create', {
  method: 'POST',
  body: JSON.stringify({ data: 'value' }),
})
// Error: AuthenticationError - Write operations require authentication

Write Operations (Authenticated)

import { configure, api } from 'sdk.do'

configure({
  apiKey: process.env.DO_API_KEY,
})

// ✅ Now works
const result = await api.fetch('https://api.example.com/create', {
  method: 'POST',
  body: JSON.stringify({ data: 'value' }),
})

Service Proxy Permissions

// ❌ Fails without authentication - all service proxy calls require auth
const customer = await api.stripe.customers.create({
  email: '[email protected]',
})
// Error: AuthenticationError

Performance Considerations

Parallel Requests

// Sequential: Slow
const repo1 = await api.github.repos.get({ owner: 'dot-do', repo: 'platform' })
const repo2 = await api.github.repos.get({ owner: 'dot-do', repo: 'ai' })
const repo3 = await api.github.repos.get({ owner: 'dot-do', repo: 'docs' })

// Parallel: Fast
const [repo1, repo2, repo3] = await Promise.all([
  api.github.repos.get({ owner: 'dot-do', repo: 'platform' }),
  api.github.repos.get({ owner: 'dot-do', repo: 'ai' }),
  api.github.repos.get({ owner: 'dot-do', repo: 'docs' }),
])

Request Caching

import { api, db } from 'sdk.do'

async function getCachedData(url: string, ttl: number = 3600): Promise<any> {
  // Check cache
  const cached = await db.get('ApiCache', url)
  if (cached && Date.now() - cached.timestamp < ttl * 1000) {
    return cached.data
  }

  // Fetch fresh data
  const response = await api.fetch(url)
  const data = await response.json()

  // Store in cache
  await db.create('ApiCache', {
    id: url,
    data,
    timestamp: Date.now(),
  })

  return data
}

Batch Operations

// Instead of N individual requests
for (const customerId of customerIds) {
  const customer = await api.stripe.customers.get(customerId)
  // Process customer
}

// Use batch endpoints when available
const customers = await api.stripe.customers.list({
  limit: 100,
})
// Process all customers at once

Common Pitfalls

Not Handling Timeouts

// ❌ No timeout handling
const data = await api.fetch('https://slow-api.example.com/data')

// ✅ With timeout
import { configure } from 'sdk.do'

configure({
  timeout: 10000, // 10 seconds
})

try {
  const data = await api.fetch('https://slow-api.example.com/data')
} catch (error) {
  if (isApiError(error) && error.status === 408) {
    console.error('Request timeout')
  }
}

Ignoring Rate Limits

// ❌ Burst requests without rate limiting
for (let i = 0; i < 1000; i++) {
  await api.github.repos.get({ owner: 'dot-do', repo: 'platform' })
}
// Will hit rate limit quickly

// ✅ Respect rate limits
async function fetchWithRateLimit(requests: any[], rateLimit: number) {
  const results = []
  for (let i = 0; i < requests.length; i++) {
    results.push(await requests[i]())

    // Wait between requests
    if (i < requests.length - 1) {
      await new Promise((resolve) => setTimeout(resolve, 1000 / rateLimit))
    }
  }
  return results
}

Not Validating Response Data

// ❌ Assuming response structure
const data = await api.fetch('https://api.example.com/user')
console.log(data.email.toLowerCase()) // May crash if email is undefined

// ✅ Validate response
const data = await api.fetch('https://api.example.com/user')
if (data && typeof data.email === 'string') {
  console.log(data.email.toLowerCase())
} else {
  console.error('Invalid response structure')
}

Missing Error Context

// ❌ Generic error handling
try {
  const result = await api.stripe.customers.create({ email: '[email protected]' })
} catch (error) {
  console.error('Error creating customer')
  // Lost error details
}

// ✅ Preserve error context
try {
  const result = await api.stripe.customers.create({ email: '[email protected]' })
} catch (error) {
  if (isApiError(error)) {
    console.error('Stripe API Error:', {
      status: error.status,
      message: error.message,
      body: error.body,
    })
  }
  throw error // Re-throw for upstream handling
}

Advanced Examples

Multi-Service Workflow

import { api, db, ai } from 'sdk.do'

async function processCustomerOrder(orderId: string) {
  // Get order from database
  const order = await db.get('Order', orderId)

  // Create Stripe payment intent
  const paymentIntent = await api.stripe.paymentIntents.create({
    amount: order.total * 100, // Convert to cents
    currency: 'usd',
    customer: order.stripeCustomerId,
  })

  // Send confirmation email
  await api.email.send({
    to: order.customer.email,
    subject: 'Order Confirmation',
    body: `Your order #${order.id} is confirmed. Total: $${order.total}`,
  })

  // Create GitHub issue for high-value orders
  if (order.total > 1000) {
    await api.github.issues.create({
      owner: 'dot-do',
      repo: 'operations',
      title: `High-value order: ${order.id}`,
      body: `Review order details for customer ${order.customer.name}`,
      labels: ['high-value'],
    })
  }

  // Generate personalized upsell recommendations
  const recommendations = await ai.generate({
    prompt: `Generate product recommendations for customer who ordered: ${order.items.map((i) => i.name).join(', ')}`,
    model: 'gpt-5',
  })

  // Send recommendations via email
  await api.email.send({
    to: order.customer.email,
    subject: 'You Might Also Like',
    body: recommendations.text,
  })

  return { paymentIntent, recommendations }
}

Sync External Data

import { api, db } from 'sdk.do'

async function syncGitHubIssues(owner: string, repo: string) {
  let page = 1
  let hasMore = true

  while (hasMore) {
    // Fetch page of issues
    const issues = await api.github.issues.list({
      owner,
      repo,
      state: 'all',
      per_page: 100,
      page,
    })

    // Store in database
    for (const issue of issues) {
      await db.create('GitHubIssue', {
        externalId: issue.id,
        number: issue.number,
        title: issue.title,
        body: issue.body,
        state: issue.state,
        createdAt: new Date(issue.created_at),
        updatedAt: new Date(issue.updated_at),
      })
    }

    // Check if there are more pages
    hasMore = issues.length === 100
    page++
  }
}

Webhook Relay

import { api, on, $ } from 'sdk.do'

// Relay webhooks from one service to another
on($.Stripe.webhook, async (payload) => {
  // Forward to internal analytics
  await api.fetch('https://analytics.example.com/webhook', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  })

  // Forward to Slack
  await api.composio.slack.sendMessage({
    channel: '#stripe-events',
    text: `Stripe event: ${payload.type}`,
  })

  // Create audit log
  await db.create('AuditLog', {
    type: 'stripe.webhook',
    data: payload,
    timestamp: new Date(),
  })
})

Cross-References

See Also