Documentation/External API Integration
v2.0.0-beta.1Snapshot bebdcd1Markdown ↗

External API Integration

External API Integration

Connect your AI agents to 50 external services with enterprise-grade resilience. The library provides both connector-based tools and direct fetch capabilities.

Need the inventory rather than a tutorial? The Connector & Tool Catalog lists every template, the generic tool each connector receives, all specialized packs, connector-free built-ins, plugin tools, and the runtime discovery APIs.

Overview

External API integration uses the Connector-First Architecture - the same pattern used for AI providers. This means:

  • Single source of truth for authentication
  • Built-in resilience (retry, timeout, circuit breaker)
  • Automatic tool generation for any service

Quick Start

typescript
import { Connector, ConnectorTools, Services, Agent } from 'oneringai';

// 1. Create a connector for an external service
Connector.create({
  name: 'github',
  serviceType: Services.Github,
  auth: { type: 'api_key', apiKey: process.env.GITHUB_TOKEN! },
  baseURL: 'https://api.github.com',
});

// 2. Generate tools from the connector
const tools = ConnectorTools.for('github');

// 3. Use with an agent
const agent = Agent.create({
  connector: 'openai',
  model: 'gpt-4.1',
  tools: tools,
});

// 4. Agent can now call the GitHub API
await agent.run('List all open issues in owner/repo');

Connector Configuration

Basic Configuration

typescript
Connector.create({
  name: 'slack',
  serviceType: Services.Slack,  // Optional: explicit service type
  auth: { type: 'api_key', apiKey: process.env.SLACK_TOKEN! },
  baseURL: 'https://slack.com/api',
});

Enterprise Resilience Features

typescript
Connector.create({
  name: 'stripe',
  serviceType: Services.Stripe,
  auth: { type: 'api_key', apiKey: process.env.STRIPE_SECRET_KEY! },
  baseURL: 'https://api.stripe.com/v1',

  // Timeout
  timeout: 30000,  // 30 seconds (default)

  // Retry with exponential backoff
  retry: {
    maxRetries: 3,
    baseDelayMs: 1000,
    maxDelayMs: 30000,
    retryableStatuses: [429, 500, 502, 503, 504],
  },

  // Circuit breaker
  circuitBreaker: {
    enabled: true,
    failureThreshold: 5,      // Open after 5 failures
    successThreshold: 2,      // Close after 2 successes
    resetTimeoutMs: 60000,    // Try again after 60s
  },

  // Logging
  logging: {
    enabled: true,
    logBody: false,           // Don't log request/response bodies
    logHeaders: false,        // Don't log headers
  },
});

Supported Services (50)

The library includes built-in definitions for 50 popular services:

Category Services
Major Vendors Microsoft, Google
Communication Slack, Discord, Telegram, X (Twitter), Zoom, HeyReach
Development GitHub, GitLab, Bitbucket, Jira, Linear, Asana, Trello
Productivity Notion, Airtable, Confluence, Cal.com, Calendly
CRM Salesforce, HubSpot, Pipedrive
Payments Stripe, PayPal, QuickBooks, Ramp
Cloud AWS, Cloudflare
Storage Dropbox, Box
Email SendGrid, Mailchimp, Postmark, Mailgun, EmailBison
Monitoring Datadog, PagerDuty, Sentry
Search Serper, Brave Search, Tavily, RapidAPI Search
Scrape ZenRows
Other Twilio, Zendesk, Intercom, Shopify, ipinfo, Clay
typescript
import { Services, getServiceInfo, getServicesByCategory } from 'oneringai';

// Use service constants
Connector.create({
  name: 'my-slack',
  serviceType: Services.Slack,  // Type-safe
  // ...
});

// Get service metadata
const info = getServiceInfo('slack');
console.log(info?.name);        // 'Slack'
console.log(info?.category);    // 'communication'
console.log(info?.docsURL);     // 'https://api.slack.com/methods'
console.log(info?.commonScopes); // ['chat:write', 'channels:read', ...]

// Filter by category
const devServices = getServicesByCategory('development');
// Returns: github, gitlab, jira, linear, bitbucket, ...

Using Connector.fetch()

For direct API calls without tools:

typescript
const connector = Connector.get('github');

