Teams & API keys

Multi-key teams for hosted MailAgent — invite CI bots and teammates without Stripe. Manage keys in the Console dashboard or via /v1/team.

Create a team (first key)

Self-host or ops with Neon access:

npm run issue:key:db -- acme-qa

Save the printed key and team_id. Use the key in dashboard, MCP, or CI.

Invite another key (dashboard)

  1. Open Console with an admin team key
  2. Scroll to Team keys
  3. Fill label, optional prefix, read-only → Create key
  4. Copy the key from the one-time banner — it is not shown again

Invite via API

POST /v1/team/keys
Authorization: Bearer <ADMIN_TEAM_KEY>
Content-Type: application/json

{ "label": "ci-bot" }

Scoped CI key: see Scoped keys.

List & revoke

GET /v1/team
DELETE /v1/team/keys/KEY_ID

You cannot revoke the last key of a team. Scoped keys cannot create or revoke other keys.

Plans (no Stripe)

PlanTeam keysActive inboxes
free510
pro20100
npm run team:plan -- TEAM_ID pro

Legacy hosted key

A single wrangler API_KEY has no team (403 team_required on /v1/team). Limit: 500 active inboxes. Migrate with issue:key:db when you need invites or scoped keys.

Team event webhook

One HTTPS URL for every inbound message on all team inboxes — Slack, PagerDuty, or your own fan-out. Per-inbox callbackUrl still works; team webhook fires in addition when the inbox was created with a registered team key.

GET /v1/team/webhooks
PUT /v1/team/webhooks
POST /v1/team/webhooks
DELETE /v1/team/webhooks

Authorization: Bearer <ADMIN_TEAM_KEY>
Content-Type: application/json

{ "url": "https://hooks.example.com/mailagent" }

GET returns configured, masked urlMasked, and events: ["message.received"]. Admin scope required for write.

Payload (POST to your URL): same shape as per-inbox callback, plus teamId and source: "team_webhook" — see QA callbacks.

curl -sS https://api.webmailagent.com/v1/team/webhooks \
  -H "Authorization: Bearer $MAILAGENT_API_KEY" | jq .

More