{"openapi":"3.0.3","info":{"title":"SignalKit API","version":"1.0.0","description":"API for tracking brand visibility across LLM platforms (ChatGPT, Claude, Gemini, Perplexity, and more). All data routes are scoped to a project. Specify the active project via the X-Project-Id header or ?projectId query parameter. If omitted, the user's default project is used."},"servers":[{"url":"https://signalkit.ai","description":"Production"}],"components":{"securitySchemes":{"cookieAuth":{"type":"apiKey","in":"cookie","name":"sb-access-token","description":"Supabase session cookie (set automatically after login)."},"apiKeyAuth":{"type":"http","scheme":"bearer","description":"API key created via the /api/api-keys endpoint. Use as: Authorization: Bearer sk_live_..."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"}}}},"parameters":{"projectId":{"name":"X-Project-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Project to scope the request to. If omitted, the user's default project is used. Can also be passed as ?projectId query parameter."}}},"security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"paths":{"/api/prompts":{"get":{"tags":["Prompts"],"summary":"List prompts","description":"Return all prompts belonging to the authenticated user, ordered by creation date descending.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"responses":{"200":{"description":"Array of prompt objects.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Prompt"}}}}},"401":{"description":"Unauthorized."}}},"post":{"tags":["Prompts"],"summary":"Create a prompt","description":"Create a new tracking prompt. The prompt will be queried against the configured LLMs on the next scheduled run.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","description":"The prompt text to track."},"category":{"type":"string","nullable":true,"description":"Optional category (e.g. 'product', 'support')."},"tags":{"type":"array","items":{"type":"string"},"description":"Optional tags for filtering."},"location":{"type":"string","default":"US","description":"ISO country code for geo-targeting."},"language":{"type":"string","default":"en","description":"Language code."},"llmsToQuery":{"type":"array","items":{"type":"string"},"default":["chatgpt","perplexity","gemini"],"description":"LLM platforms to query."}}}}}},"responses":{"201":{"description":"Prompt created."},"400":{"description":"Validation error or prompt limit reached."},"401":{"description":"Unauthorized."}}}},"/api/prompts/{id}":{"get":{"tags":["Prompts"],"summary":"Get prompt by ID","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Prompt object."},"404":{"description":"Not found."}}},"patch":{"tags":["Prompts"],"summary":"Update a prompt","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"},"category":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean"},"location":{"type":"string"},"language":{"type":"string"},"llmsToQuery":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Updated prompt."},"404":{"description":"Not found."}}},"delete":{"tags":["Prompts"],"summary":"Delete a prompt","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"Not found."}}}},"/api/projects":{"get":{"tags":["Projects"],"summary":"List projects","description":"Return all projects belonging to the authenticated user.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"responses":{"200":{"description":"Array of project objects."},"401":{"description":"Unauthorized."}}},"post":{"tags":["Projects"],"summary":"Create a project","description":"Create a new project (website/brand). Each project has its own billing, prompts, and brands.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Project name."},"domain":{"type":"string","nullable":true,"description":"Website domain (e.g. example.com)."}}}}}},"responses":{"201":{"description":"Project created."},"400":{"description":"Validation error."},"401":{"description":"Unauthorized."}}}},"/api/projects/bulk":{"post":{"tags":["Projects"],"summary":"Create up to 25 projects in one call","description":"Bulk-create projects, each optionally including inline brands and prompts. Designed for onboarding scripts. Returns both `created` and `errors` arrays — partial success returns 207. API-key callers bypass the count caps; the model tier still applies to inline prompts.","security":[{"apiKeyAuth":[]},{"cookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["projects"],"properties":{"projects":{"type":"array","maxItems":25,"items":{"type":"object","required":["name","domain"],"properties":{"name":{"type":"string"},"domain":{"type":"string"},"brands":{"type":"array","items":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"domain":{"type":"string","nullable":true},"aliases":{"type":"array","items":{"type":"string"}},"isCompetitor":{"type":"boolean"}}}},"prompts":{"type":"array","items":{"type":"object","required":["text"],"properties":{"text":{"type":"string"},"category":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"}},"location":{"type":"string"},"language":{"type":"string"},"llmsToQuery":{"type":"array","items":{"type":"string"}}}}}}}}}}}}},"responses":{"201":{"description":"All projects created."},"207":{"description":"Partial success — some projects created, some failed. See errors[]."},"400":{"description":"All projects failed validation, or batch too large."},"401":{"description":"Unauthorized."},"403":{"description":"Plan cap or API-key scope forbids creation."}}}},"/api/api-keys/me":{"get":{"tags":["API Keys"],"summary":"Introspect the calling API key","description":"Returns the calling key's scope, capabilities, plan, allowed LLM models, and visible projects. Lets scripts validate before doing destructive ops.","security":[{"apiKeyAuth":[]}],"responses":{"200":{"description":"Key context."},"401":{"description":"Not an API-key authed request."}}}},"/api/projects/{id}":{"get":{"tags":["Projects"],"summary":"Get project by ID","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Project object."},"404":{"description":"Not found."}}},"patch":{"tags":["Projects"],"summary":"Update a project","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"domain":{"type":"string","nullable":true},"logoUrl":{"type":"string","nullable":true},"isActive":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated project."},"404":{"description":"Not found."}}},"delete":{"tags":["Projects"],"summary":"Delete a project","description":"Delete a project. Cannot delete the default project.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted."},"400":{"description":"Cannot delete default project."},"404":{"description":"Not found."}}}},"/api/brands":{"get":{"tags":["Brands"],"summary":"List tracked brands","description":"Return all tracked brands (own brand and competitors) for the authenticated user.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"responses":{"200":{"description":"Array of brand objects."},"401":{"description":"Unauthorized."}}},"post":{"tags":["Brands"],"summary":"Add a tracked brand","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"domain":{"type":"string","nullable":true},"aliases":{"type":"array","items":{"type":"string"},"description":"Alternative names for matching."},"isOwnBrand":{"type":"boolean","default":false},"isCompetitor":{"type":"boolean","default":false}}}}}},"responses":{"201":{"description":"Brand created."},"400":{"description":"Validation error or competitor limit reached."},"401":{"description":"Unauthorized."}}}},"/api/alerts":{"get":{"tags":["Alerts"],"summary":"List alerts","description":"Return alerts for the authenticated user, with optional filtering.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":100}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}},{"name":"isRead","in":"query","schema":{"type":"boolean"},"description":"Filter by read/unread status."}],"responses":{"200":{"description":"Array of alert objects."},"401":{"description":"Unauthorized."}}}},"/api/reports":{"get":{"tags":["Reports"],"summary":"List reports","description":"Return all generated reports for the authenticated user.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"responses":{"200":{"description":"Array of report metadata objects."},"401":{"description":"Unauthorized."}}},"post":{"tags":["Reports"],"summary":"Generate a report","description":"Generate a new visibility, prompt, or competitor report for the given date range and format.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","format","periodStart","periodEnd"],"properties":{"type":{"type":"string","enum":["visibility","prompt","competitor"]},"format":{"type":"string","enum":["csv","json","pdf"]},"periodStart":{"type":"string","format":"date","description":"Start date (YYYY-MM-DD)."},"periodEnd":{"type":"string","format":"date","description":"End date (YYYY-MM-DD)."}}}}}},"responses":{"201":{"description":"Report metadata (generation complete)."},"400":{"description":"Validation error."},"401":{"description":"Unauthorized."}}}},"/api/reports/{id}":{"get":{"tags":["Reports"],"summary":"Get report metadata","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Report metadata object."},"404":{"description":"Not found."}}}},"/api/reports/{id}/download":{"get":{"tags":["Reports"],"summary":"Download a report","description":"Download the generated report file. Use the optional format query parameter to override the stored format (e.g. download a CSV report as PDF).","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["csv","json","pdf"]},"description":"Override the report format. If omitted, uses the format the report was generated with."}],"responses":{"200":{"description":"Report file download.","content":{"text/csv":{},"application/json":{},"application/pdf":{}}},"404":{"description":"Not found."}}}},"/api/billing":{"get":{"tags":["Billing"],"summary":"Get billing and usage info","description":"Return the current plan, usage counts, and limits for the authenticated user.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"responses":{"200":{"description":"Billing info.","content":{"application/json":{"schema":{"type":"object","properties":{"plan":{"type":"string"},"promptsUsed":{"type":"integer"},"promptsLimit":{"type":"integer"},"modelsIncluded":{"type":"integer"},"stripeCustomerId":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized."}}}},"/api/teams":{"get":{"tags":["Teams"],"summary":"Get team info","description":"Return the team the authenticated user belongs to, including all members.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"responses":{"200":{"description":"Team object with members array, or { team: null } if no team."},"401":{"description":"Unauthorized."}}},"post":{"tags":["Teams"],"summary":"Create a team","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}}}}},"responses":{"201":{"description":"Team created."},"400":{"description":"Validation error or user already in a team."},"401":{"description":"Unauthorized."}}}},"/api/api-keys":{"get":{"tags":["API Keys"],"summary":"List API keys","description":"Return all API keys for the authenticated user (key hash is not returned, only prefix).","security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Array of API key metadata objects."},"401":{"description":"Unauthorized."}}},"post":{"tags":["API Keys"],"summary":"Create an API key","description":"Generate a new API key. The full key is returned ONCE in the response. Store it securely.","security":[{"cookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Human-readable label for the key."}}}}}},"responses":{"201":{"description":"API key created. The `key` field contains the full key (shown only once)."},"400":{"description":"Validation error."},"401":{"description":"Unauthorized."}}}},"/api/settings":{"get":{"tags":["Settings"],"summary":"Get tracking settings","description":"Return notification preferences, webhook configuration, and query frequency settings.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"responses":{"200":{"description":"Settings object."},"401":{"description":"Unauthorized."}}},"post":{"tags":["Settings"],"summary":"Update tracking settings","description":"Partially update notification and tracking settings. Only provided fields are changed.","security":[{"cookieAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"emailAlerts":{"type":"boolean"},"emailFrequency":{"type":"string"},"slackWebhookUrl":{"type":"string","nullable":true},"slackChannel":{"type":"string","nullable":true},"slackAlerts":{"type":"boolean"},"webhookUrl":{"type":"string","nullable":true},"webhookSecret":{"type":"string","nullable":true},"webhookEnabled":{"type":"boolean"},"weeklyReport":{"type":"boolean"},"reportDay":{"type":"string"},"reportTime":{"type":"string"},"visibilityDropThreshold":{"type":"number"},"sentimentAlertThreshold":{"type":"number"},"queryFrequency":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated settings."},"401":{"description":"Unauthorized."}}}},"/api/health":{"get":{"tags":["System"],"summary":"Health check","description":"Returns 200 if the service is running.","security":[],"responses":{"200":{"description":"OK."}}}}}}