// Basic fetch
const query = new URLSearchParams({ state: 'open', per_page: '10' });
const response = await connector.fetch(`/repos/owner/repo/issues?${query}`, { method: 'GET' });

// JSON helper with automatic parsing
const issues = await connector.fetchJSON<Issue[]>('/repos/owner/repo/issues');

// POST with body
const newIssue = await connector.fetchJSON('/repos/owner/repo/issues', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    title: 'New Issue', body: 'Issue description', labels: ['bug'],
  }),
});

// Per-request options
const urgent = await connector.fetch('/chat.postMessage', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ channel: 'C123', text: 'Urgent!' }),
  timeout: 5000,           // Override timeout
  skipRetry: true,         // Skip retry for this request
  skipCircuitBreaker: true, // Bypass circuit breaker
});

Direct Connector.fetch/fetchJSON options extend native RequestInit: encode query parameters in the URL and serialize JSON bodies with a content type. The queryParams and object-body fields documented below belong to generated API tool arguments, not to ConnectorFetchOptions.

ConnectorTools API

Generate Tools for a Connector

typescript
import { ConnectorTools } from 'oneringai';

// Get all tools for a connector (generic API + any registered service tools)
const tools = ConnectorTools.for('github');
const toolsVariant2 = ConnectorTools.for(connector);  // Can pass instance too

// userId is automatic — all generated tools read it from ToolContext at execution time.
// No need to pass userId to ConnectorTools.for().
// Just set it on the agent: Agent.create({ userId: 'user-123', tools })

// With scoped registry (access control)
const registry = Connector.scoped({ tenantId: 'acme' });
const toolsVariant3 = ConnectorTools.for('github', undefined, { registry });

// The generic API tool is included automatically by ConnectorTools.for()
// (named `{connectorName}_api` whenever the connector has a baseURL)
const toolsVariant4 = ConnectorTools.for('github');
const apiTool = toolsVariant4.find(t => t.definition.function.name === 'github_api');

Tool Naming Convention

All tools generated by ConnectorTools.for() are prefixed with the connector name to prevent naming collisions when multiple connectors provide tools with the same base name:

Tool type Naming pattern Example
Generic API {connectorName}_api github_api, slack_api
Service-specific {connectorName}_{toolName} github_search_files, google_generate_image, main-openai_text_to_speech

Services with built-in tools:

  • GitHub — 8 tools: search_files, search_code, read_file, list_branches, get_pr, pr_files, pr_comments, create_pr (see GitHub Connector Tools)
  • Microsoft — 11 tools: email, calendar, meetings, Teams transcripts, OneDrive/SharePoint files (see Microsoft Graph Connector Tools)
  • Google Workspace — 11 tools: Gmail, Calendar, Meet transcripts, Drive files (see Google Workspace Connector Tools)
  • Zoom — 3 tools: zoom_create_meeting, zoom_update_meeting, zoom_get_transcript (see Zoom Connector Tools)
  • Telegram — 6 tools: telegram_send_message, telegram_send_photo, telegram_get_updates, telegram_set_webhook, telegram_get_me, telegram_get_chat (see Telegram Connector Tools)
  • Twilio — 4 tools: send_sms, send_whatsapp, list_messages, get_message (see Twilio Connector Tools)
  • AI Vendors (OpenAI, Google, Grok) — Multimedia tools: generate_image, generate_video, text_to_speech, speech_to_text

This ensures that tools from different vendors (e.g., google_generate_image vs main-openai_generate_image) never collide, and are clearly identified by connector in UIs and agent configs.

ToolRegistry automatically derives clean display names from these prefixed names using vendor metadata (e.g., google_generate_image displays as "Google Generate Image").

The Generic API Tool

Every connector with a baseURL gets a generic API tool that allows the agent to make any API call:

jsonc
// Tool schema:
{
  name: 'github_api',  // {connectorName}_api
  description: 'Make API requests to api.github.com',
  parameters: {
    method: { enum: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] },
    endpoint: { type: 'string' },          // API path, e.g., '/repos/owner/repo'
    body: { type: 'object' },              // JSON request body (POST/PUT/PATCH)
    queryParams: { type: 'object' },       // URL query parameters (GET filtering/pagination)
    headers: { type: 'object' },           // Additional headers (auth headers are protected)
  }
}

