Agents

AI agents, MCP and CLI

Tell an agent “set up 1DB for acme.com” in any project. It adds the website, writes its keys to the project, wires the form and sends a test lead.

Why use it

Without it, connecting a site means copying an endpoint, a key and a form slug from the dashboard into the project, then writing the form code. Your agent is already in the project and knows its framework, so it can do all of that and prove a lead arrives, without you leaving the editor. You only approve the sign-in once, and add the keys to your host when you deploy.

Before you start

  • A 1DB account where you are an admin of the organization (agent tokens act as their admin).
  • Node 18 or newer (node -v), for npx.
  • Claude Code for the one-command setup. Other agents work too: see Other MCP clients.

1. Connect once

In your own terminal, from any folder:

bash
npx @1db/cli setup

It opens 1DB in your browser to approve the sign-in (pick the organization and the scopes), then adds the 1DB MCP server to Claude Code for every project. Restart Claude Code to load it. You do this once per computer, not once per project.

It creates an agent token (1db_at_…) that acts for you in that organization. It stays in your user config, never in a project. The per-website keys (1db_…) an agent writes into a project can only send leads. See or revoke tokens in Settings → API keys → Agent tokens.

Not in CI or a shared machine

The token can manage your organization. Run setup on your own computer, never in a CI job, a container image or a project script.

2. Ask for it

Open Claude Code in the website's project and say:

text
Set up 1db for acme.com

Claude calls onboard_website, writes DB_API_ENDPOINT, DB_API_KEY and DB_FORM_SLUG to the env file (and git-ignores it), wires the form, then uses send_test_lead and list_leads to prove leads arrive. Asking twice is safe: the same website comes back, not a copy.

For a site that is already connected and needs another form:

text
Add a quote request form to acme.com in 1db

Claude calls create_form, which returns the new form's slug and fields. The site keeps its ingest key; the new form posts with its own formSlug. Pass a template (quote-request, pickup-request, contact) for ready-made fields, and defaultLeadType / defaultProductType for leads that arrive without them. See form templates and defaults.

3. Go live

.env.local only exists on your computer. The deployed site sends nothing until its host has the same variables:

  1. Add DB_API_ENDPOINT, DB_API_KEY and DB_FORM_SLUG (with any prefix the project uses) to your host's production environment variables: Vercel → Settings → Environment Variables, Netlify → Site configuration → Environment variables, Cloudflare → Settings → Variables.
  2. Redeploy. Most hosts only read new variables on the next deploy.
  3. Submit the real form on the live site, then check it arrived: npx @1db/cli leads acme.com, or ask Claude to list the leads.

A test lead from the agent proves the key and form slug. Only a submission on the live site proves the deployed form.

Already using 1DB?

Nothing changes for sites that already send leads: the endpoint and keys are the same. To confirm a project is wired up right, run this in its root folder:

bash
npx @1db/cli check          # compare the project's DB_* vars with 1DB
npx @1db/cli check --send   # also post one test lead with those exact values

It finds the variables in the project's .env* files (including older 1DB_ names and NEXT_PUBLIC_/VITE_ prefixes), checks the endpoint, key and form slug against the website, and checks the env files are git-ignored. It exits non-zero when something is wrong. To hand it to the agent in that project instead:

text
This project already sends leads to 1DB. Check the setup without rewriting working code:
1. Run `npx @1db/cli@latest check` in the project root and read the result. If it says I'm not
   logged in, stop and ask me to run `npx @1db/cli setup` in my own terminal.
2. Fix only what it marks ✗ (wrong endpoint, wrong form slug, env file tracked by git).
3. Don't rename env vars or replace values that work. Don't put any 1db_at_ token in the project.
4. Tell me which variables the live site's host needs, if any are missing there.

Configure it

With the matching scopes, an agent can finish the setup too:

