> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runflow.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Connectors

> Dynamic integrations with external services

**Connectors** are dynamic integrations with external services defined in the Runflow backend. They support two modes of usage:

1. **As Tools** - For agent execution (LLM decides when to call)
2. **Direct Invocation** - For programmatic execution (you control when to call)

## Key Features

* 🔄 **Dynamic Schema Loading** - Schemas are fetched from the backend automatically
* 🎭 **Transparent Mocking** - Enable mock mode for development and testing
* 🛣️ **Path Parameter Resolution** - Automatic extraction and URL building
* ⚡ **Lazy Initialization** - Schemas loaded only when needed, cached globally
* 🔐 **Flexible Authentication** - Supports API Key, Bearer Token, Basic Auth, OAuth2
* 🔄 **Multiple Credentials** - Override credentials per execution (multi-tenant support)
* ✅ **Type-Safe** - Automatic JSON Schema → Zod → LLM Parameters conversion

## Usage Mode 1: As Agent Tool

Use connectors as tools that the LLM can call automatically

<Tip>
  **Resource Identifier:** Use the **resource slug** (e.g., `get-customers`, `list-users`) which is auto-generated from the resource name. Slugs are stable, URL-safe identifiers that won't break if you rename the resource display name.
</Tip>

```typescript theme={null}
import { createConnectorTool, Agent, openai } from '@runflow-ai/sdk';

// Basic connector tool (schema loaded from backend)
const getClienteTool = createConnectorTool({
  connector: 'api-contabil',      // Connector instance slug
  resource: 'get-customers',      // Resource slug
  description: 'Get customer by ID from accounting API',
  enableMock: true,               // Optional: enables mock mode
});

// Use with Agent
const agent = new Agent({
  name: 'Accounting Agent',
  instructions: 'You help manage customers in the accounting system.',
  model: openai('gpt-4o'),
  tools: {
    getCliente: getClienteTool,
    listClientes: createConnectorTool({
      connector: 'api-contabil',
      resource: 'list-customers',  // Resource slug
    }),
  },
});

// First execution automatically loads schemas from backend
const result = await agent.process({
  message: 'Get customer with ID 123',
  sessionId: 'session-123',
  companyId: 'company-456',
});
```

## Usage Mode 2: Direct Invocation

Call connectors programmatically, without agent involvement. Works anywhere: standalone scripts, workflow steps, API handlers.

<Warning>
  `connector()` is a **function call**, not a client factory. You must pass all 3 arguments (connector slug, resource slug, data) in a single call. It returns a `Promise` with the result.

  ```typescript theme={null}
  // CORRECT
  const result = await connector('hubspot-prod', 'create-contact', { email: 'john@example.com' });

  // WRONG - connector() needs 3 args, not 1
  const client = connector('hubspot-prod');
  await client.execute('create-contact', data);  // TypeError!
  ```
</Warning>

<Tip>
  **Identifiers:**

  * **Connector:** Use the instance **slug** (e.g., `hubspot-prod`) - recommended over display name
  * **Resource:** Use the resource **slug** (e.g., `create-contact`) - auto-generated from resource name
</Tip>

### Response Format

The response is wrapped in a standard envelope:

```typescript theme={null}
const result = await connector('hubspot-prod', 'create-contact', { email: 'john@example.com' });

// result = {
//   success: true,
//   data: { id: 'contact_123', email: 'john@example.com', ... },  // actual API response
//   metadata: { connector: 'hubspot-prod', resource: 'create-contact', ... }
// }

// Access the actual data:
const contact = result.data;
```

### Examples

```typescript theme={null}
import { connector } from '@runflow-ai/sdk';

// Direct connector call (using slugs - recommended)
const result = await connector(
  'hubspot-prod',      // connector instance slug
  'create-contact',    // resource slug
  {                    // data
    email: 'john@example.com',
    firstname: 'John',
    lastname: 'Doe'
  }
);

console.log('Contact created:', result);
```

**With execution options:**

```typescript theme={null}
const options: ConnectorExecutionOptions = {
  credentialId: 'cred-prod-123',  // Override credential
  timeout: 10000,                  // 10 seconds timeout
  retries: 3,                      // Retry 3 times on failure
  useMock: false,                  // Use real API
};

const result = await connector(
  'api-contabil',
  'get-customer',      // Resource slug
  { id: 123 },
  options
);
```

**Multi-tenant example:**

```typescript theme={null}
// Different credentials per customer
async function createContactForCustomer(customerId: string, contactData: any) {
  // Get customer's HubSpot credential
  const credentialId = await getCustomerCredential(customerId, 'hubspot');
  
  return await connector(
    'hubspot',
    'create-contact',   // Resource slug
    contactData,
    { credentialId }
  );
}

// Usage
await createContactForCustomer('customer-1', { email: 'john@acme.com' });
await createContactForCustomer('customer-2', { email: 'jane@techcorp.com' });
```

**Authentication Priority:**

1. **Custom headers** (highest - overrides everything)
2. **credentialId override** (runtime override)
3. **Instance credential** (default from connector instance)
4. **No authentication**

