# Weavz > Weavz is MCP-native integration infrastructure for SaaS and AI applications. ## Key Facts - 500+ pre-built integrations with 3,600+ tools (actions + triggers) - MCP servers in TOOLS mode and CODE mode (80-98% context reduction) - Free tier: 1,000 actions/month, no credit card required - Pricing: Free ($0) → Pro ($29/mo) → Team ($129/mo) → Scale ($299/mo) → Enterprise (custom) - TypeScript SDK: @weavz/sdk | Python SDK: weavz-sdk - Hosted OAuth for all supported integrations ## What is Weavz? Weavz helps developers add third-party integrations to their products and AI agents. It provides connection management, hosted MCP servers, action execution, triggers, and end-user identity for 500+ services. ## Key Features - 500+ pre-built integrations (Slack, GitHub, Gmail, Google Sheets, HubSpot, Salesforce, etc.) - MCP servers in TOOLS mode and CODE mode (80-98% context reduction) - Hosted Connect for OAuth2 and credential-based auth - TypeScript SDK (`@weavz/sdk`) and Python SDK (`weavz-sdk`) - End user management and multi-tenant workspace architecture - Workspace-scoped API keys and input partials ## Getting Started - Install: `npm install @weavz/sdk` or `pip install weavz-sdk` - Docs: https://weavz.io/docs - Pricing: Free tier available, no credit card required ## Links - Website: https://weavz.io - Documentation: https://weavz.io/docs - Pricing: https://weavz.io/pricing - SDKs: https://weavz.io/sdks - Integrations: https://weavz.io/integrations ## Comparisons - [Weavz vs Merge](https://weavz.io/compare/merge) - [Weavz vs Nango](https://weavz.io/compare/nango) - [Weavz vs Composio](https://weavz.io/compare/composio) - [Weavz vs Pipedream](https://weavz.io/compare/pipedream) - [Weavz vs Paragon](https://weavz.io/compare/paragon) - [Weavz vs Zapier](https://weavz.io/compare/zapier) - [Weavz vs Make](https://weavz.io/compare/make) - [Weavz vs Tray.ai](https://weavz.io/compare/tray) - [Weavz vs Workato](https://weavz.io/compare/workato) - [Weavz vs Self-Hosting](https://weavz.io/compare/self-hosting) - [Weavz vs Unified.to](https://weavz.io/compare/unified) --- ## Getting Started ### Introduction > Learn what Weavz is and how it helps you build integrations into your application. Source: https://weavz.io/docs/getting-started # Introduction Weavz is an embedded integration platform (iPaaS) that lets you add third-party service integrations to your application without building each one from scratch. It handles OAuth2 flows, credential management, action execution, event triggers, and MCP server hosting — so you can focus on your product. ## Why Weavz Building integrations is tedious and repetitive. Each third-party service has its own authentication flow, API conventions, rate limits, and data formats. Weavz abstracts all of that behind a unified API. - **500+ pre-built integrations** — Slack, GitHub, Google Sheets, Notion, Salesforce, and more - **MCP-first approach** — expose integrations as Model Context Protocol servers for AI agents - **Secure credential management** — OAuth2 with PKCE, AES-256 encryption at rest - **Multi-tenant by design** — organizations, workspaces, and per-user connection scoping - **Dual access** — REST API and native SDKs (TypeScript + Python) ## Core Concepts ### Integrations An integration represents a third-party service (e.g., Slack, GitHub, Google Sheets). Each integration defines its authentication method, available actions, and triggers. Weavz ships with 500+ integrations plus built-in storage and key-value store integrations. ### Connections A connection is an authenticated credential for a specific integration. When a user connects their Slack account via OAuth2, or provides an OpenAI API key, that creates a connection. Connections are encrypted at rest and scoped to your organization, workspace, or individual user. [Learn more about connections](/docs/concepts/connections) ### Actions Actions are operations you can execute against a third-party service — sending a Slack message, creating a GitHub issue, or reading a Google Sheet. Each action has a defined input schema and uses a connection for authentication. [Learn more about actions](/docs/concepts/actions) ### Triggers Triggers let you receive events from third-party services. When a new Slack message arrives, a GitHub PR is opened, or a Google Sheet row is added, Weavz delivers the event to your callback URL. [Learn more about triggers](/docs/concepts/triggers) ### MCP Servers MCP (Model Context Protocol) servers expose your integrations as tools that AI agents can discover and use. Create an MCP server, add integration tools, and connect it to Claude Desktop, Cursor, or any MCP-compatible client. [Learn more about MCP servers](/docs/concepts/mcp-servers) ## How It Works ```mermaid graph LR A[Your App] --> B[Weavz API] B --> C[Third-Party Service] D[MCP Clients] --> B ``` 1. **Configure integrations** — set up OAuth credentials or API keys for the services you need 2. **Create connections** — authenticate users against those services 3. **Execute actions** — call third-party APIs through Weavz's unified interface 4. **Listen for events** — enable triggers to receive real-time webhooks 5. **Serve AI agents** — create MCP servers so AI tools can use your integrations Need on-premise deployment, dedicated service accounts, or custom SLAs? [Contact our sales team](/contact) for enterprise options. ## Next Steps - [Installation](/docs/getting-started/installation) — set up your API key and install the SDK - [Quick Start](/docs/getting-started/quick-start) — build your first integration end-to-end - [Integrations](/docs/concepts/integrations) — browse available integrations ### Installation > Set up your Weavz account and install the SDK. Source: https://weavz.io/docs/getting-started/installation # Installation Get up and running with Weavz in a few minutes. You'll create an account, generate an API key, and install the SDK. ## Create an Account 1. Go to [platform.weavz.io](https://platform.weavz.io) and sign up 2. Create your first organization — this is your top-level container for all resources 3. Optionally, create a workspace to scope your integrations (e.g., "production", "staging") ## Generate an API Key 1. In the dashboard, go to **Settings → API Keys** 2. Click **Create API Key** 3. Give it a name (e.g., "Backend Server") 4. Copy the key — it starts with `wvz_` and won't be shown again API keys are scoped to your organization and grant access to all resources within it. ## Install the SDK ### TypeScript ```bash npm install @weavz/sdk ``` Initialize the client: ```typescript import { WeavzClient } from '@weavz/sdk' const weavz = new WeavzClient({ apiKey: process.env.WEAVZ_API_KEY, // wvz_... baseUrl: 'https://api.weavz.io', // optional, this is the default }) ``` ### Python ```bash pip install weavz-sdk ``` Initialize the client: ```python from weavz_sdk import WeavzClient weavz = WeavzClient( api_key=os.environ["WEAVZ_API_KEY"], # wvz_... base_url="https://api.weavz.io", # optional, this is the default ) ``` ## Verify Your Setup Test your API key with a simple request: ```bash curl https://api.weavz.io/api/v1/integrations \ -H "Authorization: Bearer wvz_your_api_key_here" ``` You should get a JSON response listing all available integrations: ```json { "data": [ { "name": "slack", "displayName": "Slack", "description": "...", "auth": { "type": "OAUTH2", ... }, "actions": [...], "triggers": [...] }, ... ] } ``` Or verify using the SDK: ```typescript const integrations = await weavz.integrations.list() console.log(`Available integrations: ${integrations.data.length}`) ``` ## Base URL | Environment | URL | |---|---| | Production | `https://api.weavz.io` | For enterprise on-premise deployments, use your dedicated deployment URL. [Contact sales](/contact) for details. ## Authentication All API requests require authentication via the `Authorization` header: ``` Authorization: Bearer wvz_your_api_key_here ``` The SDK handles this automatically when you pass `apiKey` during initialization. ## Rate Limits API requests are rate-limited based on your plan tier. Rate limit information is returned in response headers: | Header | Description | |---|---| | `X-RateLimit-Limit` | Maximum requests per window | | `X-RateLimit-Remaining` | Requests remaining in current window | | `X-RateLimit-Reset` | Unix timestamp when the window resets | ## Next Steps - [Quick Start](/docs/getting-started/quick-start) — build your first integration - [Organizations & Workspaces](/docs/concepts/organizations-and-workspaces) — understand the resource hierarchy ### Quick Start > Connect Slack, send a message, and serve MCP tools in under 5 minutes. Source: https://weavz.io/docs/getting-started/quick-start This guide walks you through connecting Slack, executing an action, and setting up an MCP server. By the end, you'll have a working integration that AI agents can use. ## Prerequisites - A Weavz account with an API key ([Installation](/docs/getting-started/installation)) - A Slack workspace you can connect (Weavz provides the OAuth app — no setup needed) Workspaces scope your integrations, connections, and MCP servers. Create one to get started. 1. Navigate to **Workspaces** in the sidebar 2. Click **Create Workspace** 3. Enter the name "My Workspace" and slug `my-workspace` 4. Click **Create** ```bash curl -X POST https://api.weavz.io/api/v1/workspaces \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "My Workspace", "slug": "my-workspace" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { workspace } = await client.workspaces.create({ name: 'My Workspace', slug: 'my-workspace', }) console.log(`Workspace created: ${workspace.id}`) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.workspaces.create(name="My Workspace", slug="my-workspace") workspace = result["workspace"] print(f"Workspace created: {workspace['id']}") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspaces', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'My Workspace', slug: 'my-workspace' }), }) const { workspace } = await res.json() console.log(`Workspace created: ${workspace.id}`) ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/workspaces", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"name": "My Workspace", "slug": "my-workspace"}, ) workspace = res.json()["workspace"] print(f"Workspace created: {workspace['id']}") ``` Weavz provides platform OAuth apps for services like Slack, so you don't need to create your own. Just open the hosted connect popup, log in to Slack, and authorize. 1. Open your workspace and go to the **Connections** tab 2. Click **Create Connection** 3. Select **Slack** from the integration picker 4. Click **Authorize** — a popup opens with Slack's consent screen 5. Approve access — the popup closes and your connection appears in the list ```bash # Create a connect token curl -X POST https://api.weavz.io/api/v1/connect/token \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "connectionName": "My Slack", "externalId": "my_slack", "workspaceId": "YOUR_WORKSPACE_ID" }' ``` The response contains `token`, `connectUrl`, and `expiresAt`. Open the `connectUrl` in a browser popup to complete authorization. ```typescript // Step 1: Create a connect session const session = await client.connect.createToken({ integrationName: 'slack', connectionName: 'My Slack', externalId: 'my_slack', workspaceId: workspace.id, }) // Step 2: Open the popup const result = await client.connect.popup({ token: session.token, connectUrl: session.connectUrl, }) console.log(`Connected: ${result.connection.id}`) ``` ```python # Create a connect token (open connectUrl in a browser) result = client.connect.create_token( integration_name="slack", connection_name="My Slack", external_id="my_slack", workspace_id=workspace["id"], ) # result contains: token, connectUrl, expiresAt print(f"Open this URL to authorize: {result['connectUrl']}") # Open result["connectUrl"] in a browser popup ``` ```typescript // Create a connect token const res = await fetch('https://api.weavz.io/api/v1/connect/token', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', connectionName: 'My Slack', externalId: 'my_slack', workspaceId: 'YOUR_WORKSPACE_ID', }), }) const { token, connectUrl } = await res.json() // Open connectUrl in a browser popup to complete authorization ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/connect/token", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "connectionName": "My Slack", "externalId": "my_slack", "workspaceId": "YOUR_WORKSPACE_ID", }, ) data = res.json() print(f"Open this URL to authorize: {data['connectUrl']}") ``` Now use that connection to send a message to a Slack channel. 1. Open the **Playground** from the sidebar 2. Select your workspace from the dropdown 3. Pick the **Slack** integration 4. Choose the **Send Channel Message** action 5. Enter a channel name and message text 6. Click **Execute** and view the result ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "input": { "channel": "#general", "text": "Hello from Weavz!" }, "workspaceId": "YOUR_WORKSPACE_ID", "connectionExternalId": "my_slack" }' ``` ```typescript const { output } = await client.actions.execute('slack', 'send_channel_message', { input: { channel: '#general', text: 'Hello from Weavz!', }, workspaceId: workspace.id, connectionExternalId: 'my_slack', }) console.log('Message sent:', output) ``` ```python result = client.actions.execute( "slack", "send_channel_message", input={"channel": "#general", "text": "Hello from Weavz!"}, workspace_id=workspace["id"], connection_external_id="my_slack", ) print("Message sent:", result["output"]) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', input: { channel: '#general', text: 'Hello from Weavz!' }, workspaceId: 'YOUR_WORKSPACE_ID', connectionExternalId: 'my_slack', }), }) const { output } = await res.json() console.log('Message sent:', output) ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "input": {"channel": "#general", "text": "Hello from Weavz!"}, "workspaceId": "YOUR_WORKSPACE_ID", "connectionExternalId": "my_slack", }, ) print("Message sent:", res.json()["output"]) ``` The response contains the Slack API result: ```json { "success": true, "output": { "ok": true, "channel": "C01234567", "ts": "1234567890.123456", "message": { "text": "Hello from Weavz!", "type": "message" } } } ``` MCP servers let AI agents use your integrations as tools. Create one and add the Slack integration. 1. Navigate to **MCP Servers** in the sidebar 2. Click **Create Server** 3. Enter the name "My AI Tools", select **TOOLS** mode, and pick your workspace 4. Click **Create** 5. On the server detail page, click **Add Tool** 6. Select **Slack** and the **Send Channel Message** action 7. Choose your Slack connection 8. Copy the **MCP endpoint** and **bearer token** from the server details ```bash # Create the MCP server curl -X POST https://api.weavz.io/api/v1/mcp/servers \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "My AI Tools", "mode": "TOOLS", "workspaceId": "YOUR_WORKSPACE_ID" }' ``` ```bash # Add Slack tools (use the serverId from the response above) curl -X POST https://api.weavz.io/api/v1/mcp/servers/{serverId}/tools \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "CONNECTION_ID" }' ``` ```typescript const { server, bearerToken, mcpEndpoint } = await client.mcpServers.create({ name: 'My AI Tools', mode: 'TOOLS', workspaceId: workspace.id, }) await client.mcpServers.addTool(server.id, { integrationName: 'slack', actionName: 'send_channel_message', connectionId: session.connection.id, }) console.log(`MCP endpoint: ${mcpEndpoint}`) console.log(`Bearer token: ${bearerToken}`) ``` ```python result = client.mcp_servers.create( name="My AI Tools", mode="TOOLS", workspace_id=workspace["id"], ) server = result["server"] bearer_token = result["bearerToken"] mcp_endpoint = result["mcpEndpoint"] client.mcp_servers.add_tool( server["id"], integration_name="slack", action_name="send_channel_message", connection_id="CONNECTION_ID", ) print(f"MCP endpoint: {mcp_endpoint}") print(f"Bearer token: {bearer_token}") ``` ```typescript const serverRes = await fetch('https://api.weavz.io/api/v1/mcp/servers', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'My AI Tools', mode: 'TOOLS', workspaceId: 'YOUR_WORKSPACE_ID', }), }) const { server, bearerToken, mcpEndpoint } = await serverRes.json() await fetch(`https://api.weavz.io/api/v1/mcp/servers/${server.id}/tools`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'CONNECTION_ID', }), }) ``` ```python server_res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "name": "My AI Tools", "mode": "TOOLS", "workspaceId": "YOUR_WORKSPACE_ID", }, ) data = server_res.json() server_id = data["server"]["id"] bearer_token = data["bearerToken"] mcp_endpoint = data["mcpEndpoint"] httpx.post( f"https://api.weavz.io/api/v1/mcp/servers/{server_id}/tools", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "CONNECTION_ID", }, ) print(f"MCP endpoint: {mcp_endpoint}") print(f"Bearer token: {bearer_token}") ``` Use the MCP server endpoint and bearer token to connect an AI client. Add to your Claude Desktop configuration (`claude_desktop_config.json`): ```json { "mcpServers": { "weavz": { "command": "npx", "args": [ "-y", "mcp-remote", "https://api.weavz.io/api/v1/mcp/servers/{serverId}/protocol", "--header", "Authorization: Bearer mcp_your_bearer_token" ] } } } ``` Add to your Cursor MCP settings: ```json { "mcpServers": { "weavz": { "command": "npx", "args": [ "-y", "mcp-remote", "https://api.weavz.io/api/v1/mcp/servers/{serverId}/protocol", "--header", "Authorization: Bearer mcp_your_bearer_token" ] } } } ``` Now ask Claude or Cursor to "send a message to #general in Slack" and watch it use your MCP tools. ## What's Next You've connected Slack via OAuth, sent a message, and set up an MCP server. Here's where to go from here: - [Connections](/docs/concepts/connections) — learn about auth types, multi-tenant scoping, and the hosted connect flow - [Actions](/docs/concepts/actions) — explore action execution patterns and input schemas - [MCP Servers](/docs/concepts/mcp-servers) — configure TOOLS and CODE modes - [Input Partials](/docs/concepts/input-partials) — save parameter presets and enforce values - [Triggers](/docs/concepts/triggers) — receive real-time events from integrations - [Integrations](/docs/concepts/integrations) — browse all 500+ available integrations --- ## Concepts ### Organizations & Workspaces > Understand the resource hierarchy for multi-tenant integration management. Source: https://weavz.io/docs/concepts/organizations-and-workspaces # Organizations & Workspaces Weavz uses a two-level hierarchy to organize resources: **organizations** at the top and **workspaces** within them. ## Organizations An organization is the top-level container for all your Weavz resources. Every connection, MCP server, trigger, and API key belongs to an organization. When you sign up for Weavz, you create your first organization automatically. You can create additional organizations to separate distinct products or clients. ### What belongs to an organization - API keys - Workspaces - End users (scoped to workspaces) - Connections - MCP servers - Triggers - Members - Billing and usage ### API key scoping API keys are scoped to your organization by default. You can also create **workspace-scoped keys** that restrict access to specific workspaces — see [API Keys guide](/docs/guides/api-keys) for details. Treat API keys like server-side secrets. ## Workspaces Workspaces are **configured integration containers** — not empty scoping buckets. Each workspace declares which integrations it uses, how connections are resolved for each, and which actions are available. This makes workspaces the central configuration unit for multi-tenant and multi-environment setups. Common patterns: - **By environment** — `production`, `staging`, `development` - **By application** — `mobile-app`, `web-dashboard`, `internal-tools` - **By customer** — when building a multi-tenant product, create a workspace per end-customer ### Workspace integrations After creating a workspace, you configure it by adding **workspace integrations** — each one declares: - Which integration to use (e.g., `slack`, `github`) - A **connection strategy** (`fixed`, `per_user`, or `per_user_with_fallback`) - An optional **connection** (the fixed or fallback connection) - An optional **alias** for disambiguation when the same integration appears multiple times - An optional **allowed actions** list to restrict which actions are available ```bash # Create the workspace curl -X POST https://api.weavz.io/api/v1/workspaces \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"name": "Production", "slug": "production"}' # Add Slack with a fixed connection curl -X POST https://api.weavz.io/api/v1/workspaces/{workspaceId}/integrations \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "connectionStrategy": "fixed", "connectionId": "conn_slack_prod" }' # Add Gmail where each user provides their own connection curl -X POST https://api.weavz.io/api/v1/workspaces/{workspaceId}/integrations \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "gmail", "connectionStrategy": "per_user" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) // Create the workspace const { workspace } = await client.workspaces.create({ name: 'Production', slug: 'production', }) // Add Slack with a fixed connection await client.workspaces.addIntegration(workspace.id, { integrationName: 'slack', connectionStrategy: 'fixed', connectionId: 'conn_slack_prod', }) // Add Gmail where each user provides their own connection await client.workspaces.addIntegration(workspace.id, { integrationName: 'gmail', connectionStrategy: 'per_user', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") # Create the workspace result = client.workspaces.create(name="Production", slug="production") workspace = result["workspace"] # Add Slack with a fixed connection client.workspaces.add_integration(workspace["id"], integration_name="slack", connection_strategy="fixed", connection_id="conn_slack_prod", ) # Add Gmail where each user provides their own connection client.workspaces.add_integration(workspace["id"], integration_name="gmail", connection_strategy="per_user", ) ``` ```typescript // Create the workspace const wsRes = await fetch('https://api.weavz.io/api/v1/workspaces', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Production', slug: 'production' }), }) const { workspace } = await wsRes.json() // Add Slack with a fixed connection await fetch(`https://api.weavz.io/api/v1/workspaces/${workspace.id}/integrations`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', connectionStrategy: 'fixed', connectionId: 'conn_slack_prod', }), }) // Add Gmail where each user provides their own connection await fetch(`https://api.weavz.io/api/v1/workspaces/${workspace.id}/integrations`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'gmail', connectionStrategy: 'per_user', }), }) ``` ```python import httpx headers = {"Authorization": "Bearer wvz_your_api_key"} # Create the workspace res = httpx.post( "https://api.weavz.io/api/v1/workspaces", headers=headers, json={"name": "Production", "slug": "production"}, ) workspace = res.json()["workspace"] # Add Slack with a fixed connection httpx.post( f"https://api.weavz.io/api/v1/workspaces/{workspace['id']}/integrations", headers=headers, json={ "integrationName": "slack", "connectionStrategy": "fixed", "connectionId": "conn_slack_prod", }, ) # Add Gmail where each user provides their own connection httpx.post( f"https://api.weavz.io/api/v1/workspaces/{workspace['id']}/integrations", headers=headers, json={ "integrationName": "gmail", "connectionStrategy": "per_user", }, ) ``` ### Connection strategies | Strategy | Description | |---|---| | `fixed` | A single connection is always used. Best for shared service accounts. | | `per_user` | Each user must provide their own connection. No fallback. | | `per_user_with_fallback` | Users can provide their own connection, with a default fallback. | See the [Workspace Integrations API](/docs/api-reference/workspace-integrations) for full endpoint documentation. ### End users Workspaces contain [end users](/docs/concepts/end-users) — the people who use your product. Each end user can own connections to third-party integrations, enabling per-user credential management. ```mermaid graph TD Org[Organization: My SaaS Product] Org --> WS[Workspace: Production] WS --> Int[Integration: slack - per_user] WS --> Alice[End User: alice] WS --> Bob[End User: bob] WS --> Charlie[End User: charlie] Alice --> AC[Alice's Slack Connection] Bob --> BC[Bob's Slack Connection] Charlie -.- NC[no connections yet] style NC stroke-dasharray: 5 5 ``` End users are created via the API or auto-created when a connection is established through the hosted connect portal. See [Managing End Users](/docs/guides/managing-end-users) for a step-by-step guide. ### Resource isolation When you create resources within a workspace, they are scoped to that workspace: - Workspace integrations define which integrations and connections are available - End users and their connections are scoped to the workspace - Connections created in a workspace are only visible within that workspace - Triggers can be scoped to a workspace - MCP servers can be synced from a workspace's integration configuration This isolation makes workspaces ideal for multi-tenant scenarios where different end users or environments should not share credentials. ### Creating a workspace ```bash curl -X POST https://api.weavz.io/api/v1/workspaces \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Production", "slug": "production" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { workspace } = await client.workspaces.create({ name: 'Production', slug: 'production', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.workspaces.create(name="Production", slug="production") workspace = result["workspace"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspaces', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Production', slug: 'production', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/workspaces", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"name": "Production", "slug": "production"}, ) data = res.json() ``` ### MCP server auto-sync When you add, update, or remove integrations in a workspace, any MCP servers linked to that workspace automatically reflect the changes. There is no need to manually trigger a sync -- MCP server tools stay in sync with the workspace's integration configuration at all times. ## Members Organizations support role-based access control with three roles: | Role | Permissions | |---|---| | **Owner** | Full access, manage billing, delete organization | | **Admin** | Manage members, connections, integrations, and settings | | **Member** | Create and manage their own connections, view shared resources | ### Inviting members ```bash curl -X POST https://api.weavz.io/api/v1/members/invite \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "email": "teammate@example.com", "role": "ADMIN" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { member } = await client.members.create({ userId: 'user_abc123', role: 'ADMIN', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.members.create(user_id="user_abc123", role="ADMIN") member = result["member"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/members/invite', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ email: 'teammate@example.com', role: 'ADMIN', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/members/invite", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"email": "teammate@example.com", "role": "ADMIN"}, ) data = res.json() ``` ## Multi-Tenancy Patterns ### Single organization, multiple workspaces Best for SaaS products where you manage integrations on behalf of your customers. Each workspace is a configured integration container: ```mermaid graph TD Org[Organization: My SaaS Product] Org --> A[Workspace: Customer A] Org --> B[Workspace: Customer B] Org --> C[Workspace: Internal] A --> A1[slack - fixed] A --> A2[github - fixed] B --> B1[slack - fixed] B --> B2[google-sheets - per_user] C --> C1[slack - fixed] ``` ### SaaS with per-customer credentials Create a workspace per customer with `fixed` connection strategy: ``` For each customer: 1. Create a workspace 2. Create a connection with the customer's OAuth2 credentials 3. Add a workspace integration with strategy "fixed" pointing to that connection 4. All actions in that workspace context use the customer's credentials ``` ### SaaS with end-user OAuth2 Use `per_user` strategy and `externalId` to let each end-user connect their own accounts: ``` 1. Create a workspace integration with strategy "per_user" 2. When an end-user connects, create a connection with externalId = their user ID 3. When executing actions, pass externalId to resolve their connection ``` ### Hybrid approach Use `per_user_with_fallback` for optional personalization: ``` 1. Create a default connection (e.g., your company's Slack bot) 2. Add a workspace integration with strategy "per_user_with_fallback" pointing to the default 3. Users who connect their own Slack get personalized access 4. Users who don't still get functionality via the default bot ``` ### External IDs For fine-grained multi-tenancy, use `externalId` on connections. This lets you associate a connection with a specific end-user in your system without creating a separate workspace per user. ```bash curl -X POST https://api.weavz.io/api/v1/connections \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "type": "PLATFORM_OAUTH2", "integrationName": "slack", "externalId": "user_12345", "displayName": "User 12345 Slack", "accessToken": "xoxb-..." }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { connection } = await client.connections.create({ type: 'PLATFORM_OAUTH2', integrationName: 'slack', externalId: 'user_12345', displayName: 'User 12345 Slack', accessToken: 'xoxb-...', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.connections.create( type="PLATFORM_OAUTH2", integration_name="slack", external_id="user_12345", display_name="User 12345 Slack", access_token="xoxb-...", ) connection = result["connection"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'PLATFORM_OAUTH2', integrationName: 'slack', externalId: 'user_12345', displayName: 'User 12345 Slack', accessToken: 'xoxb-...', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/connections", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "type": "PLATFORM_OAUTH2", "integrationName": "slack", "externalId": "user_12345", "displayName": "User 12345 Slack", "accessToken": "xoxb-...", }, ) data = res.json() ``` Then resolve the connection by external ID when executing actions: ```bash curl -X POST https://api.weavz.io/api/v1/connections/resolve \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "workspaceId": "proj_abc123", "externalId": "user_12345" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { connection } = await client.connections.resolve({ integrationName: 'slack', workspaceId: 'proj_abc123', externalId: 'user_12345', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.connections.resolve( integration_name="slack", workspace_id="proj_abc123", external_id="user_12345", ) connection = result["connection"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections/resolve', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', workspaceId: 'proj_abc123', externalId: 'user_12345', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/connections/resolve", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "workspaceId": "proj_abc123", "externalId": "user_12345", }, ) data = res.json() ``` ## Next Steps - [End Users](/docs/concepts/end-users) — manage per-user connections and connect portals - [Integrations](/docs/concepts/integrations) — browse available integrations - [Connections](/docs/concepts/connections) — learn about connection management - [Workspace Integrations API](/docs/api-reference/workspace-integrations) — configure workspace integration instances ### Integrations > Browse available integrations and understand their capabilities. Source: https://weavz.io/docs/concepts/integrations # Integrations An integration represents a third-party service in Weavz. Each integration defines its authentication method, available actions (operations you can perform), and triggers (events you can listen for). ## Authentication Types Each integration requires a specific authentication type: | Type | Description | Example | |---|---|---| | **OAuth2** | Full OAuth2 flow with authorization URL, token exchange, and refresh | Slack, GitHub, Google services | | **API Key** | Simple secret key or token | OpenAI, SendGrid | | **Basic Auth** | Username and password | Some legacy APIs | | **Custom Auth** | Multiple fields defined by the integration | Airtable (base + token) | | **None** | No authentication required | Storage, KV Store | OAuth2 integrations support PKCE (Proof Key for Code Exchange) for enhanced security during the authorization flow. ## Available Integrations Weavz ships with 500+ pre-built external integrations. Here are some highlights: | Integration | Auth Type | Key Actions | |---|---|---| | **Airtable** | Custom Auth | Create/read/update records, list bases | | **Asana** | OAuth2 | Create tasks, list projects, manage workspaces | | **ClickUp** | OAuth2 | Create tasks, manage lists and spaces | | **Discord** | OAuth2 | Send messages, manage channels, list guilds | | **Dropbox** | OAuth2 | Upload/download files, list folders | | **Figma** | OAuth2 | Get file info, list projects | | **GitHub** | OAuth2 | Create issues, manage repos, list PRs | | **Gmail** | OAuth2 | Send/read emails, manage labels | | **Google Calendar** | OAuth2 | Create/list events, manage calendars | | **Google Contacts** | OAuth2 | Create/list contacts | | **Google Drive** | OAuth2 | Upload/download files, list folders | | **Google Forms** | OAuth2 | List forms, get responses | | **Google Sheets** | OAuth2 | Read/write rows, create spreadsheets | | **Google Tasks** | OAuth2 | Create/list tasks and task lists | | **HubSpot** | OAuth2 | Manage contacts, deals, companies | | **HTTP** | Custom Auth | Send HTTP requests (GET, POST, etc.) | | **Intercom** | OAuth2 | Send messages, manage contacts | | **Jira** | OAuth2 | Create issues, manage projects, list boards | | **Linear** | OAuth2 | Create issues, manage projects and teams | | **Microsoft Teams** | OAuth2 | Send messages, list channels and teams | | **Monday** | OAuth2 | Create items, manage boards | | **Notion** | OAuth2 | Create/query databases, manage pages | | **OpenAI** | API Key | Chat completions, text generation | | **Salesforce** | OAuth2 | Manage leads, contacts, opportunities | | **Shopify** | OAuth2 | Manage products, orders, customers | | **Slack** | OAuth2 | Send messages, manage channels, list users | | **Telegram Bot** | API Key | Send messages, manage chats | | **Todoist** | OAuth2 | Create tasks, manage projects | | **Trello** | OAuth2 | Create cards, manage boards and lists | | **Twilio** | API Key | Send SMS, make calls | | **Typeform** | OAuth2 | List forms, get responses | ### Built-in Integrations These integrations are provided by Weavz and require no external authentication: | Integration | Description | |---|---| | **Storage** | File storage (read, write, delete, list files) backed by object storage | | **KV Store** | Key-value store for persistent state (put, get, delete, lists) | | **Code** | Execute JavaScript in a lightweight sandbox — ideal for data transformation | | **Advanced Code** | Multi-language sandbox (JS, Python, Shell) with persistent state and storage | [Learn more about Storage and KV Store](/docs/concepts/storage-and-kv) · [Learn more about Code & Sandbox](/docs/concepts/code-and-sandbox) ## Actions vs Triggers Each integration can expose two types of capabilities: ### Actions Actions are operations you initiate — sending a message, creating a record, uploading a file. You call them via the REST API, through MCP servers, or from the dashboard Playground. ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "workspaceId": "proj_abc123", "input": { "channel": "#general", "text": "Hello from Weavz!" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('slack', 'send_channel_message', { workspaceId: 'proj_abc123', input: { channel: '#general', text: 'Hello from Weavz!', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("slack", "send_channel_message", workspace_id="proj_abc123", input={ "channel": "#general", "text": "Hello from Weavz!", }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', workspaceId: 'proj_abc123', input: { channel: '#general', text: 'Hello from Weavz!', }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "workspaceId": "proj_abc123", "input": { "channel": "#general", "text": "Hello from Weavz!", }, }, ) data = res.json() ``` ### Triggers Triggers are events that happen externally — a new message arrives, a form is submitted, a file is uploaded. You enable a trigger and provide a callback URL where Weavz delivers the events. ```bash curl -X POST https://api.weavz.io/api/v1/triggers/enable \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "github", "triggerName": "new_issue", "workspaceId": "proj_abc123", "input": { "repo": "my-org/my-repo" }, "callbackUrl": "https://your-app.com/webhooks/github" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.triggers.enable({ integrationName: 'github', triggerName: 'new_issue', workspaceId: 'proj_abc123', input: { repo: 'my-org/my-repo', }, callbackUrl: 'https://your-app.com/webhooks/github', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.triggers.enable( integration_name="github", trigger_name="new_issue", workspace_id="proj_abc123", input={"repo": "my-org/my-repo"}, callback_url="https://your-app.com/webhooks/github", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers/enable', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'github', triggerName: 'new_issue', workspaceId: 'proj_abc123', input: { repo: 'my-org/my-repo' }, callbackUrl: 'https://your-app.com/webhooks/github', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/triggers/enable", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "github", "triggerName": "new_issue", "workspaceId": "proj_abc123", "input": {"repo": "my-org/my-repo"}, "callbackUrl": "https://your-app.com/webhooks/github", }, ) data = res.json() ``` Not all integrations support both actions and triggers. Use the integration metadata endpoint to discover what's available: ```bash curl https://api.weavz.io/api/v1/integrations/slack \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { integration } = await client.integrations.get('slack') ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.integrations.get("slack") integration = result["integration"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/integrations?name=slack', { headers: { 'Authorization': 'Bearer wvz_your_api_key', }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/integrations", headers={"Authorization": "Bearer wvz_your_api_key"}, params={"name": "slack"}, ) data = res.json() ``` ## Listing Integrations ### All integrations ```bash curl https://api.weavz.io/api/v1/integrations \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { integrations, total } = await client.integrations.list() ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.integrations.list() integrations = result["integrations"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/integrations', { headers: { 'Authorization': 'Bearer wvz_your_api_key', }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/integrations", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` ### Single integration details ```bash curl https://api.weavz.io/api/v1/integrations/slack \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { integration } = await client.integrations.get('slack') ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.integrations.get("slack") integration = result["integration"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/integrations?name=slack', { headers: { 'Authorization': 'Bearer wvz_your_api_key', }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/integrations", headers={"Authorization": "Bearer wvz_your_api_key"}, params={"name": "slack"}, ) data = res.json() ``` The response includes full metadata — display name, logo, auth configuration, available actions with input schemas, and available triggers. ## Next Steps - [Connections](/docs/concepts/connections) — authenticate with integrations - [Actions](/docs/concepts/actions) — execute integration actions - [Triggers](/docs/concepts/triggers) — listen for integration events ### Connections > Manage authenticated credentials for third-party integrations. Source: https://weavz.io/docs/concepts/connections # Connections A connection stores authenticated credentials for an integration. Every time you need to interact with a third-party service — executing an action, enabling a trigger, or serving MCP tools — you need a connection. ## Authentication Types Connections support multiple authentication methods depending on the integration: ### OAuth2 For services like Slack, GitHub, and Google Sheets. Weavz provides a **hosted connect page** that handles the full OAuth2 authorization flow, including token exchange and PKCE. ```bash # Step 1: Create a connect token curl -X POST https://api.weavz.io/api/v1/connect/token \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "connectionName": "My Slack", "externalId": "my_slack", "workspaceId": "proj_abc123" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) // Step 1: Create a connect token const { token, connectUrl } = await client.connect.createToken({ integrationName: 'slack', connectionName: 'My Slack', externalId: 'my_slack', workspaceId: 'proj_abc123', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") # Step 1: Create a connect token result = client.connect.create_token( integration_name="slack", connection_name="My Slack", external_id="my_slack", workspace_id="proj_abc123", ) token = result["token"] connect_url = result["connectUrl"] ``` ```typescript // Step 1: Create a connect token const res = await fetch('https://api.weavz.io/api/v1/connect/token', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', connectionName: 'My Slack', externalId: 'my_slack', workspaceId: 'proj_abc123', }), }) const { token, connectUrl } = await res.json() ``` ```python import httpx # Step 1: Create a connect token res = httpx.post( "https://api.weavz.io/api/v1/connect/token", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "connectionName": "My Slack", "externalId": "my_slack", "workspaceId": "proj_abc123", }, ) data = res.json() token = data["token"] connect_url = data["connectUrl"] ``` Open the returned `connectUrl` in a popup or redirect. After the user completes authorization, retrieve the session result: ```bash # Step 2: Retrieve the session result curl https://api.weavz.io/api/v1/connect/session/cs_abc123 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) // Step 2: Retrieve the session result const { session } = await client.connect.getSession('cs_abc123') ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") # Step 2: Retrieve the session result result = client.connect.get_session("cs_abc123") session = result["session"] ``` ```typescript // Step 2: Retrieve the session result const res = await fetch('https://api.weavz.io/api/v1/connect/session/cs_abc123', { headers: { 'Authorization': 'Bearer wvz_your_api_key', }, }) const { session } = await res.json() ``` ```python import httpx # Step 2: Retrieve the session result res = httpx.get( "https://api.weavz.io/api/v1/connect/session/cs_abc123", headers={"Authorization": "Bearer wvz_your_api_key"}, ) session = res.json()["session"] ``` The session response includes a `status` field (`pending`, `completed`, or `failed`) and the resulting `connection` object when completed. OAuth2 token refresh is handled automatically. ### API Key For services like OpenAI and Twilio. Provide the secret value directly: ```bash curl -X POST https://api.weavz.io/api/v1/connections \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "type": "SECRET_TEXT", "integrationName": "openai", "externalId": "my_openai", "displayName": "Production OpenAI", "secretText": "sk-your-openai-key" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { connection } = await client.connections.create({ type: 'SECRET_TEXT', integrationName: 'openai', externalId: 'my_openai', displayName: 'Production OpenAI', secretText: 'sk-your-openai-key', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.connections.create( type="SECRET_TEXT", integration_name="openai", external_id="my_openai", display_name="Production OpenAI", secret_text="sk-your-openai-key", ) connection = result["connection"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'SECRET_TEXT', integrationName: 'openai', externalId: 'my_openai', displayName: 'Production OpenAI', secretText: 'sk-your-openai-key', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/connections", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "type": "SECRET_TEXT", "integrationName": "openai", "externalId": "my_openai", "displayName": "Production OpenAI", "secretText": "sk-your-openai-key", }, ) data = res.json() ``` ### Custom Auth For integrations requiring multiple fields (e.g., base URL + API key): ```bash curl -X POST https://api.weavz.io/api/v1/connections \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "type": "CUSTOM_AUTH", "integrationName": "airtable", "externalId": "my_airtable", "displayName": "My Airtable", "props": { "token": "pat_your_airtable_token" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { connection } = await client.connections.create({ type: 'CUSTOM_AUTH', integrationName: 'airtable', externalId: 'my_airtable', displayName: 'My Airtable', props: { token: 'pat_your_airtable_token', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.connections.create( type="CUSTOM_AUTH", integration_name="airtable", external_id="my_airtable", display_name="My Airtable", props={"token": "pat_your_airtable_token"}, ) connection = result["connection"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'CUSTOM_AUTH', integrationName: 'airtable', externalId: 'my_airtable', displayName: 'My Airtable', props: { token: 'pat_your_airtable_token', }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/connections", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "type": "CUSTOM_AUTH", "integrationName": "airtable", "externalId": "my_airtable", "displayName": "My Airtable", "props": {"token": "pat_your_airtable_token"}, }, ) data = res.json() ``` ## Encryption All connection credentials are encrypted at rest using AES-256. Secrets are never stored in plain text and are only decrypted when needed to make API calls to the third-party service. ## Connection Status Connections have two possible statuses: | Status | Description | |---|---| | **ACTIVE** | Credentials are valid and ready to use | | **ERROR** | An error occurred (e.g., OAuth2 token refresh failed) | ## End User Ownership Connections can be owned by an [end user](/docs/concepts/end-users). When you create a connection through the end user connect portal or pass `endUserId` when creating a connection, that connection is linked to the end user. This enables per-user connection management: - **View connections** — get all connections for a specific end user via `GET /api/v1/end-users/:id` - **Automatic cleanup** — when an end user is deleted, their connections are deleted too - **Connection resolution** — pass `endUserId` when executing actions or resolving connections, and Weavz finds the right connection based on the workspace's [connection strategy](/docs/concepts/organizations-and-workspaces#connection-strategies) End users are auto-created when a connection is established through the hosted connect flow with an `endUserId` parameter, if the end user doesn't exist yet. ## Multi-Tenant Scoping Connections can be scoped at three levels: ### Organization scope Available to everyone in the organization. Best for shared service accounts. ```json { "integrationName": "slack", "displayName": "Team Slack", "scope": "ORGANIZATION" } ``` ### Workspace scope Available only within a specific workspace. Best for environment-specific credentials. ```json { "integrationName": "slack", "displayName": "Production Slack", "scope": "WORKSPACE", "workspaceId": "proj_abc123" } ``` ### User scope Tied to a specific [end user](/docs/concepts/end-users). Best for personal accounts or per-user OAuth2 connections where each end user connects their own account. ## External IDs For fine-grained multi-tenancy, tag connections with an `externalId` that maps to a user in your system: ```bash curl -X POST https://api.weavz.io/api/v1/connections \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "type": "PLATFORM_OAUTH2", "integrationName": "slack", "externalId": "customer_789", "displayName": "Customer 789 Slack", "accessToken": "xoxb-..." }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { connection } = await client.connections.create({ type: 'PLATFORM_OAUTH2', integrationName: 'slack', externalId: 'customer_789', displayName: 'Customer 789 Slack', accessToken: 'xoxb-...', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.connections.create( type="PLATFORM_OAUTH2", integration_name="slack", external_id="customer_789", display_name="Customer 789 Slack", access_token="xoxb-...", ) connection = result["connection"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'PLATFORM_OAUTH2', integrationName: 'slack', externalId: 'customer_789', displayName: 'Customer 789 Slack', accessToken: 'xoxb-...', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/connections", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "type": "PLATFORM_OAUTH2", "integrationName": "slack", "externalId": "customer_789", "displayName": "Customer 789 Slack", "accessToken": "xoxb-...", }, ) data = res.json() ``` Then resolve a connection by external ID at execution time: ```bash curl -X POST https://api.weavz.io/api/v1/connections/resolve \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "workspaceId": "proj_abc123", "externalId": "customer_789" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { connection } = await client.connections.resolve({ integrationName: 'slack', workspaceId: 'proj_abc123', externalId: 'customer_789', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.connections.resolve( integration_name="slack", workspace_id="proj_abc123", external_id="customer_789", ) connection = result["connection"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections/resolve', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', workspaceId: 'proj_abc123', externalId: 'customer_789', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/connections/resolve", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "workspaceId": "proj_abc123", "externalId": "customer_789", }, ) data = res.json() ``` ## Connection Resolution When you execute an action or enable a trigger, Weavz resolves which connection to use. You can specify a connection explicitly by its external ID, or let Weavz resolve it based on the current context: **Resolution priority:** 1. Explicit `connectionExternalId` — if provided, find the connection tagged with that external ID 2. Workspace integration — if a `workspaceId` is provided, the workspace's [integration configuration](/docs/api-reference/workspace-integrations) determines the connection based on its strategy (`fixed`, `per_user`, or `per_user_with_fallback`) 3. No connection — returns a `CONNECTION_REQUIRED` error If you provide `workspaceId` and/or `endUserId`, explicit external-ID resolution is validated against that scope. Cross-workspace or cross-user matches are rejected. [Learn more about workspace integrations](/docs/api-reference/workspace-integrations) ## Managing Connections ### List connections ```bash curl https://api.weavz.io/api/v1/connections \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { connections, total } = await client.connections.list() ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.connections.list() connections = result["connections"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections', { headers: { 'Authorization': 'Bearer wvz_your_api_key', }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/connections", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` Filter by integration: ```bash curl "https://api.weavz.io/api/v1/connections?integrationName=slack" \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) // The list method returns all connections; filter client-side const { connections } = await client.connections.list() const slackConnections = connections.filter( (c: any) => c.integrationName === 'slack' ) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") # The list method returns all connections; filter client-side result = client.connections.list() slack_connections = [ c for c in result["connections"] if c["integrationName"] == "slack" ] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections?integrationName=slack', { headers: { 'Authorization': 'Bearer wvz_your_api_key', }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/connections", headers={"Authorization": "Bearer wvz_your_api_key"}, params={"integrationName": "slack"}, ) data = res.json() ``` ### Delete a connection ```bash curl -X DELETE https://api.weavz.io/api/v1/connections/{connectionId} \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.connections.delete('conn_abc123') ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.connections.delete("conn_abc123") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections/conn_abc123', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key', }, }) const data = await res.json() ``` ```python import httpx res = httpx.delete( "https://api.weavz.io/api/v1/connections/conn_abc123", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` Deleting a connection does not disable triggers or remove MCP tools that use it — those will fail with a `CONNECTION_REQUIRED` error until a new connection is configured. ## Next Steps - [End Users](/docs/concepts/end-users) — manage per-user connections and connect portals - [Actions](/docs/concepts/actions) — execute operations using connections - [Workspace Integrations](/docs/api-reference/workspace-integrations) — configure connection strategies per workspace - [Organizations & Workspaces](/docs/concepts/organizations-and-workspaces) — understand resource scoping Ready to connect? Create your first connection in the [dashboard](https://platform.weavz.io) or follow the [Setting Up Connections](/docs/guides/setting-up-connections) guide. ### Actions > Execute operations against third-party services through a unified API. Source: https://weavz.io/docs/concepts/actions # Actions An action is a single operation against a third-party service — sending a Slack message, creating a GitHub issue, reading rows from a Google Sheet, or generating text with OpenAI. ## Execution Model Actions can be executed through three interfaces: 1. **REST API** — `POST /api/v1/actions/execute` 2. **MCP servers** — AI agents call tools that map to actions 3. **Playground** — test actions interactively from the dashboard All three use the same underlying execution engine. ## Executing an Action ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "workspaceId": "proj_abc123", "input": { "channel": "#general", "text": "Hello from Weavz!" }, "connectionExternalId": "my_slack" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const result = await client.actions.execute('slack', 'send_channel_message', { workspaceId: 'proj_abc123', input: { channel: '#general', text: 'Hello from Weavz!', }, connectionExternalId: 'my_slack', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.actions.execute("slack", "send_channel_message", workspace_id="proj_abc123", input={ "channel": "#general", "text": "Hello from Weavz!", }, connection_external_id="my_slack", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', workspaceId: 'proj_abc123', input: { channel: '#general', text: 'Hello from Weavz!', }, connectionExternalId: 'my_slack', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "workspaceId": "proj_abc123", "input": { "channel": "#general", "text": "Hello from Weavz!", }, "connectionExternalId": "my_slack", }, ) data = res.json() ``` ### Response ```json { "success": true, "output": { "ts": "1234567890.123456", "channel": "C01234567" } } ``` ## Input Schemas Each action defines an input schema with required and optional properties. Property types include: | Type | Description | |---|---| | `SHORT_TEXT` | Single-line string | | `LONG_TEXT` | Multi-line text | | `NUMBER` | Numeric value | | `CHECKBOX` | Boolean | | `DROPDOWN` | Select from available values (resolved from the connected service) | | `DYNAMIC` | Properties resolved at runtime based on other inputs | | `ARRAY` | List of values | | `OBJECT` | Nested object | | `JSON` | Raw JSON input | | `FILE` | File reference | ### Discovering action inputs Fetch the integration metadata to see available actions and their input schemas: ```bash curl https://api.weavz.io/api/v1/integrations/slack \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { integration } = await client.integrations.get('slack') ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.integrations.get("slack") integration = result["integration"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/integrations?name=slack', { headers: { 'Authorization': 'Bearer wvz_your_api_key', }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/integrations", headers={"Authorization": "Bearer wvz_your_api_key"}, params={"name": "slack"}, ) data = res.json() ``` The response includes each action's `props` array with type, required flag, display name, and description. ### Dynamic properties Some actions have properties that depend on other inputs. For example, selecting a Slack channel might depend on the connected workspace. Use the input value resolution API to fetch dynamic values: ```bash curl -X POST https://api.weavz.io/api/v1/integrations/slack/properties/options \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "propertyName": "channel", "connectionExternalId": "my_slack", "input": {} }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { options } = await client.integrations.resolveOptions('slack', { propertyName: 'channel', connectionExternalId: 'my_slack', input: {}, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.integrations.resolve_options("slack", property_name="channel", connection_external_id="my_slack", input={}, ) options = result["options"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/integrations/slack/properties/options', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ propertyName: 'channel', connectionExternalId: 'my_slack', input: {}, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/integrations/slack/properties/options", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "propertyName": "channel", "connectionExternalId": "my_slack", "input": {}, }, ) data = res.json() ``` This returns the available options for dropdown or dynamic properties. ## Connection Resolution When executing an action, Weavz needs a connection to authenticate with the third-party service. You can provide credentials in several ways: - **Explicit connection** — pass `connectionExternalId` directly - **External ID** — pass `externalId` to resolve a connection tagged for a specific end-user - **Workspace context** — pass `workspaceId` to use the workspace's configured connection - **Workspace integration** — let the workspace's [integration configuration](/docs/api-reference/workspace-integrations) determine which connection to use - **Input partials** — pass `partialIds` to apply saved parameter presets with optional enforced values If the action requires authentication and no connection can be resolved, the API returns a `CONNECTION_REQUIRED` error. ```json { "error": "Connection required for this action", "code": "CONNECTION_REQUIRED" } ``` ## Error Handling Action execution can fail for several reasons: | Error Code | Description | |---|---| | `ACTION_FAILED` | The third-party API returned an error | | `CONNECTION_REQUIRED` | No valid connection found for this action | | `INTEGRATION_NOT_FOUND` | The specified integration doesn't exist | | `NOT_FOUND` | The specified action doesn't exist on this integration | | `QUOTA_EXCEEDED` | Monthly action quota exceeded for your plan | | `RATE_LIMITED` | Too many requests — retry after the window resets | ### ACTION_FAILED details When a third-party API returns an error, the response includes the original error in the `details` field: ```json { "error": "Action execution failed", "code": "ACTION_FAILED", "details": { "message": "channel_not_found", "statusCode": 404 } } ``` ## Usage Tracking Each successful action execution is counted toward your organization's monthly usage quota. Usage is tracked per calendar month and resets automatically. Check your current usage from the billing dashboard or via the API. ## Next Steps - [Triggers](/docs/concepts/triggers) — receive events from integrations - [Connections](/docs/concepts/connections) — manage authentication credentials - [MCP Servers](/docs/concepts/mcp-servers) — expose actions as AI agent tools Try it out in the [Playground](/docs/guides/playground) or learn how to [execute actions programmatically](/docs/guides/executing-actions). ### Triggers > Receive real-time events from third-party services. Source: https://weavz.io/docs/concepts/triggers # Triggers Triggers let you receive events from third-party services in real time. When a new Slack message is posted, a GitHub issue is created, or a Google Form response is submitted, Weavz delivers the event payload to your callback URL. ## Trigger Types Integrations use one of three trigger mechanisms: ### Webhook The third-party service sends events directly to Weavz via a webhook endpoint. This is the fastest method — events arrive in real time with minimal latency. **Examples:** Slack new message, GitHub push event, Typeform new response ### Polling Weavz periodically checks the third-party service for new data. Polling triggers have slightly higher latency but work with services that don't support webhooks. You can configure the polling interval via `pollingIntervalMinutes` when enabling a trigger (minimum interval depends on your plan). **Examples:** Google Sheets new row, Airtable new record ### App Webhook Similar to webhooks, but Weavz registers the webhook URL with the third-party service programmatically on your behalf. Requires a webhook secret to verify incoming events. **Examples:** GitHub repository events, Shopify order events ## Enabling a Trigger To start receiving events, enable a trigger with a callback URL where Weavz will deliver the event payloads. ```bash curl -X POST https://api.weavz.io/api/v1/triggers/enable \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "github", "triggerName": "new_issue", "workspaceId": "proj_abc123", "input": { "repo": "my-org/my-repo" }, "connectionExternalId": "my_github", "callbackUrl": "https://your-app.com/webhooks/github-issues" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { triggerSource } = await client.triggers.enable({ integrationName: 'github', triggerName: 'new_issue', workspaceId: 'proj_abc123', input: { repo: 'my-org/my-repo', }, connectionExternalId: 'my_github', callbackUrl: 'https://your-app.com/webhooks/github-issues', }) console.log(`Trigger ID: ${triggerSource.id}`) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.triggers.enable( integration_name="github", trigger_name="new_issue", workspace_id="proj_abc123", input={"repo": "my-org/my-repo"}, connection_external_id="my_github", callback_url="https://your-app.com/webhooks/github-issues", ) trigger_source = result["triggerSource"] print(f"Trigger ID: {trigger_source['id']}") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers/enable', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'github', triggerName: 'new_issue', workspaceId: 'proj_abc123', input: { repo: 'my-org/my-repo' }, connectionExternalId: 'my_github', callbackUrl: 'https://your-app.com/webhooks/github-issues', }), }) const data = await res.json() console.log(`Trigger ID: ${data.triggerSource.id}`) ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/triggers/enable", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "github", "triggerName": "new_issue", "workspaceId": "proj_abc123", "input": {"repo": "my-org/my-repo"}, "connectionExternalId": "my_github", "callbackUrl": "https://your-app.com/webhooks/github-issues", }, ) data = res.json() print(f"Trigger ID: {data['triggerSource']['id']}") ``` ## Callback Delivery When an event fires, Weavz sends a `POST` request to your callback URL with the event payload: ```json { "triggerId": "trg_abc123", "integrationName": "github", "triggerName": "new_issue", "timestamp": "2025-01-15T10:30:00.000Z", "payload": { "action": "opened", "issue": { "number": 42, "title": "Bug report", "body": "Something is broken..." } } } ``` Your endpoint should return a `200` status code to acknowledge receipt. ## Deduplication Weavz automatically deduplicates events to prevent duplicate deliveries. Each event is assigned a unique identifier based on its content, and Weavz tracks which events have already been delivered. If the same event is received again (common with webhook retries), it will not be sent to your callback URL a second time. ## Testing Triggers Before enabling a trigger in production, test it to see the event schema: ```bash curl -X POST https://api.weavz.io/api/v1/triggers/test \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "github", "triggerName": "new_issue" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { sampleData } = await client.triggers.test('github', 'new_issue') ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.triggers.test("github", "new_issue") sample_data = result["sampleData"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers/test', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'github', triggerName: 'new_issue', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/triggers/test", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "github", "triggerName": "new_issue", }, ) data = res.json() ``` This returns sample event data so you can understand the payload shape before building your handler. ## Managing Triggers ### List active triggers ```bash curl https://api.weavz.io/api/v1/triggers \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { triggers, total } = await client.triggers.list() ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.triggers.list() triggers = result["triggers"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers', { headers: { 'Authorization': 'Bearer wvz_your_api_key', }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/triggers", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` ### Disable a trigger ```bash curl -X POST https://api.weavz.io/api/v1/triggers/disable \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "triggerSourceId": "trg_abc123" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.triggers.disable('trg_abc123') ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.triggers.disable("trg_abc123") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers/disable', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ triggerSourceId: 'trg_abc123', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/triggers/disable", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"triggerSourceId": "trg_abc123"}, ) data = res.json() ``` Disabling a trigger stops event delivery and cleans up any webhook registrations with the third-party service. ## Trigger Lifecycle ```mermaid stateDiagram-v2 [*] --> Enable Enable --> Active: Webhook/polling setup Active --> Disable: Explicitly stopped Active --> Error: Connection expired or webhook deregistered Disable --> [*]: Cleaned up Error --> Disable: Manual disable ``` 1. **Enable** — Weavz sets up the webhook or starts polling 2. **Active** — events are delivered to your callback URL 3. **Error** — if the connection expires or the webhook is deregistered externally, the trigger enters an error state 4. **Disable** — you explicitly stop the trigger, cleaning up resources ## Next Steps - [Actions](/docs/concepts/actions) — execute operations against services - [MCP Servers](/docs/concepts/mcp-servers) — expose triggers and actions as AI tools - [Connections](/docs/concepts/connections) — manage the credentials triggers use Set up your first trigger in the [dashboard](https://platform.weavz.io) or via the [API guide](/docs/guides/setting-up-triggers). ### MCP Servers > Expose integrations as tools for AI agents via the Model Context Protocol. Source: https://weavz.io/docs/concepts/mcp-servers # MCP Servers MCP (Model Context Protocol) servers expose your integrations as tools that AI agents can discover and use. Create an MCP server, add integration tools, and connect it to Claude Desktop, Cursor, or any MCP-compatible client. ## Server Modes MCP servers operate in one of two modes: ### TOOLS Mode Each integration action is exposed as a separate tool. The AI agent sees a flat list of tools like `slack__send_channel_message`, `github__create_issue`, etc. Best for focused servers with a small number of integrations. ### CODE Mode Instead of individual tools, the server exposes three meta-tools: | Tool | Purpose | |---|---| | `weavz_search` | Search available integrations, actions, and their schemas | | `weavz_read_api` | Read detailed API documentation for a specific action | | `weavz_execute` | Execute code that calls integration actions | CODE mode dramatically reduces context usage (80-98% less) by letting the AI agent discover and call actions dynamically through code, rather than loading all tool schemas upfront. Best for servers with many integrations. ## Creating an MCP Server ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "My AI Tools", "workspaceId": "proj_abc123", "mode": "TOOLS" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { server, bearerToken, mcpEndpoint } = await client.mcpServers.create({ name: 'My AI Tools', workspaceId: 'proj_abc123', mode: 'TOOLS', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.mcp_servers.create( name="My AI Tools", workspace_id="proj_abc123", mode="TOOLS", ) server = result["server"] bearer_token = result["bearerToken"] mcp_endpoint = result["mcpEndpoint"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'My AI Tools', workspaceId: 'proj_abc123', mode: 'TOOLS', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "name": "My AI Tools", "workspaceId": "proj_abc123", "mode": "TOOLS", }, ) data = res.json() ``` The response includes the server's SSE endpoint and bearer token: ```json { "id": "mcp_abc123", "name": "My AI Tools", "mode": "TOOLS", "endpoint": "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/protocol", "bearerToken": "mcp_xxxxxxxxxxxxxxxx" } ``` ## Adding Tools Add integration actions as tools on your MCP server: ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers/{serverId}/tools \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_abc123" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { tool } = await client.mcpServers.addTool('mcp_abc123', { integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_abc123', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.mcp_servers.add_tool("mcp_abc123", integration_name="slack", action_name="send_channel_message", connection_id="conn_abc123", ) tool = result["tool"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_abc123', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_abc123", }, ) data = res.json() ``` Each API call adds one tool. To add multiple tools, make separate requests for each action. ### Tool Naming In TOOLS mode, tools are named using the pattern `{integrationName}__{actionName}`: - `slack__send_channel_message` - `github__create_issue` - `google_sheets__read_rows` ### Integration Aliases You can register the same integration multiple times under different aliases. This is useful when you need separate connections for the same service (e.g., a bot Slack connection and a user Slack connection): ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers/{serverId}/tools \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "integrationAlias": "slack_bot", "actionName": "send_channel_message", "connectionId": "conn_bot" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { tool } = await client.mcpServers.addTool('mcp_abc123', { integrationName: 'slack', integrationAlias: 'slack_bot', actionName: 'send_channel_message', connectionId: 'conn_bot', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.mcp_servers.add_tool("mcp_abc123", integration_name="slack", integration_alias="slack_bot", action_name="send_channel_message", connection_id="conn_bot", ) tool = result["tool"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', integrationAlias: 'slack_bot', actionName: 'send_channel_message', connectionId: 'conn_bot', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "integrationAlias": "slack_bot", "actionName": "send_channel_message", "connectionId": "conn_bot", }, ) data = res.json() ``` This creates tools named `slack_bot__send_channel_message` instead of `slack__send_channel_message`. Each alias can have its own connection and action subset. Alias format: lowercase letters, numbers, hyphens, and underscores. Must start with a letter, max 64 characters. ## Helper Tools For actions with select inputs (e.g., selecting a Slack channel), MCP servers auto-generate companion tools so the AI agent can discover valid values: ``` slack__list_channels → companion tool for the "channel" select input ``` Helper tool naming: `{integrationAlias}__list_{propertyName}s` ## Input Partials Input partials let you assign saved parameter presets to MCP tools. When a partial is assigned, its values are merged into the tool's input at execution time. Enforced keys are locked and cannot be overridden by the AI agent — they are also stripped from the tool's schema so the agent never sees them. ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers/{serverId}/tools \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_abc123", "partialIds": ["partial_001", "partial_002"] }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { tool } = await client.mcpServers.addTool('mcp_abc123', { integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_abc123', partialIds: ['partial_001', 'partial_002'], }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.mcp_servers.add_tool("mcp_abc123", integration_name="slack", action_name="send_channel_message", connection_id="conn_abc123", partial_ids=["partial_001", "partial_002"], ) tool = result["tool"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_abc123', partialIds: ['partial_001', 'partial_002'], }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_abc123", "partialIds": ["partial_001", "partial_002"], }, ) data = res.json() ``` ## Connecting AI Clients ### Claude Desktop Add to your `claude_desktop_config.json`: ```json { "mcpServers": { "weavz": { "command": "npx", "args": [ "-y", "mcp-remote", "https://api.weavz.io/api/v1/mcp/servers/{serverId}/protocol", "--header", "Authorization: Bearer mcp_your_bearer_token" ] } } } ``` ### Cursor Add to your Cursor MCP settings: ```json { "mcpServers": { "weavz": { "command": "npx", "args": [ "-y", "mcp-remote", "https://api.weavz.io/api/v1/mcp/servers/{serverId}/protocol", "--header", "Authorization: Bearer mcp_your_bearer_token" ] } } } ``` ### Any MCP Client The MCP server endpoint supports Server-Sent Events (SSE) transport. Connect using: - **Endpoint:** `https://api.weavz.io/api/v1/mcp/servers/{serverId}/protocol` - **Auth:** `Authorization: Bearer mcp_your_bearer_token` ## Managing Tools ### List tools on a server ```bash curl https://api.weavz.io/api/v1/mcp/servers/{serverId}/tools \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { server, tools } = await client.mcpServers.get('mcp_abc123') ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.mcp_servers.get("mcp_abc123") tools = result["tools"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/mcp_abc123', { headers: { 'Authorization': 'Bearer wvz_your_api_key', }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` ### Remove a tool ```bash curl -X DELETE https://api.weavz.io/api/v1/mcp/servers/{serverId}/tools/{toolId} \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.mcpServers.deleteTool('mcp_abc123', 'tool_xyz') ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.mcp_servers.delete_tool("mcp_abc123", "tool_xyz") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools/tool_xyz', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key', }, }) const data = await res.json() ``` ```python import httpx res = httpx.delete( "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools/tool_xyz", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` ## End-User MCP Servers SaaS developers can create MCP servers scoped to a specific [end user](/docs/concepts/end-users). The server resolves connections belonging to that end user, so an AI agent operating on their behalf automatically uses their connected accounts. Pass `endUserId` when creating the server: ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "User Agent", "workspaceId": "proj_abc123", "endUserId": "user_123", "mode": "TOOLS" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { server, bearerToken, mcpEndpoint } = await client.mcpServers.create({ name: 'User Agent', workspaceId: 'proj_abc123', endUserId: 'user_123', mode: 'TOOLS', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.mcp_servers.create( name="User Agent", workspace_id="proj_abc123", end_user_id="user_123", mode="TOOLS", ) server = result["server"] bearer_token = result["bearerToken"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'User Agent', workspaceId: 'proj_abc123', endUserId: 'user_123', mode: 'TOOLS', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "name": "User Agent", "workspaceId": "proj_abc123", "endUserId": "user_123", "mode": "TOOLS", }, ) data = res.json() ``` When a tool call fails because the end user hasn't connected the required integration, the error response includes a setup URL. Share this URL with the end user so they can connect their account and retry. ## Next Steps - [Actions](/docs/concepts/actions) — understand the actions that MCP tools wrap - [Integrations](/docs/concepts/integrations) — browse available integrations - [Storage & KV Store](/docs/concepts/storage-and-kv) — use built-in persistence - [End Users](/docs/concepts/end-users) — learn about the unified identity model Create your first MCP server in the [dashboard](https://platform.weavz.io) or follow the [MCP Tool Mode](/docs/guides/mcp-tool-mode) guide. ### Input Partials > Saved parameter presets with defaults and enforcement for actions and triggers. Source: https://weavz.io/docs/concepts/input-partials # Input Partials Input partials are saved parameter configurations (presets) that you attach to actions and triggers. They let you pre-fill default values, lock down enforced values that cannot be overridden, and share configurations across your team. ## How Partials Work A partial is a named configuration scoped to a workspace and integration. It stores: - **Values** — key-value pairs that pre-fill action inputs - **Enforced keys** — a subset of those values that cannot be overridden at runtime - **Scope** — either integration-wide (applies to all actions) or action-specific When you execute an action or enable a trigger, partials merge into the final input following a defined order. ## Merge Order When an action executes, inputs are merged in this order (each layer overrides the previous): 1. **Input defaults** — the integration's built-in default values 2. **Partial values** (non-enforced) — your preset values that users can override 3. **Runtime input** — the values provided at execution time 4. **Enforced values** — your preset values that cannot be overridden This means enforced keys always win, regardless of what the caller passes. ## Creating a Partial ```bash curl -X POST https://api.weavz.io/api/v1/partials \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "workspaceId": "proj_abc123", "integrationName": "slack", "actionName": "send_channel_message", "name": "General Channel Preset", "values": { "channel": "C01ABCDEF" }, "enforcedKeys": ["channel"] }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { partial } = await client.partials.create({ workspaceId: 'proj_abc123', integrationName: 'slack', actionName: 'send_channel_message', name: 'General Channel Preset', values: { channel: 'C01ABCDEF' }, enforcedKeys: ['channel'], }) console.log(`Created partial: ${partial.id}`) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.partials.create( workspace_id="proj_abc123", integration_name="slack", action_name="send_channel_message", name="General Channel Preset", values={"channel": "C01ABCDEF"}, enforced_keys=["channel"], ) print(f"Created partial: {result['partial']['id']}") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/partials', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ workspaceId: 'proj_abc123', integrationName: 'slack', actionName: 'send_channel_message', name: 'General Channel Preset', values: { channel: 'C01ABCDEF' }, enforcedKeys: ['channel'], }), }) const { partial } = await res.json() console.log(`Created partial: ${partial.id}`) ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/partials", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "workspaceId": "proj_abc123", "integrationName": "slack", "actionName": "send_channel_message", "name": "General Channel Preset", "values": {"channel": "C01ABCDEF"}, "enforcedKeys": ["channel"], }, ) partial = res.json()["partial"] print(f"Created partial: {partial['id']}") ``` In this example, the `channel` field is both set as a value and listed in `enforcedKeys`. This means the channel is always `C01ABCDEF` and callers cannot override it. ## Default Partials Mark a partial as the default for its scope, and it applies automatically when no explicit `partialIds` are provided: ```bash curl -X POST https://api.weavz.io/api/v1/partials/{partialId}/set-default \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"isDefault": true}' ``` ```typescript await client.partials.setDefault(partialId, true) ``` ```python client.partials.set_default(partial_id, True) ``` ```typescript await fetch(`https://api.weavz.io/api/v1/partials/${partialId}/set-default`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ isDefault: true }), }) ``` ```python httpx.post( f"https://api.weavz.io/api/v1/partials/{partial_id}/set-default", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"isDefault": True}, ) ``` Default partials auto-resolve in this order: action-specific default first, then integration-wide default. Up to 2 defaults can stack. ## Using Partials with Actions Pass `partialIds` when executing an action to apply specific partials: ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "input": { "text": "Hello from Weavz!" }, "workspaceId": "proj_abc123", "partialIds": ["partial_id_here"] }' ``` ```typescript const { output } = await client.actions.execute('slack', 'send_channel_message', { input: { text: 'Hello from Weavz!' }, workspaceId: 'proj_abc123', partialIds: ['partial_id_here'], }) ``` ```python result = client.actions.execute( "slack", "send_channel_message", input={"text": "Hello from Weavz!"}, workspace_id="proj_abc123", partial_ids=["partial_id_here"], ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', input: { text: 'Hello from Weavz!' }, workspaceId: 'proj_abc123', partialIds: ['partial_id_here'], }), }) ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "input": {"text": "Hello from Weavz!"}, "workspaceId": "proj_abc123", "partialIds": ["partial_id_here"], }, ) ``` Since the partial enforces `channel`, the caller only needs to provide `text`. The channel is locked to `C01ABCDEF`. ## MCP Server Behavior When a partial is assigned to an MCP server tool, enforced keys are automatically removed from the tool's input schema. This means the AI agent never sees or tries to set those fields — they are silently injected at execution time. This is useful for: - **Locking down channels** — ensure a Slack bot only posts to a specific channel - **Pre-filling API parameters** — set a default model for OpenAI calls - **Restricting scope** — limit which GitHub repo an agent can interact with Assign partials to MCP tools when adding or updating them: ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers/{serverId}/tools \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_abc", "partialIds": ["partial_id_here"] }' ``` ```typescript await client.mcpServers.addTool(serverId, { integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_abc', partialIds: ['partial_id_here'], }) ``` ```python client.mcp_servers.add_tool( server_id, integration_name="slack", action_name="send_channel_message", connection_id="conn_abc", partial_ids=["partial_id_here"], ) ``` ```typescript await fetch(`https://api.weavz.io/api/v1/mcp/servers/${serverId}/tools`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_abc', partialIds: ['partial_id_here'], }), }) ``` ```python httpx.post( f"https://api.weavz.io/api/v1/mcp/servers/{server_id}/tools", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_abc", "partialIds": ["partial_id_here"], }, ) ``` ## Integration-Wide vs Action-Specific - **Action-specific** partials (`actionName` set) only apply to that action - **Integration-wide** partials (`actionName` null) apply to all actions for that integration When both exist, action-specific partials take precedence over integration-wide ones. ## Next Steps - [Using Input Partials](/docs/guides/using-input-partials) — step-by-step guide - [Input Partials API Reference](/docs/api-reference/input-partials) — full endpoint documentation - [Actions](/docs/concepts/actions) — understand action execution - [MCP Servers](/docs/concepts/mcp-servers) — configure MCP tools with partials ### Storage & KV Store > Built-in file storage and key-value persistence for your integrations. Source: https://weavz.io/docs/concepts/storage-and-kv # Storage & KV Store Weavz includes two built-in integrations for persistent data storage. Both are available without external authentication and work alongside your other integrations. ## Storage Integration The Storage integration provides file CRUD operations backed by object storage. Use it to store files, documents, and binary data. ### Available Actions | Action | Description | |---|---| | `read_file` | Read a file's contents by path | | `write_file` | Write content to a file (creates or overwrites) | | `delete_file` | Delete a file by path | | `list_files` | List files in a directory with optional prefix filter | ### Examples **Write a file:** ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "storage", "actionName": "write_file", "workspaceId": "proj_abc123", "input": { "path": "reports/monthly.json", "content": "{\"month\": \"January\", \"total\": 1500}" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('storage', 'write_file', { workspaceId: 'proj_abc123', input: { path: 'reports/monthly.json', content: '{"month": "January", "total": 1500}', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("storage", "write_file", workspace_id="proj_abc123", input={ "path": "reports/monthly.json", "content": '{"month": "January", "total": 1500}', }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'storage', actionName: 'write_file', workspaceId: 'proj_abc123', input: { path: 'reports/monthly.json', content: '{"month": "January", "total": 1500}', }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "storage", "actionName": "write_file", "workspaceId": "proj_abc123", "input": { "path": "reports/monthly.json", "content": '{"month": "January", "total": 1500}', }, }, ) data = res.json() ``` **Read a file:** ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "storage", "actionName": "read_file", "workspaceId": "proj_abc123", "input": { "path": "reports/monthly.json" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const result = await client.actions.execute('storage', 'read_file', { workspaceId: 'proj_abc123', input: { path: 'reports/monthly.json', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.actions.execute("storage", "read_file", workspace_id="proj_abc123", input={"path": "reports/monthly.json"}, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'storage', actionName: 'read_file', workspaceId: 'proj_abc123', input: { path: 'reports/monthly.json' }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "storage", "actionName": "read_file", "workspaceId": "proj_abc123", "input": {"path": "reports/monthly.json"}, }, ) data = res.json() ``` **List files:** ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "storage", "actionName": "list_files", "workspaceId": "proj_abc123", "input": { "prefix": "reports/" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const result = await client.actions.execute('storage', 'list_files', { workspaceId: 'proj_abc123', input: { prefix: 'reports/' }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.actions.execute("storage", "list_files", workspace_id="proj_abc123", input={"prefix": "reports/"}, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'storage', actionName: 'list_files', workspaceId: 'proj_abc123', input: { prefix: 'reports/' }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "storage", "actionName": "list_files", "workspaceId": "proj_abc123", "input": {"prefix": "reports/"}, }, ) data = res.json() ``` ## KV Store Integration The KV Store integration provides key-value persistence. Use it for caching, state management, counters, and simple data structures. ### Available Actions | Action | Description | |---|---| | `put` | Set a key-value pair (string value) | | `get` | Retrieve the value for a key | | `delete` | Delete a key-value pair | | `add_to_list` | Append a value to a list stored at a key | | `remove_from_list` | Remove a value from a list stored at a key | ### Examples **Store a value:** ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "put", "workspaceId": "proj_abc123", "input": { "key": "last_sync_timestamp", "value": "2025-01-15T10:00:00Z" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('kv-store', 'put', { workspaceId: 'proj_abc123', input: { key: 'last_sync_timestamp', value: '2025-01-15T10:00:00Z', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("kv-store", "put", workspace_id="proj_abc123", input={ "key": "last_sync_timestamp", "value": "2025-01-15T10:00:00Z", }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'put', workspaceId: 'proj_abc123', input: { key: 'last_sync_timestamp', value: '2025-01-15T10:00:00Z', }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "kv-store", "actionName": "put", "workspaceId": "proj_abc123", "input": { "key": "last_sync_timestamp", "value": "2025-01-15T10:00:00Z", }, }, ) data = res.json() ``` **Retrieve a value:** ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "get", "workspaceId": "proj_abc123", "input": { "key": "last_sync_timestamp" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const result = await client.actions.execute('kv-store', 'get', { workspaceId: 'proj_abc123', input: { key: 'last_sync_timestamp' }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.actions.execute("kv-store", "get", workspace_id="proj_abc123", input={"key": "last_sync_timestamp"}, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'get', workspaceId: 'proj_abc123', input: { key: 'last_sync_timestamp' }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "kv-store", "actionName": "get", "workspaceId": "proj_abc123", "input": {"key": "last_sync_timestamp"}, }, ) data = res.json() ``` **Manage lists:** ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "add_to_list", "workspaceId": "proj_abc123", "input": { "key": "processed_orders", "value": "order_123" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('kv-store', 'add_to_list', { workspaceId: 'proj_abc123', input: { key: 'processed_orders', value: 'order_123', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("kv-store", "add_to_list", workspace_id="proj_abc123", input={ "key": "processed_orders", "value": "order_123", }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'add_to_list', workspaceId: 'proj_abc123', input: { key: 'processed_orders', value: 'order_123', }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "kv-store", "actionName": "add_to_list", "workspaceId": "proj_abc123", "input": { "key": "processed_orders", "value": "order_123", }, }, ) data = res.json() ``` ## Persistence Scoping Storage and KV Store actions include a `scope` input property that controls data isolation. Three scoping modes are available: | Scope | Value | Description | |-------|-------|-------------| | **End User Bound** | `end_user` (default) | Data is isolated per end user within the workspace. Requires `endUserId` in the request. Falls back to workspace scope if `endUserId` is not provided. | | **Workspace Bound** | `workspace` | Data is shared across the entire workspace. Different workspaces cannot access each other's data. | | **External ID Bound** | `external` | Data is scoped to a custom identifier via the `externalId` input property within the workspace. Useful for tenant, session, or entity-level isolation. | ### End-user-bound (default) The default scope is `end_user`. When you pass `endUserId` in the action execution request, data is isolated per end user within the workspace. You can omit the `scope` field — it defaults to `end_user`. ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "put", "workspaceId": "proj_abc123", "endUserId": "user_12345", "input": { "key": "preferences", "value": {"theme": "dark"}, "scope": "end_user" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('kv-store', 'put', { workspaceId: 'proj_abc123', endUserId: 'user_12345', input: { key: 'preferences', value: { theme: 'dark' }, scope: 'end_user', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("kv-store", "put", workspace_id="proj_abc123", end_user_id="user_12345", input={"key": "preferences", "value": {"theme": "dark"}, "scope": "end_user"}, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'put', workspaceId: 'proj_abc123', endUserId: 'user_12345', input: { key: 'preferences', value: { theme: 'dark' }, scope: 'end_user' }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "kv-store", "actionName": "put", "workspaceId": "proj_abc123", "endUserId": "user_12345", "input": {"key": "preferences", "value": {"theme": "dark"}, "scope": "end_user"}, }, ) data = res.json() ``` Data stored with `endUserId: "user_12345"` is isolated from data stored with `endUserId: "user_67890"` or workspace-scoped data. This is the recommended approach for multi-tenant applications. ### Workspace-bound Set `scope` to `"workspace"` to share data across all end users in a workspace. Different workspaces cannot access each other's data. ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "storage", "actionName": "write_file", "workspaceId": "proj_abc123", "input": { "path": "config.json", "content": "...", "scope": "workspace" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('storage', 'write_file', { workspaceId: 'proj_abc123', input: { path: 'config.json', content: '...', scope: 'workspace', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("storage", "write_file", workspace_id="proj_abc123", input={"path": "config.json", "content": "...", "scope": "workspace"}, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'storage', actionName: 'write_file', workspaceId: 'proj_abc123', input: { path: 'config.json', content: '...', scope: 'workspace' }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "storage", "actionName": "write_file", "workspaceId": "proj_abc123", "input": {"path": "config.json", "content": "...", "scope": "workspace"}, }, ) data = res.json() ``` ### External-ID-bound Set `scope` to `"external"` and provide an `externalId` to create a custom scope tied to an external identifier. Useful when you need scoping tied to a specific tenant, session, or entity that doesn't map to an end user. ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "put", "workspaceId": "proj_abc123", "input": { "key": "preferences", "value": {"theme": "dark"}, "scope": "external", "externalId": "tenant_123" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('kv-store', 'put', { workspaceId: 'proj_abc123', input: { key: 'preferences', value: { theme: 'dark' }, scope: 'external', externalId: 'tenant_123', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("kv-store", "put", workspace_id="proj_abc123", input={ "key": "preferences", "value": {"theme": "dark"}, "scope": "external", "externalId": "tenant_123", }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'put', workspaceId: 'proj_abc123', input: { key: 'preferences', value: { theme: 'dark' }, scope: 'external', externalId: 'tenant_123', }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "kv-store", "actionName": "put", "workspaceId": "proj_abc123", "input": { "key": "preferences", "value": {"theme": "dark"}, "scope": "external", "externalId": "tenant_123", }, }, ) data = res.json() ``` Data stored with `externalId: "tenant_123"` is isolated from data stored with `externalId: "tenant_456"` or workspace-scoped data. The same `externalId` in different workspaces is also fully isolated. ## Use Cases ### Caching Cache API responses to reduce calls to rate-limited services: ```bash # Check cache curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "get", "workspaceId": "proj_abc123", "input": { "key": "cache:slack:channels:W123" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const cached = await client.actions.execute('kv-store', 'get', { workspaceId: 'proj_abc123', input: { key: `cache:slack:channels:${workspaceId}` }, }) if (!cached.output?.value) { const channels = await client.actions.execute('slack', 'list_channels', { workspaceId: 'proj_abc123', input: {}, connectionExternalId: 'my_slack', }) await client.actions.execute('kv-store', 'put', { workspaceId: 'proj_abc123', input: { key: `cache:slack:channels:${workspaceId}`, value: JSON.stringify(channels.output), }, }) } ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") import json cached = client.actions.execute("kv-store", "get", workspace_id="proj_abc123", input={"key": f"cache:slack:channels:{workspace_id}"}, ) if not cached.get("output", {}).get("value"): channels = client.actions.execute("slack", "list_channels", workspace_id="proj_abc123", input={}, connection_external_id="my_slack", ) client.actions.execute("kv-store", "put", workspace_id="proj_abc123", input={ "key": f"cache:slack:channels:{workspace_id}", "value": json.dumps(channels["output"]), }, ) ``` ```typescript const headers = { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', } const cacheRes = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'get', workspaceId: 'proj_abc123', input: { key: `cache:slack:channels:${workspaceId}` }, }), }) const cached = await cacheRes.json() ``` ```python import httpx headers = {"Authorization": "Bearer wvz_your_api_key"} res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers=headers, json={ "integrationName": "kv-store", "actionName": "get", "workspaceId": "proj_abc123", "input": {"key": f"cache:slack:channels:{workspace_id}"}, }, ) cached = res.json() ``` ### State Management Track workflow state across multiple integration actions: ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "put", "workspaceId": "proj_abc123", "input": { "key": "sync:cust_123:status", "value": "in_progress" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('kv-store', 'put', { workspaceId: 'proj_abc123', input: { key: `sync:${customerId}:status`, value: 'in_progress', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("kv-store", "put", workspace_id="proj_abc123", input={ "key": f"sync:{customer_id}:status", "value": "in_progress", }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'put', workspaceId: 'proj_abc123', input: { key: `sync:${customerId}:status`, value: 'in_progress', }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "kv-store", "actionName": "put", "workspaceId": "proj_abc123", "input": { "key": f"sync:{customer_id}:status", "value": "in_progress", }, }, ) data = res.json() ``` ### File Storage Store generated reports, exports, or media: ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "storage", "actionName": "write_file", "workspaceId": "proj_abc123", "input": { "path": "exports/cust_123/report-2025-01.csv", "content": "name,amount\nAlice,100\nBob,200" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('storage', 'write_file', { workspaceId: 'proj_abc123', input: { path: `exports/${customerId}/report-2025-01.csv`, content: csvData, }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("storage", "write_file", workspace_id="proj_abc123", input={ "path": f"exports/{customer_id}/report-2025-01.csv", "content": csv_data, }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'storage', actionName: 'write_file', workspaceId: 'proj_abc123', input: { path: `exports/${customerId}/report-2025-01.csv`, content: csvData, }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "storage", "actionName": "write_file", "workspaceId": "proj_abc123", "input": { "path": f"exports/{customer_id}/report-2025-01.csv", "content": csv_data, }, }, ) data = res.json() ``` ## Next Steps - [Actions](/docs/concepts/actions) — learn how to execute integration actions - [Workspace Integrations](/docs/api-reference/workspace-integrations) — configure connection strategies per workspace - [Integrations](/docs/concepts/integrations) — browse all available integrations Start using storage in the [Playground](/docs/guides/playground) or follow the [Storage & KV guide](/docs/guides/using-storage-and-kv). ### Code & Sandbox > Run custom JavaScript, Python, and Shell code in secure sandbox environments. Source: https://weavz.io/docs/concepts/code-and-sandbox # Code & Sandbox Weavz includes built-in code execution integrations — from lightweight data transforms to full multi-language sandbox environments. Use them to run custom logic, process data between integration calls, or build complex multi-step workflows. ## Code Integration A lightweight, secure JavaScript sandbox for data transformation and processing. Zero setup required — works out of the box. - **Action:** `run_code` - **Input:** JavaScript code + optional `inputs` JSON object - **Output:** Return value + captured console logs - **No network access, no filesystem, no imports** — pure computation only ### Use Cases - Data transformation between API calls - Text parsing and formatting - JSON reshaping and filtering - Calculations and aggregations ### Example: Transform API data ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "code", "actionName": "run_code", "workspaceId": "proj_abc123", "input": { "code": "const data = inputs.rows.map(row => ({ name: row[0], email: row[1], score: parseInt(row[2]) })); return data.filter(d => d.score > 80);", "inputs": { "rows": [["Alice", "alice@example.com", "90"], ["Bob", "bob@example.com", "70"]] } } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('code', 'run_code', { workspaceId: 'proj_abc123', input: { code: ` const data = inputs.rows.map(row => ({ name: row[0], email: row[1], score: parseInt(row[2]) })); return data.filter(d => d.score > 80); `, inputs: { rows: sheetsData } } }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("code", "run_code", workspace_id="proj_abc123", input={ "code": """ const data = inputs.rows.map(row => ({ name: row[0], email: row[1], score: parseInt(row[2]) })); return data.filter(d => d.score > 80); """, "inputs": {"rows": sheets_data}, }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'code', actionName: 'run_code', workspaceId: 'proj_abc123', input: { code: 'const data = inputs.rows.map(row => ({ name: row[0], email: row[1], score: parseInt(row[2]) })); return data.filter(d => d.score > 80);', inputs: { rows: sheetsData }, }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "code", "actionName": "run_code", "workspaceId": "proj_abc123", "input": { "code": "const data = inputs.rows.map(row => ({ name: row[0], email: row[1], score: parseInt(row[2]) })); return data.filter(d => d.score > 80);", "inputs": {"rows": sheets_data}, }, }, ) data = res.json() ``` ## Advanced Code Integration A full multi-language sandbox environment with persistent state and network access. - **Languages:** JavaScript, Python, Shell - **Network access:** fetch, HTTP libraries, external APIs - **Filesystem:** `/tmp` and `/workspace` directories - **Persistent sandbox:** Keep installed packages and state across executions - **Persistent storage:** Mounted at `/persistent-storage` - **Timeout:** Up to 60 seconds per execution - **Storage scoping:** End-user-bound (when `endUserId` provided), workspace-bound, or external-ID-bound via custom ID. Persistent sandbox containers are also per-user when end-user scoped. ### Example: Python data processing ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "advanced-code", "actionName": "run_code", "workspaceId": "proj_abc123", "input": { "language": "python", "code": "import json\ndata = json.loads(inputs[\"raw\"])\nresult = sum(d[\"amount\"] for d in data)\nprint(f\"Total: {result}\")", "persistSandbox": true } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('advanced-code', 'run_code', { workspaceId: 'proj_abc123', input: { language: 'python', code: `import json data = json.loads(inputs["raw"]) result = sum(d["amount"] for d in data) print(f"Total: {result}")`, persistSandbox: true, }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("advanced-code", "run_code", workspace_id="proj_abc123", input={ "language": "python", "code": 'import json\ndata = json.loads(inputs["raw"])\nresult = sum(d["amount"] for d in data)\nprint(f"Total: {result}")', "persistSandbox": True, }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'advanced-code', actionName: 'run_code', workspaceId: 'proj_abc123', input: { language: 'python', code: 'import json\ndata = json.loads(inputs["raw"])\nresult = sum(d["amount"] for d in data)\nprint(f"Total: {result}")', persistSandbox: true, }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "advanced-code", "actionName": "run_code", "workspaceId": "proj_abc123", "input": { "language": "python", "code": 'import json\ndata = json.loads(inputs["raw"])\nresult = sum(d["amount"] for d in data)\nprint(f"Total: {result}")', "persistSandbox": True, }, }, ) data = res.json() ``` ### Example: Shell scripting ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "advanced-code", "actionName": "run_code", "workspaceId": "proj_abc123", "input": { "language": "shell", "code": "echo \"Files in workspace:\"\nls -la /workspace\necho \"Done\"" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.actions.execute('advanced-code', 'run_code', { workspaceId: 'proj_abc123', input: { language: 'shell', code: 'echo "Files in workspace:"\nls -la /workspace\necho "Done"', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.actions.execute("advanced-code", "run_code", workspace_id="proj_abc123", input={ "language": "shell", "code": 'echo "Files in workspace:"\nls -la /workspace\necho "Done"', }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'advanced-code', actionName: 'run_code', workspaceId: 'proj_abc123', input: { language: 'shell', code: 'echo "Files in workspace:"\nls -la /workspace\necho "Done"', }, }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "advanced-code", "actionName": "run_code", "workspaceId": "proj_abc123", "input": { "language": "shell", "code": 'echo "Files in workspace:"\nls -la /workspace\necho "Done"', }, }, ) data = res.json() ``` ## When to Use Which | Feature | Code | Advanced Code | MCP Code Mode | |---------|------|---------------|---------------| | Languages | JavaScript only | JS, Python, Shell | JavaScript only | | Network access | No | Yes | Yes (via `weavz.*`) | | Access to integrations | No | No | Yes (full `weavz.*` namespace) | | Persistent state | No | Yes (optional) | No | | Persistent storage | No | Yes | No | | Best for | Data transforms | Complex processing | AI agent workflows | | Setup | Zero | Available on supported plans | MCP server in CODE mode | ## Next Steps - [MCP Code Mode](/docs/guides/mcp-code-mode) — AI agent code execution with integration access - [Storage & KV](/docs/concepts/storage-and-kv) — persistent data storage - [Actions](/docs/concepts/actions) — execute integration actions ### End Users > Represent your customers and their connections with a unified identity model. Source: https://weavz.io/docs/concepts/end-users # End Users End users represent the people who use your product. By registering them in Weavz, you can let each end user connect their own third-party accounts, track their connections, and execute actions on their behalf. ## Why End Users? Without end users, multi-tenant connection management requires manually tracking `externalId` strings across connections, actions, and connect flows. End users provide a **first-class identity** that ties everything together: - Each end user **owns their connections** — when you delete an end user, their connections are cleaned up automatically - **Connect portal** — generate a URL where an end user can connect their own accounts - **Connection resolution** — pass `endUserId` when executing actions and Weavz resolves the right connection - **Audit trail** — see all connections belonging to a specific end user in one place - **MCP servers** — create MCP servers scoped to an end user, so AI agents use their connected integrations automatically ## End User Types End users come in two flavors: | Type | Created Via | Identity Field | Use Case | |------|-------------|----------------|----------| | **External** | API (`POST /api/v1/end-users`) | `externalId` | Your customers — users of your product | | **Member** | Dashboard invitation | `authUserId` | Your team members using the dashboard | Most integrations will use **external** end users to represent the customers of your SaaS product. ## Creating End Users End users are scoped to a workspace. Each `externalId` must be unique within its workspace. ```bash curl -X POST https://api.weavz.io/api/v1/end-users \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "externalId": "user_123", "displayName": "Alice Johnson", "email": "alice@example.com", "metadata": { "plan": "pro", "company": "Acme Inc" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { endUser } = await client.endUsers.create({ workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', externalId: 'user_123', displayName: 'Alice Johnson', email: 'alice@example.com', metadata: { plan: 'pro', company: 'Acme Inc', }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.end_users.create( workspace_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890", external_id="user_123", display_name="Alice Johnson", email="alice@example.com", metadata={"plan": "pro", "company": "Acme Inc"}, ) end_user = result["endUser"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/end-users', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', externalId: 'user_123', displayName: 'Alice Johnson', email: 'alice@example.com', metadata: { plan: 'pro', company: 'Acme Inc' }, }), }) const { endUser } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/end-users", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "externalId": "user_123", "displayName": "Alice Johnson", "email": "alice@example.com", "metadata": {"plan": "pro", "company": "Acme Inc"}, }, ) end_user = res.json()["endUser"] ``` ## Auto-Creation End users can also be created automatically when a connection is established through the hosted connect flow with an `endUserId` parameter. If the end user doesn't exist yet, Weavz creates one for you. ## Connect Portal The connect portal lets your end users connect their own third-party accounts through a hosted page. Generate a portal URL for an end user: ```bash curl -X POST https://api.weavz.io/api/v1/end-users/{endUserId}/connect-token \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { connectUrl, token, expiresAt } = await client.endUsers.createConnectToken( endUser.id, { integrationName: 'slack' } ) // Open connectUrl in a popup or redirect the end user to it ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.end_users.create_connect_token( end_user["id"], integration_name="slack", ) connect_url = result["connectUrl"] # Open connect_url in a popup or redirect the end user to it ``` ```typescript const res = await fetch(`https://api.weavz.io/api/v1/end-users/${endUserId}/connect-token`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack' }), }) const { connectUrl, token, expiresAt } = await res.json() ``` ```python import httpx res = httpx.post( f"https://api.weavz.io/api/v1/end-users/{end_user_id}/connect-token", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"integrationName": "slack"}, ) data = res.json() connect_url = data["connectUrl"] ``` ### Portal modes - **Single integration** — pass `integrationName` to restrict the portal to one integration (e.g., only Slack) - **Multi-integration** — omit `integrationName` to let the user connect any integration configured in the workspace ## Connection Ownership Every connection created through the connect portal is automatically linked to the end user. You can view all connections for an end user: ```bash curl https://api.weavz.io/api/v1/end-users/{endUserId} \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { endUser, connections } = await client.endUsers.get(endUserId) console.log(`${endUser.displayName} has ${connections.length} connections`) ``` ```python result = client.end_users.get(end_user_id) end_user = result["endUser"] connections = result["connections"] print(f"{end_user['displayName']} has {len(connections)} connections") ``` ```typescript const res = await fetch(`https://api.weavz.io/api/v1/end-users/${endUserId}`, { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const { endUser, connections } = await res.json() ``` ```python import httpx res = httpx.get( f"https://api.weavz.io/api/v1/end-users/{end_user_id}", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() connections = data["connections"] ``` When you delete an end user, all their connections are deleted as well. ## Connection Strategies End users work with [workspace integration](/docs/concepts/organizations-and-workspaces#connection-strategies) connection strategies: | Strategy | End User Behavior | |---|---| | `fixed` | All end users share the same connection. No per-user connections. | | `per_user` | Each end user must connect their own account. No fallback. | | `per_user_with_fallback` | End users can connect their own account, with a shared default fallback. | When you execute an action with `endUserId`, Weavz looks up the end user's connection for that integration. With `per_user_with_fallback`, if the end user hasn't connected their own account, the workspace's default connection is used instead. ## Executing Actions as an End User Pass `endUserId` when executing actions to use the end user's connection: ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "input": { "channel": "C0123456789", "text": "Hello from the user!" }, "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "endUserId": "user_123" }' ``` ```typescript const result = await client.actions.execute('slack', 'send_channel_message', { workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', endUserId: 'user_123', input: { channel: 'C0123456789', text: 'Hello from the user!', }, }) ``` ```python result = client.actions.execute( "slack", "send_channel_message", workspace_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890", end_user_id="user_123", input={ "channel": "C0123456789", "text": "Hello from the user!", }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', input: { channel: 'C0123456789', text: 'Hello from the user!' }, workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', endUserId: 'user_123', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "input": {"channel": "C0123456789", "text": "Hello from the user!"}, "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "endUserId": "user_123", }, ) data = res.json() ``` ## Email Invitations If an end user has an email address, you can send them an invitation with a link to connect their accounts: ```bash curl -X POST https://api.weavz.io/api/v1/end-users/{endUserId}/invite \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "email": "alice@example.com", "integrationName": "slack" }' ``` ```typescript await client.endUsers.invite(endUser.id, { email: 'alice@example.com', integrationName: 'slack', }) ``` ```python client.end_users.invite( end_user["id"], email="alice@example.com", integration_name="slack", ) ``` ```typescript await fetch(`https://api.weavz.io/api/v1/end-users/${endUserId}/invite`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ email: 'alice@example.com', integrationName: 'slack', }), }) ``` ```python import httpx httpx.post( f"https://api.weavz.io/api/v1/end-users/{end_user_id}/invite", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "email": "alice@example.com", "integrationName": "slack", }, ) ``` The email contains a link to the connect portal where the end user can authenticate with the specified integration. ## Next Steps - [End Users API Reference](/docs/api-reference/end-users) — full endpoint documentation - [Managing End Users](/docs/guides/managing-end-users) — step-by-step guide - [Connections](/docs/concepts/connections) — learn about connection ownership and resolution - [Organizations & Workspaces](/docs/concepts/organizations-and-workspaces) — understand the resource hierarchy ### Plan Limits & Quotas > Rate limits, resource quotas, overages, and add-on packs Source: https://weavz.io/docs/concepts/plan-limits # Plan Limits & Quotas Every Weavz plan includes generous resource limits. Paid plans use soft limits — you're never hard-blocked from creating resources. ## Rate Limits API rate limits are enforced per-organization on a per-minute sliding window. | Plan | Requests/min | |---|---| | Free | 60 | | Pro | 600 | | Team | 2,000 | | Scale | 5,000 | | Enterprise | Custom | Rate limit headers are returned on every response: - `X-RateLimit-Limit` — max requests per minute - `X-RateLimit-Remaining` — requests remaining in current window - `X-RateLimit-Reset` — Unix timestamp when the window resets When rate-limited, you'll receive a `429 Too Many Requests` response. ## Resource Quotas Resources are counted per-organization. Each plan includes a base amount: | Resource | Free | Pro | Team | Scale | Enterprise | |---|---|---|---|---|---| | Actions/month | 1,000 | 25,000 | 150,000 | 500,000 | Unlimited | | Connections | 5 | 50 | 250 | 1,000 | Unlimited | | MCP Servers | 25 | 250 | 2,500 | 10,000 | Unlimited | | Workspaces | 3 | 50 | 250 | 1,000 | Unlimited | | Members | 2 | 10 | 50 | 100 | Unlimited | | API Keys | 2 | 10 | 50 | 100 | Unlimited | | End Users | 1,000 | Unlimited | Unlimited | Unlimited | Unlimited | | Storage | 100 MB | 1 GB | 10 GB | 100 GB | Unlimited | | KV Entries | 1,000 | 10,000 | 100,000 | 1,000,000 | Unlimited | ## Resource Overages On paid plans, exceeding your included resource quota does **not** block you. Instead, additional resources are billed as overages: - **Connections, Workspaces, MCP Servers** — $0.10/mo each - **Team Members** — $5.00/mo each Overages are automatically calculated and added to your monthly invoice. On the Free plan, resources are hard-capped at the included amount (with a small buffer for connections and MCP servers). You can set an optional **spend cap** to limit your monthly overage costs. When the cap is reached, additional resource creation is blocked until the next billing period. ## Sandbox Limits Code execution runs in a secure, isolated sandbox environment. | Plan | Max Duration/Session | Monthly Total | |---|---|---| | Free | 5 seconds | 10 minutes | | Pro | 30 seconds | 2 hours | | Team | 300 seconds | 10 hours | | Scale | 600 seconds | 50 hours | | Enterprise | 600 seconds | Unlimited | ## Polling Triggers Polling triggers check for new events at regular intervals: | Plan | Minimum Interval | |---|---| | Free | 5 minutes | | Pro / Team / Scale / Enterprise | 1 minute | ## Activity Retention Activity logs are retained based on your plan: | Plan | Retention | |---|---| | Free | 7 days | | Pro | 30 days | | Team | 90 days | | Scale | 180 days | | Enterprise | 1 year | ## Add-On Packs Need more capacity? Purchase add-on packs from the billing dashboard. Add-ons are charged immediately and apply to the current billing period. Add-on quotas reset each billing cycle. Add-on packs require a paid plan. Each category has a minimum tier — see the table below. ### Action Packs (Pro+) Available on **Pro, Team, Scale, and Enterprise** plans. | Pack | Price | |---|---| | +10,000 actions | $5 | | +50,000 actions | $15 | | +200,000 actions | $40 | | +1,000,000 actions | $100 | ### Sandbox Packs (Team+) Available on **Team, Scale, and Enterprise** plans. | Pack | Price | |---|---| | +10 hours | $15 | | +50 hours | $50 | ### Storage Packs (Team+) Available on **Team, Scale, and Enterprise** plans. | Pack | Price | |---|---| | +5 GB | $5 | | +25 GB | $15 | ### KV Store Packs (Team+) Available on **Team, Scale, and Enterprise** plans. | Pack | Price | |---|---| | +10,000 entries | $5 | | +100,000 entries | $15 | ### Stacking You can purchase the same add-on pack multiple times (up to 10×) within a billing period. If you regularly need more capacity, consider upgrading to the next tier — it's usually more cost-effective when you need capacity across multiple dimensions. ### Tier Requirements Summary | Category | Free | Pro | Team | Scale | Enterprise | |---|---|---|---|---|---| | Action Packs | — | ✓ | ✓ | ✓ | ✓ | | Sandbox Packs | — | — | ✓ | ✓ | ✓ | | Storage Packs | — | — | ✓ | ✓ | ✓ | | KV Store Packs | — | — | ✓ | ✓ | ✓ | ## Quota Exceeded Errors When a hard limit is reached, the API returns a `402` status with: ```json { "error": "Quota exceeded: actions (1000/1000 on free plan)", "code": "QUOTA_EXCEEDED" } ``` To resolve: upgrade your plan or purchase an add-on pack from the billing dashboard. --- ## Guides ### API Keys > Create and manage API keys for authenticating with the Weavz API. Source: https://weavz.io/docs/guides/api-keys API keys are the primary way to authenticate with the Weavz API from your backend services. Each key is scoped to an organization and provides full access to that organization's resources. ## Key Format All Weavz API keys use the `wvz_` prefix followed by a random string: ```text wvz_abc123def456... ``` This prefix makes it easy to identify Weavz keys in your codebase and allows secret scanners to detect leaked credentials. ## Creating API Keys Navigate to **Settings → API Keys** in the Weavz dashboard. Click **Create API Key** and enter a descriptive name (e.g., `production-backend`, `staging-server`). Optionally set an expiration date for automatic key rotation. Click **Create** and copy the key immediately — it will only be shown once. ```bash curl -X POST https://api.weavz.io/api/v1/api-keys \ -H "Authorization: Bearer wvz_your_existing_key" \ -H "Content-Type: application/json" \ -d '{ "name": "production-backend", "expiresAt": "2026-12-31T23:59:59Z" }' ``` Response: ```json { "apiKey": { "id": "key_abc123", "name": "production-backend", "expiresAt": "2026-12-31T23:59:59Z", "createdAt": "2025-01-15T10:30:00Z" }, "plainKey": "wvz_abc123def456..." } ``` The `plainKey` field contains the full API key. This is the only time it will be returned — Weavz stores a hashed version at rest. ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_key' }) const { apiKey, plainKey } = await client.apiKeys.create({ name: 'staging-server', expiresAt: '2026-06-01T00:00:00Z', }) console.log('New key:', plainKey) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_key") result = client.api_keys.create(name="staging-server") print("New key:", result["plainKey"]) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/api-keys', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_existing_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'production-backend', expiresAt: '2026-12-31T23:59:59Z', }), }) const { apiKey, plainKey } = await res.json() console.log('New key:', plainKey) ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/api-keys", headers={"Authorization": "Bearer wvz_your_existing_key"}, json={ "name": "production-backend", "expiresAt": "2026-12-31T23:59:59Z", }, ) data = res.json() print("New key:", data["plainKey"]) ``` ## Using API Keys Include your API key in the `Authorization` header of every request: ```bash curl https://api.weavz.io/api/v1/workspaces \ -H "Authorization: Bearer wvz_your_key" ``` ## Listing Keys ```bash curl https://api.weavz.io/api/v1/api-keys \ -H "Authorization: Bearer wvz_your_key" ``` ```typescript const keys = await client.apiKeys.list() ``` ```python keys = client.api_keys.list() ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/api-keys', { headers: { 'Authorization': 'Bearer wvz_your_key' }, }) const keys = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/api-keys", headers={"Authorization": "Bearer wvz_your_key"}, ) keys = res.json() ``` ## Deleting Keys ```bash curl -X DELETE https://api.weavz.io/api/v1/api-keys/key_abc123 \ -H "Authorization: Bearer wvz_your_key" ``` ```typescript await client.apiKeys.delete('key_abc123') ``` ```python client.api_keys.delete("key_abc123") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/api-keys/key_abc123', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_key' }, }) ``` ```python import httpx res = httpx.delete( "https://api.weavz.io/api/v1/api-keys/key_abc123", headers={"Authorization": "Bearer wvz_your_key"}, ) ``` ## Key Rotation To rotate an API key without downtime: Generate a new API key via the dashboard or API. Deploy the new key to your environment variables. Confirm the new key works in production. Revoke the old key once the new one is verified. ```typescript // 1. Create new key const { plainKey: newKey } = await client.apiKeys.create({ name: 'production-backend-v2', }) // 2. Update your environment variables with the new key // 3. Verify the new key works // 4. Delete the old key await client.apiKeys.delete('old_key_id') ``` ## Scoping Keys to Workspaces By default, API keys have **org-wide** access. For tighter security, you can scope a key to specific workspaces — the key will only be able to access resources (connections, MCP servers, triggers, actions) within those workspaces. ```bash curl -X POST https://api.weavz.io/api/v1/api-keys \ -H "Authorization: Bearer wvz_your_existing_key" \ -H "Content-Type: application/json" \ -d '{ "name": "checkout-service", "permissions": { "scope": "workspace", "workspaceIds": ["WORKSPACE_UUID_1"] } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_key' }) const { apiKey, plainKey } = await client.apiKeys.create({ name: 'checkout-service', permissions: { scope: 'workspace', workspaceIds: ['WORKSPACE_UUID_1'], }, }) console.log('Scoped key:', plainKey) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_key") result = client.api_keys.create( name="checkout-service", permissions={ "scope": "workspace", "workspaceIds": ["WORKSPACE_UUID_1"], }, ) print("Scoped key:", result["plainKey"]) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/api-keys', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_existing_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'checkout-service', permissions: { scope: 'workspace', workspaceIds: ['WORKSPACE_UUID_1'], }, }), }) const { apiKey, plainKey } = await res.json() console.log('Scoped key:', plainKey) ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/api-keys", headers={"Authorization": "Bearer wvz_your_existing_key"}, json={ "name": "checkout-service", "permissions": { "scope": "workspace", "workspaceIds": ["WORKSPACE_UUID_1"], }, }, ) data = res.json() print("Scoped key:", data["plainKey"]) ``` If a workspace-scoped key tries to access a resource outside its allowed workspaces, the API returns `403` with code `SCOPE_DENIED`. Org-level administration endpoints (API key management, org settings) also require org-wide keys. When sending `connectionExternalId`/`externalId` for action execution or connection resolution, include the correct `workspaceId` (and `endUserId` when applicable). Explicit connection IDs are still validated against that context and are rejected on scope mismatch. ## Best Practices - **Use workspace-scoped keys for least-privilege access** — each service should only access the workspaces it needs - **Use environment variables** — never hardcode API keys in source code - **Separate keys per environment** — use different keys for development, staging, and production - **Set expiration dates** — rotate keys periodically for better security - **Never expose keys in client-side code** — API keys should only be used in server-side applications - **Monitor usage** — check the [Activity](/docs/guides/executing-actions) page to track API key usage - **Revoke compromised keys immediately** — if a key is leaked, delete it and create a new one ### Setting Up Connections > Connect third-party services to Weavz using OAuth2, API keys, or custom authentication. Source: https://weavz.io/docs/guides/setting-up-connections Connections store the authentication credentials needed to interact with third-party services. Weavz supports OAuth2, API key, and custom authentication methods. ## Connection Types | Type | Use Case | Example | |------|----------|---------| | `OAUTH2` | OAuth2 authorization flow | Google, Slack, GitHub | | `PLATFORM_OAUTH2` | Platform-managed OAuth2 (pre-configured) | Slack, Notion, Airtable | | `SECRET_TEXT` | Single API key or token | OpenAI, Anthropic, SendGrid | | `BASIC_AUTH` | Username and password | SMTP, legacy APIs | | `CUSTOM_AUTH` | Multi-field authentication | Custom services | ## OAuth2 Connections OAuth2 connections use the **hosted connect flow** — a Weavz-hosted page that handles the full authorization process. You create a connect token, open the connect page (as a popup or redirect), and the user completes authorization there. Once finished, you retrieve the session to get the resulting connection. Open the **Connections** page from the sidebar. Click **Create Connection** and select the integration (e.g., Slack) from the picker. Click **Authorize** — a popup opens with the provider's consent screen. Approve access in the popup — it closes automatically and your connection appears in the list. The hosted connect flow has three steps: create a token, open the connect page, and retrieve the session result. **Step 1: Create a Connect Token** ```bash curl -X POST https://api.weavz.io/api/v1/connect/token \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "connectionName": "My Slack Workspace", "externalId": "tenant_123_slack", "workspaceId": "YOUR_WORKSPACE_ID" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_key' }) const { token, connectUrl } = await client.connect.createToken({ integrationName: 'slack', connectionName: 'My Slack Workspace', externalId: 'tenant_123_slack', workspaceId: 'YOUR_WORKSPACE_ID', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_key") result = client.connect.create_token( integration_name="slack", connection_name="My Slack Workspace", external_id="tenant_123_slack", workspace_id="YOUR_WORKSPACE_ID", ) token = result["token"] connect_url = result["connectUrl"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connect/token', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', connectionName: 'My Slack Workspace', externalId: 'tenant_123_slack', workspaceId: 'YOUR_WORKSPACE_ID', }), }) const { token, connectUrl } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/connect/token", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "slack", "connectionName": "My Slack Workspace", "externalId": "tenant_123_slack", "workspaceId": "YOUR_WORKSPACE_ID", }, ) data = res.json() token = data["token"] connect_url = data["connectUrl"] ``` Response: ```json { "token": "cst_abc123...", "connectUrl": "https://api.weavz.io/connect?token=cst_abc123...", "expiresAt": "2025-01-15T14:30:00.000Z" } ``` **Step 2: Open the Connect Page** Open `connectUrl` in a popup window or redirect the user to it. The hosted connect page guides them through the OAuth2 consent flow. In a browser environment, the TypeScript SDK provides a convenience method that handles the popup automatically: ```typescript // First create a token, then open popup const { token, connectUrl } = await client.connect.createToken({ integrationName: 'slack', connectionName: 'My Slack Workspace', externalId: 'tenant_123_slack', workspaceId: 'YOUR_WORKSPACE_ID', }) // Opens a popup, waits for completion, returns the connection result const result = await client.connect.popup({ token, connectUrl }) console.log('Connection created:', result.connectionId) ``` **Step 3: Retrieve the Session** If you opened the connect page manually (not using the popup helper), poll the session endpoint to check when the user has completed authorization: ```bash curl https://api.weavz.io/api/v1/connect/session/cs_abc123 \ -H "Authorization: Bearer wvz_your_key" ``` ```typescript const session = await client.connect.getSession(sessionId) if (session.status === 'completed') { console.log('Connection created:', session.connection.id) } else if (session.status === 'failed') { console.error('Connect failed:', session.error) } ``` ```python session = client.connect.get_session(session_id) if session["status"] == "completed": print("Connection created:", session["connection"]["id"]) elif session["status"] == "failed": print("Connect failed:", session["error"]) ``` ```typescript const res = await fetch(`https://api.weavz.io/api/v1/connect/session/${sessionId}`, { headers: { 'Authorization': 'Bearer wvz_your_key' }, }) const session = await res.json() if (session.status === 'completed') { console.log('Connection created:', session.connection.id) } else if (session.status === 'failed') { console.error('Connect failed:', session.error) } ``` ```python import httpx res = httpx.get( f"https://api.weavz.io/api/v1/connect/session/{session_id}", headers={"Authorization": "Bearer wvz_your_key"}, ) session = res.json() if session["status"] == "completed": print("Connection created:", session["connection"]["id"]) elif session["status"] == "failed": print("Connect failed:", session["error"]) ``` ## API Key Connections For services that use API keys or tokens: Open the **Connections** page from the sidebar. Click **Create Connection** and select the integration (e.g., OpenAI). Enter your API key in the form. Optionally set a display name and external ID, then click **Save**. ```bash curl -X POST https://api.weavz.io/api/v1/connections \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "type": "SECRET_TEXT", "integrationName": "openai", "externalId": "tenant_123_openai", "displayName": "OpenAI Production", "secretText": "sk-proj-abc123..." }' ``` ```typescript const { connection } = await client.connections.create({ type: 'SECRET_TEXT', integrationName: 'openai', externalId: 'tenant_123_openai', displayName: 'OpenAI Production', secretText: 'sk-proj-abc123...', }) ``` ```python result = client.connections.create( type="SECRET_TEXT", integration_name="openai", external_id="tenant_123_openai", display_name="OpenAI Production", secret_text="sk-proj-abc123...", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'SECRET_TEXT', integrationName: 'openai', externalId: 'tenant_123_openai', displayName: 'OpenAI Production', secretText: 'sk-proj-abc123...', }), }) const { connection } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/connections", headers={"Authorization": "Bearer wvz_your_key"}, json={ "type": "SECRET_TEXT", "integrationName": "openai", "externalId": "tenant_123_openai", "displayName": "OpenAI Production", "secretText": "sk-proj-abc123...", }, ) connection = res.json()["connection"] ``` ## Custom Auth Connections For integrations requiring multiple fields: Open the **Connections** page from the sidebar. Click **Create Connection** and select the integration (e.g., Freshsales). The form dynamically renders the required fields for the integration. Fill in all required values (e.g., base URL and API key). Set a display name and external ID, then click **Save**. ```bash curl -X POST https://api.weavz.io/api/v1/connections \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "type": "CUSTOM_AUTH", "integrationName": "freshsales", "externalId": "tenant_123_freshsales", "displayName": "Freshsales CRM", "props": { "base_url": "https://mycompany.freshsales.io", "api_key": "abc123..." } }' ``` ```typescript const { connection } = await client.connections.create({ type: 'CUSTOM_AUTH', integrationName: 'freshsales', externalId: 'tenant_123_freshsales', displayName: 'Freshsales CRM', props: { base_url: 'https://mycompany.freshsales.io', api_key: 'abc123...', }, }) ``` ```python result = client.connections.create( type="CUSTOM_AUTH", integration_name="freshsales", external_id="tenant_123_freshsales", display_name="Freshsales CRM", props={ "base_url": "https://mycompany.freshsales.io", "api_key": "abc123...", }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'CUSTOM_AUTH', integrationName: 'freshsales', externalId: 'tenant_123_freshsales', displayName: 'Freshsales CRM', props: { base_url: 'https://mycompany.freshsales.io', api_key: 'abc123...', }, }), }) const { connection } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/connections", headers={"Authorization": "Bearer wvz_your_key"}, json={ "type": "CUSTOM_AUTH", "integrationName": "freshsales", "externalId": "tenant_123_freshsales", "displayName": "Freshsales CRM", "props": { "base_url": "https://mycompany.freshsales.io", "api_key": "abc123...", }, }, ) connection = res.json()["connection"] ``` ## End User Connections For multi-tenant applications, use [end users](/docs/concepts/end-users) to manage per-user connections. Register an end user, then generate a connect URL for them: ```typescript // Register the end user const { endUser } = await client.endUsers.create({ workspaceId: 'proj_abc123', externalId: 'user_456', displayName: 'Alice Johnson', }) // Generate a connect URL for Slack const { connectUrl } = await client.endUsers.createConnectToken( endUser.id, { integrationName: 'slack' } ) // Open connectUrl in a popup for the user to authorize ``` ```python # Register the end user result = client.end_users.create( workspace_id="proj_abc123", external_id="user_456", display_name="Alice Johnson", ) end_user = result["endUser"] # Generate a connect URL for Slack result = client.end_users.create_connect_token( end_user["id"], integration_name="slack", ) connect_url = result["connectUrl"] # Open connect_url in a popup for the user to authorize ``` ```typescript // Register the end user const userRes = await fetch('https://api.weavz.io/api/v1/end-users', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ workspaceId: 'proj_abc123', externalId: 'user_456', displayName: 'Alice Johnson', }), }) const { endUser } = await userRes.json() // Generate a connect URL for Slack const tokenRes = await fetch( `https://api.weavz.io/api/v1/end-users/${endUser.id}/connect-token`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack' }), } ) const { connectUrl } = await tokenRes.json() ``` ```python import httpx headers = {"Authorization": "Bearer wvz_your_key"} # Register the end user res = httpx.post( "https://api.weavz.io/api/v1/end-users", headers=headers, json={ "workspaceId": "proj_abc123", "externalId": "user_456", "displayName": "Alice Johnson", }, ) end_user = res.json()["endUser"] # Generate a connect URL for Slack res = httpx.post( f"https://api.weavz.io/api/v1/end-users/{end_user['id']}/connect-token", headers=headers, json={"integrationName": "slack"}, ) connect_url = res.json()["connectUrl"] ``` Connections created through the end user connect portal are automatically linked to the end user. When executing actions, pass `endUserId` to resolve the end user's connection: ```typescript const result = await client.actions.execute('slack', 'send_channel_message', { workspaceId: 'proj_abc123', endUserId: 'user_456', input: { channel: 'C0123456789', text: 'Hello!' }, }) ``` ```python result = client.actions.execute( "slack", "send_channel_message", workspace_id="proj_abc123", end_user_id="user_456", input={"channel": "C0123456789", "text": "Hello!"}, ) ``` See [Managing End Users](/docs/guides/managing-end-users) for the full workflow. ## External IDs External IDs are your identifiers for connections, used for multi-tenant applications. They let you map connections to your users or tenants. When resolving by external ID in multi-tenant setups, always pass the same context you used when creating/using the connection (`workspaceId`, and `endUserId` for user-scoped credentials). Mismatched scope is rejected. ```typescript // Create a connection with an external ID await client.connections.create({ type: 'SECRET_TEXT', integrationName: 'openai', externalId: 'user_456', // Your user's ID displayName: 'User 456 OpenAI Key', secretText: 'sk-...', }) // Later, resolve the connection by external ID const { connection } = await client.connections.resolve({ integrationName: 'openai', externalId: 'user_456', }) ``` ```python # Create a connection with an external ID client.connections.create( type="SECRET_TEXT", integration_name="openai", external_id="user_456", # Your user's ID display_name="User 456 OpenAI Key", secret_text="sk-...", ) # Later, resolve the connection by external ID result = client.connections.resolve( integration_name="openai", external_id="user_456", ) ``` ```typescript // Create a connection with an external ID await fetch('https://api.weavz.io/api/v1/connections', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'SECRET_TEXT', integrationName: 'openai', externalId: 'user_456', displayName: 'User 456 OpenAI Key', secretText: 'sk-...', }), }) // Later, resolve the connection by external ID const res = await fetch('https://api.weavz.io/api/v1/connections/resolve', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'openai', externalId: 'user_456', }), }) const { connection } = await res.json() ``` ```python import httpx headers = {"Authorization": "Bearer wvz_your_key"} # Create a connection with an external ID httpx.post( "https://api.weavz.io/api/v1/connections", headers=headers, json={ "type": "SECRET_TEXT", "integrationName": "openai", "externalId": "user_456", "displayName": "User 456 OpenAI Key", "secretText": "sk-...", }, ) # Later, resolve the connection by external ID res = httpx.post( "https://api.weavz.io/api/v1/connections/resolve", headers=headers, json={ "integrationName": "openai", "externalId": "user_456", }, ) connection = res.json()["connection"] ``` ## Token Refresh OAuth2 tokens are automatically refreshed when needed — no manual intervention required. ## Listing Connections ```bash curl https://api.weavz.io/api/v1/connections \ -H "Authorization: Bearer wvz_your_key" ``` ```typescript const { connections } = await client.connections.list() ``` ```python result = client.connections.list() connections = result["connections"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections', { headers: { 'Authorization': 'Bearer wvz_your_key' }, }) const { connections } = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/connections", headers={"Authorization": "Bearer wvz_your_key"}, ) connections = res.json()["connections"] ``` ## Deleting Connections ```bash curl -X DELETE https://api.weavz.io/api/v1/connections/conn_abc123 \ -H "Authorization: Bearer wvz_your_key" ``` ```typescript await client.connections.delete('conn_abc123') ``` ```python client.connections.delete("conn_abc123") ``` ```typescript await fetch('https://api.weavz.io/api/v1/connections/conn_abc123', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_key' }, }) ``` ```python import httpx httpx.delete( "https://api.weavz.io/api/v1/connections/conn_abc123", headers={"Authorization": "Bearer wvz_your_key"}, ) ``` ### Executing Actions > Execute integration actions to interact with third-party services through a unified API. Source: https://weavz.io/docs/guides/executing-actions Actions are the core way to interact with third-party services through Weavz. Each integration exposes a set of actions — like sending a Slack message, creating a GitHub issue, or reading a Google Sheet. ## Execute an Action Navigate to the **Playground** from the sidebar. Click the **Actions** tab at the top of the Playground. Choose the integration you want to use (e.g., **Slack**). Select a specific action (e.g., **Send Channel Message**). Enter the required parameters — channel ID, message text, etc. Click **Execute** and view the output in the result panel below. ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "channel": "C01ABCDEF", "text": "Hello from Weavz!" }, "connectionExternalId": "tenant_123_slack" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_key' }) const { output } = await client.actions.execute('slack', 'send_channel_message', { workspaceId: 'YOUR_WORKSPACE_ID', input: { channel: 'C01ABCDEF', text: 'Hello from Weavz!', }, connectionExternalId: 'tenant_123_slack', }) console.log('Message sent:', output.ts) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_key") result = client.actions.execute( "slack", "send_channel_message", workspace_id="YOUR_WORKSPACE_ID", input={ "channel": "C01ABCDEF", "text": "Hello from Weavz!", }, connection_external_id="tenant_123_slack", ) print("Message sent:", result["output"]["ts"]) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', workspaceId: 'YOUR_WORKSPACE_ID', input: { channel: 'C01ABCDEF', text: 'Hello from Weavz!', }, connectionExternalId: 'tenant_123_slack', }), }) const { output } = await res.json() console.log('Message sent:', output.ts) ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "channel": "C01ABCDEF", "text": "Hello from Weavz!", }, "connectionExternalId": "tenant_123_slack", }, ) output = res.json()["output"] print("Message sent:", output["ts"]) ``` Response: ```json { "success": true, "output": { "ok": true, "channel": "C01ABCDEF", "ts": "1234567890.123456", "message": { "text": "Hello from Weavz!", "type": "message" } } } ``` ## Request Parameters | Parameter | Required | Description | |-----------|----------|-------------| | `integrationName` | Yes | Integration identifier (e.g., `slack`, `github`, `openai`) | | `actionName` | Yes | Action identifier (e.g., `send_channel_message`, `create_issue`) | | `input` | Yes | Action-specific input parameters (object) | | `workspaceId` | Yes | Workspace scope for connection resolution and partials | | `connectionExternalId` | No | External ID of the [connection](/docs/concepts/connections) to use | | `integrationAlias` | No | Alias of the [workspace integration](/docs/api-reference/workspace-integrations) to resolve. Useful when the same integration is configured multiple times in a workspace. | | `endUserId` | No | Your end-user's identifier for per-user connection resolution | ## Using Connection External IDs The simplest way to specify which connection to use is by external ID: ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "input": { "channel": "C01ABCDEF", "text": "Hello!" }, "connectionExternalId": "my_slack_connection" }' ``` ```typescript await client.actions.execute('slack', 'send_channel_message', { input: { channel: 'C01ABCDEF', text: 'Hello!' }, connectionExternalId: 'my_slack_connection', }) ``` ```python client.actions.execute( "slack", "send_channel_message", input={"channel": "C01ABCDEF", "text": "Hello!"}, connection_external_id="my_slack_connection", ) ``` ```typescript await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', input: { channel: 'C01ABCDEF', text: 'Hello!' }, connectionExternalId: 'my_slack_connection', }), }) ``` ```python import httpx httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "input": {"channel": "C01ABCDEF", "text": "Hello!"}, "connectionExternalId": "my_slack_connection", }, ) ``` ## Using Workspace Context When a workspace has configured integrations, you can let the workspace's connection strategy resolve the connection automatically: ```bash # Let workspace integration configuration resolve the connection curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "input": { "channel": "C01ABCDEF", "text": "Hello!" }, "workspaceId": "proj_abc123" }' ``` ```bash # Target a specific alias when the same integration has multiple configurations curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "input": { "channel": "#alerts", "text": "Alert!" }, "workspaceId": "proj_abc123", "integrationAlias": "slack_bot" }' ``` ```typescript // Let workspace integration configuration resolve the connection await client.actions.execute('slack', 'send_channel_message', { input: { channel: 'C01ABCDEF', text: 'Hello!' }, workspaceId: 'proj_abc123', }) // Target a specific alias when the same integration has multiple configurations await client.actions.execute('slack', 'send_channel_message', { input: { channel: '#alerts', text: 'Alert!' }, workspaceId: 'proj_abc123', integrationAlias: 'slack_bot', }) ``` ```python # Let workspace integration configuration resolve the connection client.actions.execute( "slack", "send_channel_message", input={"channel": "C01ABCDEF", "text": "Hello!"}, workspace_id="proj_abc123", ) # Target a specific alias when the same integration has multiple configurations client.actions.execute( "slack", "send_channel_message", input={"channel": "#alerts", "text": "Alert!"}, workspace_id="proj_abc123", integration_alias="slack_bot", ) ``` ```typescript // Let workspace integration configuration resolve the connection await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', input: { channel: 'C01ABCDEF', text: 'Hello!' }, workspaceId: 'proj_abc123', }), }) // Target a specific alias when the same integration has multiple configurations await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', input: { channel: '#alerts', text: 'Alert!' }, workspaceId: 'proj_abc123', integrationAlias: 'slack_bot', }), }) ``` ```python import httpx headers = {"Authorization": "Bearer wvz_your_key"} # Let workspace integration configuration resolve the connection httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers=headers, json={ "integrationName": "slack", "actionName": "send_channel_message", "input": {"channel": "C01ABCDEF", "text": "Hello!"}, "workspaceId": "proj_abc123", }, ) # Target a specific alias when the same integration has multiple configurations httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers=headers, json={ "integrationName": "slack", "actionName": "send_channel_message", "input": {"channel": "#alerts", "text": "Alert!"}, "workspaceId": "proj_abc123", "integrationAlias": "slack_bot", }, ) ``` ## Connection Resolution When you execute an action, Weavz resolves which connection to use based on the parameters you provide and the workspace's configured integrations: 1. **Explicit connection** — `connectionExternalId` directly specifies the connection 2. **Workspace integration** — if `workspaceId` is set, the workspace's [integration configuration](/docs/api-reference/workspace-integrations) determines the connection based on its strategy (`fixed`, `per_user`, or `per_user_with_fallback`) 3. **Fallback** — if no workspace integration or explicit connection is found, returns a `CONNECTION_REQUIRED` error ## Error Handling ```typescript import { WeavzClient, WeavzError } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_key' }) try { const { output } = await client.actions.execute('slack', 'send_channel_message', { input: { channel: 'invalid', text: 'Hello!' }, connectionExternalId: 'my_slack', }) } catch (err) { if (err instanceof WeavzError) { console.error('Code:', err.code) // e.g., "ACTION_FAILED" console.error('Status:', err.status) // e.g., 400 console.error('Message:', err.message) console.error('Details:', err.details) } } ``` ```python from weavz_sdk import WeavzClient, WeavzError client = WeavzClient(api_key="wvz_your_key") try: result = client.actions.execute( "slack", "send_channel_message", input={"channel": "invalid", "text": "Hello!"}, connection_external_id="my_slack", ) except WeavzError as e: print(f"Code: {e.code}") # e.g., "ACTION_FAILED" print(f"Status: {e.status}") # e.g., 400 print(f"Message: {e}") print(f"Details: {e.details}") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', input: { channel: 'invalid', text: 'Hello!' }, connectionExternalId: 'my_slack', }), }) if (!res.ok) { const error = await res.json() console.error('Code:', error.code) // e.g., "ACTION_FAILED" console.error('Status:', res.status) // e.g., 400 console.error('Message:', error.message) } ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "input": {"channel": "invalid", "text": "Hello!"}, "connectionExternalId": "my_slack", }, ) if res.status_code >= 400: error = res.json() print(f"Code: {error['code']}") # e.g., "ACTION_FAILED" print(f"Status: {res.status_code}") # e.g., 400 print(f"Message: {error['message']}") ``` ## Common Error Codes | Code | Status | Description | |------|--------|-------------| | `ACTION_FAILED` | 400 | The action failed during execution | | `CONNECTION_REQUIRED` | 400 | The action requires a connection but none was resolved | | `CONNECTION_NOT_FOUND` | 404 | The specified connection does not exist | | `INTEGRATION_NOT_FOUND` | 404 | The integration name is invalid | | `NOT_FOUND` | 404 | The action name is invalid for this integration | | `VALIDATION_ERROR` | 400 | Input parameters failed validation | | `QUOTA_EXCEEDED` | 403 | Monthly action quota reached | | `RATE_LIMITED` | 429 | Too many requests — slow down | ## Discovering Available Actions List all available integrations and their actions: ```bash # List all integrations curl https://api.weavz.io/api/v1/integrations \ -H "Authorization: Bearer wvz_your_key" # Get details for a specific integration curl "https://api.weavz.io/api/v1/integrations?name=slack" \ -H "Authorization: Bearer wvz_your_key" ``` ```typescript // List all integrations const { integrations } = await client.integrations.list() // Get a specific integration const { integrations: [slack] } = await client.integrations.list({ name: 'slack' }) console.log(slack.actions) // Available actions with input schemas ``` ```python # List all integrations result = client.integrations.list() # Get a specific integration result = client.integrations.list(name="slack") slack = result["integrations"][0] print(slack["actions"]) # Available actions with input schemas ``` ```typescript // List all integrations const res = await fetch('https://api.weavz.io/api/v1/integrations', { headers: { 'Authorization': 'Bearer wvz_your_key' }, }) const { integrations } = await res.json() // Get details for a specific integration const slackRes = await fetch('https://api.weavz.io/api/v1/integrations?name=slack', { headers: { 'Authorization': 'Bearer wvz_your_key' }, }) const { integrations: [slack] } = await slackRes.json() console.log(slack.actions) ``` ```python import httpx headers = {"Authorization": "Bearer wvz_your_key"} # List all integrations res = httpx.get("https://api.weavz.io/api/v1/integrations", headers=headers) integrations = res.json()["integrations"] # Get details for a specific integration res = httpx.get( "https://api.weavz.io/api/v1/integrations", headers=headers, params={"name": "slack"}, ) slack = res.json()["integrations"][0] print(slack["actions"]) ``` The integration details include all available actions with their input schemas, making it easy to discover what's possible. ## Using Input Partials Input partials are saved parameter presets that pre-fill action inputs. They are scoped to a workspace and can be assigned to specific integrations or actions. When a partial is active, its values are merged into the action input automatically — and enforced keys cannot be overridden at runtime. This is useful for setting default channels, repositories, or other parameters that should remain consistent across executions. See the [Playground](/docs/guides/playground) guide for how to create and manage partials from the dashboard. ### Using the Playground > Test integrations, execute actions, and run code in the Weavz developer console. Source: https://weavz.io/docs/guides/playground The Playground is a unified developer console for testing integrations, executing actions, and running sandboxed code — all from the Weavz dashboard. It has 4 tabs: **Actions**, **Triggers**, **MCP**, and **Code**. ## Workspace Selection Before using the Playground, select a workspace from the dropdown at the top. A workspace is required — there is no "All workspaces" option. The selected workspace determines which connections, storage, KV data, and input partials are available. Playground usage is excluded from billing quotas by default. Use it freely for testing and development without worrying about action counts. ## Actions Tab Execute any integration action interactively: Navigate to **Playground** from the dashboard sidebar. Choose the integration you want to test (e.g., Slack, GitHub, OpenAI). Pick the specific action to execute (e.g., `send_channel_message`, `create_issue`). The form dynamically renders the action's input schema. Fill in the required fields — select inputs fetch available values from the connected service. Choose which connection to authenticate with. If you have multiple connections for the same integration, pick the one you want to test. Click **Execute** and view the full response payload, including output data and any errors. The Actions tab supports all integrations, including the built-in [Storage and KV Store](/docs/guides/using-storage-and-kv) integrations. You can read/write files and key-value data directly from the Playground. ## Triggers Tab Test trigger configurations with sample payloads before enabling them in production: Choose an integration (e.g., GitHub) and pick the trigger event you want to test (e.g., `new_push`, `new_issue`). Fill in any required trigger inputs and select the connection to authenticate with. Click **Test** to retrieve a sample event payload. This shows the exact shape of data your callback URL will receive when the trigger fires in production. Use this to validate your webhook handler before enabling a trigger. See [Setting Up Triggers](/docs/guides/setting-up-triggers) for the full trigger workflow. ## MCP Tab Test MCP server connections using the JSON-RPC protocol: Choose an existing MCP server from the dropdown. Both TOOLS and CODE mode servers are supported. Send a `tools/list` request to see all tools registered on the server. For CODE mode servers, this shows the 3 meta-tools (`weavz_search`, `weavz_read_api`, `weavz_execute`). Send a `tools/call` request with the tool name and arguments. View the full JSON-RPC request and response, including any errors. This is useful for debugging MCP tool configurations, verifying tool schemas, and testing tool execution without connecting an AI client. ## Code Tab Write and execute sandboxed JavaScript using the `weavz.*` API surface: Author JavaScript code in the editor. All integrations registered on your workspace are available via `await weavz.{integration}.{action}({...})`. Click **Run** to execute the code in a sandboxed environment. The execution is isolated and secure. Inspect the return value, console output, and execution trace. The trace shows every integration action called, its duration, and success status. The Code tab is ideal for prototyping multi-step workflows before deploying them to a [CODE mode MCP server](/docs/guides/mcp-code-mode). You can chain multiple integration calls, process data between services, and test complex logic interactively. ```javascript // Example: Fetch issues and post a summary to Slack const issues = await weavz.github.list_issues({ repo: 'acme/backend', state: 'open', }) await weavz.slack.send_channel_message({ channel: '#engineering', text: `Open issues: ${issues.length}`, }) return { count: issues.length } ``` ## Input Partials Input partials are saved parameter presets that pre-fill action inputs. They are scoped to a workspace and can be assigned to specific integrations or individual actions. ### How Partials Work A partial contains a set of key-value pairs that are merged into the action input at execution time. Some keys can be marked as **enforced**, meaning they cannot be overridden — the partial's value always takes precedence. The merge order is: 1. **Input defaults** -- default values defined by the action schema 2. **Partial non-enforced values** -- preset values that can be overridden 3. **Runtime input** -- values you provide at execution time 4. **Enforced values** -- partial values that always win ### Saving Partials from the Playground When working in the Actions tab, you can save the current input values as a partial: Enter the action parameters you want to save as a preset. Click **Save Partial**. Give the partial a name and optionally mark specific keys as enforced. The next time you select the same integration and action, you can load the saved partial from the dropdown to pre-fill the form. ### Loading Partials When a partial is available for the current integration and action, a dropdown appears above the input form. Select a partial to pre-fill the inputs. Enforced keys are shown as locked and cannot be edited. Partials can also be assigned to MCP server tools. When a partial is assigned, its enforced keys are stripped from the tool's input schema — the AI agent never sees or needs to provide those values. ### Managing Partials To manage all partials for a workspace, navigate to **Partials** in the dashboard sidebar. From there you can: - View all saved partials grouped by integration and action - Edit partial values and enforced keys - Delete partials you no longer need - Create new partials scoped to a specific integration or integration + action combination Partials are also available via the [Partials API](/docs/api-reference/input-partials) for programmatic management. ### Setting Up Triggers > Listen for real-time events from third-party services with webhook-based triggers. Source: https://weavz.io/docs/guides/setting-up-triggers Triggers let you receive real-time events from third-party services. When something happens — like a new Slack message, a GitHub push, or a form submission — Weavz delivers the event data to your callback URL. Weavz supports two trigger types: - **WEBHOOK** — the third-party service pushes events to a Weavz-managed URL, which forwards them to your callback - **POLLING** — Weavz periodically checks the service for new data and delivers any changes to your callback Both types deliver events in the same format to your `callbackUrl`. ## Enable a Trigger Open the dashboard and go to **Triggers** in the sidebar. Click **Enable Trigger**. Select an integration (e.g. GitHub, Slack) and pick the trigger event you want to listen for. Choose the connection that has access to the service you want to monitor. Enter the HTTPS URL where Weavz should deliver events. Optionally add callback headers and metadata. Click **Enable**. For webhook triggers, the webhook is automatically registered with the third-party service. ```bash curl -X POST https://api.weavz.io/api/v1/triggers/enable \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "github", "triggerName": "new_push", "callbackUrl": "https://yourapp.com/webhooks/github-push", "connectionExternalId": "my_github_connection" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { triggerSource } = await client.triggers.enable({ integrationName: 'github', triggerName: 'new_push', callbackUrl: 'https://yourapp.com/webhooks/github-push', connectionExternalId: 'my_github_connection', }) console.log('Trigger enabled:', triggerSource.id) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.triggers.enable( integration_name="github", trigger_name="new_push", callback_url="https://yourapp.com/webhooks/github-push", connection_external_id="my_github_connection", ) print("Trigger enabled:", result["triggerSource"]["id"]) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers/enable', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'github', triggerName: 'new_push', callbackUrl: 'https://yourapp.com/webhooks/github-push', connectionExternalId: 'my_github_connection', }), }) const { triggerSource } = await res.json() console.log('Trigger enabled:', triggerSource.id) ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/triggers/enable", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "github", "triggerName": "new_push", "callbackUrl": "https://yourapp.com/webhooks/github-push", "connectionExternalId": "my_github_connection", }, ) trigger_source = res.json()["triggerSource"] print("Trigger enabled:", trigger_source["id"]) ``` Response: ```json { "triggerSource": { "id": "ts_abc123", "integrationName": "github", "triggerName": "new_push", "callbackUrl": "https://yourapp.com/webhooks/github-push", "status": "ACTIVE", "createdAt": "2025-01-15T10:30:00Z" } } ``` ## Test a Trigger Get sample event data for a trigger to verify your callback handler before going live. Go to **Triggers**, find the trigger you want to test, and click **Test**. Weavz will show a sample payload for that trigger type. ```bash curl -X POST https://api.weavz.io/api/v1/triggers/test \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "github", "triggerName": "new_push" }' ``` ```typescript const { sampleData } = await client.triggers.test({ integrationName: 'github', triggerName: 'new_push', }) console.log('Sample payload:', sampleData) ``` ```python result = client.triggers.test( integration_name="github", trigger_name="new_push", ) print("Sample payload:", result["sampleData"]) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers/test', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'github', triggerName: 'new_push', }), }) const { sampleData } = await res.json() console.log('Sample payload:', sampleData) ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/triggers/test", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "github", "triggerName": "new_push", }, ) print("Sample payload:", res.json()["sampleData"]) ``` Response: ```json { "sampleData": { "ref": "refs/heads/main", "repository": { "full_name": "example/repo" }, "commits": [ { "message": "Sample commit", "author": { "name": "Example User" } } ] } } ``` ## Handling Webhook Events When a trigger fires, Weavz sends a POST request to your `callbackUrl`: ```http POST https://yourapp.com/webhooks/github-push Content-Type: application/json { "triggerSourceId": "ts_abc123", "integrationName": "github", "triggerName": "new_push", "data": { "ref": "refs/heads/main", "repository": { "full_name": "my-org/my-repo" }, "commits": [...] }, "metadata": {}, "timestamp": "2025-01-15T10:35:00Z" } ``` Return a `200` status from your callback endpoint within a few seconds. Events may be delivered more than once — design your handler to be idempotent. You can include custom headers and metadata when enabling a trigger. Headers are sent with every callback delivery, useful for authentication: ```bash curl -X POST https://api.weavz.io/api/v1/triggers/enable \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "triggerName": "new_message", "callbackUrl": "https://yourapp.com/webhooks/slack", "connectionExternalId": "my_slack", "callbackHeaders": { "X-Webhook-Secret": "your_secret_value", "X-Tenant-ID": "tenant_123" }, "callbackMetadata": { "tenantId": "tenant_123", "environment": "production" } }' ``` Metadata is included in the `metadata` field of every callback delivery. ## Disable a Trigger Stop receiving events by disabling the trigger source. Go to **Triggers**, find the active trigger, and click **Disable**. The webhook is automatically deregistered from the third-party service. ```bash curl -X POST https://api.weavz.io/api/v1/triggers/disable \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"triggerSourceId": "ts_abc123"}' ``` ```typescript await client.triggers.disable('ts_abc123') ``` ```python client.triggers.disable("ts_abc123") ``` ```typescript await fetch('https://api.weavz.io/api/v1/triggers/disable', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ triggerSourceId: 'ts_abc123' }), }) ``` ```python import httpx httpx.post( "https://api.weavz.io/api/v1/triggers/disable", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"triggerSourceId": "ts_abc123"}, ) ``` ## Listing Active Triggers ```bash curl https://api.weavz.io/api/v1/triggers \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { triggers, total } = await client.triggers.list() for (const trigger of triggers) { console.log(`${trigger.integrationName}.${trigger.triggerName} → ${trigger.callbackUrl}`) } ``` ```python result = client.triggers.list() for trigger in result["triggers"]: print(f"{trigger['integrationName']}.{trigger['triggerName']} → {trigger['callbackUrl']}") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const { triggers } = await res.json() for (const trigger of triggers) { console.log(`${trigger.integrationName}.${trigger.triggerName} → ${trigger.callbackUrl}`) } ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/triggers", headers={"Authorization": "Bearer wvz_your_api_key"}, ) for trigger in res.json()["triggers"]: print(f"{trigger['integrationName']}.{trigger['triggerName']} → {trigger['callbackUrl']}") ``` ## Best Practices - **Use HTTPS callback URLs** — ensure your endpoint is accessible over HTTPS - **Verify callbacks** — use `callbackHeaders` with a secret to verify requests are from Weavz - **Respond quickly** — return a `200` status within a few seconds - **Handle duplicates** — events may be delivered more than once; make your handler idempotent - **Monitor active triggers** — regularly review and disable triggers you no longer need ### MCP Tool Mode > Set up MCP servers in TOOLS mode to expose integration actions as individual tools for AI agents. Source: https://weavz.io/docs/guides/mcp-tool-mode TOOLS mode MCP servers expose each integration action as an individual tool. AI agents like Claude, Cursor, and others see every action as a separate callable tool with its own typed input schema. ## Create an MCP Server Open the dashboard and go to **MCP Servers** in the sidebar. Click **Create MCP Server**. Enter a name and optional description. Choose **TOOLS** as the server mode. Click **Create**. Copy the **bearer token** and **SSE endpoint** — you'll need these to connect your AI client. ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "My AI Agent Tools", "workspaceId": "YOUR_WORKSPACE_ID", "mode": "TOOLS" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const result = await client.mcpServers.create({ name: 'My AI Agent Tools', workspaceId: 'YOUR_WORKSPACE_ID', mode: 'TOOLS', }) const serverId = result.server.id const bearerToken = result.bearerToken const endpoint = result.mcpEndpoint ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.mcp_servers.create( name="My AI Agent Tools", workspace_id="YOUR_WORKSPACE_ID", mode="TOOLS", ) server_id = result["server"]["id"] bearer_token = result["bearerToken"] endpoint = result["mcpEndpoint"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'My AI Agent Tools', workspaceId: 'YOUR_WORKSPACE_ID', mode: 'TOOLS', }), }) const { server, bearerToken, mcpEndpoint } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "name": "My AI Agent Tools", "workspaceId": "YOUR_WORKSPACE_ID", "mode": "TOOLS", }, ) data = res.json() server_id = data["server"]["id"] bearer_token = data["bearerToken"] endpoint = data["mcpEndpoint"] ``` Response: ```json { "server": { "id": "mcp_abc123", "name": "My AI Agent Tools", "mode": "TOOLS" }, "bearerToken": "mcp_token_xyz...", "mcpEndpoint": "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/sse" } ``` ## Add Tools Each tool maps to one integration action. You can add tools from different integrations to the same server. Go to **MCP Servers** and click on the server you created. Click **Add Tool**. Select an integration (e.g. Slack, GitHub) and pick the action you want to expose. Choose the connection that this tool should use for authentication. Click **Save**. The tool is now available to any AI client connected to this server. ```bash # Add Slack messaging curl -X POST https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_slack" }' # Add GitHub issue creation curl -X POST https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "github", "actionName": "create_issue", "connectionId": "conn_github" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const serverId = 'mcp_abc123' // Add Slack messaging await client.mcpServers.addTool(serverId, { integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_slack', }) // Add GitHub issue creation await client.mcpServers.addTool(serverId, { integrationName: 'github', actionName: 'create_issue', connectionId: 'conn_github', }) // Add Google Sheets reading await client.mcpServers.addTool(serverId, { integrationName: 'google-sheets', actionName: 'read_sheet', connectionId: 'conn_gsheets', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") server_id = "mcp_abc123" # Add Slack messaging client.mcp_servers.add_tool( server_id, integration_name="slack", action_name="send_channel_message", connection_id="conn_slack", ) # Add GitHub issue creation client.mcp_servers.add_tool( server_id, integration_name="github", action_name="create_issue", connection_id="conn_github", ) # Add Google Sheets reading client.mcp_servers.add_tool( server_id, integration_name="google-sheets", action_name="read_sheet", connection_id="conn_gsheets", ) ``` ```typescript const headers = { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', } // Add Slack messaging await fetch('https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools', { method: 'POST', headers, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_slack', }), }) // Add GitHub issue creation await fetch('https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools', { method: 'POST', headers, body: JSON.stringify({ integrationName: 'github', actionName: 'create_issue', connectionId: 'conn_github', }), }) ``` ```python import httpx headers = {"Authorization": "Bearer wvz_your_api_key"} # Add Slack messaging httpx.post( "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools", headers=headers, json={ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_slack", }, ) # Add GitHub issue creation httpx.post( "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools", headers=headers, json={ "integrationName": "github", "actionName": "create_issue", "connectionId": "conn_github", }, ) ``` ## Tool Naming Convention Tools are automatically named using the pattern `{integrationAlias}__{actionName}`: | Integration | Action | Tool Name | |---|---|---| | `slack` | `send_channel_message` | `slack__send_channel_message` | | `github` | `create_issue` | `github__create_issue` | | `google-sheets` | `read_sheet` | `google_sheets__read_sheet` | You can register the same integration multiple times under different **aliases** (e.g. `slack_bot`, `slack_user`), each with its own connection. See the [Integration Aliases](/docs/guides/integration-aliases) guide. ## MCP Helper Tools For actions with select inputs — like selecting a Slack channel or a GitHub repo — Weavz auto-generates **companion tools** that let AI agents discover valid values at runtime. | Helper Tool | Purpose | |---|---| | `slack__list_channels` | List available Slack channels | | `github__list_repos` | List available GitHub repositories | | `google_sheets__list_spreadsheets` | List available spreadsheets | Helper tools are created automatically whenever you add a tool that has dropdown inputs. The AI agent calls them to resolve IDs before executing the main action. ## Connect an AI Client Use the SSE endpoint and bearer token from the server creation step. Add to your Claude Desktop config (`claude_desktop_config.json`): ```json { "mcpServers": { "weavz": { "command": "npx", "args": [ "mcp-remote", "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/sse", "--header", "Authorization:Bearer mcp_token_xyz..." ] } } } ``` Add to your Cursor MCP settings (`.cursor/mcp.json`): ```json { "mcpServers": { "weavz": { "command": "npx", "args": [ "mcp-remote", "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/sse", "--header", "Authorization:Bearer mcp_token_xyz..." ] } } } ``` ```bash claude mcp add weavz \ --transport sse \ https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/sse \ --header "Authorization:Bearer mcp_token_xyz..." ``` ## Managing Tools ```bash curl -X PATCH https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools/tool_xyz \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "description": "Send a message to a Slack channel", "inputDefaults": { "channel": "C01ABCDEF" } }' ``` ```bash curl -X DELETE https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools/tool_xyz \ -H "Authorization: Bearer wvz_your_api_key" ``` If a token is compromised, regenerate it and update your AI client config: ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/regenerate-token \ -H "Authorization: Bearer wvz_your_api_key" ``` ## End-User MCP Servers You can scope an MCP server to a specific [end user](/docs/concepts/end-users) by passing `endUserId` when creating the server. The server will resolve connections belonging to that end user, so an AI agent automatically uses their connected accounts. ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "User Agent", "workspaceId": "proj_abc123", "endUserId": "user_123", "mode": "TOOLS" }' ``` ```typescript const { server, bearerToken } = await client.mcpServers.create({ name: 'User Agent', workspaceId: 'proj_abc123', endUserId: 'user_123', mode: 'TOOLS', }) ``` ```python result = client.mcp_servers.create( name="User Agent", workspace_id="proj_abc123", end_user_id="user_123", mode="TOOLS", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'User Agent', workspaceId: 'proj_abc123', endUserId: 'user_123', mode: 'TOOLS', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "name": "User Agent", "workspaceId": "proj_abc123", "endUserId": "user_123", "mode": "TOOLS", }, ) data = res.json() ``` When a tool call fails because the end user hasn't connected the required integration, the error includes a **setup URL**. Share this URL with the end user — they open it, connect their account, and the agent can retry the tool call. ## When to Use TOOLS Mode TOOLS mode works best when: - You need a **small number of focused tools** (under 20) - Each tool should be **independently callable** by the AI agent - You want **simple setup** without code generation - Your AI agent benefits from seeing all available tools at once For scenarios with many integrations or where context efficiency matters, consider [CODE mode](/docs/guides/mcp-code-mode) instead. ### MCP Code Mode > Set up MCP servers in CODE mode for context-efficient AI agent usage with 3 meta-tools. Source: https://weavz.io/docs/guides/mcp-code-mode CODE mode replaces individual tools with **3 meta-tools** that dramatically reduce context usage. Instead of exposing dozens of separate tools, CODE mode gives AI agents a search → read → execute workflow that uses **80–98% fewer tokens**. ## Why Code Mode? Traditional MCP servers expose every integration action as a separate tool. With 10 integrations and 50 actions, that's 50 tools competing for the AI agent's context window — most of which won't be used in any given request. Code Mode flips this: instead of listing tools, it gives the agent a **programming environment**. The agent discovers what's available on demand, reads typed APIs, then writes code to accomplish its goal — often calling multiple integrations in a single execution. **The result:** - **80–98% fewer tokens** consumed per request - **Multi-step workflows** in a single call (read from Sheets → process → post to Slack) - **Type-safe** — TypeScript declarations guide the agent to correct usage - **Observable** — every integration call is traced with duration and status ## The Three Meta-Tools | Tool | Purpose | |---|---| | `weavz_search` | Discover available integrations and actions by keyword | | `weavz_read_api` | Get detailed TypeScript declarations for an integration's actions | | `weavz_execute` | Execute JavaScript code in a sandboxed environment using `weavz.*` | The AI agent follows a natural workflow: 1. **Search** for the right integration and action 2. **Read** the typed API to understand input parameters and return types 3. **Execute** code that calls one or more actions — including multi-step compositions ## Create a CODE Mode Server Open the dashboard and go to **MCP Servers** in the sidebar. Click **Create MCP Server**. Enter a name and optional description. Choose **CODE** as the server mode. Click **Create**. Copy the **bearer token** and **SSE endpoint**. ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "AI Code Agent", "workspaceId": "YOUR_WORKSPACE_ID", "mode": "CODE" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const result = await client.mcpServers.create({ name: 'AI Code Agent', workspaceId: 'YOUR_WORKSPACE_ID', mode: 'CODE', }) const serverId = result.server.id const bearerToken = result.bearerToken ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.mcp_servers.create( name="AI Code Agent", workspace_id="YOUR_WORKSPACE_ID", mode="CODE", ) server_id = result["server"]["id"] bearer_token = result["bearerToken"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'AI Code Agent', workspaceId: 'YOUR_WORKSPACE_ID', mode: 'CODE', }), }) const { server, bearerToken, mcpEndpoint } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "name": "AI Code Agent", "workspaceId": "YOUR_WORKSPACE_ID", "mode": "CODE", }, ) data = res.json() server_id = data["server"]["id"] bearer_token = data["bearerToken"] ``` Response: ```json { "server": { "id": "mcp_abc123", "name": "AI Code Agent", "mode": "CODE" }, "bearerToken": "mcp_token_xyz...", "mcpEndpoint": "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/sse" } ``` ## Add Integrations Register integrations on the server. In CODE mode, each integration's actions become available under the `weavz.*` namespace. Go to **MCP Servers** and click on the server you created. Click **Add Tool**. Select integrations and choose which actions to include. Assign a connection for each integration to handle authentication. ```bash # Add Slack curl -X POST https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_slack" }' # Add GitHub curl -X POST https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "github", "actionName": "create_issue", "connectionId": "conn_github" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const serverId = 'mcp_abc123' await client.mcpServers.addTool(serverId, { integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_slack', }) await client.mcpServers.addTool(serverId, { integrationName: 'github', actionName: 'create_issue', connectionId: 'conn_github', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") server_id = "mcp_abc123" client.mcp_servers.add_tool( server_id, integration_name="slack", action_name="send_channel_message", connection_id="conn_slack", ) client.mcp_servers.add_tool( server_id, integration_name="github", action_name="create_issue", connection_id="conn_github", ) ``` ```typescript const headers = { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', } // Add Slack await fetch('https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools', { method: 'POST', headers, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_slack', }), }) // Add GitHub await fetch('https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools', { method: 'POST', headers, body: JSON.stringify({ integrationName: 'github', actionName: 'create_issue', connectionId: 'conn_github', }), }) ``` ```python import httpx headers = {"Authorization": "Bearer wvz_your_api_key"} # Add Slack httpx.post( "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools", headers=headers, json={ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_slack", }, ) # Add GitHub httpx.post( "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools", headers=headers, json={ "integrationName": "github", "actionName": "create_issue", "connectionId": "conn_github", }, ) ``` ## Connect an AI Client Connect to a CODE mode server the same way as TOOLS mode — the AI client will see 3 tools instead of dozens. Add to your Claude Desktop config (`claude_desktop_config.json`): ```json { "mcpServers": { "weavz": { "command": "npx", "args": [ "mcp-remote", "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/sse", "--header", "Authorization:Bearer mcp_token_xyz..." ] } } } ``` Add to your Cursor MCP settings (`.cursor/mcp.json`): ```json { "mcpServers": { "weavz": { "command": "npx", "args": [ "mcp-remote", "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/sse", "--header", "Authorization:Bearer mcp_token_xyz..." ] } } } ``` ```bash claude mcp add weavz \ --transport sse \ https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/sse \ --header "Authorization:Bearer mcp_token_xyz..." ``` ## How Code Mode Works Once connected, the AI agent uses the 3 meta-tools in sequence: ### weavz_search Search for available integrations and actions by keyword: ```text Agent calls: weavz_search({ query: "send slack message" }) Returns: - slack.send_channel_message — Send a message to a Slack channel - slack.send_direct_message — Send a direct message to a user ``` ### weavz_read_api Read the TypeScript declarations for an integration's actions: ```text Agent calls: weavz_read_api({ integration: "slack" }) Returns: declare namespace weavz { namespace slack { function send_channel_message(input: { channel: string; text: string; }): Promise<{ ok: boolean; ts: string }>; } } ``` ### weavz_execute Execute JavaScript code in a sandboxed environment. All registered integrations are available under the `weavz` namespace: ```javascript // Single action const result = await weavz.slack.send_channel_message({ channel: '#general', text: 'Hello from AI!', }) // Multi-action composition const channels = await weavz.slack.list_channels({}) const issues = await weavz.github.list_issues({ repo: 'my-org/my-repo' }) // Chain results between services const sheet = await weavz.google_sheets.read_sheet({ spreadsheetId: 'abc123', range: 'A1:B10', }) for (const row of sheet.values) { await weavz.slack.send_channel_message({ channel: '#updates', text: `Row: ${row.join(', ')}`, }) } ``` Some actions have dropdown fields (e.g. selecting a Slack channel by ID). Use `weavz.$options` to discover valid values inside `weavz_execute`: ```javascript // Get available Slack channels const channels = await weavz.$options('slack', 'send_channel_message', 'channel') // Returns: [{ label: '#general', value: 'C01ABCDEF' }, ...] // Optional: pass alias when the same action exists under multiple aliases const botChannels = await weavz.$options('slack', 'send_channel_message', 'channel', {}, 'slack_bot') // Use the value in an action await weavz.slack.send_channel_message({ channel: channels[0].value, text: 'Hello!', }) ``` `weavz.$options()` takes the original integration name (with hyphens), not the underscore version used in the namespace. For example, use `weavz.$options('google-sheets', ...)` even though the namespace is `weavz.google_sheets`. If an action is registered under multiple aliases on one server, pass the alias as the 5th argument: `weavz.$options(integration, action, property, context?, alias)`. ## Real-World Example: Weekly Report Bot An AI agent uses Code Mode to generate a weekly report from multiple sources: ```javascript // 1. Fetch open issues from GitHub const issues = await weavz.github.list_issues({ repo: 'acme/backend', state: 'open', }) // 2. Get latest metrics from Google Sheets const metrics = await weavz.google_sheets.read_sheet({ spreadsheetId: 'abc123', range: 'Metrics!A1:D10', }) // 3. Build a summary const summary = [ `Weekly Report — ${new Date().toLocaleDateString()}`, `\nOpen Issues: ${issues.length}`, `Critical: ${issues.filter(i => i.labels.includes('critical')).length}`, `\nKey Metrics:`, ...metrics.values.map(row => ` ${row[0]}: ${row[1]}`), ].join('\n') // 4. Post to Slack await weavz.slack.send_channel_message({ channel: '#engineering', text: summary, }) return { issueCount: issues.length, posted: true } ``` This runs as a **single `weavz_execute` call** — the agent wrote one script that orchestrates 3 integrations. In TOOLS mode, this would require at minimum 3 separate tool calls with the agent manually threading data between them. ## Execution Tracing Every `weavz_execute` call returns structured output including a trace of every integration action called: ```json { "result": { "issueCount": 12, "posted": true }, "logs": ["Fetched 12 issues", "Read 10 metric rows"], "actionsExecuted": [ { "integration": "github", "action": "list_issues", "duration": 340, "success": true }, { "integration": "google_sheets", "action": "read_sheet", "duration": 180, "success": true }, { "integration": "slack", "action": "send_channel_message", "duration": 95, "success": true } ], "duration": 650 } ``` This gives full observability into what happened — useful for debugging, auditing, and understanding agent behavior. ## Context Reduction The context savings compared to TOOLS mode are dramatic: | Scenario | TOOLS Mode | CODE Mode | Savings | |---|---|---|---| | 10 integrations, 50 actions | ~25,000 tokens | ~500 tokens | 98% | | 5 integrations, 20 actions | ~10,000 tokens | ~500 tokens | 95% | | 3 integrations, 10 actions | ~5,000 tokens | ~500 tokens | 90% | CODE mode always uses roughly the same ~500 tokens for the 3 meta-tools, regardless of how many integrations are registered. ## When to Use CODE vs TOOLS Mode | Factor | TOOLS Mode | CODE Mode | |---|---|---| | Number of actions | Few (< 10) | Many (10+) | | Context window usage | Higher | Minimal (~500 tokens) | | Multi-step workflows | One action per call | Multiple actions per call | | Setup complexity | Simpler | Requires code execution | | AI agent capability | Any MCP client | Needs code-capable agent | ### Choosing by scenario - **Building a chatbot** with a few integrations → **TOOLS** (simple, focused) - **Building an AI assistant** that handles 20+ services → **CODE** (context efficiency) - **Multi-step data pipelines** (fetch → transform → send) → **CODE** (compose in one call) - **AI agent chaining results between APIs** → **CODE** (natural data flow) - **Simple single-action tools** (search, lookup) → **TOOLS** (lower overhead) **Use CODE mode when** you have many integrations, token efficiency matters, or workflows require chaining multiple actions together. **Use TOOLS mode when** you have a small, focused set of tools and simplicity is preferred. See the [TOOLS mode guide](/docs/guides/mcp-tool-mode). ## End-User MCP Servers You can scope a CODE mode server to a specific [end user](/docs/concepts/end-users) by passing `endUserId` when creating the server. The server resolves connections belonging to that end user, so all `weavz.*` calls use their connected accounts. ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "User Code Agent", "workspaceId": "proj_abc123", "endUserId": "user_123", "mode": "CODE" }' ``` ```typescript const { server, bearerToken } = await client.mcpServers.create({ name: 'User Code Agent', workspaceId: 'proj_abc123', endUserId: 'user_123', mode: 'CODE', }) ``` ```python result = client.mcp_servers.create( name="User Code Agent", workspace_id="proj_abc123", end_user_id="user_123", mode="CODE", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'User Code Agent', workspaceId: 'proj_abc123', endUserId: 'user_123', mode: 'CODE', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "name": "User Code Agent", "workspaceId": "proj_abc123", "endUserId": "user_123", "mode": "CODE", }, ) data = res.json() ``` When a `weavz_execute` call fails because the end user hasn't connected the required integration, the error includes a **setup URL**. Share this URL with the end user — they open it, connect their account, and the agent can retry. ### Using Input Partials > Create and manage saved parameter presets for actions and triggers. Source: https://weavz.io/docs/guides/using-input-partials Input partials let you save parameter configurations as reusable presets. They pre-fill values, enforce immutable fields, and simplify action execution for your team and AI agents. ## Creating a Partial ### From the Dashboard Navigate to the **Playground** from the sidebar and select a workspace. Select an integration and action, then fill in the input fields you want to save as a preset. Click the **Save** button in the input panel. Enter a name for the partial and optionally mark fields as enforced. ### From the API ```bash curl -X POST https://api.weavz.io/api/v1/partials \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "workspaceId": "proj_abc123", "integrationName": "slack", "actionName": "send_channel_message", "name": "Alerts Channel", "description": "Always post to #alerts with bot username", "values": { "channel": "C0ALERTS", "username": "alert-bot" }, "enforcedKeys": ["channel"] }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_key' }) const { partial } = await client.partials.create({ workspaceId: 'proj_abc123', integrationName: 'slack', actionName: 'send_channel_message', name: 'Alerts Channel', description: 'Always post to #alerts with bot username', values: { channel: 'C0ALERTS', username: 'alert-bot', }, enforcedKeys: ['channel'], }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_key") result = client.partials.create( workspace_id="proj_abc123", integration_name="slack", action_name="send_channel_message", name="Alerts Channel", description="Always post to #alerts with bot username", values={"channel": "C0ALERTS", "username": "alert-bot"}, enforced_keys=["channel"], ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/partials', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ workspaceId: 'proj_abc123', integrationName: 'slack', actionName: 'send_channel_message', name: 'Alerts Channel', description: 'Always post to #alerts with bot username', values: { channel: 'C0ALERTS', username: 'alert-bot' }, enforcedKeys: ['channel'], }), }) const { partial } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/partials", headers={"Authorization": "Bearer wvz_your_key"}, json={ "workspaceId": "proj_abc123", "integrationName": "slack", "actionName": "send_channel_message", "name": "Alerts Channel", "description": "Always post to #alerts with bot username", "values": {"channel": "C0ALERTS", "username": "alert-bot"}, "enforcedKeys": ["channel"], }, ) partial = res.json()["partial"] ``` ## Loading a Partial in the Playground Navigate to the **Playground** and select your workspace. Pick the integration and action that has saved partials. Click the **Load** button in the input panel. Select a partial from the dropdown to populate the input fields. Modify any non-enforced fields as needed, then click **Execute**. ## Enforced vs Non-Enforced Values Partial values come in two flavors: | Type | Behavior | Use Case | |------|----------|----------| | **Non-enforced** | Pre-fills the field. Callers can override. | Default model, default channel | | **Enforced** | Locked. Callers cannot override, even at runtime. | Security constraints, channel locks | Enforced keys are listed in the `enforcedKeys` array. Any key in this array has its value locked at execution time, regardless of what the caller passes. ## Default Partials Mark a partial as default and it auto-applies whenever no explicit `partialIds` are provided: ```bash # Set as default curl -X POST https://api.weavz.io/api/v1/partials/{partialId}/set-default \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{"isDefault": true}' ``` ```typescript // Set as default await client.partials.setDefault(partialId, true) // Unset await client.partials.setDefault(partialId, false) ``` ```python # Set as default client.partials.set_default(partial_id, True) # Unset client.partials.set_default(partial_id, False) ``` ```typescript await fetch(`https://api.weavz.io/api/v1/partials/${partialId}/set-default`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ isDefault: true }), }) ``` ```python httpx.post( f"https://api.weavz.io/api/v1/partials/{partial_id}/set-default", headers={"Authorization": "Bearer wvz_your_key"}, json={"isDefault": True}, ) ``` Default resolution stacks up to 2 levels: action-specific default + integration-wide default. ## Using Partials with MCP Servers Assign partials to MCP server tools to control what AI agents can do: ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers/{serverId}/tools \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_abc", "partialIds": ["partial_id"] }' ``` ```typescript await client.mcpServers.addTool(serverId, { integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_abc', partialIds: ['partial_id'], }) ``` ```python client.mcp_servers.add_tool( server_id, integration_name="slack", action_name="send_channel_message", connection_id="conn_abc", partial_ids=["partial_id"], ) ``` ```typescript await fetch(`https://api.weavz.io/api/v1/mcp/servers/${serverId}/tools`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_abc', partialIds: ['partial_id'], }), }) ``` ```python httpx.post( f"https://api.weavz.io/api/v1/mcp/servers/{server_id}/tools", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "connectionId": "conn_abc", "partialIds": ["partial_id"], }, ) ``` Enforced keys are automatically removed from the MCP tool schema, so AI agents cannot see or override them. ## Managing Partials ### Updating Values ```bash curl -X PATCH https://api.weavz.io/api/v1/partials/{partialId} \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "values": { "channel": "C0ALERTS", "username": "weavz-bot" }, "enforcedKeys": ["channel", "username"] }' ``` ```typescript const { partial } = await client.partials.update(partialId, { values: { channel: 'C0ALERTS', username: 'weavz-bot' }, enforcedKeys: ['channel', 'username'], }) ``` ```python result = client.partials.update( partial_id, values={"channel": "C0ALERTS", "username": "weavz-bot"}, enforced_keys=["channel", "username"], ) ``` ```typescript const res = await fetch(`https://api.weavz.io/api/v1/partials/${partialId}`, { method: 'PATCH', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ values: { channel: 'C0ALERTS', username: 'weavz-bot' }, enforcedKeys: ['channel', 'username'], }), }) ``` ```python httpx.patch( f"https://api.weavz.io/api/v1/partials/{partial_id}", headers={"Authorization": "Bearer wvz_your_key"}, json={ "values": {"channel": "C0ALERTS", "username": "weavz-bot"}, "enforcedKeys": ["channel", "username"], }, ) ``` ### Deleting a Partial Deleting a partial automatically removes it from any MCP server tools that reference it. ```bash curl -X DELETE https://api.weavz.io/api/v1/partials/{partialId} \ -H "Authorization: Bearer wvz_your_key" ``` ```typescript await client.partials.delete(partialId) ``` ```python client.partials.delete(partial_id) ``` ```typescript await fetch(`https://api.weavz.io/api/v1/partials/${partialId}`, { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_key' }, }) ``` ```python httpx.delete( f"https://api.weavz.io/api/v1/partials/{partial_id}", headers={"Authorization": "Bearer wvz_your_key"}, ) ``` ### Integration Aliases > Register the same integration multiple times on an MCP server with different connections using aliases. Source: https://weavz.io/docs/guides/integration-aliases Integration aliases let you add the same integration to an MCP server multiple times, each with its own connection and identity. This is useful when you need separate connections for the same service — like a Slack bot token and a Slack user token. ## Use Cases - **Slack Bot vs User** — `slack_bot` for automated messages, `slack_user` for user-context messages - **GitHub Org vs Personal** — `github_work` for work repos, `github_personal` for personal repos - **Multiple Google Accounts** — `google_marketing` and `google_engineering` with different OAuth connections - **Staging vs Production** — `airtable_staging` and `airtable_prod` pointing to different bases ## Creating Aliased Tools Navigate to **MCP Servers** and select the server you want to configure. Click **Add Tool** and select the integration (e.g., Slack). In the **Alias** field, enter a custom name like `slack_bot`. This overrides the default integration name for tool naming. Select the connection to use for this alias (e.g., your bot token connection). Add the same integration again with a different alias (e.g., `slack_user`) and a different connection. ```bash # Add Slack with alias "slack_bot" curl -X POST https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "integrationAlias": "slack_bot", "connectionId": "conn_slack_bot" }' # Add Slack again with alias "slack_user" curl -X POST https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "integrationAlias": "slack_user", "connectionId": "conn_slack_user" }' ``` ```typescript const serverId = 'mcp_abc123' // Bot connection await client.mcpServers.addTool(serverId, { integrationName: 'slack', actionName: 'send_channel_message', integrationAlias: 'slack_bot', connectionId: 'conn_slack_bot', }) // User connection await client.mcpServers.addTool(serverId, { integrationName: 'slack', actionName: 'send_channel_message', integrationAlias: 'slack_user', connectionId: 'conn_slack_user', }) ``` ```python server_id = "mcp_abc123" # Bot connection client.mcp_servers.add_tool(server_id, { "integration_name": "slack", "action_name": "send_channel_message", "integration_alias": "slack_bot", "connection_id": "conn_slack_bot", }) # User connection client.mcp_servers.add_tool(server_id, { "integration_name": "slack", "action_name": "send_channel_message", "integration_alias": "slack_user", "connection_id": "conn_slack_user", }) ``` ```typescript const headers = { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', } // Add Slack with alias "slack_bot" await fetch('https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools', { method: 'POST', headers, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', integrationAlias: 'slack_bot', connectionId: 'conn_slack_bot', }), }) // Add Slack again with alias "slack_user" await fetch('https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools', { method: 'POST', headers, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', integrationAlias: 'slack_user', connectionId: 'conn_slack_user', }), }) ``` ```python import httpx headers = {"Authorization": "Bearer wvz_your_key"} # Add Slack with alias "slack_bot" httpx.post( "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools", headers=headers, json={ "integrationName": "slack", "actionName": "send_channel_message", "integrationAlias": "slack_bot", "connectionId": "conn_slack_bot", }, ) # Add Slack again with alias "slack_user" httpx.post( "https://api.weavz.io/api/v1/mcp/servers/mcp_abc123/tools", headers=headers, json={ "integrationName": "slack", "actionName": "send_channel_message", "integrationAlias": "slack_user", "connectionId": "conn_slack_user", }, ) ``` ## Naming Rules Aliases must follow these rules: - **Format:** lowercase letters, numbers, hyphens, and underscores only (`/^[a-z][a-z0-9_-]*$/`) - **Length:** maximum 64 characters - **Must start** with a lowercase letter - **Consistent mapping:** all tools with the same alias on a server must use the same `integrationName` Valid examples: `slack_bot`, `github-work`, `airtable_prod`, `google_eng` Invalid examples: `Slack_Bot` (uppercase), `123slack` (starts with number), `slack bot` (spaces) ## Tool Naming with Aliases In TOOLS mode, tool names use the alias instead of the integration name: | Alias | Action | Tool Name | |-------|--------|-----------| | `slack_bot` | `send_channel_message` | `slack_bot__send_channel_message` | | `slack_user` | `send_channel_message` | `slack_user__send_channel_message` | | `github_work` | `create_issue` | `github_work__create_issue` | Without an alias, the tool name defaults to using the integration name (e.g., `slack__send_channel_message`). ## Code Mode with Aliases In CODE mode, aliases create separate namespaces under `weavz.*`: ```javascript // With aliases, each has its own namespace await weavz.slack_bot.send_channel_message({ channel: '#alerts', text: 'Automated alert!', }) await weavz.slack_user.send_channel_message({ channel: '#general', text: 'Message from user context', }) ``` The `weavz_read_api` tool returns separate TypeScript declarations for each alias: ```text AI Agent calls: weavz_read_api({ integration: "slack_bot" }) Returns: declare namespace weavz { namespace slack_bot { function send_channel_message(input: { channel: string; text: string; }): Promise<{ ok: boolean }>; } } ``` ## Alias Conflicts If you try to add a tool with an alias that's already associated with a different integration on the same server, you'll get a `409 ALIAS_CONFLICT` error: ```json { "error": "Alias 'slack_bot' is already associated with integration 'slack' on this server", "code": "ALIAS_CONFLICT" } ``` This prevents confusion — one alias always maps to one integration per server. ## Default Behavior When no `integrationAlias` is provided, the integration name itself is used as the alias. This means existing tools work without any changes, and aliases are an opt-in feature for advanced use cases. ### Custom OAuth Apps > Register your own OAuth applications for branded consent screens and custom scopes. Source: https://weavz.io/docs/guides/custom-oauth-apps By default, Weavz provides pre-configured OAuth credentials for supported integrations. Custom OAuth apps let you use your own OAuth application credentials instead, giving you control over branding, scopes, and consent screens. ## Why Use Custom OAuth Apps - **Branded consent screens** — users see your app name instead of "Weavz" - **Custom scopes** — request only the permissions your app needs - **Different environments** — separate OAuth apps for development, staging, and production - **Compliance** — some organizations require using their own OAuth credentials - **Rate limits** — use your own API quota instead of shared platform limits ## Registering an OAuth App ### Step 1: Create the App with the Provider First, create an OAuth application in the third-party service's developer portal: 1. Go to the provider's developer settings (e.g., Slack API, GitHub Developer Settings) 2. Create a new OAuth application 3. Set the redirect URL to your Weavz instance's connect callback URL: ```text https://api.weavz.io/api/v1/connect/oauth-callback ``` 4. Note the **Client ID** and **Client Secret** ### Step 2: Register with Weavz Navigate to **Settings > OAuth Apps** in the Weavz dashboard. Click **Create OAuth App** and select the integration (e.g., Slack, GitHub). Paste the **Client ID** and **Client Secret** from the provider's developer portal. Enter custom scopes if you want to override the defaults. Leave blank to use the integration's default scopes. Click **Save**. All new connections for this integration will use your custom OAuth app. ## Optional Configuration Some OAuth providers use non-standard endpoints or require additional parameters. When registering your OAuth app in the dashboard, you can optionally configure: | Field | Required | Description | |-------|----------|-------------| | `integrationName` | Yes | The integration this OAuth app is for | | `clientId` | Yes | OAuth Client ID from the provider | | `clientSecret` | Yes | OAuth Client Secret from the provider | | `authUrl` | No | Custom authorization endpoint URL | | `tokenUrl` | No | Custom token exchange endpoint URL | | `scope` | No | Space-separated OAuth scopes to request | | `extraParams` | No | Additional parameters to include in the auth request | ## Redirect URL Configuration When creating your OAuth application with the provider, set the redirect URL to: ```text https://api.weavz.io/api/v1/connect/oauth-callback ``` For enterprise on-premise deployments, replace `api.weavz.io` with your dedicated API URL. [Contact sales](/contact) for details. ## Priority When a custom OAuth app is registered for an integration, it takes priority over the platform's built-in OAuth credentials. This applies organization-wide — all users in your organization will use your custom OAuth app when connecting to that integration. ### Using Storage & KV Store > Store files and key-value data using Weavz's built-in Storage and KV Store integrations. Source: https://weavz.io/docs/guides/using-storage-and-kv Weavz includes two built-in integrations for persistent data: **Storage** for files and **KV Store** for key-value data. Both are accessed through the standard [action execution](/docs/guides/executing-actions) API — no additional connections required. ## Storage Integration The Storage integration provides file CRUD operations backed by S3-compatible object storage. ### Write a File ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "storage", "actionName": "write_file", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "path": "reports/monthly.json", "content": "{\"revenue\": 50000, \"month\": \"January\"}" } }' ``` ```typescript await client.actions.execute('storage', 'write_file', { workspaceId: 'YOUR_WORKSPACE_ID', input: { path: 'reports/monthly.json', content: JSON.stringify({ revenue: 50000, month: 'January' }), }, }) ``` ```python import json client.actions.execute("storage", "write_file", workspace_id="YOUR_WORKSPACE_ID", input={ "path": "reports/monthly.json", "content": json.dumps({"revenue": 50000, "month": "January"}), }, ) ``` ```typescript await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'storage', actionName: 'write_file', workspaceId: 'YOUR_WORKSPACE_ID', input: { path: 'reports/monthly.json', content: JSON.stringify({ revenue: 50000, month: 'January' }), }, }), }) ``` ```python import httpx import json httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "storage", "actionName": "write_file", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "path": "reports/monthly.json", "content": json.dumps({"revenue": 50000, "month": "January"}), }, }, ) ``` ### Read a File ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "storage", "actionName": "read_file", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "path": "reports/monthly.json" } }' ``` ```typescript const { output } = await client.actions.execute('storage', 'read_file', { workspaceId: 'YOUR_WORKSPACE_ID', input: { path: 'reports/monthly.json' }, }) ``` ```python result = client.actions.execute("storage", "read_file", workspace_id="YOUR_WORKSPACE_ID", input={ "path": "reports/monthly.json", }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'storage', actionName: 'read_file', workspaceId: 'YOUR_WORKSPACE_ID', input: { path: 'reports/monthly.json' }, }), }) const { output } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "storage", "actionName": "read_file", "workspaceId": "YOUR_WORKSPACE_ID", "input": {"path": "reports/monthly.json"}, }, ) output = res.json()["output"] ``` ### List Files ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "storage", "actionName": "list_files", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "prefix": "reports/" } }' ``` ```typescript const { output } = await client.actions.execute('storage', 'list_files', { workspaceId: 'YOUR_WORKSPACE_ID', input: { prefix: 'reports/' }, }) ``` ```python result = client.actions.execute("storage", "list_files", workspace_id="YOUR_WORKSPACE_ID", input={ "prefix": "reports/", }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'storage', actionName: 'list_files', workspaceId: 'YOUR_WORKSPACE_ID', input: { prefix: 'reports/' }, }), }) const { output } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "storage", "actionName": "list_files", "workspaceId": "YOUR_WORKSPACE_ID", "input": {"prefix": "reports/"}, }, ) output = res.json()["output"] ``` ### Delete a File ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "storage", "actionName": "delete_file", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "path": "reports/monthly.json" } }' ``` ```typescript await client.actions.execute('storage', 'delete_file', { workspaceId: 'YOUR_WORKSPACE_ID', input: { path: 'reports/monthly.json' }, }) ``` ```python client.actions.execute("storage", "delete_file", workspace_id="YOUR_WORKSPACE_ID", input={ "path": "reports/monthly.json", }, ) ``` ```typescript await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'storage', actionName: 'delete_file', workspaceId: 'YOUR_WORKSPACE_ID', input: { path: 'reports/monthly.json' }, }), }) ``` ```python import httpx httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "storage", "actionName": "delete_file", "workspaceId": "YOUR_WORKSPACE_ID", "input": {"path": "reports/monthly.json"}, }, ) ``` ### Storage Actions Summary | Action | Input | Description | |--------|-------|-------------| | `write_file` | `path`, `content` | Write or overwrite a file | | `read_file` | `path` | Read file contents | | `list_files` | `prefix` | List files matching a prefix | | `delete_file` | `path` | Delete a file | ## KV Store Integration The KV Store integration provides key-value operations for storing structured data. ### Put a Value ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "put", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "key": "user:settings:123", "value": "{\"theme\": \"dark\", \"notifications\": true}" } }' ``` ```typescript await client.actions.execute('kv-store', 'put', { workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'user:settings:123', value: JSON.stringify({ theme: 'dark', notifications: true }), }, }) ``` ```python import json client.actions.execute("kv-store", "put", workspace_id="YOUR_WORKSPACE_ID", input={ "key": "user:settings:123", "value": json.dumps({"theme": "dark", "notifications": True}), }, ) ``` ```typescript await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'put', workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'user:settings:123', value: JSON.stringify({ theme: 'dark', notifications: true }), }, }), }) ``` ```python import httpx import json httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "kv-store", "actionName": "put", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "key": "user:settings:123", "value": json.dumps({"theme": "dark", "notifications": True}), }, }, ) ``` ### Get a Value ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "get", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "key": "user:settings:123" } }' ``` ```typescript const { output } = await client.actions.execute('kv-store', 'get', { workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'user:settings:123' }, }) ``` ```python result = client.actions.execute("kv-store", "get", input={ "key": "user:settings:123", }) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'get', workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'user:settings:123' }, }), }) const { output } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "kv-store", "actionName": "get", "workspaceId": "YOUR_WORKSPACE_ID", "input": {"key": "user:settings:123"}, }, ) output = res.json()["output"] ``` ### Delete a Value ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "delete", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "key": "user:settings:123" } }' ``` ```typescript await client.actions.execute('kv-store', 'delete', { workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'user:settings:123' }, }) ``` ```python client.actions.execute("kv-store", "delete", input={ "key": "user:settings:123", }) ``` ```typescript await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'delete', workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'user:settings:123' }, }), }) ``` ```python import httpx httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "kv-store", "actionName": "delete", "workspaceId": "YOUR_WORKSPACE_ID", "input": {"key": "user:settings:123"}, }, ) ``` ### List Operations The KV Store supports list-based operations on a single key: ```bash # Add to a list curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "add_to_list", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "key": "processed:emails", "value": "msg_abc123" } }' # Remove from a list curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "kv-store", "actionName": "remove_from_list", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "key": "processed:emails", "value": "msg_abc123" } }' ``` ```typescript // Add to a list await client.actions.execute('kv-store', 'add_to_list', { workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'processed:emails', value: 'msg_abc123' }, }) // Remove from a list await client.actions.execute('kv-store', 'remove_from_list', { workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'processed:emails', value: 'msg_abc123' }, }) ``` ```python # Add to a list client.actions.execute("kv-store", "add_to_list", input={ "key": "processed:emails", "value": "msg_abc123", }) # Remove from a list client.actions.execute("kv-store", "remove_from_list", input={ "key": "processed:emails", "value": "msg_abc123", }) ``` ```typescript const headers = { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', } // Add to a list await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'add_to_list', workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'processed:emails', value: 'msg_abc123' }, }), }) // Remove from a list await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers, body: JSON.stringify({ integrationName: 'kv-store', actionName: 'remove_from_list', workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'processed:emails', value: 'msg_abc123' }, }), }) ``` ```python import httpx headers = {"Authorization": "Bearer wvz_your_key"} # Add to a list httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers=headers, json={ "integrationName": "kv-store", "actionName": "add_to_list", "workspaceId": "YOUR_WORKSPACE_ID", "input": {"key": "processed:emails", "value": "msg_abc123"}, }, ) # Remove from a list httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers=headers, json={ "integrationName": "kv-store", "actionName": "remove_from_list", "workspaceId": "YOUR_WORKSPACE_ID", "input": {"key": "processed:emails", "value": "msg_abc123"}, }, ) ``` ### KV Store Actions Summary | Action | Input | Description | |--------|-------|-------------| | `put` | `key`, `value` | Store a value | | `get` | `key` | Retrieve a value | | `delete` | `key` | Delete a key | | `add_to_list` | `key`, `value` | Append a value to a list | | `remove_from_list` | `key`, `value` | Remove a value from a list | ## Data Scoping Storage and KV Store actions include a `scope` input property that controls data isolation. The default scope is `end_user`, which isolates data per end user within the workspace when `endUserId` is provided. | Scope | Value | Description | |-------|-------|-------------| | **End User Bound** | `end_user` (default) | Isolated per end user. Requires `endUserId` in the request. | | **Workspace Bound** | `workspace` | Shared across the entire workspace. | | **External ID Bound** | `external` | Scoped to a custom `externalId` value within the workspace. | ### End-User Scoping (Default) When you pass `endUserId` in the request, data is isolated per end user. You can omit `scope` — it defaults to `end_user`. ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "storage", "actionName": "write_file", "workspaceId": "YOUR_WORKSPACE_ID", "endUserId": "user_12345", "input": { "path": "preferences.json", "content": "{\"theme\": \"dark\"}", "scope": "end_user" } }' ``` ```typescript await client.actions.execute('storage', 'write_file', { workspaceId: 'YOUR_WORKSPACE_ID', endUserId: 'user_12345', input: { path: 'preferences.json', content: JSON.stringify({ theme: 'dark' }), scope: 'end_user', }, }) ``` ```python client.actions.execute("storage", "write_file", workspace_id="YOUR_WORKSPACE_ID", end_user_id="user_12345", input={ "path": "preferences.json", "content": json.dumps({"theme": "dark"}), "scope": "end_user", }, ) ``` ```typescript await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'storage', actionName: 'write_file', workspaceId: 'YOUR_WORKSPACE_ID', endUserId: 'user_12345', input: { path: 'preferences.json', content: JSON.stringify({ theme: 'dark' }), scope: 'end_user', }, }), }) ``` ```python import httpx import json httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "storage", "actionName": "write_file", "workspaceId": "YOUR_WORKSPACE_ID", "endUserId": "user_12345", "input": { "path": "preferences.json", "content": json.dumps({"theme": "dark"}), "scope": "end_user", }, }, ) ``` Files written by `user_12345` are fully isolated from files written by `user_67890`. This is the recommended approach for multi-tenant applications where each end user should have their own storage namespace. ### External ID Scoping Set `scope` to `"external"` and provide an `externalId` to create custom scopes — useful for isolating data per tenant, session, or entity: ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "storage", "actionName": "write_file", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "path": "config.json", "content": "{\"setting\": \"value\"}", "scope": "external", "externalId": "tenant_456" } }' ``` ```typescript await client.actions.execute('storage', 'write_file', { workspaceId: 'YOUR_WORKSPACE_ID', input: { path: 'config.json', content: JSON.stringify({ setting: 'value' }), scope: 'external', externalId: 'tenant_456', }, }) ``` ```python client.actions.execute("storage", "write_file", workspace_id="YOUR_WORKSPACE_ID", input={ "path": "config.json", "content": json.dumps({"setting": "value"}), "scope": "external", "externalId": "tenant_456", }, ) ``` ```typescript await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'storage', actionName: 'write_file', workspaceId: 'YOUR_WORKSPACE_ID', input: { path: 'config.json', content: JSON.stringify({ setting: 'value' }), scope: 'external', externalId: 'tenant_456', }, }), }) ``` ```python import httpx import json httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_key"}, json={ "integrationName": "storage", "actionName": "write_file", "workspaceId": "YOUR_WORKSPACE_ID", "input": { "path": "config.json", "content": json.dumps({"setting": "value"}), "scope": "external", "externalId": "tenant_456", }, }, ) ``` With external ID scoping, files from different tenants are fully isolated within the workspace — `tenant_456/config.json` and `tenant_789/config.json` are completely separate, and the same `externalId` in different workspaces is also isolated. ## Practical Examples ### Caching API Responses ```typescript const cacheKey = `cache:weather:${city}` // Check cache const cached = await client.actions.execute('kv-store', 'get', { workspaceId: 'YOUR_WORKSPACE_ID', input: { key: cacheKey }, }) if (cached.output.value) { const data = JSON.parse(cached.output.value) const age = Date.now() - new Date(data.cachedAt).getTime() // Use cache if less than 5 minutes old if (age < 300_000) return data.weather } // Fetch fresh data and cache it const weather = await fetchWeatherApi(city) await client.actions.execute('kv-store', 'put', { workspaceId: 'YOUR_WORKSPACE_ID', input: { key: cacheKey, value: JSON.stringify({ weather, cachedAt: new Date().toISOString() }), }, }) ``` ### Tracking Processed Items ```typescript // Check if already processed const processed = await client.actions.execute('kv-store', 'get', { workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'processed:webhooks' }, }) const list = JSON.parse(processed.output.value || '[]') if (list.includes(webhookId)) return // Skip duplicate // Process the webhook await handleWebhook(payload) // Mark as processed await client.actions.execute('kv-store', 'add_to_list', { workspaceId: 'YOUR_WORKSPACE_ID', input: { key: 'processed:webhooks', value: webhookId }, }) ``` ### Managing End Users > Register users, generate connect URLs, and execute actions on behalf of your customers. Source: https://weavz.io/docs/guides/managing-end-users This guide walks through the full lifecycle of managing end users in Weavz — from registering a user to executing actions with their connections. ## 1. Create a Workspace End users live within workspaces. Start by creating a workspace and configuring its integrations. ```bash # Create a workspace curl -X POST https://api.weavz.io/api/v1/workspaces \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"name": "My App", "slug": "my-app"}' # Add Slack with per-user connections curl -X POST https://api.weavz.io/api/v1/workspaces/{workspaceId}/integrations \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "connectionStrategy": "per_user" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) // Create a workspace const { workspace } = await client.workspaces.create({ name: 'My App', slug: 'my-app', }) // Add Slack with per-user connections await client.workspaces.addIntegration(workspace.id, { integrationName: 'slack', connectionStrategy: 'per_user', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") # Create a workspace result = client.workspaces.create(name="My App", slug="my-app") workspace = result["workspace"] # Add Slack with per-user connections client.workspaces.add_integration(workspace["id"], integration_name="slack", connection_strategy="per_user", ) ``` ```typescript // Create a workspace const wsRes = await fetch('https://api.weavz.io/api/v1/workspaces', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'My App', slug: 'my-app' }), }) const { workspace } = await wsRes.json() // Add Slack with per-user connections await fetch(`https://api.weavz.io/api/v1/workspaces/${workspace.id}/integrations`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', connectionStrategy: 'per_user', }), }) ``` ```python import httpx headers = {"Authorization": "Bearer wvz_your_api_key"} # Create a workspace res = httpx.post( "https://api.weavz.io/api/v1/workspaces", headers=headers, json={"name": "My App", "slug": "my-app"}, ) workspace = res.json()["workspace"] # Add Slack with per-user connections httpx.post( f"https://api.weavz.io/api/v1/workspaces/{workspace['id']}/integrations", headers=headers, json={ "integrationName": "slack", "connectionStrategy": "per_user", }, ) ``` ## 2. Register an End User When a new customer signs up for your product, register them as an end user. Use their ID from your system as the `externalId`. ```bash curl -X POST https://api.weavz.io/api/v1/end-users \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "externalId": "user_123", "displayName": "Alice Johnson", "email": "alice@example.com" }' ``` ```typescript const { endUser } = await client.endUsers.create({ workspaceId: workspace.id, externalId: 'user_123', displayName: 'Alice Johnson', email: 'alice@example.com', }) ``` ```python result = client.end_users.create( workspace_id=workspace["id"], external_id="user_123", display_name="Alice Johnson", email="alice@example.com", ) end_user = result["endUser"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/end-users', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ workspaceId: workspace.id, externalId: 'user_123', displayName: 'Alice Johnson', email: 'alice@example.com', }), }) const { endUser } = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/end-users", headers=headers, json={ "workspaceId": workspace["id"], "externalId": "user_123", "displayName": "Alice Johnson", "email": "alice@example.com", }, ) end_user = res.json()["endUser"] ``` ## 3. Generate a Connect URL Create a connect token so the end user can connect their Slack account through the hosted connect portal. ```bash curl -X POST https://api.weavz.io/api/v1/end-users/{endUserId}/connect-token \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"integrationName": "slack"}' ``` ```typescript const { connectUrl } = await client.endUsers.createConnectToken( endUser.id, { integrationName: 'slack' } ) // Send connectUrl to your frontend to open in a popup console.log('Connect URL:', connectUrl) ``` ```python result = client.end_users.create_connect_token( end_user["id"], integration_name="slack", ) connect_url = result["connectUrl"] # Send connect_url to your frontend to open in a popup print("Connect URL:", connect_url) ``` ```typescript const res = await fetch( `https://api.weavz.io/api/v1/end-users/${endUser.id}/connect-token`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack' }), } ) const { connectUrl } = await res.json() ``` ```python res = httpx.post( f"https://api.weavz.io/api/v1/end-users/{end_user['id']}/connect-token", headers=headers, json={"integrationName": "slack"}, ) connect_url = res.json()["connectUrl"] ``` Open `connectUrl` in a popup or redirect the end user to it. The hosted connect page guides them through the OAuth2 consent flow. Once they approve, the connection is automatically linked to the end user. ## 4. Execute Actions as the End User Once the end user has connected their Slack, you can execute actions on their behalf by passing `endUserId`: ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "input": { "channel": "C0123456789", "text": "Hello from Alice!" }, "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "endUserId": "user_123" }' ``` ```typescript const result = await client.actions.execute('slack', 'send_channel_message', { workspaceId: workspace.id, endUserId: 'user_123', input: { channel: 'C0123456789', text: 'Hello from Alice!', }, }) ``` ```python result = client.actions.execute( "slack", "send_channel_message", workspace_id=workspace["id"], end_user_id="user_123", input={ "channel": "C0123456789", "text": "Hello from Alice!", }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', input: { channel: 'C0123456789', text: 'Hello from Alice!' }, workspaceId: workspace.id, endUserId: 'user_123', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers=headers, json={ "integrationName": "slack", "actionName": "send_channel_message", "input": {"channel": "C0123456789", "text": "Hello from Alice!"}, "workspaceId": workspace["id"], "endUserId": "user_123", }, ) data = res.json() ``` Weavz resolves Alice's Slack connection automatically based on the `endUserId` and the workspace's `per_user` connection strategy. ## 5. Send Email Invitations Instead of generating connect URLs programmatically, you can send email invitations directly: ```bash curl -X POST https://api.weavz.io/api/v1/end-users/{endUserId}/invite \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "email": "alice@example.com", "integrationName": "slack" }' ``` ```typescript await client.endUsers.invite(endUser.id, { email: 'alice@example.com', integrationName: 'slack', }) ``` ```python client.end_users.invite( end_user["id"], email="alice@example.com", integration_name="slack", ) ``` ```typescript await fetch(`https://api.weavz.io/api/v1/end-users/${endUser.id}/invite`, { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ email: 'alice@example.com', integrationName: 'slack', }), }) ``` ```python httpx.post( f"https://api.weavz.io/api/v1/end-users/{end_user['id']}/invite", headers=headers, json={ "email": "alice@example.com", "integrationName": "slack", }, ) ``` The email contains a link to the connect portal where Alice can authorize her Slack account. ## 6. View End User Connections Check which integrations an end user has connected: ```bash curl https://api.weavz.io/api/v1/end-users/{endUserId} \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { endUser, connections } = await client.endUsers.get(endUser.id) for (const conn of connections) { console.log(`${conn.integrationName}: ${conn.status}`) } ``` ```python result = client.end_users.get(end_user["id"]) for conn in result["connections"]: print(f"{conn['integrationName']}: {conn['status']}") ``` ```typescript const res = await fetch(`https://api.weavz.io/api/v1/end-users/${endUserId}`, { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const { endUser, connections } = await res.json() ``` ```python res = httpx.get( f"https://api.weavz.io/api/v1/end-users/{end_user['id']}", headers=headers, ) data = res.json() connections = data["connections"] ``` ## 7. Create MCP Servers for End Users You can create an MCP server scoped to an end user. The AI agent uses the server's bearer token and all tool calls resolve to that end user's connections. Register the end user as shown in step 2 above. ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Agent for Alice", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "endUserId": "user_123", "mode": "TOOLS" }' ``` ```typescript const { server, bearerToken } = await client.mcpServers.create({ name: 'Agent for Alice', workspaceId: workspace.id, endUserId: 'user_123', mode: 'TOOLS', }) ``` ```python result = client.mcp_servers.create( name="Agent for Alice", workspace_id=workspace["id"], end_user_id="user_123", mode="TOOLS", ) bearer_token = result["bearerToken"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Agent for Alice', workspaceId: workspace.id, endUserId: 'user_123', mode: 'TOOLS', }), }) const { server, bearerToken } = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers", headers=headers, json={ "name": "Agent for Alice", "workspaceId": workspace["id"], "endUserId": "user_123", "mode": "TOOLS", }, ) bearer_token = res.json()["bearerToken"] ``` Configure your AI agent with the MCP server's bearer token and endpoint. When a tool call fails because the end user hasn't connected the required integration, the error includes a setup URL. Share this URL with the end user so they can connect their account and the agent can retry. ## Multi-Tenant Patterns ### One workspace per customer Best for strict isolation. Each customer gets their own workspace with separate integrations, connections, and end users. ```mermaid graph TD Org[Organization: My SaaS] Org --> A[Workspace: Customer A] Org --> B[Workspace: Customer B] A --> Alice[alice - alice_123] A --> Bob[bob - bob_456] Alice --> AC[Alice's Slack] Bob --> BC[Bob's Slack] B --> Charlie[charlie - charlie_789] Charlie --> CC[Charlie's Gmail] ``` ### Shared workspace with per-user connections Best for simpler setups where all customers share the same integration configuration. ```mermaid graph TD Org[Organization: My SaaS] Org --> WS[Workspace: Production] WS --> S[slack - per_user] WS --> G[gmail - per_user_with_fallback] WS --> Alice[alice] WS --> Bob[bob] WS --> Charlie[charlie] Alice --> AS[Slack conn.] Alice --> AG[Gmail conn.] Bob --> BS[Slack conn.] Bob -.- BG[Gmail fallback] Charlie --> CG[Gmail conn.] Charlie -.- CS[no Slack yet] style BG stroke-dasharray: 5 5 style CS stroke-dasharray: 5 5 ``` With `per_user_with_fallback`, end users who haven't connected their own account still get functionality through the workspace's default connection. ## Cleanup When you delete an end user, all their connections are automatically cleaned up: ```bash curl -X DELETE https://api.weavz.io/api/v1/end-users/{endUserId} \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript await client.endUsers.delete(endUser.id) ``` ```python client.end_users.delete(end_user["id"]) ``` ```typescript await fetch(`https://api.weavz.io/api/v1/end-users/${endUserId}`, { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) ``` ```python httpx.delete( f"https://api.weavz.io/api/v1/end-users/{end_user['id']}", headers=headers, ) ``` ## Next Steps - [End Users API Reference](/docs/api-reference/end-users) — full endpoint documentation - [End Users Concept](/docs/concepts/end-users) — understand the identity model - [Setting Up Connections](/docs/guides/setting-up-connections) — learn about connection types - [Workspace Integrations](/docs/api-reference/workspace-integrations) — configure connection strategies ### Activity Logs > Monitor and audit every action, connection, trigger, and MCP event across your organization. Source: https://weavz.io/docs/guides/activity-logs Activity logs give you a real-time audit trail of everything happening in your Weavz organization. Every action execution, connection change, trigger event, and MCP server call is recorded with status, duration, and metadata. ## What Gets Logged Weavz automatically logs the following events: | Event Type | When It Fires | |------------|---------------| | **Action Executed** | Every time an integration action runs (success or error) | | **Connection Created** | When a new OAuth or API key connection is established | | **Connection Deleted** | When a connection is removed | | **Trigger Enabled** | When a webhook or polling trigger is activated | | **Trigger Disabled** | When a trigger is deactivated | | **Trigger Fired** | When an incoming webhook or poll cycle delivers data | | **MCP Tool Called** | When an MCP client calls a tool in TOOLS mode | | **MCP Code Executed** | When an MCP client runs code via `weavz_execute` in CODE mode | | **MCP Server Created** | When a new MCP server is provisioned | Each event records: - **Integration and action/trigger name** — what ran - **Status** — success or error - **Duration** — execution time in milliseconds - **Workspace** — which workspace the event belongs to - **Metadata** — additional context (error messages on failure, trigger payloads, etc.) ## Viewing Activity Logs Navigate to **Activity** in the left sidebar of the Weavz dashboard. Use the **Type** dropdown to filter for specific events — for example, only action executions or only connection changes. Click any event row to expand it and view the full metadata JSON, including error messages, trigger payloads, or execution context. ## Live Monitoring Toggle **Auto-refresh** in the top-right corner to enable live updates. The log refreshes every 10 seconds, giving you a near real-time view of what your integrations and MCP servers are doing. This is useful for: - **Debugging** — watch action executions as they happen while testing a new integration - **Monitoring** — keep the activity page open during a deployment to catch errors early - **Auditing** — review what a specific MCP server or workspace has been doing ## Retention by Plan Activity logs are retained based on your organization's plan: | Plan | Retention | |------|-----------| | Free | 7 days | | Pro | 30 days | | Team | 90 days | | Scale | 180 days | | Enterprise | 365 days | Events older than your retention window are automatically deleted. If you need longer retention, consider upgrading your plan or exporting logs to an external system via the API. ### Pricing & Add-Ons FAQ > Frequently asked questions about plans, add-ons, overages, and upgrades Source: https://weavz.io/docs/guides/pricing-faq # Pricing & Add-Ons FAQ Common questions about Weavz plans, add-on packs, overages, and upgrade timing. ## Plans ### What happens when I hit my plan's action limit? It depends on your plan: - **Free plan** — Actions are hard-capped. You'll receive a `402 QUOTA_EXCEEDED` error. Upgrade to a paid plan or wait for the next billing period. - **Paid plans (Pro, Team, Scale)** — Actions use soft limits. You're never hard-blocked. The API returns an `overIncluded` flag so your application can prompt users to upgrade, but execution continues. ### Can I switch plans at any time? Yes. Upgrades take effect immediately. Downgrades take effect at the end of your current billing period. ### Do unused actions roll over? No. Action quotas and add-on allowances reset each billing period (monthly or annually). ## Add-On Packs ### Which add-ons are available on my plan? Add-on packs are tier-restricted to encourage natural upgrade paths: | Category | Free | Pro | Team | Scale | Enterprise | |---|---|---|---|---|---| | Action Packs | — | ✓ | ✓ | ✓ | ✓ | | Sandbox Packs | — | — | ✓ | ✓ | ✓ | | Storage Packs | — | — | ✓ | ✓ | ✓ | | KV Store Packs | — | — | ✓ | ✓ | ✓ | If you need sandbox, storage, or KV add-ons on Pro, upgrading to Team ($129/mo) is usually more cost-effective — you get higher limits across all resource types. ### Can I buy the same add-on multiple times? Yes. Add-ons can be stacked up to **10× per billing period**. For example, you can purchase the 50K action pack three times to add 150K extra actions. If you're consistently buying 5× or more of a single add-on, consider upgrading — the next tier typically includes more capacity at a better per-unit rate. ### When are add-ons charged? Add-ons are charged immediately when purchased. The extra quota applies to your current billing period and resets at the start of the next one. ### What are the add-on prices? **Action Packs (Pro+):** | Pack | Price | Per-Action Cost | |---|---|---| | +10,000 actions | $5 | $0.0005 | | +50,000 actions | $15 | $0.0003 | | +200,000 actions | $40 | $0.0002 | | +1,000,000 actions | $100 | $0.0001 | **Sandbox Packs (Team+):** | Pack | Price | Per-Hour Cost | |---|---|---| | +10 hours | $15 | $1.50 | | +50 hours | $50 | $1.00 | **Storage Packs (Team+):** | Pack | Price | |---|---| | +5 GB | $5 | | +25 GB | $15 | **KV Store Packs (Team+):** | Pack | Price | |---|---| | +10,000 entries | $5 | | +100,000 entries | $15 | ## Resource Overages ### What are resource overages? On paid plans, exceeding your included resource count (connections, MCP servers, workspaces, team members) does **not** block you. Extra resources are billed as monthly overages: - **Connections** — $0.10/mo each - **MCP Servers** — $0.10/mo each - **Workspaces** — $0.10/mo each - **Team Members** — $5.00/mo each Overages are automatically calculated and added to your monthly invoice. ### Can I set a spending limit on overages? Yes. Set an optional **spend cap** in the billing dashboard to limit your monthly overage costs. When the cap is reached, additional resource creation is blocked until the next billing period. ### Do overages apply on the Free plan? No. On the Free plan, resources are hard-capped. Connections and MCP servers allow a small buffer (2× the included amount), but there's no overage billing. ## Upgrade Timing ### When should I upgrade from Pro to Team? Consider upgrading when: - You regularly purchase action add-ons totaling $50+/month - You need sandbox time beyond 2 hours/month - You need storage or KV add-on packs (Team+ only) - You're approaching 50+ connections **Team ($129/mo) includes**: 150K actions, 10hr sandbox, 10 GB storage, 100K KV entries, 250 connections, 50 members. ### When should I upgrade from Team to Scale? Consider upgrading when: - Your action usage regularly exceeds 300K/month (with add-ons) - You need 50+ hours of sandbox time per month - You're managing 250+ connections - You need 180-day activity retention **Scale ($299/mo) includes**: 500K actions, 50hr sandbox, 100 GB storage, 1M KV entries, 1,000 connections, 100 members. ### Is annual billing available? Yes. Annual billing saves ~17% compared to monthly: | Plan | Monthly | Annual (per month) | Savings | |---|---|---|---| | Pro | $29 | ~$24 ($290/yr) | 17% | | Team | $129 | ~$107 ($1,290/yr) | 17% | | Scale | $299 | ~$249 ($2,990/yr) | 17% | ## Downgrading ### What happens to purchased add-ons if I downgrade my plan? Add-ons you've already purchased remain active through your current billing period. However, tier-restricted add-ons cannot be re-purchased on a lower-tier plan. **How it works:** - ✅ **Current period** — All purchased add-ons continue working until the period ends. You won't lose any quota you've already paid for. - ✅ **Next period** — Your plan downgrades and included limits adjust to the new tier. Previously purchased add-on quota does not carry over (add-ons never roll over). - ❌ **Re-purchasing** — If the add-on requires a higher tier than your new plan, you won't be able to buy it again. For example, Sandbox packs require Team or above. **Example:** You're on **Team ($129/mo)** with a +50hr sandbox pack ($50). You downgrade to **Pro ($29/mo)**: 1. ✅ Your 50hr sandbox add-on works for the rest of the current billing period 2. ✅ Pro's included 2hr sandbox limit applies next period 3. ❌ You cannot purchase new sandbox packs on Pro (Team+ only) 4. ✅ You *can* still purchase action packs on Pro > **Tip:** If you rely on sandbox, storage, or KV add-ons, staying on Team is usually more cost-effective than downgrading and losing access to those packs. --- ## API Reference ### Authentication > Authenticate with the Weavz API using API keys. Source: https://weavz.io/docs/api-reference/authentication # Authentication All API requests require authentication via an API key passed as a Bearer token in the `Authorization` header. ## API Key Authentication Include your API key in every request: ```bash curl https://api.weavz.io/api/v1/workspaces \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { workspaces } = await client.workspaces.list() ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.workspaces.list() ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspaces', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/workspaces", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` API keys are scoped to an organization. All resources accessed through the key belong to that organization. ### Org-Wide vs Workspace-Scoped Keys By default, API keys have **org-wide** access — they can read and modify all resources across the organization. For least-privilege access, you can create **workspace-scoped** keys that are restricted to specific workspaces. Workspace-scoped keys can only interact with resources (connections, MCP servers, triggers, actions) belonging to their allowed workspaces. Requests that target resources outside the permitted workspaces return a `403` error with code `SCOPE_DENIED`. Org-level administration endpoints (managing API keys, org settings, billing) also require org-wide keys. See [API Keys](/docs/api-reference/api-keys) for details on the `permissions` field. ### Key Format API keys are prefixed with `wvz_` for easy identification. When you create a key, the full key value is returned **only once** — store it securely. ### Creating API Keys Create keys via the [dashboard](https://platform.weavz.io) under **Settings > API Keys**, or programmatically through the [API Keys endpoint](/docs/api-reference/api-keys). ```bash curl -X POST https://api.weavz.io/api/v1/api-keys \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"name": "Production Key"}' ``` ```typescript const { apiKey, plainKey } = await client.apiKeys.create({ name: 'Production Key', }) ``` ```python result = client.api_keys.create(name="Production Key") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/api-keys', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Production Key' }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/api-keys", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"name": "Production Key"}, ) data = res.json() ``` The response includes a `plainKey` field with the full key — this is the only time it will be visible. ## Rate Limiting API requests are rate-limited based on your organization's plan tier. Rate limit information is included in every response: | Header | Description | |--------|-------------| | `X-RateLimit-Limit` | Maximum requests allowed per window | | `X-RateLimit-Remaining` | Requests remaining in the current window | | `X-RateLimit-Reset` | Unix timestamp when the window resets | When you exceed the rate limit, the API returns a `429 Too Many Requests` response. ```json { "error": "Rate limit exceeded", "code": "RATE_LIMIT_EXCEEDED" } ``` ## Error Responses All errors follow a consistent format: ```json { "error": "Human-readable error message", "code": "ERROR_CODE", "details": {} } ``` ### Common Error Codes | Status | Code | Description | |--------|------|-------------| | `401` | `UNAUTHENTICATED` | Missing or invalid API key | | `403` | `FORBIDDEN` | Key lacks permission for this action | | `403` | `SCOPE_DENIED` | Workspace-scoped key cannot access this resource | | `403` | `QUOTA_EXCEEDED` | Organization quota limit reached | | `429` | `RATE_LIMIT_EXCEEDED` | Too many requests | ## MCP Server Tokens MCP servers use separate bearer tokens (prefixed with `mcp_`) for MCP protocol connections. These tokens are generated when you create an MCP server and can be regenerated at any time. See the [MCP Servers](/docs/api-reference/mcp-servers) documentation for details. ## Base URL All API endpoints use the following base URL: ``` https://api.weavz.io ``` For enterprise on-premise deployments, [contact sales](/contact) for your dedicated URL. ### Workspaces > Create and manage workspaces within your organization. Source: https://weavz.io/docs/api-reference/workspaces # Workspaces Workspaces provide logical grouping for connections, triggers, and other resources within an organization. Use workspaces to separate environments (staging, production) or teams. ## List Workspaces List all workspaces in your organization. **Response** ```json { "workspaces": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "orgId": "550e8400-e29b-41d4-a716-446655440000", "name": "Production", "slug": "production", "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } ], "total": 1 } ``` **Example** ```bash curl https://api.weavz.io/api/v1/workspaces \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { workspaces } = await client.workspaces.list() ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.workspaces.list() workspaces = result["workspaces"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspaces', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/workspaces", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` ## Create Workspace Create a new workspace. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | Yes | Workspace name | | `slug` | string | Yes | URL-friendly slug (unique within org) | **Response** (201) ```json { "workspace": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "orgId": "550e8400-e29b-41d4-a716-446655440000", "name": "Production", "slug": "production", "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/workspaces \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"name": "Production", "slug": "production"}' ``` ```typescript const { workspace } = await client.workspaces.create({ name: 'Production', slug: 'production', }) ``` ```python result = client.workspaces.create(name="Production", slug="production") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspaces', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Production', slug: 'production' }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/workspaces", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"name": "Production", "slug": "production"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Invalid or missing name/slug | | `403` | `QUOTA_EXCEEDED` | Workspace limit reached for your plan | | `409` | `DUPLICATE` | Workspace slug already exists | ## Get Workspace Retrieve a specific workspace. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | Workspace ID | **Response** ```json { "workspace": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "orgId": "550e8400-e29b-41d4-a716-446655440000", "name": "Production", "slug": "production", "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } } ``` **Example** ```bash curl https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { workspace } = await client.workspaces.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890') ``` ```python result = client.workspaces.get("a1b2c3d4-e5f6-7890-abcd-ef1234567890") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.get( "https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Workspace not found | ## Delete Workspace Delete a workspace and all associated resources. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | Workspace ID | **Response** ```json { "deleted": true, "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" } ``` **Example** ```bash curl -X DELETE https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript await client.workspaces.delete('a1b2c3d4-e5f6-7890-abcd-ef1234567890') ``` ```python client.workspaces.delete("a1b2c3d4-e5f6-7890-abcd-ef1234567890") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.delete( "https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Workspace not found | ### Connections > Manage integration connections and credentials. Source: https://weavz.io/docs/api-reference/connections # Connections Connections store authentication credentials for third-party integrations. Each connection is tied to a specific integration (e.g., Slack, Gmail) and can be scoped to an organization, workspace, or individual user. ## List Connections List all connections in your organization, or fetch a single connection by ID. **Query Parameters** | Field | Type | Required | Description | |-------|------|----------|-------------| | `id` | string (uuid) | No | Fetch a specific connection by ID | **Response** (list) ```json { "connections": [ { "id": "c1d2e3f4-5678-90ab-cdef-1234567890ab", "externalId": "slack-main", "displayName": "Slack (Main Workspace)", "integrationName": "slack", "type": "PLATFORM_OAUTH2", "status": "ACTIVE", "scope": "ORGANIZATION", "workspaceId": null, "endUserId": null, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } ], "total": 1 } ``` **Response** (single, with `?id=...`) ```json { "connection": { "id": "c1d2e3f4-5678-90ab-cdef-1234567890ab", "externalId": "slack-main", "displayName": "Slack (Main Workspace)", "integrationName": "slack", "type": "PLATFORM_OAUTH2", "status": "ACTIVE", "scope": "ORGANIZATION", "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } } ``` **Example** ```bash curl https://api.weavz.io/api/v1/connections \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { connections } = await client.connections.list() ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.connections.list() connections = result["connections"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/connections", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` ## Create Connection Create a new connection with stored credentials. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `type` | string | Yes | One of: `SECRET_TEXT`, `BASIC_AUTH`, `CUSTOM_AUTH`, `OAUTH2`, `PLATFORM_OAUTH2` | | `externalId` | string | Yes | Unique external identifier for this connection | | `displayName` | string | Yes | Human-readable name | | `integrationName` | string | Yes | Integration name (e.g., `slack`, `gmail`) | | `workspaceId` | string (uuid) | No | Associate with a workspace | | `endUserId` | string | No | Your end-user's identifier for per-user connection resolution | | `scope` | string | No | `ORGANIZATION`, `WORKSPACE`, or `USER` | **Type-Specific Fields** For `SECRET_TEXT`: | Field | Type | Required | Description | |-------|------|----------|-------------| | `secretText` | string | Yes | The secret value (API key, token, etc.) | For `BASIC_AUTH`: | Field | Type | Required | Description | |-------|------|----------|-------------| | `username` | string | Yes | Username | | `password` | string | Yes | Password | For `CUSTOM_AUTH`: | Field | Type | Required | Description | |-------|------|----------|-------------| | `props` | object | Yes | Custom authentication properties | For `OAUTH2` / `PLATFORM_OAUTH2`: | Field | Type | Required | Description | |-------|------|----------|-------------| | `accessToken` | string | Yes | OAuth access token | | `refreshToken` | string | No | OAuth refresh token | | `tokenType` | string | No | Token type (e.g., `Bearer`) | | `expiresIn` | integer | No | Token expiry in seconds | | `scope_oauth` | string | No | OAuth scopes granted | | `data` | object | No | Additional OAuth data | **Response** (201) ```json { "connection": { "id": "c1d2e3f4-5678-90ab-cdef-1234567890ab", "externalId": "openai-prod", "displayName": "OpenAI Production", "integrationName": "openai", "type": "SECRET_TEXT", "status": "ACTIVE", "scope": "ORGANIZATION", "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/connections \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "type": "SECRET_TEXT", "externalId": "openai-prod", "displayName": "OpenAI Production", "integrationName": "openai", "secretText": "sk-..." }' ``` ```typescript const { connection } = await client.connections.create({ type: 'SECRET_TEXT', externalId: 'openai-prod', displayName: 'OpenAI Production', integrationName: 'openai', secretText: 'sk-...', }) ``` ```python result = client.connections.create( type="SECRET_TEXT", external_id="openai-prod", display_name="OpenAI Production", integration_name="openai", secret_text="sk-...", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'SECRET_TEXT', externalId: 'openai-prod', displayName: 'OpenAI Production', integrationName: 'openai', secretText: 'sk-...', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/connections", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "type": "SECRET_TEXT", "externalId": "openai-prod", "displayName": "OpenAI Production", "integrationName": "openai", "secretText": "sk-...", }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing or invalid fields | | `403` | `QUOTA_EXCEEDED` | Connection limit reached | | `409` | `DUPLICATE` | Connection with this `externalId` already exists | ## Delete Connection Delete a connection. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | Connection ID | **Response** ```json { "deleted": true, "id": "c1d2e3f4-5678-90ab-cdef-1234567890ab" } ``` **Example** ```bash curl -X DELETE https://api.weavz.io/api/v1/connections/c1d2e3f4-5678-90ab-cdef-1234567890ab \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript await client.connections.delete('c1d2e3f4-5678-90ab-cdef-1234567890ab') ``` ```python client.connections.delete("c1d2e3f4-5678-90ab-cdef-1234567890ab") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections/c1d2e3f4-5678-90ab-cdef-1234567890ab', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.delete( "https://api.weavz.io/api/v1/connections/c1d2e3f4-5678-90ab-cdef-1234567890ab", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Connection not found | ## Resolve Connection Find a connection by integration name and optional scoping parameters. This is useful when you know the integration and external ID but not the connection's internal UUID. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `integrationName` | string | Yes | Integration name | | `externalId` | string | No | External identifier | | `workspaceId` | string (uuid) | Yes | Workspace scope | | `endUserId` | string | No | Your end-user's identifier for per-user connection resolution | **Response** ```json { "connection": { "id": "c1d2e3f4-5678-90ab-cdef-1234567890ab", "externalId": "slack-main", "displayName": "Slack (Main Workspace)", "integrationName": "slack", "type": "PLATFORM_OAUTH2", "status": "ACTIVE", "scope": "ORGANIZATION", "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/connections/resolve \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "externalId": "slack-main", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }' ``` ```typescript const { connection } = await client.connections.resolve({ integrationName: 'slack', workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', externalId: 'slack-main', }) ``` ```python result = client.connections.resolve( integration_name="slack", workspace_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890", external_id="slack-main", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connections/resolve', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', externalId: 'slack-main', workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/connections/resolve", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "externalId": "slack-main", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing integration name | | `404` | `CONNECTION_NOT_FOUND` | No matching connection found | ### Connect > Create connections via the hosted connect flow for OAuth2 and all other authentication types. Source: https://weavz.io/docs/api-reference/oauth # Connect The Connect endpoints provide a hosted connect flow for creating connections across all authentication types (OAuth2, API keys, custom auth). Weavz hosts the entire authorization process — you create a session token, open the connect page, and retrieve the result. ## Hosted Connect Flow Create a connect session token. Returns a `token` and a `connectUrl` that you open in a popup or redirect to start the authorization flow. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `integrationName` | string | Yes | Integration to connect (e.g., `slack`, `google-sheets`) | | `connectionName` | string | Yes | Display name for the resulting connection | | `externalId` | string | Yes | External identifier for the connection (for multi-tenant scoping) | | `workspaceId` | string (uuid) | Yes | Workspace to create the connection in | | `endUserId` | string | No | End user external ID to associate the connection with | | `scope` | string | No | Connection scope: `ORGANIZATION`, `WORKSPACE`, or `USER` | **Response** ```json { "token": "cst_abc123def456", "connectUrl": "https://api.weavz.io/connect?token=cst_abc123def456", "expiresAt": "2025-01-15T14:30:00.000Z" } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/connect/token \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "google-sheets", "connectionName": "Google Sheets", "externalId": "tenant_123_gsheets", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { token, connectUrl } = await client.connect.createToken({ integrationName: 'google-sheets', connectionName: 'Google Sheets', externalId: 'tenant_123_gsheets', workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.connect.create_token( integration_name="google-sheets", connection_name="Google Sheets", external_id="tenant_123_gsheets", workspace_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connect/token', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'google-sheets', connectionName: 'Google Sheets', externalId: 'tenant_123_gsheets', workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/connect/token", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "google-sheets", "connectionName": "Google Sheets", "externalId": "tenant_123_gsheets", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", }, ) data = res.json() ``` Open the `connectUrl` in a popup window or redirect the user to it. The hosted page handles the full OAuth2 consent flow. **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `NOT_OAUTH2` | Integration does not support OAuth2 | | `400` | `MISSING_OAUTH2_CONFIG` | No OAuth app configured for this integration | | `404` | `INTEGRATION_NOT_FOUND` | Integration not found | Retrieve the status and result of a connect session. Poll this endpoint after the user completes (or closes) the connect page. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `sessionId` | string | The token returned from `POST /api/v1/connect/token` | **Response** ```json { "status": "completed", "connection": { "id": "c1d2e3f4-5678-90ab-cdef-1234567890ab", "externalId": "tenant_123_gsheets", "displayName": "Google Sheets", "integrationName": "google-sheets", "type": "PLATFORM_OAUTH2", "status": "ACTIVE", "scope": "ORGANIZATION", "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } } ``` Session statuses: | Status | Description | |--------|-------------| | `pending` | Connect page not yet opened or user still authorizing | | `completed` | Authorization succeeded, `connection` field contains the new connection | | `failed` | Authorization failed, `error` field contains the error message | **Example** ```bash curl https://api.weavz.io/api/v1/connect/session/cs_abc123def456 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { session } = await client.connect.getSession('cs_abc123def456') ``` ```python result = client.connect.get_session("cs_abc123def456") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/connect/session/cs_abc123def456', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.get( "https://api.weavz.io/api/v1/connect/session/cs_abc123def456", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `SESSION_NOT_FOUND` | Connect session not found or expired | ### Actions > Execute integration actions via the Weavz API. Source: https://weavz.io/docs/api-reference/actions # Actions Actions are operations performed against third-party services through their integrations. For example, sending a Slack message, creating a Google Sheet row, or fetching GitHub issues. ## Execute Action Execute an integration action with the provided input. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `integrationName` | string | Yes | Integration name (e.g., `slack`, `gmail`) | | `actionName` | string | Yes | Action to execute (e.g., `send_channel_message`, `send_email`) | | `input` | object | No | Action input parameters (defaults to `{}`) | | `connectionExternalId` | string | No | External ID of the connection to use | | `workspaceId` | string (uuid) | Yes | Workspace scope for connection resolution | | `endUserId` | string | No | Your end-user's identifier. Used for per-user connection resolution. KV Store and Storage actions use this for `end_user` scope (the default) — set the `scope` input property to control data isolation. | | `partialIds` | string[] | No | Partial IDs to apply. If omitted, default partials auto-resolve. | If `connectionExternalId` is not provided, the system resolves a connection based on the workspace's [integration configuration](/docs/api-reference/workspace-integrations) when a `workspaceId` is supplied. **Response** ```json { "success": true, "output": { "ok": true, "channel": "C0123456789", "ts": "1234567890.123456", "message": { "text": "Hello from Weavz!" } } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "input": { "channel": "C0123456789", "text": "Hello from Weavz!" }, "connectionExternalId": "slack-main", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const result = await client.actions.execute('slack', 'send_channel_message', { workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', input: { channel: 'C0123456789', text: 'Hello from Weavz!', }, connectionExternalId: 'slack-main', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.actions.execute( "slack", "send_channel_message", workspace_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890", input={ "channel": "C0123456789", "text": "Hello from Weavz!", }, connection_external_id="slack-main", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/actions/execute', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', input: { channel: 'C0123456789', text: 'Hello from Weavz!', }, connectionExternalId: 'slack-main', workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', }), }) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/actions/execute", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "input": { "channel": "C0123456789", "text": "Hello from Weavz!", }, "connectionExternalId": "slack-main", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing required fields | | `400` | `ACTION_FAILED` | The action execution failed (error details in response) | | `400` | `CONNECTION_REQUIRED` | Action requires a connection but none was found | | `400` | `CONNECTION_NOT_FOUND` | Specified connection does not exist | | `400` | `INTEGRATION_NOT_FOUND` | Integration not found | | `403` | `QUOTA_EXCEEDED` | Monthly action limit reached | ### Discovering Actions Use the [Integrations API](/docs/api-reference/integrations) to list available actions for each integration, including their input schemas and required properties. ```bash curl "https://api.weavz.io/api/v1/integrations?name=slack" \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { integration } = await client.integrations.get('slack') ``` ```python result = client.integrations.get("slack") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/integrations?name=slack', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/integrations", headers={"Authorization": "Bearer wvz_your_api_key"}, params={"name": "slack"}, ) data = res.json() ``` The response includes an `actions` object with all available actions and their input property definitions. ### Triggers > Enable and manage event triggers for integrations. Source: https://weavz.io/docs/api-reference/triggers # Triggers Triggers listen for events from third-party services and deliver them to your callback URL. Weavz supports three trigger types: **webhook** (real-time push), **polling** (periodic checks), and **app-webhook** (platform-managed webhooks). ## List Triggers List all active trigger sources in your organization. **Response** ```json { "triggers": [ { "id": "t1a2b3c4-d5e6-7890-abcd-ef1234567890", "orgId": "550e8400-e29b-41d4-a716-446655440000", "triggerType": "WEBHOOK", "integrationName": "github", "triggerName": "new_push", "webhookUrl": "https://api.weavz.io/api/v1/webhooks/github/abc123", "callbackUrl": "https://your-app.com/webhooks/github-push", "simulate": false, "createdAt": "2025-01-15T10:30:00.000Z" } ], "total": 1 } ``` **Example** ```bash curl https://api.weavz.io/api/v1/triggers \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { triggers } = await client.triggers.list() ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.triggers.list() triggers = result["triggers"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/triggers", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` ## Enable Trigger Enable a trigger to start receiving events. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `integrationName` | string | Yes | Integration name (e.g., `github`, `slack`) | | `triggerName` | string | Yes | Trigger name (e.g., `new_push`, `new_message`) | | `callbackUrl` | string (uri) | Yes | URL to receive trigger events | | `callbackHeaders` | object | No | Custom headers to include with callback requests | | `callbackMetadata` | object | No | Metadata passed through with each callback | | `connectionExternalId` | string | No | External ID of the connection to use | | `workspaceId` | string (uuid) | Yes | Workspace scope for connection resolution and partials | | `endUserId` | string | No | Your end-user's identifier for per-user connection resolution | | `partialIds` | string[] | No | Partial IDs to apply. If omitted, default partials auto-resolve. | | `pollingIntervalMinutes` | number | No | Polling interval in minutes (1-1440). Only applies to polling triggers. Minimum interval depends on your plan. | | `simulate` | boolean | No | Enable simulation mode for testing | **Response** (201) ```json { "triggerSource": { "id": "t1a2b3c4-d5e6-7890-abcd-ef1234567890", "orgId": "550e8400-e29b-41d4-a716-446655440000", "triggerType": "WEBHOOK", "integrationName": "github", "triggerName": "new_push", "webhookUrl": "https://api.weavz.io/api/v1/webhooks/github/abc123", "callbackUrl": "https://your-app.com/webhooks/github-push", "simulate": false, "createdAt": "2025-01-15T10:30:00.000Z" } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/triggers/enable \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "github", "triggerName": "new_push", "callbackUrl": "https://your-app.com/webhooks/github-push", "connectionExternalId": "github-main", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }' ``` ```typescript const { triggerSource } = await client.triggers.enable({ integrationName: 'github', triggerName: 'new_push', callbackUrl: 'https://your-app.com/webhooks/github-push', connectionExternalId: 'github-main', workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', }) ``` ```python result = client.triggers.enable( integration_name="github", trigger_name="new_push", callback_url="https://your-app.com/webhooks/github-push", connection_external_id="github-main", workspace_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers/enable', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'github', triggerName: 'new_push', callbackUrl: 'https://your-app.com/webhooks/github-push', connectionExternalId: 'github-main', workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/triggers/enable", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "github", "triggerName": "new_push", "callbackUrl": "https://your-app.com/webhooks/github-push", "connectionExternalId": "github-main", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", }, ) data = res.json() ``` For **webhook** triggers, the response includes a `webhookUrl` that you need to register in the third-party service. For **polling** triggers, Weavz automatically checks for new data at regular intervals. **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing required fields | | `403` | `POLLING_INTERVAL_TOO_SHORT` | Polling interval below plan minimum | | `404` | `TRIGGER_NOT_FOUND` | Trigger not found on the integration | ## Disable Trigger Disable an active trigger and stop receiving events. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `triggerSourceId` | string (uuid) | Yes | ID of the trigger source to disable | **Response** ```json { "disabled": true, "triggerSourceId": "t1a2b3c4-d5e6-7890-abcd-ef1234567890" } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/triggers/disable \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"triggerSourceId": "t1a2b3c4-d5e6-7890-abcd-ef1234567890"}' ``` ```typescript await client.triggers.disable('t1a2b3c4-d5e6-7890-abcd-ef1234567890') ``` ```python client.triggers.disable("t1a2b3c4-d5e6-7890-abcd-ef1234567890") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers/disable', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ triggerSourceId: 't1a2b3c4-d5e6-7890-abcd-ef1234567890', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/triggers/disable", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"triggerSourceId": "t1a2b3c4-d5e6-7890-abcd-ef1234567890"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `MISSING_ID` | Missing trigger source ID | | `404` | `NOT_FOUND` | Trigger source not found | ## Test Trigger Get sample data for a trigger to understand its event payload format. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `integrationName` | string | Yes | Integration name | | `triggerName` | string | Yes | Trigger name | **Response** ```json { "sampleData": { "ref": "refs/heads/main", "repository": { "full_name": "owner/repo" }, "commits": [ { "id": "abc123", "message": "Update README" } ] } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/triggers/test \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"integrationName": "github", "triggerName": "new_push"}' ``` ```typescript const { sampleData } = await client.triggers.test('github', 'new_push') ``` ```python result = client.triggers.test("github", "new_push") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/triggers/test', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'github', triggerName: 'new_push', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/triggers/test", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"integrationName": "github", "triggerName": "new_push"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `MISSING_FIELDS` | Missing required fields | | `404` | `INTEGRATION_NOT_FOUND` | Integration not found | | `404` | `TRIGGER_NOT_FOUND` | Trigger not found | ### MCP Servers > Create and manage Model Context Protocol (MCP) servers. Source: https://weavz.io/docs/api-reference/mcp-servers # MCP Servers MCP servers expose integration actions as tools for AI agents via the [Model Context Protocol](https://modelcontextprotocol.io). Each server has its own bearer token and endpoint URL that can be used with any MCP-compatible client. Servers operate in two modes: - **TOOLS** — each integration action is exposed as an individual tool - **CODE** — meta-tools let AI agents write code to orchestrate multiple actions ## List MCP Servers List all MCP servers in your organization. **Response** ```json { "servers": [ { "id": "abc123def456", "orgId": "550e8400-e29b-41d4-a716-446655440000", "name": "Sales Tools", "description": "CRM and email integrations", "mode": "TOOLS", "endUserId": null, "createdBy": "user123", "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z", "mcpEndpoint": "https://api.weavz.io/mcp/srv_abc123def456" } ], "total": 1 } ``` **Example** ```bash curl https://api.weavz.io/api/v1/mcp/servers \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { servers } = await client.mcpServers.list() ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.mcp_servers.list() servers = result["servers"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/mcp/servers", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` ## Create MCP Server Create a new MCP server. The response includes a `bearerToken` that MCP clients use to authenticate — this is only shown once. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | Yes | Server name | | `description` | string | No | Server description | | `workspaceId` | string (uuid) | Yes | Associate with a workspace | | `mode` | string | No | Server mode: `TOOLS` or `CODE` (default: `TOOLS`) | | `endUserId` | string | No | Scope the server to an [end user](/docs/concepts/end-users). Connections resolve to this user's accounts. | **Response** (201) ```json { "server": { "id": "abc123def456", "orgId": "550e8400-e29b-41d4-a716-446655440000", "name": "Sales Tools", "description": "CRM and email integrations", "mode": "TOOLS", "endUserId": null, "createdBy": "user123", "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z", "mcpEndpoint": "https://api.weavz.io/mcp/srv_abc123def456" }, "bearerToken": "mcp_abc123...", "mcpEndpoint": "https://api.weavz.io/mcp/srv_abc123def456" } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Sales Tools", "description": "CRM and email integrations", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "mode": "TOOLS" }' ``` ```typescript const { server, bearerToken, mcpEndpoint } = await client.mcpServers.create({ name: 'Sales Tools', description: 'CRM and email integrations', workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', mode: 'TOOLS', }) ``` ```python result = client.mcp_servers.create( name="Sales Tools", description="CRM and email integrations", workspace_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890", mode="TOOLS", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Sales Tools', description: 'CRM and email integrations', workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', mode: 'TOOLS', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "name": "Sales Tools", "description": "CRM and email integrations", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "mode": "TOOLS", }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing server name | | `403` | `QUOTA_EXCEEDED` | MCP server limit reached | ## Get MCP Server Get server details including its configured tools. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string | Server ID | **Response** ```json { "server": { "id": "abc123def456", "orgId": "550e8400-e29b-41d4-a716-446655440000", "name": "Sales Tools", "mode": "TOOLS", "endUserId": null, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z", "mcpEndpoint": "https://api.weavz.io/mcp/srv_abc123def456" }, "tools": [ { "id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "mcpServerId": "abc123def456", "integrationName": "slack", "integrationAlias": "slack", "actionName": "send_channel_message", "toolType": "ACTION", "connectionId": "c1d2e3f4-5678-90ab-cdef-1234567890ab", "displayName": null, "description": null, "inputDefaults": null, "sortOrder": 0 } ] } ``` **Example** ```bash curl https://api.weavz.io/api/v1/mcp/servers/abc123def456 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { server, tools } = await client.mcpServers.get('abc123def456') ``` ```python result = client.mcp_servers.get("abc123def456") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/abc123def456', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.get( "https://api.weavz.io/api/v1/mcp/servers/abc123def456", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | MCP server not found | ## Update MCP Server Update server properties. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string | Server ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | No | Server name | | `description` | string | No | Server description | | `mode` | string | No | `TOOLS` or `CODE` | | `endUserId` | string \| null | No | Scope to an end user, or `null` to remove | **Response** ```json { "server": { "id": "abc123def456", "name": "Updated Name", "mode": "CODE", "updatedAt": "2025-01-16T14:00:00.000Z" } } ``` **Example** ```bash curl -X PATCH https://api.weavz.io/api/v1/mcp/servers/abc123def456 \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"name": "Updated Name", "mode": "CODE"}' ``` ```typescript const { server } = await client.mcpServers.update('abc123def456', { name: 'Updated Name', mode: 'CODE', }) ``` ```python result = client.mcp_servers.update("abc123def456", name="Updated Name", mode="CODE") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/abc123def456', { method: 'PATCH', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Updated Name', mode: 'CODE' }), }) const data = await res.json() ``` ```python res = httpx.patch( "https://api.weavz.io/api/v1/mcp/servers/abc123def456", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"name": "Updated Name", "mode": "CODE"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | MCP server not found | ## Delete MCP Server Delete an MCP server and all its tools. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string | Server ID | **Response** ```json { "deleted": true, "id": "abc123def456" } ``` **Example** ```bash curl -X DELETE https://api.weavz.io/api/v1/mcp/servers/abc123def456 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript await client.mcpServers.delete('abc123def456') ``` ```python client.mcp_servers.delete("abc123def456") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/abc123def456', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.delete( "https://api.weavz.io/api/v1/mcp/servers/abc123def456", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | MCP server not found | ## Regenerate Token Regenerate the MCP bearer token. The old token is immediately invalidated. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string | Server ID | **Response** ```json { "bearerToken": "mcp_new_token_here...", "mcpEndpoint": "https://api.weavz.io/mcp/srv_abc123def456" } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers/abc123def456/regenerate-token \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { bearerToken, mcpEndpoint } = await client.mcpServers.regenerateToken('abc123def456') ``` ```python result = client.mcp_servers.regenerate_token("abc123def456") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/abc123def456/regenerate-token', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers/abc123def456/regenerate-token", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | MCP server not found | ## Add Tool Add an integration action as a tool to the server. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string | Server ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `integrationName` | string | Yes | Integration name | | `actionName` | string | Yes | Action name | | `integrationAlias` | string | No | Alias for the integration (defaults to `integrationName`). Must match `^[a-z][a-z0-9_-]*$`, max 64 chars | | `toolType` | string | No | `ACTION` or `TRIGGER` (default: `ACTION`) | | `connectionId` | string (uuid) | No | Connection to use for this tool | | `displayName` | string | No | Custom display name | | `description` | string | No | Custom description | | `inputDefaults` | object | No | Default input values | | `partialIds` | string[] | No | Partial IDs to apply to this tool | | `sortOrder` | number | No | Sort position (default: 0) | Integration aliases allow the same integration to appear multiple times on a server under different names (e.g., `slack_bot` and `slack_user`), each with its own connection. **Response** (201) ```json { "tool": { "id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "mcpServerId": "abc123def456", "integrationName": "slack", "integrationAlias": "slack_bot", "actionName": "send_channel_message", "toolType": "ACTION", "connectionId": "c1d2e3f4-5678-90ab-cdef-1234567890ab", "sortOrder": 0 } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers/abc123def456/tools \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "integrationAlias": "slack_bot", "connectionId": "c1d2e3f4-5678-90ab-cdef-1234567890ab" }' ``` ```typescript const { tool } = await client.mcpServers.addTool('abc123def456', { integrationName: 'slack', actionName: 'send_channel_message', integrationAlias: 'slack_bot', connectionId: 'c1d2e3f4-5678-90ab-cdef-1234567890ab', }) ``` ```python result = client.mcp_servers.add_tool( "abc123def456", integration_name="slack", action_name="send_channel_message", integration_alias="slack_bot", connection_id="c1d2e3f4-5678-90ab-cdef-1234567890ab", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/abc123def456/tools', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', actionName: 'send_channel_message', integrationAlias: 'slack_bot', connectionId: 'c1d2e3f4-5678-90ab-cdef-1234567890ab', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers/abc123def456/tools", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "actionName": "send_channel_message", "integrationAlias": "slack_bot", "connectionId": "c1d2e3f4-5678-90ab-cdef-1234567890ab", }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing required fields or invalid alias format | | `404` | `NOT_FOUND` | MCP server not found | | `409` | `DUPLICATE` | Tool already exists on this server | | `409` | `ALIAS_CONFLICT` | Alias is already mapped to a different integration | ## Update Tool Update a tool's configuration. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string | Server ID | | `toolId` | string (uuid) | Tool ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `displayName` | string | No | Custom display name | | `description` | string | No | Custom description | | `inputDefaults` | object | No | Default input values | | `connectionId` | string (uuid) | No | Connection to use | | `sortOrder` | number | No | Sort position | | `integrationAlias` | string | No | Updated alias | **Response** ```json { "tool": { "id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", "integrationAlias": "slack_bot", "displayName": "Send Bot Message", "sortOrder": 1 } } ``` **Example** ```bash curl -X PATCH https://api.weavz.io/api/v1/mcp/servers/abc123def456/tools/f1e2d3c4-b5a6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"displayName": "Send Bot Message", "sortOrder": 1}' ``` ```typescript const { tool } = await client.mcpServers.updateTool('abc123def456', 'f1e2d3c4-b5a6-7890-abcd-ef1234567890', { displayName: 'Send Bot Message', sortOrder: 1, }) ``` ```python result = client.mcp_servers.update_tool( "abc123def456", "f1e2d3c4-b5a6-7890-abcd-ef1234567890", display_name="Send Bot Message", sort_order=1, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/abc123def456/tools/f1e2d3c4-b5a6-7890-abcd-ef1234567890', { method: 'PATCH', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ displayName: 'Send Bot Message', sortOrder: 1 }), }) const data = await res.json() ``` ```python res = httpx.patch( "https://api.weavz.io/api/v1/mcp/servers/abc123def456/tools/f1e2d3c4-b5a6-7890-abcd-ef1234567890", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"displayName": "Send Bot Message", "sortOrder": 1}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Invalid fields | | `404` | `NOT_FOUND` | Server or tool not found | ## Remove Tool Remove a tool from the server. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string | Server ID | | `toolId` | string (uuid) | Tool ID | **Response** ```json { "deleted": true, "id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890" } ``` **Example** ```bash curl -X DELETE https://api.weavz.io/api/v1/mcp/servers/abc123def456/tools/f1e2d3c4-b5a6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript await client.mcpServers.deleteTool('abc123def456', 'f1e2d3c4-b5a6-7890-abcd-ef1234567890') ``` ```python client.mcp_servers.delete_tool("abc123def456", "f1e2d3c4-b5a6-7890-abcd-ef1234567890") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/abc123def456/tools/f1e2d3c4-b5a6-7890-abcd-ef1234567890', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.delete( "https://api.weavz.io/api/v1/mcp/servers/abc123def456/tools/f1e2d3c4-b5a6-7890-abcd-ef1234567890", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Server or tool not found | ## Execute Code Execute code against a CODE mode server. Used for testing code-mode integrations. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string | Server ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `code` | string | Yes | JavaScript code to execute | **Response** ```json { "content": [ { "type": "text", "text": "Execution result..." } ], "isError": false } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/mcp/servers/abc123def456/execute-code \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"code": "const result = await weavz.slack.send_channel_message({ channel: \"C123\", text: \"Hello\" }); return result;"}' ``` ```typescript const { content, isError } = await client.mcpServers.executeCode( 'abc123def456', 'const result = await weavz.slack.send_channel_message({ channel: "C123", text: "Hello" }); return result;', ) ``` ```python result = client.mcp_servers.execute_code( "abc123def456", 'const result = await weavz.slack.send_channel_message({ channel: "C123", text: "Hello" }); return result;', ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/abc123def456/execute-code', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ code: 'const result = await weavz.slack.send_channel_message({ channel: "C123", text: "Hello" }); return result;', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/mcp/servers/abc123def456/execute-code", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "code": 'const result = await weavz.slack.send_channel_message({ channel: "C123", text: "Hello" }); return result;', }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing code | | `403` | `QUOTA_EXCEEDED` | Sandbox quota exceeded | | `404` | `NOT_FOUND` | MCP server not found | ## Get TypeScript Declarations Get TypeScript declarations for an integration on a CODE mode server. Returns type definitions for the `weavz.*` API surface. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string | Server ID | | `integrationOrAlias` | string | Integration name or alias | **Response** ```json { "declarations": "declare namespace weavz {\n namespace slack {\n function send_channel_message(input: { channel: string; text: string }): Promise;\n }\n}" } ``` **Example** ```bash curl https://api.weavz.io/api/v1/mcp/servers/abc123def456/declarations/slack \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { declarations } = await client.mcpServers.getDeclarations('abc123def456', 'slack') ``` ```python result = client.mcp_servers.get_declarations("abc123def456", "slack") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/mcp/servers/abc123def456/declarations/slack', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.get( "https://api.weavz.io/api/v1/mcp/servers/abc123def456/declarations/slack", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Server or integration not found | ### Integrations > List available integrations and resolve dynamic properties. Source: https://weavz.io/docs/api-reference/integrations # Integrations The Integrations API lets you discover available integrations, view their actions and triggers, and resolve dynamic input values that depend on a live connection. ## List Integrations List all available integrations, or fetch a specific one by name. This endpoint does not require authentication. **Query Parameters** | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | No | Fetch a specific integration by name | **Response** (list) ```json { "integrations": [ { "name": "slack", "displayName": "Slack", "description": "Send messages and manage channels", "logoUrl": "data:image/svg+xml;base64,...", "categories": ["communication"], "auth": { "type": ["OAUTH2"], "oauth2": { "authUrl": "https://slack.com/oauth/v2/authorize" } }, "actions": { "send_channel_message": { "name": "send_channel_message", "displayName": "Send Channel Message", "description": "Send a message to a Slack channel", "props": {} } }, "triggers": {} } ], "total": 34, "registered": ["slack", "gmail", "github"] } ``` The `registered` array lists integration names that have at least one connection or MCP server tool configured in your organization. **Response** (single, with `?name=slack`) ```json { "integration": { "name": "slack", "displayName": "Slack", "description": "Send messages and manage channels", "logoUrl": "data:image/svg+xml;base64,...", "categories": ["communication"], "auth": { "type": ["OAUTH2"] }, "actions": { "send_channel_message": { ... } }, "triggers": {} } } ``` **Example** ```bash curl https://api.weavz.io/api/v1/integrations ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { integrations } = await client.integrations.list() ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.integrations.list() integrations = result["integrations"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/integrations') const data = await res.json() ``` ```python import httpx res = httpx.get("https://api.weavz.io/api/v1/integrations") data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `INTEGRATION_NOT_FOUND` | Integration with the given name not found | ## Resolve Input Options Resolve available options for select inputs in an action or trigger. This fetches available values from the connected service (e.g., list of Slack channels, Google Sheets spreadsheets). **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `integrationName` | string | Integration name | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `propertyName` | string | Yes | Property to resolve options for | | `actionName` | string | No | Action containing the property | | `triggerName` | string | No | Trigger containing the property | | `connectionExternalId` | string | No | Connection for authenticated requests | | `workspaceId` | string (uuid) | No | Workspace scope | | `endUserId` | string | No | Your end-user's identifier for per-user connection resolution | | `input` | object | No | Current form values (for inputs that depend on other field values) | | `searchValue` | string | No | Filter options by search text | Provide either `actionName` or `triggerName`, not both. **Response** ```json { "options": [ { "label": "#general", "value": "C0123456789" }, { "label": "#engineering", "value": "C9876543210" } ], "disabled": false } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/integrations/slack/properties/options \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "propertyName": "channel", "actionName": "send_channel_message", "connectionExternalId": "slack-main" }' ``` ```typescript const { options } = await client.integrations.resolveOptions('slack', { propertyName: 'channel', actionName: 'send_channel_message', connectionExternalId: 'slack-main', }) ``` ```python result = client.integrations.resolve_options( "slack", property_name="channel", action_name="send_channel_message", connection_external_id="slack-main", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/integrations/slack/properties/options', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ propertyName: 'channel', actionName: 'send_channel_message', connectionExternalId: 'slack-main', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/integrations/slack/properties/options", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "propertyName": "channel", "actionName": "send_channel_message", "connectionExternalId": "slack-main", }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `NOT_DROPDOWN` | Property does not support value resolution | | `400` | `NO_OPTIONS_FN` | No values available to resolve | | `400` | `OPTIONS_FAILED` | Options function threw an error | | `404` | `INTEGRATION_NOT_FOUND` | Integration not found | ## Resolve Dynamic Properties Resolve a dynamic property schema. Dynamic properties are properties whose schema depends on runtime values (e.g., column fields that change based on a selected spreadsheet). **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `integrationName` | string | Integration name | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `propertyName` | string | Yes | Dynamic property to resolve | | `actionName` | string | No | Action containing the property | | `triggerName` | string | No | Trigger containing the property | | `connectionExternalId` | string | No | Connection for authenticated requests | | `workspaceId` | string (uuid) | No | Workspace scope | | `endUserId` | string | No | Your end-user's identifier for per-user connection resolution | | `input` | object | No | Current form values | **Response** The response is the resolved property schema, which varies per integration: ```json { "column_a": { "type": "SHORT_TEXT", "displayName": "Name", "required": true }, "column_b": { "type": "NUMBER", "displayName": "Amount", "required": false } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/integrations/google-sheets/properties/resolve \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "propertyName": "columns", "actionName": "insert_row", "connectionExternalId": "google-sheets-main", "input": { "spreadsheet_id": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms", "sheet_id": "Sheet1" } }' ``` ```typescript const result = await client.integrations.resolveProperty('google-sheets', { propertyName: 'columns', actionName: 'insert_row', connectionExternalId: 'google-sheets-main', input: { spreadsheet_id: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms', sheet_id: 'Sheet1', }, }) ``` ```python result = client.integrations.resolve_property( "google-sheets", property_name="columns", action_name="insert_row", connection_external_id="google-sheets-main", input={ "spreadsheet_id": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms", "sheet_id": "Sheet1", }, ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/integrations/google-sheets/properties/resolve', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ propertyName: 'columns', actionName: 'insert_row', connectionExternalId: 'google-sheets-main', input: { spreadsheet_id: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms', sheet_id: 'Sheet1', }, }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/integrations/google-sheets/properties/resolve", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "propertyName": "columns", "actionName": "insert_row", "connectionExternalId": "google-sheets-main", "input": { "spreadsheet_id": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms", "sheet_id": "Sheet1", }, }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `NOT_DYNAMIC` | Property is not a dynamic type | | `400` | `NO_PROPS_FN` | Property has no resolve function | | `400` | `RESOLVE_FAILED` | Resolve function threw an error | | `404` | `INTEGRATION_NOT_FOUND` | Integration not found | ## Get OAuth Status Check which integrations have OAuth apps configured (either platform-provided or custom). **Response** ```json { "configured": ["slack", "google-sheets", "github", "gmail", "notion", "discord", "hubspot"] } ``` **Example** ```bash curl https://api.weavz.io/api/v1/integrations/oauth-status \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { configured } = await client.integrations.oauthStatus() ``` ```python result = client.integrations.oauth_status() ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/integrations/oauth-status', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.get( "https://api.weavz.io/api/v1/integrations/oauth-status", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` ### Workspace Integrations > Configure integrations within workspaces, including connection strategies and action subsets. Source: https://weavz.io/docs/api-reference/workspace-integrations # Workspace Integrations Workspace integrations define how an integration is configured within a workspace. Each workspace integration specifies which integration to use, how connections are resolved (the connection strategy), which actions are available, and an optional alias for disambiguation. ## List Workspace Integrations List all integrations configured for a workspace. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `workspaceId` | string (uuid) | Workspace ID | **Response** ```json { "integrations": [ { "id": "pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "orgId": "550e8400-e29b-41d4-a716-446655440000", "integrationName": "slack", "integrationAlias": "slack", "connectionStrategy": "fixed", "connectionId": "c1d2e3f4-5678-90ab-cdef-1234567890ab", "allowedActions": null, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } ], "total": 1 } ``` **Example** ```bash curl https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { integrations } = await client.workspaces.listIntegrations('a1b2c3d4-e5f6-7890-abcd-ef1234567890') ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.workspaces.list_integrations("a1b2c3d4-e5f6-7890-abcd-ef1234567890") integrations = result["integrations"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` ## Create Workspace Integration Add an integration to a workspace with a connection strategy. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `workspaceId` | string (uuid) | Workspace ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `integrationName` | string | Yes | Integration identifier (e.g., `slack`, `github`) | | `integrationAlias` | string | No | Alias for this integration instance (defaults to `integrationName`). Useful when the same integration is configured multiple times with different connections. | | `connectionStrategy` | string | Yes | One of: `fixed`, `per_user`, `per_user_with_fallback` | | `connectionId` | string (uuid) | No | Connection ID. Required for `fixed` and `per_user_with_fallback` strategies. | | `allowedActions` | string[] | No | Restrict to specific actions. `null` or omitted means all actions are available. | **Response** (201) ```json { "integration": { "id": "pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "orgId": "550e8400-e29b-41d4-a716-446655440000", "integrationName": "slack", "integrationAlias": "slack", "connectionStrategy": "fixed", "connectionId": "c1d2e3f4-5678-90ab-cdef-1234567890ab", "allowedActions": null, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "connectionStrategy": "fixed", "connectionId": "c1d2e3f4-5678-90ab-cdef-1234567890ab" }' ``` ```typescript const { integration } = await client.workspaces.addIntegration('a1b2c3d4-e5f6-7890-abcd-ef1234567890', { integrationName: 'slack', connectionStrategy: 'fixed', connectionId: 'c1d2e3f4-5678-90ab-cdef-1234567890ab', }) ``` ```python result = client.workspaces.add_integration( "a1b2c3d4-e5f6-7890-abcd-ef1234567890", integration_name="slack", connection_strategy="fixed", connection_id="c1d2e3f4-5678-90ab-cdef-1234567890ab", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack', connectionStrategy: 'fixed', connectionId: 'c1d2e3f4-5678-90ab-cdef-1234567890ab', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "integrationName": "slack", "connectionStrategy": "fixed", "connectionId": "c1d2e3f4-5678-90ab-cdef-1234567890ab", }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing required fields or invalid strategy | | `409` | `DUPLICATE` | Integration with this alias already exists in the workspace | | `409` | `ALIAS_CONFLICT` | Alias is already associated with a different integration in this workspace | ## Update Workspace Integration Update a workspace integration's connection strategy, connection, or allowed actions. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `workspaceId` | string (uuid) | Workspace ID | | `id` | string (uuid) | Workspace integration ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `connectionStrategy` | string | No | New connection strategy | | `connectionId` | string (uuid) | No | New connection ID | | `allowedActions` | string[] \| null | No | Updated action list, or `null` for all | **Response** ```json { "integration": { "id": "pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "orgId": "550e8400-e29b-41d4-a716-446655440000", "integrationName": "slack", "integrationAlias": "slack", "connectionStrategy": "per_user_with_fallback", "connectionId": "c1d2e3f4-5678-90ab-cdef-1234567890ab", "allowedActions": ["send_channel_message", "list_channels"], "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-16T14:00:00.000Z" } } ``` **Example** ```bash curl -X PATCH https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations/pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "connectionStrategy": "per_user_with_fallback", "allowedActions": ["send_channel_message", "list_channels"] }' ``` ```typescript const { integration } = await client.workspaces.updateIntegration( 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', 'pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890', { connectionStrategy: 'per_user_with_fallback', enabledActions: ['send_channel_message', 'list_channels'], }, ) ``` ```python result = client.workspaces.update_integration( "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890", connection_strategy="per_user_with_fallback", enabled_actions=["send_channel_message", "list_channels"], ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations/pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890', { method: 'PATCH', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ connectionStrategy: 'per_user_with_fallback', allowedActions: ['send_channel_message', 'list_channels'], }), }) const data = await res.json() ``` ```python res = httpx.patch( "https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations/pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "connectionStrategy": "per_user_with_fallback", "allowedActions": ["send_channel_message", "list_channels"], }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `NO_UPDATES` | No fields provided to update | | `404` | `NOT_FOUND` | Workspace integration not found | ## Delete Workspace Integration Remove an integration from a workspace. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `workspaceId` | string (uuid) | Workspace ID | | `id` | string (uuid) | Workspace integration ID | **Response** ```json { "deleted": true, "id": "pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890" } ``` **Example** ```bash curl -X DELETE https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations/pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript await client.workspaces.removeIntegration( 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', 'pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890', ) ``` ```python client.workspaces.remove_integration( "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations/pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.delete( "https://api.weavz.io/api/v1/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/integrations/pi_a1b2c3d4-e5f6-7890-abcd-ef1234567890", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Workspace integration not found | ## Auto-Sync with MCP Servers When you add, update, or remove workspace integrations, any MCP servers linked to the workspace automatically reflect the changes. MCP server tools are kept in sync with the workspace's integration configuration -- there is no manual sync step required. ## Connection Strategies Connection strategies control how Weavz resolves which connection to use when executing actions for a workspace integration. ### fixed A single connection is always used for this integration in this workspace. Every action execution uses the specified connection regardless of who initiated it. **Best for:** Shared service accounts, organization-wide API keys, per-customer connections in multi-tenant setups. **Requires:** `connectionId` ```bash curl -X POST https://api.weavz.io/api/v1/workspaces/{workspaceId}/integrations \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "openai", "connectionStrategy": "fixed", "connectionId": "conn_org_openai" }' ``` ### per_user Each user must provide their own connection. If the user has not connected their account, the action fails with a `CONNECTION_REQUIRED` error. **Best for:** Personal integrations where each end-user needs their own OAuth2 authorization (e.g., personal Gmail, calendar access). ```bash curl -X POST https://api.weavz.io/api/v1/workspaces/{workspaceId}/integrations \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "gmail", "connectionStrategy": "per_user" }' ``` ### per_user_with_fallback Users can provide their own connection, but if they have not connected, a default connection is used as a fallback. **Best for:** Optional personalization. For example, users can connect their own Slack account, but if they have not, the team's shared Slack bot connection is used. **Requires:** `connectionId` (the fallback connection) ```bash curl -X POST https://api.weavz.io/api/v1/workspaces/{workspaceId}/integrations \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "connectionStrategy": "per_user_with_fallback", "connectionId": "conn_slack_default" }' ``` ## Integration Aliases When configuring the same integration multiple times in a workspace (e.g., two Slack connections for different workspaces), use `integrationAlias` to disambiguate: ```bash # Bot workspace curl -X POST https://api.weavz.io/api/v1/workspaces/{workspaceId}/integrations \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "integrationAlias": "slack_bot", "connectionStrategy": "fixed", "connectionId": "conn_slack_bot" }' # User workspace curl -X POST https://api.weavz.io/api/v1/workspaces/{workspaceId}/integrations \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "integrationAlias": "slack_user", "connectionStrategy": "per_user" }' ``` When executing actions, specify the `integrationAlias` to target the correct workspace integration instance: ```bash curl -X POST https://api.weavz.io/api/v1/actions/execute \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "integrationName": "slack", "actionName": "send_channel_message", "integrationAlias": "slack_bot", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "input": { "channel": "#alerts", "text": "Automated alert!" } }' ``` See [Integration Aliases](/docs/guides/integration-aliases) for alias naming rules and MCP server behavior. ### Input Partials > Manage saved parameter presets for actions and triggers. Source: https://weavz.io/docs/api-reference/input-partials # Input Partials Input partials are saved parameter configurations (presets) scoped to a workspace and integration. They store default values and enforced keys that merge into action and trigger inputs at execution time. ## Create Partial Create a new input partial. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `workspaceId` | string (uuid) | Yes | Workspace to scope this partial to | | `integrationName` | string | Yes | Integration name (e.g., `slack`, `github`) | | `actionName` | string | No | Action name. Null means integration-wide (applies to all actions) | | `name` | string | Yes | Display name (max 100 chars) | | `description` | string | No | Description (max 500 chars) | | `values` | object | Yes | Key-value pairs to pre-fill | | `enforcedKeys` | string[] | No | Keys whose values cannot be overridden at runtime | | `isDefault` | boolean | No | Whether this partial auto-applies when no `partialIds` are specified (default: `false`) | **Response** (201) ```json { "partial": { "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab", "orgId": "org_abc123", "workspaceId": "proj_abc123", "integrationName": "slack", "actionName": "send_channel_message", "name": "General Channel Preset", "description": "Always post to #general", "values": { "channel": "C01ABCDEF" }, "enforcedKeys": ["channel"], "isDefault": false, "createdAt": "2025-01-15T10:00:00.000Z", "updatedAt": "2025-01-15T10:00:00.000Z" } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/partials \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "workspaceId": "proj_abc123", "integrationName": "slack", "actionName": "send_channel_message", "name": "General Channel Preset", "values": { "channel": "C01ABCDEF" }, "enforcedKeys": ["channel"] }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { partial } = await client.partials.create({ workspaceId: 'proj_abc123', integrationName: 'slack', actionName: 'send_channel_message', name: 'General Channel Preset', values: { channel: 'C01ABCDEF' }, enforcedKeys: ['channel'], }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.partials.create( workspace_id="proj_abc123", integration_name="slack", action_name="send_channel_message", name="General Channel Preset", values={"channel": "C01ABCDEF"}, enforced_keys=["channel"], ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/partials', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ workspaceId: 'proj_abc123', integrationName: 'slack', actionName: 'send_channel_message', name: 'General Channel Preset', values: { channel: 'C01ABCDEF' }, enforcedKeys: ['channel'], }), }) const { partial } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/partials", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "workspaceId": "proj_abc123", "integrationName": "slack", "actionName": "send_channel_message", "name": "General Channel Preset", "values": {"channel": "C01ABCDEF"}, "enforcedKeys": ["channel"], }, ) partial = res.json()["partial"] ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing required fields or invalid data | | `409` | `DUPLICATE` | A partial with this name already exists in the same scope | ## List Partials List input partials for a workspace, optionally filtered by integration or action. **Query Parameters** | Field | Type | Required | Description | |-------|------|----------|-------------| | `workspaceId` | string (uuid) | Yes | Workspace ID to list partials for | | `integrationName` | string | No | Filter by integration name | | `actionName` | string | No | Filter by action name | **Response** ```json { "partials": [ { "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab", "orgId": "org_abc123", "workspaceId": "proj_abc123", "integrationName": "slack", "actionName": "send_channel_message", "name": "General Channel Preset", "description": null, "values": { "channel": "C01ABCDEF" }, "enforcedKeys": ["channel"], "isDefault": false, "createdAt": "2025-01-15T10:00:00.000Z", "updatedAt": "2025-01-15T10:00:00.000Z" } ], "total": 1 } ``` **Example** ```bash curl "https://api.weavz.io/api/v1/partials?workspaceId=proj_abc123&integrationName=slack" \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { partials } = await client.partials.list({ workspaceId: 'proj_abc123', integrationName: 'slack', }) ``` ```python result = client.partials.list( workspace_id="proj_abc123", integration_name="slack", ) ``` ```typescript const res = await fetch( 'https://api.weavz.io/api/v1/partials?workspaceId=proj_abc123&integrationName=slack', { headers: { 'Authorization': 'Bearer wvz_your_api_key' } }, ) const { partials } = await res.json() ``` ```python res = httpx.get( "https://api.weavz.io/api/v1/partials", headers={"Authorization": "Bearer wvz_your_api_key"}, params={"workspaceId": "proj_abc123", "integrationName": "slack"}, ) partials = res.json()["partials"] ``` ## Get Partial Get a single input partial by ID. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | Partial ID | **Example** ```bash curl https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { partial } = await client.partials.get('a1b2c3d4-5678-90ab-cdef-1234567890ab') ``` ```python result = client.partials.get("a1b2c3d4-5678-90ab-cdef-1234567890ab") ``` ```typescript const res = await fetch( 'https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab', { headers: { 'Authorization': 'Bearer wvz_your_api_key' } }, ) const { partial } = await res.json() ``` ```python res = httpx.get( "https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab", headers={"Authorization": "Bearer wvz_your_api_key"}, ) partial = res.json()["partial"] ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Partial not found | ## Update Partial Update an existing input partial. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | Partial ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | No | New display name | | `description` | string | No | New description | | `values` | object | No | New values (replaces existing) | | `enforcedKeys` | string[] | No | New enforced keys (replaces existing) | | `isDefault` | boolean | No | Set as default partial | **Example** ```bash curl -X PATCH https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "values": { "channel": "C01ABCDEF", "username": "weavz-bot" }, "enforcedKeys": ["channel", "username"] }' ``` ```typescript const { partial } = await client.partials.update('a1b2c3d4-5678-90ab-cdef-1234567890ab', { values: { channel: 'C01ABCDEF', username: 'weavz-bot' }, enforcedKeys: ['channel', 'username'], }) ``` ```python result = client.partials.update( "a1b2c3d4-5678-90ab-cdef-1234567890ab", values={"channel": "C01ABCDEF", "username": "weavz-bot"}, enforced_keys=["channel", "username"], ) ``` ```typescript const res = await fetch( 'https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab', { method: 'PATCH', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ values: { channel: 'C01ABCDEF', username: 'weavz-bot' }, enforcedKeys: ['channel', 'username'], }), }, ) const { partial } = await res.json() ``` ```python res = httpx.patch( "https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "values": {"channel": "C01ABCDEF", "username": "weavz-bot"}, "enforcedKeys": ["channel", "username"], }, ) partial = res.json()["partial"] ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | No updates provided or invalid data | | `404` | `NOT_FOUND` | Partial not found | | `409` | `DUPLICATE` | A partial with this name already exists | ## Delete Partial Delete an input partial. Any MCP server tools referencing this partial in their `partialIds` arrays are automatically cleaned up. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | Partial ID | **Response** ```json { "deleted": true, "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab" } ``` **Example** ```bash curl -X DELETE https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript await client.partials.delete('a1b2c3d4-5678-90ab-cdef-1234567890ab') ``` ```python client.partials.delete("a1b2c3d4-5678-90ab-cdef-1234567890ab") ``` ```typescript await fetch( 'https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }, ) ``` ```python httpx.delete( "https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab", headers={"Authorization": "Bearer wvz_your_api_key"}, ) ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Partial not found | ## Set Default Set or unset a partial as the default for its scope. Default partials auto-apply when no explicit `partialIds` are provided during action execution. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | Partial ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `isDefault` | boolean | Yes | Whether this partial should be the default | **Example** ```bash curl -X POST https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab/set-default \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"isDefault": true}' ``` ```typescript await client.partials.setDefault('a1b2c3d4-5678-90ab-cdef-1234567890ab', true) ``` ```python client.partials.set_default("a1b2c3d4-5678-90ab-cdef-1234567890ab", True) ``` ```typescript await fetch( 'https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab/set-default', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ isDefault: true }), }, ) ``` ```python httpx.post( "https://api.weavz.io/api/v1/partials/a1b2c3d4-5678-90ab-cdef-1234567890ab/set-default", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"isDefault": True}, ) ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Partial not found | ### API Keys > Create and manage API keys for programmatic access. Source: https://weavz.io/docs/api-reference/api-keys # API Keys API keys provide programmatic access to the Weavz API. Keys are scoped to an organization and prefixed with `wvz_`. ## List API Keys List all API keys for your organization. Key values are masked — only the `keyPrefix` (first 8 characters) is shown. **Response** ```json { "apiKeys": [ { "id": "k1a2b3c4-d5e6-7890-abcd-ef1234567890", "orgId": "550e8400-e29b-41d4-a716-446655440000", "name": "Production Key", "keyPrefix": "wvz_ab12", "permissions": null, "lastUsedAt": "2025-01-16T08:00:00.000Z", "expiresAt": null, "createdAt": "2025-01-15T10:30:00.000Z" } ], "total": 1 } ``` **Example** ```bash curl https://api.weavz.io/api/v1/api-keys \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { apiKeys } = await client.apiKeys.list() ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.api_keys.list() api_keys = result["apiKeys"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/api-keys', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/api-keys", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` ## Create API Key Create a new API key. The full key value is returned **only once** in the `plainKey` field — store it securely. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | Yes | Descriptive name for the key | | `expiresAt` | string (date-time) | No | Expiration timestamp (no expiry if omitted) | | `permissions` | object | No | Permission scope (unrestricted if omitted). See below. | **Permissions Object** | Field | Type | Required | Description | |-------|------|----------|-------------| | `scope` | string | Yes | `"org"` for full access, `"workspace"` for workspace-scoped | | `workspaceIds` | string[] | When scope is `"workspace"` | UUIDs of the workspaces this key can access | **Response** (201) ```json { "apiKey": { "id": "k1a2b3c4-d5e6-7890-abcd-ef1234567890", "orgId": "550e8400-e29b-41d4-a716-446655440000", "name": "Production Key", "keyPrefix": "wvz_ab12", "permissions": null, "lastUsedAt": null, "expiresAt": null, "createdAt": "2025-01-15T10:30:00.000Z" }, "plainKey": "wvz_ab12cd34ef56gh78ij90kl12mn34op56" } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/api-keys \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"name": "Production Key"}' ``` ```typescript const { apiKey, plainKey } = await client.apiKeys.create({ name: 'Production Key', }) ``` ```python result = client.api_keys.create(name="Production Key") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/api-keys', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Production Key' }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/api-keys", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"name": "Production Key"}, ) data = res.json() ``` Create a workspace-scoped key: ```bash curl -X POST https://api.weavz.io/api/v1/api-keys \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Workspace-Only Key", "permissions": { "scope": "workspace", "workspaceIds": ["PROJECT_UUID_1", "PROJECT_UUID_2"] } }' ``` ```typescript const { apiKey, plainKey } = await client.apiKeys.create({ name: 'Workspace-Only Key', permissions: { scope: 'workspace', workspaceIds: ['PROJECT_UUID_1', 'PROJECT_UUID_2'], }, }) ``` ```python result = client.api_keys.create( name="Workspace-Only Key", scope="workspace", workspace_ids=["PROJECT_UUID_1", "PROJECT_UUID_2"], ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/api-keys', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Workspace-Only Key', permissions: { scope: 'workspace', workspaceIds: ['PROJECT_UUID_1', 'PROJECT_UUID_2'], }, }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/api-keys", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "name": "Workspace-Only Key", "permissions": { "scope": "workspace", "workspaceIds": ["PROJECT_UUID_1", "PROJECT_UUID_2"], }, }, ) data = res.json() ``` Workspace-scoped keys can only access resources within the specified workspaces. Requests to resources outside the allowed workspaces return `403 SCOPE_DENIED`. **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing key name | | `403` | `QUOTA_EXCEEDED` | API key limit reached for your plan | | `403` | `SCOPE_DENIED` | Workspace-scoped key cannot access this resource | ## Revoke API Key Revoke an API key. The key is immediately invalidated and can no longer be used for authentication. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | API key ID | **Response** ```json { "deleted": true, "id": "k1a2b3c4-d5e6-7890-abcd-ef1234567890" } ``` **Example** ```bash curl -X DELETE https://api.weavz.io/api/v1/api-keys/k1a2b3c4-d5e6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript await client.apiKeys.delete('k1a2b3c4-d5e6-7890-abcd-ef1234567890') ``` ```python client.api_keys.delete("k1a2b3c4-d5e6-7890-abcd-ef1234567890") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/api-keys/k1a2b3c4-d5e6-7890-abcd-ef1234567890', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.delete( "https://api.weavz.io/api/v1/api-keys/k1a2b3c4-d5e6-7890-abcd-ef1234567890", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | API key not found | ### Members > Manage organization members and invitations. Source: https://weavz.io/docs/api-reference/members # Members Manage who has access to your organization and individual workspaces. Invite new members by email, manage roles, and control workspace-level access. ## Organization Members List all members of your organization. **Response** ```json { "members": [ { "id": "m1a2b3c4-d5e6-7890-abcd-ef1234567890", "organizationId": "550e8400-e29b-41d4-a716-446655440000", "userId": "user123", "role": "owner", "userName": "Jane Smith", "userEmail": "jane@example.com", "userImage": null, "createdAt": "2025-01-15T10:30:00.000Z" } ], "total": 1 } ``` **Example** ```bash curl https://api.weavz.io/api/v1/members \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { members } = await client.members.list() ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.members.list() members = result["members"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/members', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/members", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` --- ## Invitations Invite a new member to your organization by email. The invited user will receive an email with a link to accept the invitation. Invitations expire after 7 days. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `email` | string | Yes | Email address to invite | | `role` | string | No | `admin` or `member` (default: `member`) | **Response** ```json { "invitation": { "id": "inv-abc123", "email": "john@example.com", "organizationId": "550e8400-e29b-41d4-a716-446655440000", "role": "member", "status": "pending", "expiresAt": "2025-01-23T14:00:00.000Z", "createdAt": "2025-01-16T14:00:00.000Z" } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/members/invite \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"email": "john@example.com", "role": "admin"}' ``` ```typescript const { invitation } = await client.invitations.send({ email: 'john@example.com', role: 'admin', }) ``` ```python result = client.invitations.send(email="john@example.com", role="admin") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/members/invite', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ email: 'john@example.com', role: 'admin' }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/members/invite", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"email": "john@example.com", "role": "admin"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Invalid email address | | `403` | `QUOTA_EXCEEDED` | Member limit reached for your plan | | `409` | `DUPLICATE` | User is already a member or has a pending invitation | List all pending invitations for your organization. **Response** ```json { "invitations": [ { "id": "inv-abc123", "email": "john@example.com", "organizationId": "550e8400-e29b-41d4-a716-446655440000", "role": "member", "status": "pending", "expiresAt": "2025-01-23T14:00:00.000Z", "createdAt": "2025-01-16T14:00:00.000Z" } ] } ``` **Example** ```bash curl https://api.weavz.io/api/v1/members/invitations \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { invitations } = await client.invitations.list() ``` ```python result = client.invitations.list() invitations = result["invitations"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/members/invitations', { headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.get( "https://api.weavz.io/api/v1/members/invitations", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` Revoke a pending invitation. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `invitationId` | string | Invitation ID | **Response** ```json { "deleted": true, "id": "inv-abc123" } ``` **Example** ```bash curl -X DELETE https://api.weavz.io/api/v1/members/invitations/inv-abc123 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript await client.invitations.revoke('inv-abc123') ``` ```python client.invitations.revoke("inv-abc123") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/members/invitations/inv-abc123', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.delete( "https://api.weavz.io/api/v1/members/invitations/inv-abc123", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Invitation not found | Accept an invitation to join an organization. The authenticated user must match the invited email address. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `invitationId` | string | Invitation ID | **Response** ```json { "member": { "id": "m1a2b3c4-d5e6-7890-abcd-ef1234567890", "organizationId": "550e8400-e29b-41d4-a716-446655440000", "userId": "user456", "role": "member", "createdAt": "2025-01-16T14:00:00.000Z" } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/members/invitations/inv-abc123/accept \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript const { member } = await client.invitations.accept('inv-abc123') ``` ```python result = client.invitations.accept("inv-abc123") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/members/invitations/inv-abc123/accept', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/members/invitations/inv-abc123/accept", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `403` | `FORBIDDEN` | Authenticated user's email does not match invitation | | `404` | `NOT_FOUND` | Invitation not found or already accepted | | `400` | `EXPIRED` | Invitation has expired | | `409` | `DUPLICATE` | Already a member of this organization | --- ## Manage Members Update a member's role. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string | Member ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `role` | string | Yes | `owner`, `admin`, or `member` | **Response** ```json { "member": { "id": "m1a2b3c4-d5e6-7890-abcd-ef1234567890", "organizationId": "550e8400-e29b-41d4-a716-446655440000", "userId": "user456", "role": "admin", "createdAt": "2025-01-16T14:00:00.000Z" } } ``` **Example** ```bash curl -X PATCH https://api.weavz.io/api/v1/members/m1a2b3c4-d5e6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"role": "admin"}' ``` ```typescript const { member } = await client.members.update('m1a2b3c4-d5e6-7890-abcd-ef1234567890', { role: 'admin', }) ``` ```python result = client.members.update("m1a2b3c4-d5e6-7890-abcd-ef1234567890", role="admin") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/members/m1a2b3c4-d5e6-7890-abcd-ef1234567890', { method: 'PATCH', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ role: 'admin' }), }) const data = await res.json() ``` ```python res = httpx.patch( "https://api.weavz.io/api/v1/members/m1a2b3c4-d5e6-7890-abcd-ef1234567890", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"role": "admin"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Invalid role (must be `owner`, `admin`, or `member`) | | `404` | `NOT_FOUND` | Member not found | Remove a member from your organization. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string | Member ID | **Response** ```json { "deleted": true, "id": "m1a2b3c4-d5e6-7890-abcd-ef1234567890" } ``` **Example** ```bash curl -X DELETE https://api.weavz.io/api/v1/members/m1a2b3c4-d5e6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript await client.members.delete('m1a2b3c4-d5e6-7890-abcd-ef1234567890') ``` ```python client.members.delete("m1a2b3c4-d5e6-7890-abcd-ef1234567890") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/members/m1a2b3c4-d5e6-7890-abcd-ef1234567890', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.delete( "https://api.weavz.io/api/v1/members/m1a2b3c4-d5e6-7890-abcd-ef1234567890", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Member not found | --- ## Workspace Members Add an organization member to a workspace. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `workspaceId` | string (uuid) | Yes | Workspace ID | | `memberId` | string | Yes | Organization member ID | | `role` | string | No | `admin` or `member` (default: `member`) | **Response** (201) ```json { "projectMember": { "id": "pm1a2b3c-d5e6-7890-abcd-ef1234567890", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "memberId": "m1a2b3c4-d5e6-7890-abcd-ef1234567890", "role": "member", "createdAt": "2025-01-16T14:00:00.000Z" } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/workspace-members \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "memberId": "m1a2b3c4-d5e6-7890-abcd-ef1234567890", "role": "member" }' ``` ```typescript const { projectMember } = await client.projectMembers.create({ workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', memberId: 'm1a2b3c4-d5e6-7890-abcd-ef1234567890', role: 'member', }) ``` ```python result = client.workspace_members.create( workspace_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890", member_id="m1a2b3c4-d5e6-7890-abcd-ef1234567890", role="member", ) ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspace-members', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', memberId: 'm1a2b3c4-d5e6-7890-abcd-ef1234567890', role: 'member', }), }) const data = await res.json() ``` ```python res = httpx.post( "https://api.weavz.io/api/v1/workspace-members", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "memberId": "m1a2b3c4-d5e6-7890-abcd-ef1234567890", "role": "member", }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing required fields | | `409` | `DUPLICATE` | Member is already in this workspace | Remove a member from a workspace. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | Workspace member ID | **Response** ```json { "deleted": true, "id": "pm1a2b3c-d5e6-7890-abcd-ef1234567890" } ``` **Example** ```bash curl -X DELETE https://api.weavz.io/api/v1/workspace-members/pm1a2b3c-d5e6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript await client.projectMembers.delete('pm1a2b3c-d5e6-7890-abcd-ef1234567890') ``` ```python client.workspace_members.delete("pm1a2b3c-d5e6-7890-abcd-ef1234567890") ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/workspace-members/pm1a2b3c-d5e6-7890-abcd-ef1234567890', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, }) const data = await res.json() ``` ```python res = httpx.delete( "https://api.weavz.io/api/v1/workspace-members/pm1a2b3c-d5e6-7890-abcd-ef1234567890", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | Workspace member not found | ### End Users > Manage end user identities and their integration connections. Source: https://weavz.io/docs/api-reference/end-users # End Users End users represent the people who use your product. Each end user is scoped to a workspace and can own connections to third-party integrations. ## Create End User Create a new end user within a workspace. **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `workspaceId` | string (uuid) | Yes | Workspace to create the end user in | | `externalId` | string | Yes | Unique external identifier within the workspace | | `displayName` | string | No | Human-readable display name | | `email` | string (email) | No | End user email address | | `metadata` | object | No | Arbitrary metadata to attach | **Response** (201) ```json { "endUser": { "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "externalId": "user_123", "displayName": "Alice Johnson", "email": "alice@example.com", "metadata": { "plan": "pro" }, "type": "external", "connectionCount": 0, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/end-users \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "externalId": "user_123", "displayName": "Alice Johnson", "email": "alice@example.com", "metadata": { "plan": "pro" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { endUser } = await client.endUsers.create({ workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', externalId: 'user_123', displayName: 'Alice Johnson', email: 'alice@example.com', metadata: { plan: 'pro' }, }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.end_users.create( workspace_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890", external_id="user_123", display_name="Alice Johnson", email="alice@example.com", metadata={"plan": "pro"}, ) end_user = result["endUser"] ``` ```typescript const res = await fetch('https://api.weavz.io/api/v1/end-users', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', externalId: 'user_123', displayName: 'Alice Johnson', email: 'alice@example.com', metadata: { plan: 'pro' }, }), }) const { endUser } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/end-users", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "externalId": "user_123", "displayName": "Alice Johnson", "email": "alice@example.com", "metadata": {"plan": "pro"}, }, ) end_user = res.json()["endUser"] ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | Missing or invalid fields | | `409` | `DUPLICATE` | End user with this `externalId` already exists in the workspace | ## List End Users List all end users in a workspace. **Query Parameters** | Field | Type | Required | Description | |-------|------|----------|-------------| | `workspaceId` | string (uuid) | Yes | Filter by workspace ID | **Response** ```json { "endUsers": [ { "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "externalId": "user_123", "displayName": "Alice Johnson", "email": "alice@example.com", "metadata": { "plan": "pro" }, "type": "external", "connectionCount": 2, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } ], "total": 1 } ``` **Example** ```bash curl "https://api.weavz.io/api/v1/end-users?workspaceId=a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { endUsers, total } = await client.endUsers.list({ workspaceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', }) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.end_users.list( workspace_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890", ) end_users = result["endUsers"] ``` ```typescript const res = await fetch( 'https://api.weavz.io/api/v1/end-users?workspaceId=a1b2c3d4-e5f6-7890-abcd-ef1234567890', { headers: { 'Authorization': 'Bearer wvz_your_api_key' } } ) const { endUsers, total } = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/end-users", headers={"Authorization": "Bearer wvz_your_api_key"}, params={"workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}, ) data = res.json() end_users = data["endUsers"] ``` ## Get End User Get an end user by ID, including their connections. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | End user ID | **Response** ```json { "endUser": { "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "externalId": "user_123", "displayName": "Alice Johnson", "email": "alice@example.com", "metadata": { "plan": "pro" }, "type": "external", "connectionCount": 2, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" }, "connections": [ { "id": "c1d2e3f4-5678-90ab-cdef-1234567890ab", "externalId": "user_123_slack", "displayName": "Alice's Slack", "integrationName": "slack", "type": "PLATFORM_OAUTH2", "status": "ACTIVE", "createdAt": "2025-01-15T12:00:00.000Z", "updatedAt": "2025-01-15T12:00:00.000Z" } ] } ``` **Example** ```bash curl https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { endUser, connections } = await client.endUsers.get( 'a1b2c3d4-5678-90ab-cdef-1234567890ab' ) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.end_users.get("a1b2c3d4-5678-90ab-cdef-1234567890ab") end_user = result["endUser"] connections = result["connections"] ``` ```typescript const res = await fetch( 'https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab', { headers: { 'Authorization': 'Bearer wvz_your_api_key' } } ) const { endUser, connections } = await res.json() ``` ```python import httpx res = httpx.get( "https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() end_user = data["endUser"] connections = data["connections"] ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | End user not found | ## Update End User Update an end user's display name, email, or metadata. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | End user ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `displayName` | string \| null | No | Updated display name (null to clear) | | `email` | string \| null | No | Updated email address (null to clear) | | `metadata` | object \| null | No | Updated metadata (null to clear) | **Response** ```json { "endUser": { "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab", "workspaceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "externalId": "user_123", "displayName": "Alice J.", "email": "alice.j@example.com", "metadata": { "plan": "enterprise" }, "type": "external", "connectionCount": 2, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-16T08:00:00.000Z" } } ``` **Example** ```bash curl -X PATCH https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "displayName": "Alice J.", "metadata": { "plan": "enterprise" } }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { endUser } = await client.endUsers.update( 'a1b2c3d4-5678-90ab-cdef-1234567890ab', { displayName: 'Alice J.', metadata: { plan: 'enterprise' }, } ) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.end_users.update( "a1b2c3d4-5678-90ab-cdef-1234567890ab", display_name="Alice J.", metadata={"plan": "enterprise"}, ) end_user = result["endUser"] ``` ```typescript const res = await fetch( 'https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab', { method: 'PATCH', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ displayName: 'Alice J.', metadata: { plan: 'enterprise' }, }), } ) const { endUser } = await res.json() ``` ```python import httpx res = httpx.patch( "https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "displayName": "Alice J.", "metadata": {"plan": "enterprise"}, }, ) end_user = res.json()["endUser"] ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `VALIDATION_ERROR` | No updates provided | | `404` | `NOT_FOUND` | End user not found | ## Delete End User Delete an end user and cascade-delete all their connections. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | End user ID | **Response** ```json { "deleted": true, "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab" } ``` **Example** ```bash curl -X DELETE https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab \ -H "Authorization: Bearer wvz_your_api_key" ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) await client.endUsers.delete('a1b2c3d4-5678-90ab-cdef-1234567890ab') ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") client.end_users.delete("a1b2c3d4-5678-90ab-cdef-1234567890ab") ``` ```typescript const res = await fetch( 'https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab', { method: 'DELETE', headers: { 'Authorization': 'Bearer wvz_your_api_key' }, } ) const data = await res.json() ``` ```python import httpx res = httpx.delete( "https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab", headers={"Authorization": "Bearer wvz_your_api_key"}, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | End user not found | ## Generate Connect Token Generate a connect portal URL for an end user. The portal lets them connect their own third-party accounts. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | End user ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `integrationName` | string | No | Restrict to a specific integration | | `expiresIn` | integer | No | Token expiration in seconds (default: 14400 = 4 hours) | **Response** ```json { "connectUrl": "https://api.weavz.io/connect?token=cst_abc123...", "token": "cst_abc123...", "expiresAt": "2025-01-15T14:30:00.000Z" } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab/connect-token \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{"integrationName": "slack"}' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { connectUrl, token, expiresAt } = await client.endUsers.createConnectToken( 'a1b2c3d4-5678-90ab-cdef-1234567890ab', { integrationName: 'slack' } ) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.end_users.create_connect_token( "a1b2c3d4-5678-90ab-cdef-1234567890ab", integration_name="slack", ) connect_url = result["connectUrl"] ``` ```typescript const res = await fetch( 'https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab/connect-token', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ integrationName: 'slack' }), } ) const { connectUrl, token, expiresAt } = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab/connect-token", headers={"Authorization": "Bearer wvz_your_api_key"}, json={"integrationName": "slack"}, ) data = res.json() connect_url = data["connectUrl"] ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `404` | `NOT_FOUND` | End user not found | ## Send Email Invitation Send an email invitation to an end user with a link to connect their accounts. **Path Parameters** | Field | Type | Description | |-------|------|-------------| | `id` | string (uuid) | End user ID | **Request Body** | Field | Type | Required | Description | |-------|------|----------|-------------| | `email` | string (email) | Yes | Email address to send the invitation to | | `integrationName` | string | No | Restrict to a specific integration | | `expiresIn` | integer | No | Link expiration in seconds (default: 14400 = 4 hours) | **Response** ```json { "sent": true, "email": "alice@example.com" } ``` **Example** ```bash curl -X POST https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab/invite \ -H "Authorization: Bearer wvz_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "email": "alice@example.com", "integrationName": "slack" }' ``` ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key' }) const { sent } = await client.endUsers.invite( 'a1b2c3d4-5678-90ab-cdef-1234567890ab', { email: 'alice@example.com', integrationName: 'slack', } ) ``` ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") result = client.end_users.invite( "a1b2c3d4-5678-90ab-cdef-1234567890ab", email="alice@example.com", integration_name="slack", ) ``` ```typescript const res = await fetch( 'https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab/invite', { method: 'POST', headers: { 'Authorization': 'Bearer wvz_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ email: 'alice@example.com', integrationName: 'slack', }), } ) const data = await res.json() ``` ```python import httpx res = httpx.post( "https://api.weavz.io/api/v1/end-users/a1b2c3d4-5678-90ab-cdef-1234567890ab/invite", headers={"Authorization": "Bearer wvz_your_api_key"}, json={ "email": "alice@example.com", "integrationName": "slack", }, ) data = res.json() ``` **Errors** | Status | Code | Description | |--------|------|-------------| | `400` | `EMAIL_NOT_CONFIGURED` | Email sending is not configured | | `404` | `NOT_FOUND` | End user not found | --- ## SDKs ### TypeScript SDK > Official TypeScript SDK for the Weavz API. Source: https://weavz.io/docs/sdks/typescript # TypeScript SDK The official TypeScript SDK provides a typed, ergonomic interface for the Weavz API. ## Installation ```bash npm install @weavz/sdk ``` ## Quick Start ```typescript import { WeavzClient } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_api_key', }) // Execute an action const { output } = await client.actions.execute('slack', 'send_channel_message', { workspaceId: 'proj_abc123', input: { channel: '#general', text: 'Hello from Weavz!' }, connectionExternalId: 'my_slack', }) console.log('Message sent:', output) ``` ## Configuration ```typescript const client = new WeavzClient({ apiKey: 'wvz_your_api_key', baseUrl: 'https://api.weavz.io', // Default }) ``` | Option | Required | Default | Description | |--------|----------|---------|-------------| | `apiKey` | Yes | — | Your API key (`wvz_...` prefix) | | `baseUrl` | No | `https://api.weavz.io` | API base URL | ## Resources The client exposes namespaced resources for each API area: | Resource | Methods | Description | |----------|---------|-------------| | `client.workspaces` | `list`, `create`, `get`, `delete`, `listIntegrations`, `addIntegration`, `updateIntegration`, `removeIntegration` | Workspace management | | `client.connections` | `list`, `create`, `delete`, `resolve` | Connection management | | `client.actions` | `execute` | Execute integration actions | | `client.triggers` | `list`, `enable`, `disable`, `test` | Trigger management | | `client.mcpServers` | `list`, `create`, `get`, `update`, `delete`, `regenerateToken`, `addTool`, `updateTool`, `deleteTool`, `executeCode`, `getDeclarations` | MCP server management | | `client.apiKeys` | `list`, `create`, `delete` | API key management | | `client.members` | `list`, `create`, `update`, `delete` | Organization members | | `client.workspaceMembers` | `create`, `delete` | Workspace member management | | `client.integrations` | `list`, `get`, `resolveOptions`, `resolveProperty`, `oauthStatus` | Integration metadata | | `client.connect` | `createToken`, `getSession`, `popup` | Hosted connect flow | | `client.partials` | `list`, `get`, `create`, `update`, `delete`, `setDefault` | Input partial presets | ## Common Operations ### Managing Workspaces ```typescript // List workspaces const { workspaces } = await client.workspaces.list() // Create a workspace const { workspace } = await client.workspaces.create({ name: 'My Workspace', slug: 'my-workspace', }) // Delete a workspace await client.workspaces.delete(workspace.id) ``` ### Managing Connections ```typescript // Create an API key connection const { connection } = await client.connections.create({ type: 'SECRET_TEXT', integrationName: 'openai', externalId: 'tenant_123_openai', displayName: 'OpenAI Key', secretText: 'sk-...', }) // Resolve a connection const resolved = await client.connections.resolve({ integrationName: 'openai', workspaceId: 'proj_abc123', externalId: 'tenant_123_openai', }) // Delete a connection await client.connections.delete(connection.id) ``` ### Executing Actions ```typescript const { output } = await client.actions.execute('github', 'create_issue', { workspaceId: 'proj_abc123', input: { repo: 'my-org/my-repo', title: 'Bug Report', body: 'Something went wrong', labels: ['bug'], }, connectionExternalId: 'my_github', }) ``` ### Managing MCP Servers ```typescript // Create a server const { server, bearerToken, mcpEndpoint } = await client.mcpServers.create({ name: 'AI Agent Tools', mode: 'TOOLS', workspaceId: 'proj_abc123', }) // Create a server scoped to an end user const { server: userServer, bearerToken: userToken } = await client.mcpServers.create({ name: 'User Agent', workspaceId: 'proj_abc123', endUserId: 'user_123', }) // Add a tool await client.mcpServers.addTool(server.id, { integrationName: 'slack', actionName: 'send_channel_message', connectionId: 'conn_abc', }) // Regenerate token const { bearerToken: newToken } = await client.mcpServers.regenerateToken(server.id) ``` ### Managing Triggers ```typescript // Enable a trigger const { triggerSource } = await client.triggers.enable({ integrationName: 'github', triggerName: 'new_push', workspaceId: 'proj_abc123', callbackUrl: 'https://yourapp.com/webhooks/github', connectionExternalId: 'my_github', }) // List active triggers const { triggers } = await client.triggers.list() // Disable a trigger await client.triggers.disable(triggerSource.id) ``` ### Managing Input Partials ```typescript // Create a partial (saved parameter preset) const { partial } = await client.partials.create({ name: 'Default Slack Channel', workspaceId: 'proj_abc123', integrationName: 'slack', actionName: 'send_channel_message', values: { channel: '#general' }, enforcedKeys: ['channel'], }) // List partials for a workspace const { partials } = await client.partials.list({ workspaceId: 'proj_abc123' }) // Set as default for this action await client.partials.setDefault(partial.id, true) // Use partial with action execution const { output } = await client.actions.execute('slack', 'send_channel_message', { workspaceId: 'proj_abc123', partialIds: [partial.id], input: { text: 'Hello!' }, // channel comes from the partial }) // Delete a partial await client.partials.delete(partial.id) ``` ### Hosted Connect Flow Use the hosted connect page to create OAuth2 connections. The flow is two steps: create a token, then open the popup: ```typescript // Step 1: Create a connect session const session = await client.connect.createToken({ integrationName: 'google-sheets', connectionName: 'Google Sheets', externalId: 'tenant_123_gsheets', workspaceId: 'proj_abc123', }) // Step 2: Open the popup (browser environments) const result = await client.connect.popup({ token: session.token, connectUrl: session.connectUrl, }) console.log('Connection created:', result.connection.id) ``` For server-side or custom flows, create a token and open the connect URL manually: ```typescript // Step 1: Create a connect token const { token, connectUrl } = await client.connect.createToken({ integrationName: 'google-sheets', connectionName: 'Google Sheets', externalId: 'tenant_123_gsheets', workspaceId: 'proj_abc123', }) // Step 2: Open connectUrl in a browser window... // The response contains: token, connectUrl, expiresAt ``` ## Error Handling All API errors throw `WeavzError` with structured error information: ```typescript import { WeavzClient, WeavzError } from '@weavz/sdk' const client = new WeavzClient({ apiKey: 'wvz_your_key' }) try { await client.actions.execute('slack', 'send_channel_message', { workspaceId: 'proj_abc123', input: { channel: 'invalid', text: 'Hello!' }, }) } catch (err) { if (err instanceof WeavzError) { console.error(err.message) // Human-readable error message console.error(err.code) // Machine-readable error code (e.g., "ACTION_FAILED") console.error(err.status) // HTTP status code (e.g., 400) console.error(err.details) // Additional error details (if available) } } ``` ### Common Error Codes | Code | Description | |------|-------------| | `VALIDATION_ERROR` | Invalid request parameters | | `ACTION_FAILED` | Action execution failed | | `CONNECTION_REQUIRED` | Action needs a connection | | `CONNECTION_NOT_FOUND` | Connection doesn't exist | | `INTEGRATION_NOT_FOUND` | Invalid integration name | | `QUOTA_EXCEEDED` | Monthly usage limit reached | | `RATE_LIMITED` | Too many requests | ## TypeScript Support The SDK is written in TypeScript and ships with full type definitions. You get autocomplete and type checking for all resource methods and their parameters. ```typescript // Typed integration inputs (generated from integration schemas) import type { SlackSendChannelMessageInput } from '@weavz/sdk' const input: SlackSendChannelMessageInput = { channel: '#general', text: 'Typed input!', } await client.actions.execute('slack', 'send_channel_message', { workspaceId: 'proj_abc123', input, }) ``` ### Key Types ```typescript import type { WeavzClient, WeavzError, InputPartial, WorkspaceIntegration, McpServer, McpServerTool, Connection, Workspace, TriggerSource, } from '@weavz/sdk' ``` | Type | Description | |------|-------------| | `WeavzClient` | Main client class with all resource methods | | `WeavzError` | Error class with `message`, `code`, `status`, `details` | | `InputPartial` | Partial preset with `values`, `enforcedKeys`, `isDefault` | | `WorkspaceIntegration` | Integration instance on a workspace with alias and connection strategy | | `McpServer` | MCP server with `mode`, `mcpEndpoint` | | `McpServerTool` | Tool on an MCP server with `integrationAlias`, `partialIds` | | `Connection` | Connection with `type`, `integrationName`, `externalId` | | `Workspace` | Workspace with `name`, `slug` | | `TriggerSource` | Active trigger with `integrationName`, `triggerName`, `callbackUrl` | ### Integration Input Types The SDK ships with generated input types for all 500+ integrations. Import them by pattern: ```typescript import type { // Slack SlackSendChannelMessageInput, SlackSendDirectMessageInput, // GitHub GithubCreateIssueInput, GithubCreatePullRequestInput, // Google Sheets GoogleSheetsInsertRowInput, GoogleSheetsReadRowsInput, // ... all integrations follow the same pattern } from '@weavz/sdk' ``` The naming pattern is `{IntegrationName}{ActionName}Input` in PascalCase. ### Python SDK > Official Python SDK for the Weavz API. Source: https://weavz.io/docs/sdks/python # Python SDK The official Python SDK provides a clean, Pythonic interface for the Weavz API. ## Installation ```bash pip install weavz-sdk ``` ## Quick Start ```python from weavz_sdk import WeavzClient client = WeavzClient(api_key="wvz_your_api_key") # Execute an action result = client.actions.execute( "slack", "send_channel_message", workspace_id="proj_abc123", input={"channel": "#general", "text": "Hello from Weavz!"}, connection_external_id="my_slack", ) print("Message sent:", result["output"]) ``` ## Configuration ```python client = WeavzClient( api_key="wvz_your_api_key", base_url="https://api.weavz.io", # Default timeout=30.0, # Request timeout in seconds ) ``` | Option | Required | Default | Description | |--------|----------|---------|-------------| | `api_key` | Yes | — | Your API key (`wvz_...` prefix) | | `base_url` | No | `https://api.weavz.io` | API base URL | | `timeout` | No | `30.0` | Request timeout in seconds | ## Context Manager The client supports Python's context manager protocol to automatically close the HTTP connection: ```python with WeavzClient(api_key="wvz_your_key") as client: result = client.actions.execute("slack", "send_channel_message", input={ "channel": "#general", "text": "Hello!", }) # Connection automatically closed ``` You can also close manually: ```python client = WeavzClient(api_key="wvz_your_key") try: # ... use client ... pass finally: client.close() ``` ## Resources The client exposes namespaced resources for each API area: | Resource | Methods | Description | |----------|---------|-------------| | `client.workspaces` | `list`, `create`, `get`, `delete`, `list_integrations`, `add_integration`, `update_integration`, `remove_integration` | Workspace management | | `client.connections` | `list`, `create`, `delete`, `resolve` | Connection management | | `client.actions` | `execute` | Execute integration actions | | `client.triggers` | `list`, `enable`, `disable`, `test` | Trigger management | | `client.mcp_servers` | `list`, `create`, `get`, `update`, `delete`, `regenerate_token`, `add_tool`, `update_tool`, `delete_tool`, `execute_code`, `get_declarations` | MCP server management | | `client.api_keys` | `list`, `create`, `delete` | API key management | | `client.members` | `list`, `create`, `update`, `delete` | Organization members | | `client.workspace_members` | `create`, `delete` | Workspace member management | | `client.integrations` | `list`, `get`, `resolve_options`, `resolve_property`, `oauth_status` | Integration metadata | | `client.connect` | `create_token`, `get_session` | Hosted connect flow | | `client.partials` | `list`, `get`, `create`, `update`, `delete`, `set_default` | Input partial presets | ## Common Operations ### Managing Workspaces ```python # List workspaces result = client.workspaces.list() for ws in result["workspaces"]: print(ws["name"]) # Create a workspace result = client.workspaces.create(name="My Workspace", slug="my-workspace") workspace_id = result["workspace"]["id"] # Delete a workspace client.workspaces.delete(workspace_id) ``` ### Managing Connections ```python # Create an API key connection result = client.connections.create( type="SECRET_TEXT", integration_name="openai", external_id="tenant_123_openai", display_name="OpenAI Key", secret_text="sk-...", ) # Resolve a connection resolved = client.connections.resolve( integration_name="openai", workspace_id="proj_abc123", external_id="tenant_123_openai", ) # Delete a connection client.connections.delete(result["connection"]["id"]) ``` ### Executing Actions ```python result = client.actions.execute( "github", "create_issue", workspace_id="proj_abc123", input={ "repo": "my-org/my-repo", "title": "Bug Report", "body": "Something went wrong", "labels": ["bug"], }, connection_external_id="my_github", ) print("Issue created:", result["output"]) ``` ### Managing MCP Servers ```python # Create a server result = client.mcp_servers.create( name="AI Agent Tools", mode="TOOLS", workspace_id="proj_abc123", ) server_id = result["server"]["id"] token = result["bearerToken"] endpoint = result["mcpEndpoint"] # Create a server scoped to an end user result = client.mcp_servers.create( name="User Agent", workspace_id="proj_abc123", end_user_id="user_123", ) user_token = result["bearerToken"] # Add a tool client.mcp_servers.add_tool( server_id, integration_name="slack", action_name="send_channel_message", connection_id="conn_abc", ) # Regenerate token result = client.mcp_servers.regenerate_token(server_id) new_token = result["bearerToken"] ``` ### Managing Triggers ```python # Enable a trigger result = client.triggers.enable( integration_name="github", trigger_name="new_push", workspace_id="proj_abc123", callback_url="https://yourapp.com/webhooks/github", connection_external_id="my_github", ) trigger_id = result["triggerSource"]["id"] # List active triggers result = client.triggers.list() for trigger in result["triggers"]: print(f"{trigger['integrationName']}.{trigger['triggerName']}") # Disable a trigger client.triggers.disable(trigger_id) ``` ### Managing Input Partials ```python # Create a partial (saved parameter preset) result = client.partials.create( name="Default Slack Channel", workspace_id="proj_abc123", integration_name="slack", action_name="send_channel_message", values={"channel": "#general"}, enforced_keys=["channel"], ) partial = result["partial"] # List partials for a workspace result = client.partials.list(workspace_id="proj_abc123") # Set as default for this action client.partials.set_default(partial["id"], is_default=True) # Use partial with action execution result = client.actions.execute( "slack", "send_channel_message", workspace_id="proj_abc123", partial_ids=[partial["id"]], input={"text": "Hello!"}, # channel comes from the partial ) # Delete a partial client.partials.delete(partial["id"]) ``` ### Hosted Connect Flow Use the hosted connect page to create OAuth2 connections. Create a token, open the connect page, and poll for the result: ```python # Step 1: Create a connect token result = client.connect.create_token( integration_name="google-sheets", connection_name="Google Sheets", external_id="tenant_123_gsheets", workspace_id="proj_abc123", ) token = result["token"] connect_url = result["connectUrl"] # result also contains: expiresAt # Step 2: Open connect_url in a browser popup to complete authorization ``` ## Error Handling All API errors raise `WeavzError` with structured error information: ```python from weavz_sdk import WeavzClient, WeavzError client = WeavzClient(api_key="wvz_your_key") try: client.actions.execute( "slack", "send_channel_message", workspace_id="proj_abc123", input={"channel": "invalid", "text": "Hello!"}, ) except WeavzError as e: print(f"Message: {e}") # Human-readable error message print(f"Code: {e.code}") # Machine-readable code (e.g., "ACTION_FAILED") print(f"Status: {e.status}") # HTTP status code (e.g., 400) print(f"Details: {e.details}") # Additional details (if available) ``` ### Common Error Codes | Code | Description | |------|-------------| | `VALIDATION_ERROR` | Invalid request parameters | | `ACTION_FAILED` | Action execution failed | | `CONNECTION_REQUIRED` | Action needs a connection | | `CONNECTION_NOT_FOUND` | Connection doesn't exist | | `INTEGRATION_NOT_FOUND` | Invalid integration name | | `QUOTA_EXCEEDED` | Monthly usage limit reached | | `RATE_LIMITED` | Too many requests | ## Type Hints The Python SDK includes type hints and Pydantic models for all API responses. You get IDE autocomplete and validation for all resource methods. ### Key Types ```python from weavz_sdk import WeavzClient, WeavzError from weavz_sdk.types import ( InputPartial, WorkspaceIntegration, McpServer, McpServerTool, Connection, Workspace, TriggerSource, ) ``` | Type | Description | |------|-------------| | `WeavzClient` | Main client class with all resource methods | | `WeavzError` | Exception class with `message`, `code`, `status`, `details` | | `InputPartial` | Partial preset with `values`, `enforced_keys`, `is_default` | | `WorkspaceIntegration` | Integration instance on a workspace with alias and connection strategy | | `McpServer` | MCP server with `mode`, `mcp_endpoint` | | `McpServerTool` | Tool on an MCP server with `integration_alias`, `partial_ids` | | `Connection` | Connection with `type`, `integration_name`, `external_id` | | `Workspace` | Workspace with `name`, `slug` | | `TriggerSource` | Active trigger with `integration_name`, `trigger_name`, `callback_url` | ### Integration Input Types The SDK ships with generated Pydantic models for all 500+ integration action inputs: ```python from weavz_sdk.integrations import ( # Slack SlackSendChannelMessageInput, SlackSendDirectMessageInput, # GitHub GithubCreateIssueInput, GithubCreatePullRequestInput, # Google Sheets GoogleSheetsInsertRowInput, GoogleSheetsReadRowsInput, # ... all integrations follow the same pattern ) # Validated input with autocomplete input_data = SlackSendChannelMessageInput( channel="#general", text="Typed input!", ) client.actions.execute( "slack", "send_channel_message", workspace_id="proj_abc123", input=input_data.model_dump(), ) ``` The naming pattern is `{IntegrationName}{ActionName}Input` in PascalCase. ## Python Version The SDK requires Python 3.10 or later and depends on: - [httpx](https://www.python-httpx.org/) for HTTP requests - [pydantic](https://docs.pydantic.dev/) for data validation --- ## LLM Resources ### LLM Resources > Machine-readable documentation for AI assistants and LLMs Source: https://weavz.io/docs/llm-resources # LLM Resources These files provide machine-readable versions of the Weavz documentation, optimized for use with Large Language Models (LLMs), AI coding assistants, and agent frameworks. ## Available Files | File | Description | |------|-------------| | [llms.txt](/llms.txt) | Compact index with page titles and URLs | | [llms-full.txt](/llms-full.txt) | Complete documentation content | ## Usage ### With AI Coding Assistants Point your AI assistant to `https://weavz.io/llms-full.txt` for complete API reference and guides. Most assistants that support external context files can ingest this directly. ### With Agent Frameworks Use `https://weavz.io/llms.txt` as a lightweight context source — it contains page summaries and links without full content. This is useful when you need to minimize context window usage. ### With MCP Servers If you are building an MCP server that interacts with the Weavz API, feed `llms-full.txt` to your LLM for complete coverage of all endpoints, SDKs, and integration patterns.