# BriefGate BriefGate is an agent-native client intake tool. Coding agents (Claude Code, Cursor, or any MCP-compatible agent) call `define_intake` to define what assets or credentials they need from a client; BriefGate emails the client a branded portal, chases them on a configured schedule, and collects typed submissions. When assets are ready, the agent calls `get_intake_results` to receive typed JSON — file URLs, structured objects, validated strings, one-time secret tokens — and continues building without any human handoff. ## Base URLs - API: https://api.briefgate.dev - Portal (client-facing): https://p.briefgate.dev - App (developer dashboard): https://app.briefgate.dev - Machine-readable pricing: https://api.briefgate.dev/pricing.json (no auth) - OpenAPI spec: https://api.briefgate.dev/openapi.json (no auth) ## Authentication All API requests require a Bearer token: ``` Authorization: Bearer bg_live_xxxxx ``` Key prefixes: - `bg_live_` — production key (counts against production quota) - `bg_test_` — test key (separate quota, no real emails sent) Scopes: `intakes:read`, `intakes:write`, `webhooks:read`, `webhooks:write`, `account:read`, `account:write`. Default API key has all scopes. ## MCP tools Install: `npm install -g @briefgate/mcp` Add to Claude Code: `claude mcp add briefgate -- briefgate-mcp --api-key bg_live_xxxxx` | Tool | Description | Key params | |---|---|---| | `define_intake` | Create a new intake and (optionally) email the client portal link | `project_name`, `client.email`, `client.name`, `items[]`, `chase_schedule`, `template`, `due_date`, `send` (bool) | | `get_intake_status` | Poll for current status and per-item completion | `intake_id` | | `get_intake_results` | Retrieve all submitted values as typed JSON | `intake_id`, `only_new` (bool) | | `request_revision` | Flag an item and ask the client to resubmit with a note | `intake_id`, `item_key`, `note` | | `send_chase` | Send a manual reminder outside the schedule | `intake_id`, `channel` (`email`\|`sms`) | | `list_intakes` | List intakes with optional status filter | `status`, `limit`, `offset` | | `list_templates` | List available templates (public + custom) | `public` (bool) | ## Core REST endpoints ### Auth / API keys - `POST /v1/auth/signup` — create account (requires `ALLOW_SIGNUP=true`) - `POST /v1/auth/login` — get session token - `GET /v1/auth/keys` — list API keys - `POST /v1/auth/keys` — create API key - `DELETE /v1/auth/keys/:id` — revoke key ### Intakes - `POST /v1/intakes` — create intake (same as `define_intake`) - `GET /v1/intakes` — list intakes - `GET /v1/intakes/:id` — get intake detail - `PATCH /v1/intakes/:id` — update (chase_schedule, client.email, due_date, etc.) - `DELETE /v1/intakes/:id` — delete intake and all associated files - `GET /v1/intakes/:id/results` — get typed results (same as `get_intake_results`) - `POST /v1/intakes/:id/send` — send portal link to client (if created with `send: false`) - `POST /v1/intakes/:id/chase` — send manual reminder - `POST /v1/intakes/:id/approve` — approve intake in `pending_approval` state - `POST /v1/intakes/:id/revisions` — request item revision ### Templates - `GET /v1/templates` — list templates (`?public=true` for public only) - `POST /v1/templates` — create custom template - `GET /v1/templates/:slug` — get template - `DELETE /v1/templates/:slug` — delete custom template ### Webhooks - `POST /v1/webhooks` — register endpoint - `GET /v1/webhooks` — list registered endpoints - `DELETE /v1/webhooks/:id` — deregister - `POST /v1/webhooks/:id/test` — send synthetic test payload - `GET /v1/webhooks/:id/deliveries` — view delivery history ### Account and billing - `GET /v1/account` — get account info and settings - `PATCH /v1/account` — update settings (retention_days, secrets_ttl_days, etc.) - `GET /v1/usage` — current period usage vs limits - `POST /v1/billing/checkout` — start Stripe Checkout (params: `plan`, `period`) - `POST /v1/billing/portal` — get Stripe Customer Portal URL ### Secrets - `GET /v1/secrets/:token` — one-time reveal of secret item value - `GET /v1/audit` — audit log (params: `action`, `intake_id`, `client_email`) ### Portal (client-facing, no auth) - `GET /portal/:slug` — serve portal UI - `POST /portal/:slug/redeem` — exchange magic link token for session cookie ### Public (no auth) - `GET /pricing.json` — machine-readable plan limits and pricing - `GET /openapi.json` — OpenAPI 3.1 spec - `GET /healthz` — liveness - `GET /readyz` — readiness (DB + Redis) ## Item types All items share: `key` (string, unique in intake), `type`, `label`, `help` (optional), `optional` (bool, default false). | Type | Description | Key constraints | |---|---|---| | `text` | Single-line string | `max_chars`, `pattern` (regex), `min_chars` | | `longtext` | Multi-line string | `max_chars`, `min_chars` | | `image` | Single image file | `min_width`, `min_height`, `accept` (MIME list), `transparent_background` (bool) | | `file` | Single file of any type | `accept` (MIME list), `max_size_bytes` | | `file_list` | Multiple files | `min_files`, `max_files`, `accept`, `max_size_bytes` per file | | `url` | URL string with format validation | `pattern` | | `color` | Single hex color | — | | `color_list` | Multiple hex colors | `min_colors`, `max_colors` | | `select` | Enum choice | `options: [{value, label}]`, `multiple` (bool) | | `boolean` | True/false toggle | — | | `structured` | Object or array, rendered as form | `schema` (JSON Schema) | | `secret` | Encrypted credential, one-time reveal | Auto-expires 30d after submission (configurable) | ## Error codes | Code | HTTP status | Meaning | |---|---|---| | `invalid_request` | 400 | Malformed request body or missing required field | | `unauthorized` | 401 | Missing or invalid API key | | `forbidden` | 403 | Valid key but insufficient scope or ownership | | `not_found` | 404 | Resource does not exist | | `conflict` | 409 | Duplicate (e.g. template slug already exists) | | `gone` | 410 | Resource was deleted or secret already revealed | | `payload_too_large` | 413 | File or body exceeds size limit | | `unprocessable` | 422 | Valid JSON but fails business validation (e.g. min_width not met) | | `rate_limited` | 429 | Hourly request limit exceeded; check `Retry-After` header | | `quota_exceeded` | 402 | Plan limit reached (active intakes, storage) | | `plan_required` | 402 | Feature not available on current plan (e.g. secrets vault on Free) | | `internal_error` | 500 | Server error; retry with backoff; include `request_id` when reporting | All error responses include `error` (code string), `message` (human-readable), and `request_id`. ## Webhook events Signature header: `X-BriefGate-Signature: t=,v1=` Verify: `HMAC-SHA256(webhook_secret, "${t}.${rawBody}")`, tolerance 300s. | Event | Key payload fields | |---|---| | `item.submitted` | `intake_id`, `item_key`, `item_type`, `status: "submitted"`, `submitted_at` | | `intake.completed` | `intake_id`, `project_name`, `client_email`, `completed_at`, `items_count` | | `client.viewed` | `intake_id`, `client_email`, `viewed_at`, `ip` (hashed) | | `chase.bounced` | `intake_id`, `chase_id`, `channel`, `client_email`, `bounced_at`, `reason` | | `intake.stalled` | `intake_id`, `project_name`, `client_email`, `stalled_at`, `missing_items` (string[]) | Return HTTP 2xx to acknowledge. Return HTTP 410 to permanently deregister the endpoint. Retry schedule: immediate, +1m, +5m, +25m, +2h, +12h, +12h (7 attempts total). ## Rate limits | Tier | Requests per hour | |---|---| | Free | 60 | | Solo | 600 | | Agency | 3,000 | Rate limits are per API key (keys on the same account have independent counters). Test keys (`bg_test_`) use a separate bucket that does not consume production quota. Prefer webhooks over polling. A `rate_limited` 429 response includes `Retry-After` in seconds. If polling is required: Free — no more than once per 5 minutes; Solo — once per 30s; Agency — once per 12s. ## Chase schedules | Schedule | Reminders | |---|---| | `gentle` | T+3d, T+8d, then every 14 days. No weekends. | | `default` | T+2d, T+5d, T+9d, then weekly. | | `aggressive` | T+1d, T+3d, T+5d, then every other day. | | `off` | No automatic reminders. Manual `send_chase` only. | Reminders are held outside 8:00–19:00 client local time (based on `client.timezone`). ## Plans | Plan | Price | Active intakes | Items/intake | Storage | Rate limit | Secrets | Notes | |---|---|---|---|---|---|---|---| | Free | $0 | 1 | 10 | 1 GB | 60/h | No | "Powered by BriefGate" shown | | Solo | $29/mo | 15 | Unlimited | 25 GB | 600/h | Yes | Annual: $23.20/mo | | Agency | $79/mo | 60 | Unlimited | 100 GB | 3,000/h | Yes | 3 seats, SMS, custom domain. Annual: $63.20/mo | ## Full documentation - Webhooks: https://briefgate.dev/docs/webhooks - Chase engine: https://briefgate.dev/docs/chase - Secrets vault: https://briefgate.dev/docs/secrets - Client portal: https://briefgate.dev/docs/portal - Templates: https://briefgate.dev/docs/templates - Billing and plans: https://briefgate.dev/docs/billing - Rate limits: https://briefgate.dev/docs/rate-limits - GDPR and data privacy: https://briefgate.dev/docs/gdpr - Self-hosting: https://briefgate.dev/docs/self-hosting - Claude Code integration guide: https://briefgate.dev/docs/claude-code-client-intake ## Use-case guides (auto-generated) - BriefGate vs Content Snare: The Developer's Alternative: https://briefgate.dev/docs/content-snare-alternative.html - Client Intake for Claude Code: Collect Assets Without Leaving Your Agent: https://briefgate.dev/docs/claude-code-client-intake.html - How to Collect Client Assets with Claude Code: https://briefgate.dev/docs/client-assets-claude-code.html