Important: For POST/PUT/PATCH requests, data must be passed in the body parameter as a JSON object — not as query string parameters in the endpoint URL. The body is sent as application/json. For example, to post a Slack message:

jsonc
// Correct: data in body
{ method: 'POST', endpoint: '/chat.postMessage', body: { channel: 'C123', text: 'Hello!' } }

// Wrong: data in query string — many APIs will reject this
{ method: 'POST', endpoint: '/chat.postMessage?channel=C123&text=Hello!' }

Security: Authorization headers cannot be overridden by the agent.

Register Custom Service Tools

For frequently-used operations, register service-specific tools. Note that tool names returned by the factory use generic names — ConnectorTools.for() automatically prefixes them with the connector name:

typescript
import { ConnectorTools, type ToolFunction } from 'oneringai';

// Register tools for a service type
ConnectorTools.registerService('slack', (connector) => {
  const listChannels: ToolFunction = {
    definition: {
      type: 'function',
      function: {
        name: 'list_channels',
        description: 'List all Slack channels',
        parameters: {
          type: 'object',
          properties: {
            types: {
              type: 'string',
              description: 'Filter by channel types',
              enum: ['public_channel', 'private_channel'],
            },
            limit: { type: 'number', description: 'Max results' },
          },
        },
      },
    },
    execute: async (args) => {
      const query = new URLSearchParams({ types: String(args.types ?? 'public_channel'), limit: String(args.limit ?? 100) });
      return connector.fetchJSON(`/conversations.list?${query}`);
    },
    describeCall: (args) => `List ${args.types || 'all'} channels`,
  };

  const postMessage: ToolFunction = {
    definition: {
      type: 'function',
      function: {
        name: 'post_message',
        description: 'Post a message to a Slack channel',
        parameters: {
          type: 'object',
          properties: {
            channel: { type: 'string', description: 'Channel ID' },
            text: { type: 'string', description: 'Message text' },
          },
          required: ['channel', 'text'],
        },
      },
    },
    execute: async (args) => {
      return connector.fetchJSON('/chat.postMessage', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ channel: args.channel, text: args.text }),
      });
    },
    describeCall: (args) => `Post to ${args.channel}`,
    permission: { riskLevel: 'medium', scope: 'session' },
  };

  return [listChannels, postMessage];
});

// Now ConnectorTools.for('slack-connector') returns:
// slack-connector_api, slack-connector_list_channels, slack-connector_post_message

Discover All Connectors

typescript
// Get tools for all connectors with serviceType
const allTools = ConnectorTools.discoverAll();
// Returns: Map<connectorName, ToolFunction[]>

for (const [name, tools] of allTools) {
  console.log(`${name}: ${tools.length} tools`);
}

// Find connector by service type
const slackConnector = ConnectorTools.findConnector(Services.Slack);

// Find all connectors for a service type
const allSlackConnectors = ConnectorTools.findConnectors(Services.Slack);

// Check if service has custom tools
if (ConnectorTools.hasServiceTools('slack')) {
  // ...
}

// List all services with custom tools registered
const services = ConnectorTools.listSupportedServices();

ToolRegistry API

Unified view of all tools (built-in + connector-generated). Use this for UI tool pickers, inventory screens, or any code that needs to enumerate available tools.

Basic Usage

typescript
import { ToolRegistry } from 'oneringai';

// Get ALL tools (main API for UIs)
const allTools = ToolRegistry.getAllTools();

// Built-in tools only (filesystem, shell, web, code, json, connector, desktop, custom-tools, routines, other)
const builtInTools = ToolRegistry.getBuiltInTools();

// All connector-generated tools
const connectorTools = ToolRegistry.getAllConnectorTools();

// Tools for a specific connector
const githubTools = ToolRegistry.getConnectorTools('github');

// Filter by service type
const slackTools = ToolRegistry.getToolsByService('slack');

// Filter by connector name
const myApiTools = ToolRegistry.getToolsByConnector('my-api');

Type Guard

Use isConnectorTool() to distinguish built-in from connector tools:

