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

  1. 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.
  2. The workspace must be enabled for Clay's public HTTP API. If it is not, Clay answers 401 to a correct key, and a new key does not help — Clay support enables it.
  3. 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 answers 403.

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.

ToolTagRequest
clay-api.get_credit_balancereadGET /credits/balance — also the key check Connect and Re-check run; uses no credits
clay-api.run_functionwrite, spendPOST /routines/{routineId}/run with up to 100 {id, inputs} items
clay-api.get_function_runreadGET /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 429 carries Retry-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.