text
Make the quote form on acme.com default to product type pallets
Email ops@acme.com when the quote form gets a lead
Forward every new lead to https://api.acme.com/leads with our API key
  • update_website, list_product_types: name, domain, status, product types and the website-level fallback product type.
  • get_form, update_form: rename a form, change its slug, replace its fields or set its default lead type and product type.
  • set_form_notifications: notification emails (up to 10) and a webhook per form.
  • list_forwarding_rules, create_forwarding_rule, update_forwarding_rule, delete_forwarding_rule: send each new lead to an outside endpoint, with a generic or repackify profile. New rules start disabled; secrets are stored and never returned.
  • delete_form, delete_website: need confirm set to the slug. Leads are kept, but a live form posting to it starts failing.

Other tools: get_website, list_websites, scan_domain, whoami. Destinations must be public https:// URLs. HubSpot and Salesforce connections use OAuth, so they are set up in the dashboard.

Token scopes

Each token only does what its scopes allow; anything else gets a 403 naming the missing scope. Pick them when creating a token in Settings or approving a CLI sign-in. whoami shows a token's scopes.

ScopeAllows
sitesAdd websites and forms, change their settings, get ingest keys, send test leads
leadsRead leads and their contact details
routingForwarding rules, notification emails and webhooks: anything that sends leads somewhere
deleteDelete websites, forms and forwarding rules

The defaults, sites and leads, cover setting up a site. Give an agent you don't run yourself sites only. Tokens created before scopes existed keep sites and leads.

Test leads are real leads

send_test_lead, 1db send and 1db check --send post through the same endpoint as your site. The lead shows in the dashboard and counts in stats, and it runs the site's CRM sync, notification emails, webhooks and forwarding. It is tagged with source 1db-test so you can find and delete it.

Agents are told to send one per check. If the site already syncs to a CRM or forwards leads, expect one test contact to show up there too.

Keeping tokens safe

  • Two kinds of key. The agent token (1db_at_…) manages your organization and lives in ~/.config/1db/config.json and your Claude Code config. The ingest key (1db_…) goes in projects and can only send leads. 1db check fails if an agent token ends up in a project.
  • A token leaked? Revoke it in Settings → API keys → Agent tokens; it stops working at once. Then run npx @1db/cli setup --relogin for a new one.
  • You'll know when one is made. Organization owners get an email whenever a new agent token is created.
  • Switch organization with npx @1db/cli setup --relogin and pick the other one when approving.
  • Sign out with npx @1db/cli logout and claude mcp remove 1db, then revoke the token in Settings.

Troubleshooting

You seeWhat to do
Claude has no 1DB toolsRestart Claude Code after setup. claude mcp list should show 1db.
401 invalid or revoked tokenThe token was revoked. Run npx @1db/cli setup --relogin.
403 missing scopeThe message names the scope. Run npx @1db/cli setup --relogin and tick it.
404 website not foundThe token is for another organization, or the slug is wrong. whoami and websites show both.
429Over 60 requests a minute. Wait a minute.
Sign-in code expiredCodes last 10 minutes. Run the command again.
Leads arrive locally but not from the live siteThe host is missing the variables, or wasn't redeployed. See Go live.
Lead rejected: Form not foundDB_FORM_SLUG isn't a form on that site. npx @1db/cli check lists the right ones.

Other MCP clients

Create a token in Settings (or run npx @1db/cli mcp after logging in) and point any Streamable HTTP client (Cursor, Windsurf, VS Code and others) at the server with the token as a header:

bash
claude mcp add --scope user --transport http 1db https://www.1-db.com/api/mcp \
  --header "Authorization: Bearer 1db_at_..."

The server takes the token as a header, not an OAuth sign-in, so it can't be added as a connector on claude.ai or in the Claude desktop chat yet. Use Claude Code, another client that sends headers, or the CLI.

Or use the CLI yourself

bash
npx @1db/cli login           # browser sign-in (or --token 1db_at_...)
npx @1db/cli init acme.com   # scan + add the site, write DB_* vars to .env.local
npx @1db/cli check acme.com  # compare this project's DB_* vars with 1DB
npx @1db/cli check --send    # ...and post one test lead with the project's own values
npx @1db/cli leads acme.com  # see it arrive
npx @1db/cli keys acme.com   # print the site's endpoint, key and form slug
npx @1db/cli form acme.com --name "Quote request" --fields "email*,name,phone:phone,message:textarea"
                             # add another form to the site, print its slug
