Connectors
Every first-class connector: the exact tools you can call, their risk tiers, and a working example for each.
Tenet resolves each (service, tool_name) pair to a concrete downstream HTTP call from a curated catalog. That catalog (not the downstream service's full API) defines what's callable today. This page lists the exact tool set per connector, so you never have to guess a tool name.
Every connector needs its credential added once on the Protections page (/protections) — click the service under Available services and paste its key. Your agent only ever holds its TENET_API_KEY; Tenet injects the downstream credential server-side on each call.
Verified connectors — the ones in the connect picker today — are Anthropic, GitHub, Stripe, and Notion: each verified end-to-end with real downstream calls. OpenAI and Slack are cataloged but in verification; they return to the picker once their canary checks pass.
Risk tiers drive the defaults under the Gated trust level: read_only and reversible_write calls allow, and irreversible calls escalate for human approval (or hard-block when context.env is "production"). Note that every newly connected service starts Locked — every call escalates until you relax the trust level at /protections.
Anthropic
The inference path. Routing model calls through Tenet is what makes the cost cap real: spend is metered per call from the usage block.
| Tool | Method | Risk tier |
|---|---|---|
anthropic.messages.create | POST | reversible_write |
decision = client.execute(
service="anthropic",
tool_name="anthropic.messages.create",
arguments={
"model": "claude-sonnet-4-6",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Summarize this diff"}],
},
)
OpenAI (in verification)
| Tool | Method | Risk tier |
|---|---|---|
openai.chat.completions.create | POST | reversible_write |
decision = client.execute(
service="openai",
tool_name="openai.chat.completions.create",
arguments={
"model": "gpt-4o-mini",
"max_tokens": 512,
"messages": [{"role": "user", "content": "Classify this ticket"}],
},
)
GitHub
| Tool | Method | Risk tier |
|---|---|---|
github.repos.get | GET | read_only |
github.issues.list | GET | read_only |
github.issues.create | POST | reversible_write |
github.repos.delete | DELETE | irreversible (escalates) |
decision = client.execute(
service="github",
tool_name="github.issues.create",
arguments={"owner": "your-org", "repo": "api", "title": "Flaky test in CI"},
)
github.repos.delete is the canonical approval-gate demo: it returns ESCALATE and waits at /reviews instead of running.
Slack (in verification)
| Tool | Method | Risk tier |
|---|---|---|
slack.conversations.list | GET | read_only |
slack.chat.postMessage | POST | reversible_write |
decision = client.execute(
service="slack",
tool_name="slack.chat.postMessage",
arguments={"channel": "#alerts", "text": "Deploy finished"},
)
Stripe
Money movement is classified irreversible even though it's a POST. The method alone would misclassify it, so the catalog overrides.
| Tool | Method | Risk tier |
|---|---|---|
stripe.charges.list | GET | read_only |
stripe.customers.create | POST | reversible_write |
stripe.charges.create | POST | irreversible (escalates) |
stripe.refunds.create | POST | irreversible (escalates) |
decision = client.execute(
service="stripe",
tool_name="stripe.refunds.create",
arguments={"charge": "ch_123", "amount": 1500},
)
# → ESCALATE: a human approves the refund at /reviews before it runs
Notion
| Tool | Method | Risk tier |
|---|---|---|
notion.pages.create | POST | reversible_write |
notion.databases.query | POST | reversible_write |
decision = client.execute(
service="notion",
tool_name="notion.databases.query",
arguments={"database_id": "abc123", "page_size": 10},
)
A tool you need isn't listed?
Submit a request and we'll add it. Calling a tool outside this catalog returns unknown_tool rather than passing through unguarded.