Skip to content

Connect and Execute a Tool with a Connector

In this tutorial you will install a Slack connector instance, store a bot token, sync the available tools, execute the send_message tool, and inspect the execution history. By the end you will have a working connector that AI agents in your workspace can invoke.

Prerequisites

  • A Chainabit account with a valid access token
  • curl available in your terminal
  • A Slack workspace and a Slack Bot Token (starts with xoxb-...)

Set your environment variables:

bash
export BASE="https://api.chainabit.com/api/v1"
export TOKEN="your-access-token"
export SLACK_BOT_TOKEN="xoxb-..."

Connector Workflow


Step 1: Browse Available Connector Definitions

List the available connector definitions to find the Slack connector key:

bash
curl "https://api.chainabit.com/api/v1/connectors?category=communication" \
  -H "Authorization: Bearer $TOKEN"
javascript
const res = await fetch(`https://api.chainabit.com/api/v1/connectors?category=communication`, {
  headers: { Authorization: `Bearer ${TOKEN}` },
});
const { data } = await res.json();
console.log(data.map((c) => c.key));
python
import requests

res = requests.get(
    f"{BASE}/connectors",
    params={"category": "communication"},
    headers={"Authorization": f"Bearer {TOKEN}"},
)
data = res.json()["data"]
print([c["key"] for c in data])

Response excerpt:

json
{
  "data": [
    {
      "key": "slack",
      "displayName": "Slack",
      "category": "communication",
      "authMethod": "api_key",
      "isActive": true
    },
    {
      "key": "gmail",
      "displayName": "Gmail",
      "category": "communication",
      "authMethod": "oauth2",
      "isActive": true
    }
  ]
}

Note the authMethod field. Slack supports api_key (bot token), which means you can authenticate without a browser redirect. The key for the next step is "slack".


Step 2: Create a Connector Instance

An instance is a workspace-scoped installation of a connector. One workspace can have multiple Slack instances:

bash
curl -s -X POST "https://api.chainabit.com/api/v1/connectors/instances" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "connectorKey": "slack",
    "displayName": "Team Slack"
  }'
javascript
const res = await fetch(`https://api.chainabit.com/api/v1/connectors/instances`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    connectorKey: 'slack',
    displayName: 'Team Slack',
  }),
});
const { data } = await res.json();
console.log(data.id, data.status); // "inst_abc123", "pending_auth"
python
res = requests.post(
    f"{BASE}/connectors/instances",
    headers={"Authorization": f"Bearer {TOKEN}"},
    json={"connectorKey": "slack", "displayName": "Team Slack"},
)
data = res.json()["data"]
print(data["id"], data["status"])  # "inst_abc123", "pending_auth"

Response:

json
{
  "data": {
    "id": "inst_abc123",
    "connectorKey": "slack",
    "displayName": "Team Slack",
    "status": "pending_auth",
    "enabled": true,
    "config": {},
    "lastHealthCheck": null,
    "healthMessage": null,
    "createdAt": "2026-03-23T10:00:00Z",
    "updatedAt": "2026-03-23T10:00:00Z"
  }
}

The instance starts with status: "pending_auth". Save the instance ID:

bash
export INSTANCE_ID="inst_abc123"

Step 3: Store Credentials

Store the Slack bot token. Credentials are encrypted at rest and never returned in API responses:

bash
curl -s -X POST "https://api.chainabit.com/api/v1/connectors/instances/$INSTANCE_ID/credentials" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"credType\": \"api_key\",
    \"credentials\": {
      \"apiKey\": \"$SLACK_BOT_TOKEN\"
    }
  }"
javascript
const res = await fetch(
  `https://api.chainabit.com/api/v1/connectors/instances/${INSTANCE_ID}/credentials`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      credType: 'api_key',
      credentials: { apiKey: process.env.SLACK_BOT_TOKEN },
    }),
  },
);
const { data } = await res.json();
console.log(data.stored); // true
python
import os

res = requests.post(
    f"{BASE}/connectors/instances/{INSTANCE_ID}/credentials",
    headers={"Authorization": f"Bearer {TOKEN}"},
    json={
        "credType": "api_key",
        "credentials": {"apiKey": os.environ["SLACK_BOT_TOKEN"]},
    },
)
data = res.json()["data"]
print(data["stored"])  # True

Response:

json
{
  "data": {
    "stored": true
  }
}

Credentials are write-only. You can check whether credentials are stored via GET /connectors/instances/:id/credentials/status, but their values are never readable through the API.


Step 4: Test the Connection

Send a health-check to confirm the bot token works and Slack is reachable:

bash
curl -s -X POST "https://api.chainabit.com/api/v1/connectors/instances/$INSTANCE_ID/test" \
  -H "Authorization: Bearer $TOKEN"
