Clay (API) connector setup
Operator·4 minutes to read
Clay's public API does not fit the "bring your own OAuth app" shape most other pages here describe.
There is no client id, no client secret and no
docs/connectors/README.md
botseon oauth-app set step for it, and nothing for the operator to configure: each member creates
a workspace API key in Clay and pastes it into the plugin sheet's own Connect field — the same
pasted-key path granola.md describes. The catalogue entry (clay-api, shown as
Clay (API)) is available from the start.
The catalogue's other Clay entry, clay, is Clay's hosted MCP server. It is independent of this
one and needs nothing on this page.
1. What the member creates in Clay
- In Clay, API and CLI in the left sidebar (under Orchestration) → API keys → Add API key: a name, the scopes, then copy the key (shown once). Admins, Members and Viewers can create one; the Sales Rep role cannot.
- The workspace must be enabled for Clay's public HTTP API. If it is not, Clay answers
401to a correct key, and a new key does not help — Clay support enables it. - For each function a bot should run: tick API & CLI in the function's Integrations
settings (outside edit mode) and note its Routine ID (
function:t_…). A function without it answers403.
2. The declared scope checklist
The plugin sheet shows two boxes (API_KEY_CONNECTORS['clay-api'] in
packages/core/src/connector-catalog.ts):
clay-api:read— the credit balance and a run's results.clay-api:run— running a Clay function. Leave it unticked to connect read-only.
At least one must be ticked. Neither is "required" in the sheet's sense, because neither is a scope
Clay grants a key: a refused key is answered with "check it and try again", never with "create it
with clay-api:read".
Clay picks a key's scopes in its own UI and its public API names no scope string for these
endpoints, so the boxes are Botseon's own words for what the member declares, never probed against
Clay (D508b). A tool call Clay refuses with 401 or
403 marks that tool needs scope on the account; the member fixes the key or the function in
Clay and presses I updated the key.
3. What the tools do
All three call https://api.clay.com/public/v0 with the key in the clay-api-key header.
| Tool | Tag | Request |
|---|---|---|
clay-api.get_credit_balance | read | GET /credits/balance — also the key check Connect and Re-check run; uses no credits |
clay-api.run_function | write, spend | POST /routines/{routineId}/run with up to 100 {id, inputs} items |
clay-api.get_function_run | read | GET /routines/run/{runId}/results — progress while running, the rows once complete |
clay-api.run_function adds its records to the function's table and uses the workspace's Clay
credits, so it is tagged write and spend: every run raises
an approval card and no always_allow rule can release it.
4. Pitfalls
- The personal key is not the workspace key. The key on a Clay profile page (or the legacy key under Settings → Account) is refused by the public API.
- A provisioning 401 looks like a bad key. The member is told to check the key either way; the message names both causes.
- Rate limit: 300 requests per minute per workspace, polling included; a
429carriesRetry-After(at least 5 seconds). - No row writes, no table queries. See the research note,
docs/research/connectors/clay-api.md, §4.
5. Live check
packages/connectors/src/clay-api.live.test.ts runs in the nightly connector-live workflow with
CLAY_TEST_API_KEY (and, for the run case, CLAY_TEST_ROUTINE_ID); without them every case skips.
The test account is described in
docs/operations/connector-live-setup/clay-api.md.
Last verified against build bdc9de6.