typescript
for (const tool of ToolRegistry.getAllTools()) {
  if (ToolRegistry.isConnectorTool(tool)) {
    // ConnectorToolEntry - has connectorName, serviceType
    console.log(`API: ${tool.displayName} (${tool.connectorName})`);
  } else {
    // ToolRegistryEntry - built-in tool
    console.log(`Built-in: ${tool.displayName}`);
  }
}

Methods Reference

Method Returns Description
getAllTools() (ToolRegistryEntry | ConnectorToolEntry)[] All tools (main API)
getBuiltInTools() ToolRegistryEntry[] Built-in tools only
getAllConnectorTools() ConnectorToolEntry[] All connector tools
getConnectorTools(name) ConnectorToolEntry[] Tools for specific connector
getToolsByService(type) ConnectorToolEntry[] Filter by service type
getToolsByConnector(name) ConnectorToolEntry[] Filter by connector name
isConnectorTool(entry) boolean Type guard for ConnectorToolEntry

Entry Properties

ToolRegistryEntry (built-in tools):

Property Type Description
name string Tool name (e.g., read_file)
displayName string Human-readable name (e.g., Read File)
category ToolCategory filesystem, shell, web, code, json, connector, desktop, custom-tools, routines, other
description string Brief description
safeByDefault boolean Whether safe without approval
tool ToolFunction The actual tool function
requiresConnector boolean? If tool needs a connector
connectorServiceTypes string[]? Supported service types

ConnectorToolEntry extends ToolRegistryEntry with:

Property Type Description
connectorName string Source connector name
serviceType string? Detected service type (e.g., github)

Service Detection

Services are detected from URL patterns or explicit serviceType:

typescript
import { detectServiceFromURL, Services } from 'oneringai';

// Automatic detection from URL
detectServiceFromURL('https://api.github.com/repos');     // 'github'
detectServiceFromURL('https://slack.com/api/chat');       // 'slack'
detectServiceFromURL('https://api.stripe.com/v1');        // 'stripe'
detectServiceFromURL('https://company.atlassian.net/jira'); // 'jira'

// Explicit serviceType takes precedence
Connector.create({
  name: 'custom',
  serviceType: Services.Jira,                        // Explicit
  baseURL: 'https://api.github.com',                 // Ignored for detection
});

Metrics and Monitoring

typescript
const connector = Connector.get('github');

// Get metrics
const metrics = connector.getMetrics();
console.log(`Requests: ${metrics.requestCount}`);
console.log(`Success: ${metrics.successCount}`);
console.log(`Failures: ${metrics.failureCount}`);
console.log(`Avg Latency: ${metrics.avgLatencyMs}ms`);
console.log(`Circuit: ${metrics.circuitBreakerState}`);

// Reset circuit breaker manually
connector.resetCircuitBreaker();

// Check if connector is disposed
if (connector.isDisposed()) {
  // Recreate connector
}

Complete Example

typescript
import { Connector, ConnectorTools, Services, Agent, Vendor } from 'oneringai';

// Setup AI connector
Connector.create({
  name: 'openai',
  vendor: Vendor.OpenAI,
  auth: { type: 'api_key', apiKey: process.env.OPENAI_API_KEY! },
});

// Setup GitHub connector with resilience
Connector.create({
  name: 'github',
  serviceType: Services.Github,
  auth: { type: 'api_key', apiKey: process.env.GITHUB_TOKEN! },
  baseURL: 'https://api.github.com',
  timeout: 15000,
  retry: { maxRetries: 2, baseDelayMs: 500 },
  circuitBreaker: { enabled: true, failureThreshold: 3 },
});

// Setup Slack connector
Connector.create({
  name: 'slack',
  serviceType: Services.Slack,
  auth: { type: 'api_key', apiKey: process.env.SLACK_TOKEN! },
  baseURL: 'https://slack.com/api',
});

// Create agent with external API tools
const agent = Agent.create({
  connector: 'openai',
  model: 'gpt-4.1',
  tools: [
    ...ConnectorTools.for('github'),
    ...ConnectorTools.for('slack'),
  ],
});

// Agent can now interact with both services
await agent.run(`
  Check if there are any critical issues in owner/repo,
  and if so, post a summary to the #alerts Slack channel.
`);

Documentation snapshot · 2026-11-02Suggest a correction ↗

Search documentation

Type to search the v2 documentation.