Developers / API & MCP

Build on Focus Flow

Two ways in: connect your AI assistant in one click, or integrate with the REST API.
01

Connect Claude & ChatGPT — one click, no code

Focus Flow is an MCP server: your AI assistant can look at your real studio — clients, jobs, calendar, unpaid invoices — and act on it, with your permission. You sign in with your Focus Flow account; there are no keys to copy.

Add to Claude

  • In claude.ai: Settings → Connectors → Add custom connector
  • Paste the URL: https://focusflowstudio.app/api/mcp
  • Sign in with Focus Flow, pick your studio and what Claude may do, approve
  • Ask: “What shoots do I have this week?”

Add to ChatGPT

  • In ChatGPT: Settings → Connectors → Create (requires a plan with custom connectors)
  • Same URL: https://focusflowstudio.app/api/mcp — same Focus Flow sign-in

Safe by design

You choose per-connection which areas the assistant can touch (read CRM, read finances, send email…). Anything that leaves the studio — an email, a calendar event — first comes back as a preview to confirm: nothing is sent until you say so. You can revoke a connected assistant anytime from Settings → Integrations.

Available on every plan. On Starter, assistant actions share the monthly Flowy AI quota (50/month); Studio is unlimited.

02

Claude Code, Cursor & other MCP clients

Headless clients authenticate with a brand API key instead of the sign-in flow. Create one in Settings → Integrations → Focus Flow MCP, then point your client at the same URL with a Bearer header:

# Claude Code
claude mcp add --transport http focus-flow https://focusflowstudio.app/api/mcp \
  --header "Authorization: Bearer ffs_live_..."

# Any MCP client (generic config)
{
  "mcpServers": {
    "focus-flow": {
      "type": "http",
      "url": "https://focusflowstudio.app/api/mcp",
      "headers": { "Authorization": "Bearer ffs_live_..." }
    }
  }
}

The tool list is filtered by the key’s scopes — a read-only key never even sees send_email. 24 tools are exposed: studio overview, client/lead/job search, schedule and availability, gallery stats, unpaid invoices and revenue, price list, plus guarded actions (create lead, update job status, calendar events, email with two-step confirm).

03

REST API quickstart

Base URL https://focusflowstudio.app/api/v1. Create an API key in Settings → Integrations → Focus Flow MCP (it is shown once — store it like a password), then:

# 1. Verify the key — who am I?
curl https://focusflowstudio.app/api/v1/me \
  -H "Authorization: Bearer ffs_live_..."

# 2. List your clients
curl "https://focusflowstudio.app/api/v1/clients?limit=10" \
  -H "Authorization: Bearer ffs_live_..."

# 3. Create a lead (the API intake for new inquiries)
curl -X POST https://focusflowstudio.app/api/v1/leads \
  -H "Authorization: Bearer ffs_live_..." \
  -H "Content-Type: application/json" \
  -d '{"firstName":"Anna","lastName":"Rossi","email":"anna@example.com","phone":"+39 333 1234567"}'
04

Authentication & scopes

Every request carries Authorization: Bearer ffs_live_…. A key belongs to one brand: everything you read or write is scoped to that studio — the brandId can never be switched from the request body. Keys are stored hashed, can expire, and are revocable instantly from the panel.

ScopeGrants
crm:readRead clients, leads, jobs
crm:writeCreate/update clients and leads, update jobs
galleries:readRead galleries and their public share links
bookings:readRead booking requests
bookings:writeApprove / decline booking requests
calendar:readRead calendar events and availability
calendar:writeCreate/update calendar events
finance:readRead documents (quotes, invoices, contracts) and payments
catalog:readRead services, packages and pricing
email:sendSend email to your clients (explicit opt-in, never default)

Defaults at creation: all read scopes + crm:write. email:send and bookings:write are explicit opt-ins.

05

Responses & pagination

Every response uses the same envelope:

// success                                  // failure
{                                            {
  "success": true,                             "success": false,
  "data": { ... },                             "error": "human message",
  "meta": { "nextCursor": "...", "count": 25 } "code": "machine_code"
}                                            }

Lists are cursor-paginated: pass ?limit= (default 25, max 100) and feed meta.nextCursor back as ?cursor= until it comes back null. Cursors are opaque — never build one by hand. Entities are JSON objects in camelCase.

06

Endpoints

EndpointScopeNotes
GET /v1/meVerify a key: brand, scopes, plan and rate limits
GET·POST /v1/clients · GET·PATCH /v1/clients/{id}crm:read / crm:writeCRM clients
GET·POST /v1/leads · GET·PATCH /v1/leads/{id}crm:read / crm:writeLeads — POST is the API intake for new inquiries
GET /v1/jobs · GET·PATCH /v1/jobs/{id}crm:read / crm:writeJobs (created in-app; paidAmount is read-only)
GET /v1/galleries · GET /v1/galleries/{id}galleries:readGalleries with shareUrl for published ones
GET /v1/bookings · GET·PATCH /v1/bookings/{id}bookings:read / bookings:writeBooking requests — PATCH approves or declines
GET·POST /v1/calendar/events · GET·PATCH /v1/calendar/events/{id}calendar:read / calendar:writeCalendar with non-blocking conflict check on create
GET /v1/documents · GET /v1/documents/{id}finance:readQuotes, invoices, contracts (read-only)
GET /v1/paymentsfinance:readPayments (read-only)
GET /v1/services · GET /v1/packagescatalog:readPrice list: services and packages with items
POST /v1/emails/sendemail:sendEmail to your clients — max 2 recipients, GDPR consent enforced

Deliberate boundaries: bookings cannot be created via API (they are born in your public booking page — use POST /v1/leads for intake), lead conversion and job creation stay in the app, and galleries, documents and payments are read-only in v1.

07

Errors

StatusCodesWhat to do
400validation_error · invalid_json · invalid_cursorBad input; details lists field errors
401invalid_key · key_revoked · key_expiredFix or rotate the key in Settings → Integrations
403invalid_scope · access_revoked · recipient_not_client · recipients_blockedMissing scope, or email guardrails stopped the send
404not_foundResource does not exist in this brand
409duplicate_email · unsupported_transitionConflict with current state
422email_not_configuredSet up your sender in Settings → Email first
429rate_limitedRespect Retry-After and X-RateLimit-* headers
5xxinternal_error · email_send_failedRetry with backoff; contact us if it persists
08

Rate limits & plans

PlanREST APIMCP tool calls
Starter / Trial60 req/min · 5,000/dayShares the Flowy AI monthly quota (Starter 50/month, Trial unlimited)
Studio300 req/min · 25,000/dayUnlimited

Watch X-RateLimit-Limit / X-RateLimit-Remaining on every response; a 429 includes Retry-After.

09

OpenAPI reference

The full machine-readable spec lives at /api/v1/openapi.json (OpenAPI 3.1) — point your generator, Postman or your LLM at it. Prefer it browsable? Open the interactive reference.

Questions?

Write to us — integrations are a first-class feature, not an afterthought. If something in the API blocks you, we want to know.