javascript
const res = await fetch(
  `https://api.chainabit.com/api/v1/connectors/instances/${INSTANCE_ID}/test`,
  {
    method: 'POST',
    headers: { Authorization: `Bearer ${TOKEN}` },
  },
);
const { data } = await res.json();
if (!data.healthy) throw new Error(data.message);
console.log(`Connected (${data.latencyMs}ms)`);
python
res = requests.post(
    f"{BASE}/connectors/instances/{INSTANCE_ID}/test",
    headers={"Authorization": f"Bearer {TOKEN}"},
)
data = res.json()["data"]
if not data["healthy"]:
    raise RuntimeError(data["message"])
print(f"Connected ({data['latencyMs']}ms)")

Response:

json
{
  "data": {
    "healthy": true,
    "message": "Connection successful",
    "latencyMs": 187
  }
}

If healthy is false, check that your bot token starts with xoxb- and that the bot is installed in your Slack workspace.


Step 5: Sync and List Tools

Pull the available tools from the Slack adapter, then list them:

bash
curl -s -X POST "https://api.chainabit.com/api/v1/connectors/instances/$INSTANCE_ID/sync-tools" \
  -H "Authorization: Bearer $TOKEN"
bash
curl -s "https://api.chainabit.com/api/v1/connectors/instances/$INSTANCE_ID/tools" \
  -H "Authorization: Bearer $TOKEN"

List tools response:

json
{
  "data": [
    {
      "id": "tool_abc123",
      "connectorKey": "slack",
      "toolKey": "send_message",
      "displayName": "Send Message",
      "description": "Send a message to a Slack channel or user",
      "inputSchema": {
        "type": "object",
        "properties": {
          "channel": { "type": "string", "description": "Channel name or ID" },
          "text": { "type": "string", "description": "Message content" }
        },
        "required": ["channel", "text"]
      },
      "isActive": true,
      "source": "auto_discovered"
    }
  ]
}

Save the tool ID for the send_message tool:

bash
export TOOL_ID="tool_abc123"

Step 6: Execute a Tool

Call send_message to post to a Slack channel. The input is validated against the tool's inputSchema:

bash
curl -s -X POST "https://api.chainabit.com/api/v1/connectors/instances/$INSTANCE_ID/tools/$TOOL_ID/execute" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "input": {
      "channel": "#general",
      "text": "Hello from Chainabit!"
    }
  }'
javascript
const res = await fetch(
  `https://api.chainabit.com/api/v1/connectors/instances/${INSTANCE_ID}/tools/${TOOL_ID}/execute`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      input: { channel: '#general', text: 'Hello from Chainabit!' },
    }),
  },
);
const { data } = await res.json();
if (data.success) {
  console.log('Message sent:', data.output);
} else {
  console.error('Tool error:', data.error);
}
python
res = requests.post(
    f"{BASE}/connectors/instances/{INSTANCE_ID}/tools/{TOOL_ID}/execute",
    headers={"Authorization": f"Bearer {TOKEN}"},
    json={"input": {"channel": "#general", "text": "Hello from Chainabit!"}},
)
data = res.json()["data"]
if data["success"]:
    print("Message sent:", data["output"])
else:
    print("Tool error:", data["error"])

Response on success:

json
{
  "data": {
    "success": true,
    "output": {
      "ok": true,
      "channel": "C01234567",
      "ts": "1711234567.000100"
    },
    "error": null,
    "httpStatus": 200,
    "durationMs": 342
  }
}

Common errors

ErrorCauseFix
channel_not_foundThe #channel does not exist or the bot is not a memberAdd the bot to the channel
No credentials configuredStep 3 was skipped or credentials were deletedRe-run Step 3
Tool is disabled on this instanceisActive: false on the toolPATCH the tool to re-enable it

Step 7: Inspect Execution History

Every tool execution is logged. Retrieve the log for your instance:

bash
curl -s "https://api.chainabit.com/api/v1/connectors/instances/$INSTANCE_ID/executions?limit=5" \
  -H "Authorization: Bearer $TOKEN"

Response excerpt:

json
{
  "data": [
    {
      "id": "exec_01HQZ...",
      "toolKey": "send_message",
      "success": true,
      "durationMs": 342,
      "executedAt": "2026-03-23T10:15:00Z"
    }
  ]
}

Summary

In this tutorial you:

  1. Browsed connector definitions to confirm the slack key and its auth method
  2. Created a connector instance (starts as pending_auth)
  3. Stored an API key credential (write-only, encrypted at rest)
  4. Tested the connection to confirm the token is valid
  5. Synced and listed tools exposed by the Slack adapter
  6. Executed the send_message tool with channel and text input
  7. Inspected the execution history log

Next Steps

Built with purpose.