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
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 trackingHelper 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 authenticationWrite 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: AuthenticationErrorPerformance 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 onceCommon 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
- $ - Semantic Types - Semantic webhook patterns
- db - Database Operations - Store external data
- ai - AI Operations - Process external data with AI
- on - Event Handlers - React to external events
- send - Event Publishing - Trigger external webhooks
- Configuration - API key setup
- Authentication - Security model
See Also
- Stripe API Documentation - Stripe integration
- GitHub API Documentation - GitHub integration
- Composio Documentation - Composio integrations
- Zapier Platform - Zapier integrations
- Fetch API MDN - Standard Fetch API
ai - AI Operations
Complete guide to AI operations in MCP.do - text generation, structured output, embeddings, and batch processing with support for multiple models including GPT-5, Claude Sonnet 4.5, Llama 4, Grok 4, and Gemini 2.5 Pro
on - Event Handlers
Subscribe to and handle domain events using semantic event patterns in the SDK.do event system