{"openapi":"3.1.0","info":{"title":"gary.club Public API","version":"1.0.0","description":"REST + outbound webhooks for AI Agency Unlocked. Two key prefixes:\n  - `gc_live_…`  org-wide (agency)\n  - `cl_live_…`  bound to a single client\n\nUse `Authorization: Bearer <key>` on every request.\nAgency keys can pass `X-Gary-Client-Id: <client-uuid>` to act-as a specific client.\nKeys are full-access at their tenancy boundary — no scope catalog.","contact":{"name":"gary.club","url":"https://docs.gary.club/api"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://agency.gary.club/api/public/v1"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"gary-api-key","description":"Bearer token in the format `gc_live_…` (agency) or `cl_live_…` (client-bound)."}},"schemas":{"Error":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","description":"machine-readable error code"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}}},"ApiKeyIntrospection":{"type":"object","properties":{"api_key":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string"},"kind":{"type":"string","enum":["agency","client","legacy_sms"]},"rate_limit_per_minute":{"type":"integer"},"expires_at":{"type":["string","null"],"format":"date-time"},"tag":{"type":["string","null"]}}},"tenant":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"client_id":{"type":["string","null"],"format":"uuid"},"is_client_scoped":{"type":"boolean"}}}}},"Contact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid"},"full_name":{"type":["string","null"]},"first_name":{"type":["string","null"]},"last_name":{"type":["string","null"]},"title":{"type":["string","null"]},"lifecycle_stage":{"type":["string","null"]},"company_id":{"type":["string","null"],"format":"uuid"},"owner_user_id":{"type":["string","null"],"format":"uuid"},"tags":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Company":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"domain":{"type":["string","null"]},"website":{"type":["string","null"]},"industry":{"type":["string","null"]},"business_description":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"}}},"Deal":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"amount":{"type":["number","null"]},"currency":{"type":"string"},"stage_id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["open","won","lost"]},"owner_user_id":{"type":["string","null"],"format":"uuid"},"primary_contact_id":{"type":["string","null"],"format":"uuid"},"company_id":{"type":["string","null"],"format":"uuid"},"expected_close_date":{"type":["string","null"],"format":"date"},"tags":{"type":"array","items":{"type":"string"}},"custom_fields":{"type":"object","additionalProperties":true},"created_at":{"type":"string","format":"date-time"}}},"Activity":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"activity_type":{"type":"string"},"direction":{"type":["string","null"],"enum":["inbound","outbound","internal",null]},"contact_id":{"type":["string","null"],"format":"uuid"},"company_id":{"type":["string","null"],"format":"uuid"},"deal_id":{"type":["string","null"],"format":"uuid"},"subject":{"type":["string","null"]},"body":{"type":["string","null"]},"outcome":{"type":["string","null"]},"duration_seconds":{"type":["integer","null"]},"performed_at":{"type":"string","format":"date-time"}}},"Task":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"body":{"type":["string","null"]},"task_type":{"type":"string"},"priority":{"type":"string","enum":["low","normal","high","urgent"]},"assignee_user_id":{"type":["string","null"],"format":"uuid"},"due_at":{"type":["string","null"],"format":"date-time"},"status":{"type":"string","enum":["open","in_progress","completed","cancelled"]}}},"SmsConversation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"phone_number":{"type":"string"},"contact_id":{"type":["string","null"],"format":"uuid"},"status":{"type":"string"},"last_message_at":{"type":["string","null"],"format":"date-time"},"unread_count":{"type":"integer"},"total_messages":{"type":"integer"},"provider":{"type":"string"}}},"Call":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["inbound","outbound"]},"contact_phone":{"type":["string","null"]},"contact_name":{"type":["string","null"]},"agent_id":{"type":["string","null"],"format":"uuid"},"status":{"type":"string"},"disposition":{"type":["string","null"]},"recording_url":{"type":["string","null"]},"recording_duration_seconds":{"type":["integer","null"]},"created_at":{"type":"string","format":"date-time"}}},"Webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"active":{"type":"boolean"},"description":{"type":["string","null"]},"secret_last4":{"type":"string"},"consecutive_failures":{"type":"integer"},"disabled_at":{"type":["string","null"],"format":"date-time"}}}}},"security":[{"bearerAuth":[]}],"paths":{"/me":{"get":{"tags":["Auth"],"summary":"Introspect the current API key","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyIntrospection"}}}}}}},"/crm/contacts":{"get":{"tags":["CRM"],"summary":"List contacts","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}},{"name":"q","in":"query","schema":{"type":"string"}},{"name":"lifecycle","in":"query","schema":{"type":"string"}},{"name":"owner","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","next_page_token","limit"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"next_page_token":{"type":["string","null"]},"total":{"type":["integer","null"]},"limit":{"type":"integer"}}}}}}}},"post":{"tags":["CRM"],"summary":"Create or upsert a contact (idempotent by email or phone)","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"required":false,"description":"Optional. Replay-safe creation token. If you send the same key for a duplicate POST within 24h, you receive the original response and no duplicate side-effect occurs."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"phone":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"full_name":{"type":"string"},"title":{"type":"string"},"company_id":{"type":"string","format":"uuid"},"company_name":{"type":"string"},"source":{"type":"string"}}}}}},"responses":{"200":{"description":"Existing contact returned (no creation)"},"201":{"description":"Created"}}}},"/crm/contacts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["CRM"],"summary":"Read one contact","responses":{"200":{"description":"OK"},"404":{"description":"Not found"}}},"patch":{"tags":["CRM"],"summary":"Update contact fields","responses":{"200":{"description":"OK"}}},"delete":{"tags":["CRM"],"summary":"Soft-archive contact","responses":{"204":{"description":"Archived"}}}},"/crm/companies":{"get":{"tags":["CRM"],"summary":"List companies","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["CRM"],"summary":"Create or upsert a company","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"responses":{"201":{"description":"Created"}}}},"/crm/companies/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["CRM"],"summary":"Read one company","responses":{"200":{"description":"OK"}}},"patch":{"tags":["CRM"],"summary":"Update company","responses":{"200":{"description":"OK"}}},"delete":{"tags":["CRM"],"summary":"Archive company","responses":{"204":{"description":"Archived"}}}},"/crm/deals":{"get":{"tags":["CRM"],"summary":"List deals","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["CRM"],"summary":"Create a deal","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"required":false,"description":"Optional. Replay-safe creation token. If you send the same key for a duplicate POST within 24h, you receive the original response and no duplicate side-effect occurs."}],"responses":{"201":{"description":"Created"}}}},"/crm/deals/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["CRM"],"summary":"Read one deal","responses":{"200":{"description":"OK"}}},"patch":{"tags":["CRM"],"summary":"Update deal (PATCH stage_id fires deal.stage_changed webhook)","responses":{"200":{"description":"OK"}}},"delete":{"tags":["CRM"],"summary":"Archive deal","responses":{"204":{"description":"Archived"}}}},"/crm/contacts/{id}/phones":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["CRM"],"summary":"List phones attached to a contact","responses":{"200":{"description":"OK"}}},"post":{"tags":["CRM"],"summary":"Add a phone to a contact (idempotent on phone_e164)","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"required":false,"description":"Optional. Replay-safe creation token. If you send the same key for a duplicate POST within 24h, you receive the original response and no duplicate side-effect occurs."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phone"],"properties":{"phone":{"type":"string","description":"E.164 (+15551234567). Normalized server-side."},"phone_type":{"type":"string","enum":["mobile","work","home","other"]},"is_primary":{"type":"boolean","description":"If true, demotes any existing primary first."},"consent_status":{"type":"string","enum":["unknown","opt_in","opt_out","do_not_call"]},"consent_source":{"type":"string"},"consented_at":{"type":"string","format":"date-time"},"source":{"type":"string"}}}}}},"responses":{"200":{"description":"Idempotent — phone already attached"},"201":{"description":"Created"}}}},"/crm/contacts/{id}/phones/{phoneId}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"phoneId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["CRM"],"summary":"Read a single phone row","responses":{"200":{"description":"OK"}}},"patch":{"tags":["CRM"],"summary":"Update phone fields (consent, primary, type, status, DNC scope)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"phone_type":{"type":"string","enum":["mobile","work","home","other"]},"is_primary":{"type":"boolean"},"status":{"type":"string","enum":["unverified","verified","invalid"]},"consent_status":{"type":"string","enum":["unknown","opt_in","opt_out","do_not_call"]},"consent_source":{"type":"string"},"consented_at":{"type":"string","format":"date-time"},"dnc_scope":{"type":"string","enum":["individual","company","global"]}}}}}},"responses":{"200":{"description":"OK"}}},"delete":{"tags":["CRM"],"summary":"Hard-delete this phone row","responses":{"204":{"description":"Deleted"}}}},"/crm/contacts/{id}/emails":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["CRM"],"summary":"List emails attached to a contact","responses":{"200":{"description":"OK"}}},"post":{"tags":["CRM"],"summary":"Add an email to a contact (idempotent on lower(email))","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"required":false,"description":"Optional. Replay-safe creation token. If you send the same key for a duplicate POST within 24h, you receive the original response and no duplicate side-effect occurs."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"is_primary":{"type":"boolean"},"status":{"type":"string","enum":["unverified","verified","bounced"]},"source":{"type":"string"}}}}}},"responses":{"200":{"description":"Idempotent — email already attached"},"201":{"description":"Created"}}}},"/crm/contacts/{id}/emails/{emailId}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"emailId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["CRM"],"summary":"Read a single email row","responses":{"200":{"description":"OK"}}},"patch":{"tags":["CRM"],"summary":"Update email fields (primary, status)","responses":{"200":{"description":"OK"}}},"delete":{"tags":["CRM"],"summary":"Hard-delete this email row","responses":{"204":{"description":"Deleted"}}}},"/crm/activities":{"get":{"tags":["CRM"],"summary":"List activities (timeline)","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["CRM"],"summary":"Log a call/note/email/meeting/sms/task activity","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"required":false,"description":"Optional. Replay-safe creation token. If you send the same key for a duplicate POST within 24h, you receive the original response and no duplicate side-effect occurs."}],"responses":{"201":{"description":"Created"}}}},"/crm/activities/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["CRM"],"summary":"Read a single activity","responses":{"200":{"description":"OK"}}},"patch":{"tags":["CRM"],"summary":"Update mutable activity fields (subject, body, outcome, pinned, visibility, ...)","responses":{"200":{"description":"OK"}}},"delete":{"tags":["CRM"],"summary":"Hard-delete the activity row","responses":{"204":{"description":"Deleted"}}}},"/crm/tasks":{"get":{"tags":["CRM"],"summary":"List tasks","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["CRM"],"summary":"Create task","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"responses":{"201":{"description":"Created"}}}},"/crm/tasks/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["CRM"],"summary":"Read task","responses":{"200":{"description":"OK"}}},"patch":{"tags":["CRM"],"summary":"Update task (set completed=true to mark complete)","responses":{"200":{"description":"OK"}}},"delete":{"tags":["CRM"],"summary":"Delete task","responses":{"204":{"description":"Deleted"}}}},"/crm/lists":{"get":{"tags":["CRM"],"summary":"List CRM lists","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}}},"/crm/lists/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["CRM"],"summary":"Read a single list (incl. filter_branch for smart lists)","responses":{"200":{"description":"OK"}}},"patch":{"tags":["CRM"],"summary":"Rename, change processing_type, toggle exclusion flags","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"processing_type":{"type":"string","enum":["static","smart"]},"filter_branch":{"type":"object","additionalProperties":true,"description":"Smart-list criteria (only on processing_type=smart)"},"exclude_dnc":{"type":"boolean"},"exclude_unsubscribed":{"type":"boolean"},"exclude_archived":{"type":"boolean"},"emit_flow_triggers":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK"}}},"delete":{"tags":["CRM"],"summary":"Delete the list and cascade its members","responses":{"204":{"description":"Deleted"}}}},"/crm/lists/{id}/members":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["CRM"],"summary":"Bulk add members to a list (max 10,000 per call, chunked at 100)","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"contact_ids":{"type":"array","items":{"type":"string","format":"uuid"}}}},{"type":"object","properties":{"entity_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"entity_type":{"type":"string","enum":["contact","company","deal"]}}}]}}}},"responses":{"200":{"description":"OK"}}}},"/crm/lists/{id}/members/{entityId}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"delete":{"tags":["CRM"],"summary":"Remove a single member from a list","responses":{"204":{"description":"Removed"}}}},"/crm/pipelines":{"get":{"tags":["CRM"],"summary":"List pipelines + their stages","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"responses":{"200":{"description":"OK"}}}},"/sms/messages":{"post":{"tags":["SMS"],"summary":"Send an outbound SMS (deducts FUEL via the provider pipeline)","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to","body"],"properties":{"to":{"type":"string","description":"E.164 phone number"},"body":{"type":"string","maxLength":1600},"contact_id":{"type":"string","format":"uuid"},"company_id":{"type":"string","format":"uuid"},"deal_id":{"type":"string","format":"uuid"},"media_urls":{"type":"array","items":{"type":"string","format":"uri"}}}}}}},"responses":{"202":{"description":"Queued for delivery"},"402":{"description":"FUEL exhausted"}}}},"/sms/conversations":{"get":{"tags":["SMS"],"summary":"List SMS conversations","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}}},"/sms/conversations/{id}/messages":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["SMS"],"summary":"List messages within a conversation","responses":{"200":{"description":"OK"}}}},"/calls":{"get":{"tags":["Voice"],"summary":"List phone calls","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Voice"],"summary":"Initiate an outbound call (Phase 1.5 — currently returns 403 with status note)","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"responses":{"403":{"description":"Outbound dial trigger ships in Phase 1.5"}}}},"/calls/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["Voice"],"summary":"Read full call detail with transcript","responses":{"200":{"description":"OK"}}}},"/agents":{"get":{"tags":["Agents"],"summary":"List agents with multi-agent identity fields","description":"Returns agents in the caller's tenant scope, with kind, slug, purpose, labels, state. Filterable by client_id, kind, purpose, label, state, and free-text q.","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}},{"name":"client_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"kind","in":"query","schema":{"type":"string","enum":["inbound_voice","outbound_voice","sms","google_my_business"]}},{"name":"purpose","in":"query","schema":{"type":"string"}},{"name":"label","in":"query","schema":{"type":"string"}},{"name":"state","in":"query","schema":{"type":"string","enum":["active","paused","archived"]}},{"name":"q","in":"query","schema":{"type":"string"},"description":"Free-text search across name, slug, purpose"}],"responses":{"200":{"description":"OK"}}}},"/agents/{idOrSlug}":{"parameters":[{"name":"idOrSlug","in":"path","required":true,"schema":{"type":"string"},"description":"Agent UUID or slug (e.g. agent_3kf9ab). Past slugs (renamed) auto-redirect via agent_aliases."},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["Agents"],"summary":"Get agent detail by UUID or slug","responses":{"200":{"description":"OK"},"404":{"description":"Agent not found in this org"},"410":{"description":"Agent is archived (alias still resolves but agent is not callable)"}}},"patch":{"tags":["Agents"],"summary":"Update agent identity (purpose, labels, state, slug, name)","description":"Slug renames preserve the old slug as an alias for ~12 months so existing integrations keep working.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"slug":{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{2,63}$"},"purpose":{"type":"string","maxLength":64,"nullable":true},"labels":{"type":"array","items":{"type":"string","maxLength":32},"maxItems":16},"state":{"type":"string","enum":["active","paused","archived"]},"location_label":{"type":"string","maxLength":80,"nullable":true},"greeting":{"type":"string","maxLength":4000},"voice_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated"},"400":{"description":"Validation error (invalid slug, immutable kind, etc.)"},"404":{"description":"Agent not found"},"409":{"description":"Slug collision"}}}},"/ai/contacts/{id}/gist":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["AI"],"summary":"AI-generated contact gist (1 FUEL on miss, 0 on cache hit)","parameters":[{"name":"force","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK"},"402":{"description":"FUEL exhausted"}}}},"/ai/companies/{id}/gist":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["AI"],"summary":"AI-generated company gist (1 FUEL on miss, 0 on cache hit)","parameters":[{"name":"force","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK"},"402":{"description":"FUEL exhausted"}}}},"/ai/deals/{id}/gist":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["AI"],"summary":"AI-generated deal gist (1 FUEL on miss, 0 on cache hit)","parameters":[{"name":"force","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK"},"402":{"description":"FUEL exhausted"}}}},"/kb":{"get":{"tags":["KB"],"summary":"List knowledge bases","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"responses":{"200":{"description":"OK"}}}},"/kb/{id}/documents":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}}],"get":{"tags":["KB"],"summary":"List documents in a knowledge base","responses":{"200":{"description":"OK"}}},"post":{"tags":["KB"],"summary":"Add a manual / URL / uploaded document (async ingest)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","source_type"],"properties":{"title":{"type":"string","maxLength":200},"source_type":{"type":"string","enum":["manual","url","upload"]},"content":{"type":"string","description":"Required when source_type=manual; up to 200,000 chars"},"source_url":{"type":"string","format":"uri","description":"Required when source_type=url"},"storage_path":{"type":"string","format":"uri","description":"Required when source_type=upload — must be R2 URL under your org prefix"},"mime_type":{"type":"string"},"byte_size":{"type":"integer"}}}}}},"responses":{"201":{"description":"Created (status=pending; ingestion begins async)"}}}},"/kb/{id}/documents/{docId}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"docId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["KB"],"summary":"Read a single document with ingestion status","responses":{"200":{"description":"OK"},"404":{"description":"Not found"}}},"delete":{"tags":["KB"],"summary":"Soft-delete (chunks removed by cleanup cron)","responses":{"200":{"description":"OK"}}}},"/sequences":{"get":{"tags":["Sequences"],"summary":"List message sequences","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","active","paused","archived"]}}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Sequences"],"summary":"Create a new message sequence (draft by default)","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"required":false,"description":"Optional. Replay-safe creation token. If you send the same key for a duplicate POST within 24h, you receive the original response and no duplicate side-effect occurs."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":200},"description":{"type":"string"},"status":{"type":"string","enum":["draft","active"],"default":"draft"},"steps":{"type":"array","items":{"type":"object"},"description":"Step ladder (channel + delay + body)"},"sender_user_id":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Created"}}}},"/sequences/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["Sequences"],"summary":"Read one sequence (includes steps ladder)","responses":{"200":{"description":"OK"},"404":{"description":"Not found"}}},"patch":{"tags":["Sequences"],"summary":"Rename, edit steps, or change status (active/paused/archived)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"status":{"type":"string","enum":["draft","active","paused","archived"]},"steps":{"type":"array","items":{"type":"object"}},"sender_user_id":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"OK"}}},"delete":{"tags":["Sequences"],"summary":"Archive sequence (status=archived); pauses all in-flight enrollments","responses":{"204":{"description":"Archived"}}}},"/sequences/{id}/enrollments":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["Sequences"],"summary":"List enrollments for a sequence","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["active","paused","completed","cancelled"]}}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Sequences"],"summary":"Enroll a contact (idempotent on active enrollment)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contact_id"],"properties":{"contact_id":{"type":"string","format":"uuid"},"metadata":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"Existing enrollment returned (idempotent: true)"},"201":{"description":"New enrollment created"},"404":{"description":"Sequence or contact not found in tenant"},"422":{"description":"Sequence archived or contact archived"}}}},"/sequences/{id}/enrollments/{enrollmentId}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"enrollmentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["Sequences"],"summary":"Read a single enrollment","responses":{"200":{"description":"OK"}}},"patch":{"tags":["Sequences"],"summary":"Pause / resume / cancel an enrollment, or advance the cursor","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","paused","cancelled"]},"paused_reason":{"type":"string"},"current_step":{"type":"integer","minimum":0},"next_run_at":{"type":"string","format":"date-time"},"metadata":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"OK"}}},"delete":{"tags":["Sequences"],"summary":"Unenroll the contact (status=cancelled). Emits sequence.contact_unenrolled.","responses":{"204":{"description":"Unenrolled"}}}},"/billing/balance":{"get":{"tags":["Billing"],"summary":"Current FUEL balance + subscription state","responses":{"200":{"description":"OK"}}}},"/billing/usage":{"get":{"tags":["Billing"],"summary":"Aggregated FUEL consumption by service_type","parameters":[{"name":"from","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"OK"},"400":{"description":"Invalid date range (max 365 days)"}}}},"/billing/transactions":{"get":{"tags":["Billing"],"summary":"Paginated FUEL transaction ledger","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}},{"name":"type","in":"query","schema":{"type":"string","enum":["subscription_credit","auto_reload","manual_topup","consumption","expiration","forfeiture","adjustment","chargeback_reversal","package_switch"]}},{"name":"service_type","in":"query","schema":{"type":"string"}},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"OK"}}}},"/sdr/campaigns":{"get":{"tags":["SDR"],"summary":"List outbound SDR campaigns","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","scheduled","active","paused","completed","cancelled","archived"]}}],"responses":{"200":{"description":"OK"},"403":{"description":"Client-scoped key (SDR is agency-only)"}}},"post":{"tags":["SDR"],"summary":"Create an outbound voice SDR campaign","responses":{"201":{"description":"Created"},"403":{"description":"Feature disabled or client-scoped key"},"422":{"description":"No inbound SDR provisioned for org"}}}},"/sdr/campaigns/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["SDR"],"summary":"Read one campaign","responses":{"200":{"description":"OK"},"404":{"description":"Not found"}}},"patch":{"tags":["SDR"],"summary":"Update / pause / resume","responses":{"200":{"description":"OK"}}},"delete":{"tags":["SDR"],"summary":"Archive (does NOT cancel in-flight dials — pause first)","responses":{"204":{"description":"Archived"}}}},"/sdr/prospects":{"get":{"tags":["SDR"],"summary":"List prospects (org-scoped only — 403 for client-scope keys)","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}},{"name":"campaign_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","schema":{"type":"string","description":"pending|queued|called|booked|do_not_call|exhausted"}},{"name":"q","in":"query","schema":{"type":"string","description":"Free-text on name/phone/company"}}],"responses":{"200":{"description":"OK"},"403":{"description":"Client-scoped key not allowed"}}},"post":{"tags":["SDR"],"summary":"Create a prospect","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"required":false,"description":"Optional. Replay-safe creation token. If you send the same key for a duplicate POST within 24h, you receive the original response and no duplicate side-effect occurs."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["campaign_id","phone"],"properties":{"campaign_id":{"type":"string","format":"uuid"},"phone":{"type":"string","description":"E.164 (+15551234567)."},"first_name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string","format":"email"},"company":{"type":"string"},"title":{"type":"string"},"notes":{"type":"string"},"dedup":{"type":"boolean","description":"If true and a prospect with this phone exists in the campaign, returns existing instead of erroring."}}}}}},"responses":{"200":{"description":"Existing prospect returned (dedup match)"},"201":{"description":"Created"},"403":{"description":"Client-scoped key not allowed"}}}},"/sdr/prospects/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["SDR"],"summary":"Read prospect","responses":{"200":{"description":"OK"},"404":{"description":"Not found"}}},"patch":{"tags":["SDR"],"summary":"Update mutable fields incl. status and DNC flags","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"first_name":{"type":"string","nullable":true},"last_name":{"type":"string","nullable":true},"email":{"type":"string","format":"email","nullable":true},"company":{"type":"string","nullable":true},"title":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"status":{"type":"string","description":"pending | queued | called | booked | do_not_call | exhausted"},"dnc_scope":{"type":"string","enum":["individual","company","global"]},"dnc_source":{"type":"string"}}}}}},"responses":{"200":{"description":"OK"}}},"delete":{"tags":["SDR"],"summary":"Hard-delete the prospect row (prefer status=do_not_call)","responses":{"204":{"description":"Deleted"}}}},"/sms-broadcasts":{"get":{"tags":["SMS Broadcasts"],"summary":"List broadcasts","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}},{"name":"agent_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","scheduled","pending_approval","approved","sending","completed","cancelled"]}}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["SMS Broadcasts"],"summary":"Create a one-shot, scheduled, or recurring broadcast","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id","name","body"],"properties":{"client_id":{"type":"string","format":"uuid","description":"Required for agency keys without X-Gary-Client-Id"},"agent_id":{"type":"string","format":"uuid"},"list_id":{"type":"string","format":"uuid"},"smart_list_slug":{"type":"string"},"name":{"type":"string","maxLength":200},"body":{"type":"string","maxLength":1600},"media_urls":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":10},"schedule_mode":{"type":"string","enum":["one_shot","scheduled","recurring"],"default":"one_shot"},"scheduled_at":{"type":"string","format":"date-time"},"recurrence_rule":{"type":"string"},"recurrence_timezone":{"type":"string","default":"UTC"}}}}}},"responses":{"201":{"description":"Created"},"404":{"description":"Client / agent / list not found"},"422":{"description":"agent_id does not belong to client_id"}}}},"/sms-broadcasts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["SMS Broadcasts"],"summary":"Read one broadcast with stats","responses":{"200":{"description":"OK"}}},"patch":{"tags":["SMS Broadcasts"],"summary":"Update mutable fields (only while draft / scheduled)","responses":{"200":{"description":"OK"}}}},"/sms-broadcasts/{id}/approve":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["SMS Broadcasts"],"summary":"Approve a broadcast that requires sign-off","responses":{"200":{"description":"OK"}}}},"/sms-broadcasts/{id}/send-now":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["SMS Broadcasts"],"summary":"Force-send immediately","responses":{"202":{"description":"Queued"}}}},"/sms-broadcasts/{id}/recipients":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["queued","sent","delivered","failed","opted_out"]}}],"get":{"tags":["SMS Broadcasts"],"summary":"Per-recipient delivery state","responses":{"200":{"description":"OK"}}}},"/voice/broadcasts":{"get":{"tags":["Voice Broadcasts"],"summary":"List voice broadcasts","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}},{"name":"agent_id","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","scheduled","running","paused","completed","cancelled","expired","failed"]}},{"name":"source_type","in":"query","schema":{"type":"string","enum":["csv","crm_list","api","webhook"]}}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Voice Broadcasts"],"summary":"Create an outbound voice broadcast","description":"Source types: csv | crm_list | api | webhook. Inline recipients accept our `recipients[]`, Bland-style `calls[]`, and Vapi-style `customers[]`. Created in draft unless `auto_launch=true`.","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"required":false,"description":"Optional. Replay-safe creation token. If you send the same key for a duplicate POST within 24h, you receive the original response and no duplicate side-effect occurs."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id","name"],"properties":{"agent_id":{"type":"string","description":"Agent slug or UUID — must be an outbound voice agent"},"client_id":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":200},"description":{"type":"string"},"source_type":{"type":"string","enum":["csv","crm_list","api","webhook"],"default":"csv"},"source_mode":{"type":"string","enum":["snapshot","live"],"default":"snapshot"},"source_config":{"type":"object","additionalProperties":true},"recipients":{"type":"array","items":{"type":"object","properties":{"phone":{"type":"string"},"to_number":{"type":"string"},"variables":{"type":"object","additionalProperties":true},"external_id":{"type":"string"},"metadata":{"type":"object","additionalProperties":true}}}},"calls":{"type":"array","description":"Bland-style alias for recipients","items":{"type":"object"}},"customers":{"type":"array","description":"Vapi-style alias for recipients","items":{"type":"object"}},"system_prompt_override":{"type":"string"},"opening_message_override":{"type":"string"},"voicemail_message":{"type":"string"},"voicemail_action":{"type":"string","enum":["hang_up","leave_message","ignore"]},"from_number":{"type":"string"},"voice_id":{"type":"string"},"schedule_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"},"timezone":{"type":"string","default":"America/Los_Angeles"},"calling_window":{"type":"object","properties":{"start":{"type":"string","description":"HH:MM"},"end":{"type":"string","description":"HH:MM"},"days":{"type":"array","items":{"type":"string"}}}},"retry_config":{"type":"object","properties":{"max_attempts":{"type":"integer","minimum":1,"maximum":10},"wait_minutes":{"type":"integer","minimum":1},"on":{"type":"array","items":{"type":"string"}}}},"max_concurrent":{"type":"integer","minimum":1,"maximum":50},"variable_schema":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"required":{"type":"boolean"},"example":{"type":"string"},"description":{"type":"string"}}}},"analysis_schema":{"type":"object","additionalProperties":true},"metadata":{"type":"object","additionalProperties":true},"webhook_url":{"type":"string","format":"uri"},"result_webhook_url":{"type":"string","format":"uri"},"result_webhook_secret":{"type":"string"},"result_webhook_events":{"type":"array","items":{"type":"string"}},"intake_rate_limit_per_minute":{"type":"integer","minimum":1},"tcpa_consent_acknowledged":{"type":"boolean"},"auto_launch":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Created"},"400":{"description":"Validation error"},"403":{"description":"client_id mismatch with API key scope"}}}},"/voice/broadcasts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["Voice Broadcasts"],"summary":"Read one broadcast","responses":{"200":{"description":"OK"},"404":{"description":"Not found"}}},"patch":{"tags":["Voice Broadcasts"],"summary":"Update editable fields","description":"Editable while non-terminal: name, description, expires_at, calling_window, retry_config, max_concurrent, variable_schema, analysis_schema, system_prompt_override, opening_message_override, voicemail_message, voice_id, result_webhook_url, result_webhook_events, metadata.","responses":{"200":{"description":"OK"},"409":{"description":"Broadcast is in a terminal state"}}}},"/voice/broadcasts/{id}/launch":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["Voice Broadcasts"],"summary":"Transition draft → running and seed the dispatcher","responses":{"200":{"description":"OK"}}}},"/voice/broadcasts/{id}/pause":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["Voice Broadcasts"],"summary":"Pause a running broadcast","responses":{"200":{"description":"OK"}}}},"/voice/broadcasts/{id}/resume":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["Voice Broadcasts"],"summary":"Resume a paused broadcast","responses":{"200":{"description":"OK"}}}},"/voice/broadcasts/{id}/cancel":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["Voice Broadcasts"],"summary":"Cancel a broadcast (terminal)","responses":{"200":{"description":"OK"}}}},"/voice/broadcasts/{id}/test-call":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["Voice Broadcasts"],"summary":"Fire a non-billable test call against the broadcast script","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to_number"],"properties":{"to_number":{"type":"string","description":"E.164 number to dial"},"variables":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"Test call dispatched"},"400":{"description":"to_number required"}}}},"/voice/broadcasts/{id}/recipients":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["Voice Broadcasts"],"summary":"List recipients with delivery state","parameters":[{"name":"status","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Voice Broadcasts"],"summary":"Bulk-add recipients","description":"Idempotent on (broadcast_id, to_number). Backend chunks at 100; client should chunk larger lists.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["recipients"],"properties":{"recipients":{"type":"array","minItems":1,"items":{"type":"object","properties":{"phone":{"type":"string"},"to_number":{"type":"string"},"variables":{"type":"object","additionalProperties":true},"external_id":{"type":"string"},"metadata":{"type":"object","additionalProperties":true},"timezone":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"OK"},"400":{"description":"recipients[] required"}}}},"/voice/broadcasts/{id}/recipients/{rid}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"rid","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"delete":{"tags":["Voice Broadcasts"],"summary":"Remove a single pending recipient","description":"Refused if the recipient has already been dialed.","responses":{"204":{"description":"Removed"},"409":{"description":"Already dialed"}}}},"/voice/broadcasts/{id}/calls":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"page_token","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"}}],"get":{"tags":["Voice Broadcasts"],"summary":"Paged list of dial attempts","responses":{"200":{"description":"OK"}}}},"/voice/broadcasts/{id}/csv":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"post":{"tags":["Voice Broadcasts"],"summary":"Upload a CSV of recipients","description":"multipart/form-data with `file` (CSV) and `mapping` (JSON {phone_column, variable_columns?, external_id_column?, timezone_column?}). Server parses + chunks to /recipients in batches of 100.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","mapping"],"properties":{"file":{"type":"string","format":"binary"},"mapping":{"type":"string","description":"JSON-encoded ColumnMapping"}}}}}},"responses":{"200":{"description":"Upload processed"},"400":{"description":"Validation error"}}}},"/voice/broadcasts/{id}/intake-credentials":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"get":{"tags":["Voice Broadcasts"],"summary":"Reveal intake URL + HMAC secret (webhook source only)","description":"Returns the secret in plain text on every read. Refused if source_type !== webhook.","responses":{"200":{"description":"OK"},"400":{"description":"Not a webhook source"}}}},"/voice/broadcasts/intake/{token}":{"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["Voice Broadcasts"],"summary":"HMAC-signed public intake — append a single recipient to a webhook-source broadcast","description":"Requires X-Voice-Broadcast-Signature header (HMAC-SHA256 over raw body, hex). The broadcast must be source_type=webhook. Body shape mirrors a single recipient {to_number, variables?, external_id?, metadata?, timezone?}.","security":[],"responses":{"202":{"description":"Accepted"},"401":{"description":"Bad signature"},"404":{"description":"Token unknown"},"410":{"description":"Broadcast expired"},"429":{"description":"Rate limit exceeded"}}}},"/voice/defaults":{"get":{"tags":["Voice Broadcasts"],"summary":"Resolve effective voice-broadcast defaults","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"scope","in":"query","schema":{"type":"string","enum":["agency","client"]}},{"name":"client_id","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}},"put":{"tags":["Voice Broadcasts"],"summary":"Upsert defaults at the requested scope","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"scope","in":"query","required":true,"schema":{"type":"string","enum":["agency","client"]}},{"name":"client_id","in":"query","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"voice_id":{"type":"string","nullable":true},"calling_window":{"type":"object","nullable":true},"retry_config":{"type":"object","nullable":true},"voicemail_message":{"type":"string","nullable":true},"opening_message":{"type":"string","nullable":true},"expires_after_days":{"type":"integer","nullable":true},"analysis_schema":{"type":"object","nullable":true},"result_webhook_url":{"type":"string","format":"uri","nullable":true},"result_webhook_events":{"type":"array","items":{"type":"string"},"nullable":true},"max_concurrent":{"type":"integer","nullable":true}}}}}},"responses":{"200":{"description":"OK"}}},"delete":{"tags":["Voice Broadcasts"],"summary":"Clear defaults at the requested scope","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."},{"name":"scope","in":"query","required":true,"schema":{"type":"string","enum":["agency","client"]}},{"name":"client_id","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Cleared"}}}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List outbound webhook subscriptions","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Webhooks"],"summary":"Create a webhook subscription. Returns the signing secret ONCE.","parameters":[{"name":"X-Gary-Client-Id","in":"header","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional. When using a `gc_live_` agency-scope key, set this to act as a specific client. Rejected on client-bound `cl_live_` keys with 400 invalid_request."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["call.received","call.answered","call.completed","call.voicemail_left","call.failed","sms.received","sms.sent","sms.delivery_failed","contact.created","contact.updated","contact.archived","company.created","company.updated","company.archived","deal.created","deal.updated","deal.stage_changed","deal.won","deal.lost","deal.archived","task.created","task.updated","task.due_soon","task.completed","task.archived","activity.logged","list.member_added","list.member_removed","voice_broadcast.created","voice_broadcast.queued","voice_broadcast.started","voice_broadcast.paused","voice_broadcast.resumed","voice_broadcast.completed","voice_broadcast.cancelled","voice_broadcast.expired","voice_broadcast.recipient.added","voice_broadcast.recipient.rejected","voice_broadcast.call.queued","voice_broadcast.call.dialing","voice_broadcast.call.started","voice_broadcast.call.completed","voice_broadcast.call.voicemail_left","voice_broadcast.call.no_answer","voice_broadcast.call.failed","sequence.contact_enrolled","sequence.completed","sequence.contact_unenrolled","sms_broadcast.created","sms_broadcast.updated","sms_broadcast.approved","sms_broadcast.dispatched","sms_broadcast.archived","sdr.campaign.created","sdr.campaign.started","sdr.campaign.paused","sdr.campaign.completed","sdr.outbound.completed","agent.updated","agent.archived","ai.precall_brief.completed","ai.lead_enrichment.completed","ai.kb_ingest.completed","ai.job.failed","webhook.test","*"]},"description":"Use [\"*\"] to subscribe to all events"},"description":{"type":"string"},"client_id":{"type":"string","format":"uuid"},"active":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Created. Stash `secret` immediately — it is shown once."}}}},"/webhooks/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Webhooks"],"summary":"Read webhook subscription","responses":{"200":{"description":"OK"}}},"patch":{"tags":["Webhooks"],"summary":"Update events / active / rotate secret","responses":{"200":{"description":"OK"}}},"delete":{"tags":["Webhooks"],"summary":"Delete subscription (cascades deliveries)","responses":{"204":{"description":"Deleted"}}}},"/webhooks/{id}/test":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Webhooks"],"summary":"Fire a webhook.test event","responses":{"202":{"description":"Queued"}}}},"/webhooks/{id}/deliveries":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Webhooks"],"summary":"Recent delivery attempts (debugging)","responses":{"200":{"description":"OK"}}}},"/webhooks/{id}/deliveries/{deliveryId}/replay":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Webhooks"],"summary":"Replay a single failed/dead delivery (resets status=pending; cumulative attempts preserved)","responses":{"202":{"description":"Queued for redelivery"},"404":{"description":"Webhook or delivery not found"},"422":{"description":"Webhook is disabled or already in pending state"}}}},"/docs/products":{"get":{"tags":["Docs"],"summary":"List doc products","description":"Public, no auth required. Lists products gary.club ships docs for.","security":[],"responses":{"200":{"description":"OK"}}}},"/docs/pages":{"get":{"tags":["Docs"],"summary":"List doc pages by product (titles + slugs only — no body)","description":"Public, no auth required.","security":[],"parameters":[{"name":"product","in":"query","required":true,"schema":{"type":"string","enum":["ai-agency-unlocked","gary-club-ecosystem"]}},{"name":"category","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"OK"}}}},"/docs/pages/{slug}":{"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"product","in":"query","schema":{"type":"string","enum":["ai-agency-unlocked","gary-club-ecosystem"]}}],"get":{"tags":["Docs"],"summary":"Fetch a single doc page (full body)","description":"Public, no auth required. Returns content_html + content_text.","security":[],"responses":{"200":{"description":"OK"},"404":{"description":"Not found"}}}},"/docs/search":{"get":{"tags":["Docs"],"summary":"Full-text search across doc pages","description":"Public, no auth required. Returns ranked previews; fetch full bodies via /docs/pages/{slug}.","security":[],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"product","in":"query","schema":{"type":"string","enum":["ai-agency-unlocked","gary-club-ecosystem"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":10}}],"responses":{"200":{"description":"OK"}}}},"/docs/changelog":{"get":{"tags":["Docs"],"summary":"Recent changelog entries","description":"Public, no auth required. Newest first.","security":[],"parameters":[{"name":"product","in":"query","schema":{"type":"string","enum":["ai-agency-unlocked","gary-club-ecosystem"]}},{"name":"type","in":"query","schema":{"type":"string","enum":["feature","improvement","fix","breaking","deprecation"]}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"OK"}}}}}}