### Public APIs — call a template directly (no instance)

For connector **templates** with `authRequired = false` (public APIs imported via OpenAPI, like JSONPlaceholder, public REST endpoints, etc.), you can skip the instance step entirely and pass the **template slug** as the first argument. The resolver tries an instance match first and transparently falls back to the template when no instance exists.

```typescript theme={null}
import { connector } from '@runflow-ai/sdk';

// Template slug (no instance created)
const todo = await connector(
  'jsonplaceholder',   // template slug — no `-prod` instance needed
  'get-todo',
  { id: 1 }
);
```

This works for both `connector(...)` and `createConnectorTool({ connector: 'slug', ... })`. The shortcut only kicks in when the template has no auth — anything requiring a credential still needs an instance.

## Using Connectors in Workflows

### Inside `.step()` (recommended)

Call `connector()` directly inside a workflow step:

```typescript theme={null}
import { flow, connector } from '@runflow-ai/sdk';
import { z } from 'zod';

const workflow = flow({
  id: 'crm-pipeline',
  inputSchema: z.object({ cpf: z.string(), name: z.string() }),
  outputSchema: z.any(),
})
  .step('check-eligibility', async (input) => {
    const result = await connector(
      'api-elegibilidade',          // connector slug
      'consulta-por-cpf',           // resource slug
      { path: { cpf: input.cpf } }  // data (path params, query, body)
    );
    return { eligible: result.status === 'active', data: result };
  })
  .step('create-contact', {
    handler: async (input, ctx) => {
      const contact = await connector('hubspot-prod', 'create-contact', {
        email: `${ctx.input.cpf}@example.com`,
        firstname: ctx.input.name,
        properties: { eligibility: input.eligible ? 'approved' : 'denied' },
      });
      return { contactId: contact.id, eligible: input.eligible };
    },
    when: (ctx) => ctx.results['check-eligibility'].eligible,
  })
  .build();
```

### Using `.connector()` step (native)

The FlowBuilder also has a native `.connector()` method for simple cases:

```typescript theme={null}
flow({ id: 'simple', inputSchema, outputSchema })
  .connector('create-ticket', 'hubspot', 'tickets', 'create', {
    subject: 'New Support Request',
    content: '{{input.description}}',
    priority: 'medium',
  })
  .build();
```

<Note>
  The native `.connector()` step uses template interpolation (`{{input.field}}`) for parameters. For dynamic logic (conditionals, transformations), use `connector()` inside a `.step()` instead.
</Note>

## Using loadConnector Helper

For connectors with many resources, use the `loadConnector` helper:

```typescript theme={null}
import { loadConnector } from '@runflow-ai/sdk';

const contabil = loadConnector('api-contabil');

const agent = new Agent({
  name: 'Accounting Agent',
  instructions: 'You manage accounting data.',
  model: openai('gpt-4o'),
  tools: {
    // Using resource slugs
    listClientes: contabil.tool('list-customers'),
    getCliente: contabil.tool('get-customer'),
    createCliente: contabil.tool('create-customer'),
    updateCliente: contabil.tool('update-customer'),
  },
});
```

## Path Parameters

Connectors automatically resolve path parameters from the resource URL:

```typescript theme={null}
// Resource defined in backend with path: /clientes/{id}/pedidos/{pedidoId}
const getClientePedidoTool = createConnectorTool({
  connector: 'api-contabil',
  resource: 'get-customer-order',  // Resource slug
  description: 'Get specific order from a customer',
});

// Agent automatically extracts path params from context
const result = await agent.process({
  message: 'Get order 456 from customer 123',
  sessionId: 'session-123',
  companyId: 'company-456',
});

// Backend automatically resolves: /clientes/123/pedidos/456
```

## Mock Execution

Enable mock mode for development and testing:

```typescript theme={null}
const tool = createConnectorTool({
  connector: 'api-contabil',
  resource: 'list-customers',  // Resource slug
  enableMock: true,            // Adds useMock parameter
});

// Use mock mode in development
const result = await agent.process({
  message: 'List customers (use mock data)',
  sessionId: 'dev-session',
  companyId: 'dev-company',
  // Tool will automatically include useMock=true if mock data is configured
});
```

## How It Works

1. **Tool Creation**: `createConnectorTool` creates a tool with a temporary schema
2. **Lazy Loading**: On first agent execution, schemas are fetched from the backend in parallel
3. **Schema Conversion**: JSON Schema → Zod → LLM Parameters (automatic)
4. **Caching**: Schemas are cached globally to avoid repeated API calls
5. **Execution**: Tool/API executes with authentication, path resolution, and error handling

## Next Steps

<CardGroup cols={2}>
  <Card title="Workflows" icon="diagram-project" href="/core-concepts/workflows">
    Orchestrate complex processes
  </Card>

  <Card title="Tools" icon="wrench" href="/core-concepts/tools">
    Learn more about tools
  </Card>

  <Card title="Channels" icon="comments" href="/core-concepts/channels">
    WhatsApp, Telegram and more — replies are sent through connectors
  </Card>
</CardGroup>
