# 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.