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
curlavailable in your terminal- A Slack workspace and a Slack Bot Token (starts with
xoxb-...)
Set your environment variables:
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:
curl "https://api.chainabit.com/api/v1/connectors?category=communication" \
-H "Authorization: Bearer $TOKEN"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));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:
{
"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:
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"
}'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"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:
{
"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:
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:
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\"
}
}"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); // trueimport 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"]) # TrueResponse:
{
"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:
curl -s -X POST "https://api.chainabit.com/api/v1/connectors/instances/$INSTANCE_ID/test" \
-H "Authorization: Bearer $TOKEN"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)`);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:
{
"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:
curl -s -X POST "https://api.chainabit.com/api/v1/connectors/instances/$INSTANCE_ID/sync-tools" \
-H "Authorization: Bearer $TOKEN"curl -s "https://api.chainabit.com/api/v1/connectors/instances/$INSTANCE_ID/tools" \
-H "Authorization: Bearer $TOKEN"List tools response:
{
"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:
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:
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!"
}
}'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);
}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:
{
"data": {
"success": true,
"output": {
"ok": true,
"channel": "C01234567",
"ts": "1711234567.000100"
},
"error": null,
"httpStatus": 200,
"durationMs": 342
}
}Common errors
| Error | Cause | Fix |
|---|---|---|
channel_not_found | The #channel does not exist or the bot is not a member | Add the bot to the channel |
No credentials configured | Step 3 was skipped or credentials were deleted | Re-run Step 3 |
Tool is disabled on this instance | isActive: false on the tool | PATCH the tool to re-enable it |
Step 7: Inspect Execution History
Every tool execution is logged. Retrieve the log for your instance:
curl -s "https://api.chainabit.com/api/v1/connectors/instances/$INSTANCE_ID/executions?limit=5" \
-H "Authorization: Bearer $TOKEN"Response excerpt:
{
"data": [
{
"id": "exec_01HQZ...",
"toolKey": "send_message",
"success": true,
"durationMs": 342,
"executedAt": "2026-03-23T10:15:00Z"
}
]
}Summary
In this tutorial you:
- Browsed connector definitions to confirm the
slackkey and its auth method - Created a connector instance (starts as
pending_auth) - Stored an API key credential (write-only, encrypted at rest)
- Tested the connection to confirm the token is valid
- Synced and listed tools exposed by the Slack adapter
- Executed the
send_messagetool with channel and text input - Inspected the execution history log
Next Steps
- Connectors API Reference for all available endpoints
- Connector Catalog to browse all supported connectors
- Chain Triggers to run chains (workflows) that invoke connector tools