npx @1db/cli product-types add "Pallets"   # new organizations start with no product types
npx @1db/cli form acme.com --template quote-request --product-type pallets
                             # or start from a template, with form defaults
npx @1db/cli form-edit acme-quote-request --lead-type buy
npx @1db/cli site acme.com --product-type pallets --status active   # website-level fallback
npx @1db/cli notify acme-quote-request --emails ops@acme.com
npx @1db/cli forwarding add --name "Our API" --endpoint https://api.acme.com/leads --auth-token ... --profile generic --enable

Run it from the project's root folder: init and check read and write the env files there. init never replaces values a project already has; it lists the differences and leaves them (pass --force to overwrite).

Every command takes --json. Use --prefix NEXT_PUBLIC_ or --prefix VITE_ when the variables must reach the browser. Install it with npm i -g @1db/cli to type 1db instead of npx @1db/cli.

Or call the agent API

bash
curl -X POST https://gallant-goshawk-513.convex.site/v1/agent/onboard \
  -H "Authorization: Bearer $ONEDB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"domain":"acme.com"}'
  • POST /v1/agent/onboard { domain, name?, fields? }: scans the domain and creates the website with its ingest key and contact form. Retrying returns the same website with created: false.
  • POST /v1/agent/forms { website, name?, slug?, fields?, preset?, template?, defaultLeadType?, defaultProductType? }: adds a form to an existing website (name or template required). Fields default to the preset, then the organization's default preset, then the standard contact fields. Retrying with the same slug (or name) returns the same form.
  • GET /v1/agent/website?website=acme.com: endpoint, ingest key, forms and fields.
  • POST /v1/agent/test-lead { website, data?, formSlug? }: sends a real lead through /v1/leads, tagged source 1db-test.
  • GET /v1/agent/leads?website=acme.com&limit=20: newest leads first.
  • GET /v1/agent/websites, GET /v1/agent/me, POST /v1/agent/scan.
  • POST /v1/agent/website/update { website, name?, domain?, status?, defaultProductType?, productTypes? }, GET /v1/agent/product-types, POST /v1/agent/product-types { name, slug?, category? }, POST /v1/agent/product-types/import { rule } (routing; adds the product types that rule's destination accepts).
  • GET /v1/agent/form?form=slug, POST /v1/agent/forms/update { form, name?, slug?, fields?, defaultLeadType?, defaultProductType? } ("" clears a default).
  • POST /v1/agent/forms/notifications { form, email?: { enabled, recipients }, webhook?: { enabled, url, headers? } } (routing).
  • GET|POST /v1/agent/forwarding, POST /v1/agent/forwarding/update { id, ..., profile?: "generic" | "repackify" } (routing); POST /v1/agent/forwarding/delete { id, confirm: name } (delete).
  • POST /v1/agent/forms/delete { form, confirm }, POST /v1/agent/website/delete { website, confirm } (delete).

Errors come back as { error, hint? }. Limit: 60 requests a minute per token (bursts to 120).

What lands in the project

.env.local
DB_API_ENDPOINT=https://gallant-goshawk-513.convex.site
DB_API_KEY=1db_...
DB_FORM_SLUG=contact
# one per extra form made with create_form
DB_QUOTE_REQUEST_FORM_SLUG=acme-quote-request

The form posts to ${DB_API_ENDPOINT}/v1/leads with the key in an X-API-Key header and formSlug in the JSON body. Keep the call on the server and the variables stay unprefixed. If the browser sends it, add the prefix your framework needs (NEXT_PUBLIC_DB_API_KEY, VITE_DB_API_KEY) with --prefix. The ingest key can only send leads, so that is safe, but a server route keeps it out of view.

The form code itself is in the Next.js, React and HTML forms guides, which use the same variable names. Agents can read /llms.txt for a plain-text index.