{"openapi":"3.0.3","info":{"title":"Zudo API","version":"1.0.0","description":"External API for accessing and creating data in your Zudo workspace programmatically.\n\nAuthenticate every request by including your API key in the `x-api-key` header."},"servers":[{"url":"https://zudo.so/api/v1","description":"Production"}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Your Zudo API key (starts with `psk_`)"}},"headers":{"X-RateLimit-Limit":{"description":"Your per-minute request quota","schema":{"type":"integer","example":100}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":87}},"X-RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":42}}},"schemas":{"Pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"pageSize":{"type":"integer","example":25},"total":{"type":"integer","example":142},"totalPages":{"type":"integer","example":6},"hasNextPage":{"type":"boolean"},"hasPrevPage":{"type":"boolean"}}},"Error":{"type":"object","properties":{"error":{"type":"string"}}},"Account":{"type":"object","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Pied Piper"},"externalId":{"type":"string","nullable":true,"example":"acme-123","description":"Your unique identifier for this account. Used to match incoming product-usage events to this account."},"mrr":{"type":"number","nullable":true,"example":48000},"active":{"type":"boolean","example":true},"churned":{"type":"boolean","example":false},"onboarding":{"type":"boolean","example":false},"logoUrl":{"type":"string","nullable":true},"contactActivityAt":{"type":"string","format":"date-time","nullable":true,"description":"When a contact was last active (set via API or synced from Vitally)"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Request":{"type":"object","properties":{"id":{"type":"integer","example":1},"title":{"type":"string","example":"SSO integration"},"notes":{"type":"string","nullable":true},"status":{"type":"string","enum":["Open","Done"],"example":"Open"},"severity":{"type":"number","nullable":true,"minimum":0,"maximum":100,"example":62.4,"description":"Computed 0-100 request impact score stored in the legacy `severity` field on response objects."},"userSeverity":{"type":"integer","nullable":true,"minimum":1,"maximum":5,"example":4,"description":"Echo of the 1-5 customer urgency input. Returned on create responses only."},"effectiveUserSeverity":{"type":"number","nullable":true,"minimum":1,"maximum":5,"example":4.3,"description":"Rolled-up request-level urgency derived from linked account urgency overrides and the request default urgency."},"requestedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"customerUrgency":{"type":"integer","nullable":true,"minimum":1,"maximum":5,"description":"Optional account-specific customer urgency override for this request."},"effectiveCustomerUrgency":{"type":"number","nullable":true,"minimum":1,"maximum":5,"description":"Resolved urgency used for this account on the request after falling back to the request default urgency."}}}},"issues":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"identifier":{"type":"string"},"title":{"type":"string"},"state":{"type":"string"}}}}}},"Sentence":{"type":"object","description":"A single utterance from a meeting transcript.","properties":{"text":{"type":"string","description":"What was said."},"speaker_name":{"type":"string","nullable":true,"description":"Display name of the speaker, when known."},"speaker_id":{"oneOf":[{"type":"integer"},{"type":"string"}],"nullable":true,"description":"Stable speaker identifier from the source transcript."},"start_time":{"type":"number","nullable":true,"description":"Offset from the start of the meeting, in seconds."}},"required":["text"]},"Meeting":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"startAt":{"type":"string","format":"date-time","nullable":true},"endAt":{"type":"string","format":"date-time","nullable":true},"overview":{"type":"string","nullable":true},"topicsDiscussed":{"type":"string","nullable":true},"gist":{"type":"string","nullable":true},"transcriptUrl":{"type":"string","nullable":true},"transcriptText":{"type":"string","nullable":true,"description":"Flattened, plain-text transcript. Convenience field for full-text search; derived from `sentences`. (Detail endpoint only.)"},"sentences":{"type":"array","nullable":true,"description":"Structured transcript broken into per-utterance objects with speaker and timestamp. (Detail endpoint only.)","items":{"$ref":"#/components/schemas/Sentence"}},"transcriptMatch":{"type":"string","nullable":true,"description":"Snippet of the transcript surrounding the search term, when the list endpoint's `search` matched the transcript text. (List endpoint only.)"},"durationMinutes":{"type":"number","nullable":true,"description":"Calculated duration in minutes (detail endpoint only)"},"account":{"type":"object","nullable":true,"properties":{"id":{"type":"integer"},"name":{"type":"string"}}},"attendees":{"type":"array","description":"Attendees (detail endpoint only)","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"email":{"type":"string"}}}}}},"Thread":{"type":"object","properties":{"id":{"type":"integer"},"subject":{"type":"string"},"snippet":{"type":"string","nullable":true},"latestMessageDirection":{"type":"string","enum":["inbound","outbound","unknown"],"example":"inbound","description":"Persisted direction of the most recent message in the thread, computed when the message is created or imported."},"latestMessageAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"messageCount":{"type":"integer"},"account":{"type":"object","nullable":true,"properties":{"id":{"type":"integer"},"name":{"type":"string"}}},"messages":{"type":"array","description":"Initial messages included on create responses only.","items":{"$ref":"#/components/schemas/Message"}}}},"Issue":{"type":"object","properties":{"id":{"type":"integer","example":10},"identifier":{"type":"string","example":"ENG-142"},"title":{"type":"string","example":"Implement compression API"},"description":{"type":"string","nullable":true},"state":{"type":"string","description":"Issue state synced from your issue tracker (e.g. Backlog, In Progress, Done)","example":"In Progress"},"creator":{"type":"string","nullable":true},"url":{"type":"string","nullable":true},"issueCreatedAt":{"type":"string","format":"date-time","nullable":true},"issueUpdatedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"requests":{"type":"array","description":"Linked requests (detail endpoint only)","items":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"status":{"type":"string"}}}},"accounts":{"type":"array","description":"Linked accounts (detail endpoint only, deduped from requests)","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}}}}}},"Contact":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"email":{"type":"string"},"lastSeenAt":{"type":"string","format":"date-time","nullable":true,"description":"Most recent recorded activity timestamp for this contact"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}}}}}},"Message":{"type":"object","properties":{"id":{"type":"integer","example":1},"direction":{"type":"string","enum":["inbound","outbound","unknown"],"example":"outbound","description":"Persisted when the message is created or imported, using the owning organization's configured email domains at that time."},"isInternalSender":{"type":"boolean","nullable":true,"example":true,"description":"Persisted flag indicating whether the sender email matched one of the owning organization's configured domains when the message was created or imported."},"isInternalRecipient":{"type":"boolean","nullable":true,"example":false,"description":"Persisted flag indicating whether any recipient email matched one of the owning organization's configured domains when the message was created or imported."},"fromEmail":{"type":"string","example":"richard@piedpiper.com"},"toEmails":{"type":"array","items":{"type":"string"},"example":["jared@piedpiper.com"]},"subject":{"type":"string","nullable":true},"snippet":{"type":"string","nullable":true},"receivedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"Task":{"type":"object","properties":{"id":{"type":"integer","example":1},"title":{"type":"string","example":"Follow up on renewal"},"description":{"type":"string","nullable":true},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","DONE","CANCELLED"],"example":"OPEN"},"priority":{"type":"string","nullable":true,"enum":["LOW","MEDIUM","HIGH","URGENT"],"example":"HIGH"},"dueAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"assignee":{"type":"object","nullable":true,"description":"Assigned user (detail endpoint only)","properties":{"id":{"type":"integer"},"fullName":{"type":"string"}}}}},"CreateAccount":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Account name"},"externalId":{"type":"string","nullable":true,"description":"Your unique identifier for this account. Used to match incoming product-usage events. Must be unique within your organization."},"mrr":{"type":"number","description":"Monthly recurring revenue","nullable":true},"status":{"type":"string","enum":["active","onboarding","churned"],"default":"active","description":"Account status"},"contactName":{"type":"string","description":"Optionally create a primary contact","nullable":true},"contactEmail":{"type":"string","description":"Primary contact email (required if contactName is provided)","nullable":true}}},"CreateContact":{"type":"object","required":["name","email","accountIds"],"properties":{"name":{"type":"string","description":"Contact full name"},"email":{"type":"string","format":"email","description":"Contact email address"},"accountIds":{"type":"array","items":{"type":"integer"},"description":"Account IDs to link this contact to","minItems":1}}},"CreateTask":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"Task title"},"description":{"type":"string","nullable":true,"description":"Task description"},"priority":{"type":"string","nullable":true,"enum":["LOW","MEDIUM","HIGH","URGENT"],"description":"Task priority"},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","DONE","CANCELLED"],"default":"OPEN","description":"Task status"},"dueAt":{"type":"string","format":"date-time","nullable":true,"description":"Due date (normalized to noon UTC)"},"accountIds":{"type":"array","items":{"type":"integer"},"description":"Account IDs to link"},"accountUrgencies":{"type":"object","additionalProperties":{"type":"integer","minimum":1,"maximum":5},"description":"Optional per-account customer urgency overrides keyed by account ID. Omitted accounts inherit the request-level default urgency."},"issueIds":{"type":"array","items":{"type":"integer"},"description":"Issue IDs to link"},"requestIds":{"type":"array","items":{"type":"integer"},"description":"Request IDs to link"}}},"CreateRequest":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"Request title"},"notes":{"type":"string","nullable":true,"description":"Additional notes or context"},"severity":{"type":"integer","minimum":1,"maximum":5,"default":1,"example":4,"description":"Customer urgency input (1-5). On create, this request-body field is stored as `userSeverity`."},"requestedAt":{"type":"string","format":"date-time","description":"When the request was made (defaults to now)"},"accountIds":{"type":"array","items":{"type":"integer"},"description":"Account IDs to link"},"issueIds":{"type":"array","items":{"type":"integer"},"description":"Issue IDs to link"}}},"CreateMeeting":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"Meeting title"},"startAt":{"type":"string","format":"date-time","nullable":true,"description":"Meeting start time"},"endAt":{"type":"string","format":"date-time","nullable":true,"description":"Meeting end time"},"overview":{"type":"string","nullable":true,"description":"Meeting overview or summary"},"topicsDiscussed":{"type":"string","nullable":true,"description":"Topics discussed"},"gist":{"type":"string","nullable":true,"description":"Brief meeting gist"},"transcriptUrl":{"type":"string","nullable":true,"description":"URL to transcript"},"sentences":{"type":"array","nullable":true,"description":"Optional structured transcript. When provided, `transcriptText` is derived automatically and the meeting becomes searchable by its content.","items":{"$ref":"#/components/schemas/Sentence"}},"accountId":{"type":"integer","description":"Account ID to link the meeting to"},"attendees":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"name":{"type":"string"},"displayName":{"type":"string"}},"required":["email"]},"description":"Meeting attendees"}}},"CreateThread":{"type":"object","required":["accountId","subject"],"properties":{"accountId":{"type":"integer","description":"Account ID to link the thread to"},"subject":{"type":"string","description":"Email thread subject"},"body":{"type":"string","nullable":true,"description":"Body of the initial message"},"fromEmail":{"type":"string","nullable":true,"description":"Sender email address"},"toEmails":{"type":"array","items":{"type":"string"},"description":"Recipient email address(es). Also accepts a single string."},"receivedAt":{"type":"string","format":"date-time","description":"When the message was received (defaults to now)"}}}}},"security":[{"ApiKeyAuth":[]}],"paths":{"/accounts":{"get":{"summary":"List accounts","tags":["Accounts"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":25,"maximum":100}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Search by account name or externalId (case-insensitive substring match)"},{"name":"externalId","in":"query","schema":{"type":"string"},"description":"Filter to the account with this exact externalId."},{"name":"status","in":"query","schema":{"type":"string","enum":["active","onboarding","churned","inactive"]}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["name","mrr","createdAt","updatedAt"],"default":"name"}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"asc"}}],"responses":{"200":{"description":"Paginated list of accounts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Account"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create account","tags":["Accounts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccount"}}}},"responses":{"201":{"description":"Account created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Account"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/accounts/{accountId}":{"get":{"summary":"Get account by ID","tags":["Accounts"],"parameters":[{"name":"accountId","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Account details with contacts, recent meetings, and linked requests","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Account"}}}}}},"404":{"description":"Account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update account","tags":["Accounts"],"parameters":[{"name":"accountId","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"externalId":{"type":"string","nullable":true,"description":"Your unique identifier for this account. Used to match incoming product-usage events. Must be unique within your organization. Set to null or empty string to clear."},"contactActivityAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"integer"}],"nullable":true,"description":"ISO 8601 timestamp or Unix timestamp in seconds or milliseconds of when a contact was last active. Used as a health score factor. Set to null to clear. Cannot be in the future."}}}}}},"responses":{"200":{"description":"Updated account","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Account"}}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/requests":{"get":{"summary":"List requests","description":"Returns requests for the current organization. In response objects, `severity` is the computed 0-100 impact score stored in the legacy field name.","tags":["Requests"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":25,"maximum":100}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Search by title"},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"minSeverity","in":"query","schema":{"type":"integer"},"description":"Minimum computed impact score filter applied to the legacy `severity` field (0-100)."},{"name":"maxSeverity","in":"query","schema":{"type":"integer"},"description":"Maximum computed impact score filter applied to the legacy `severity` field (0-100)."},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["title","status","severity","requestedAt","updatedAt","createdAt"],"default":"requestedAt"},"description":"Sort by a request field. `severity` sorts by the computed impact score stored in the legacy field."},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Paginated list of requests","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Request"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"summary":"Create request","description":"Creates a request. In this request body, `severity` means the 1-5 customer urgency input, not the computed response impact score.","tags":["Requests"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRequest"}}}},"responses":{"201":{"description":"Request created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Request"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/requests/{requestId}":{"get":{"summary":"Get request by ID","description":"Returns one request. In the response object, `severity` is the computed 0-100 impact score stored in the legacy field name.","tags":["Requests"],"parameters":[{"name":"requestId","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Request details with linked accounts and issues","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Request"}}}}}},"404":{"description":"Request not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/meetings":{"get":{"summary":"List meetings","tags":["Meetings"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":25,"maximum":100}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring match against title, gist, overview, and transcript text. Transcript hits are returned with a `transcriptMatch` snippet."},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"Meetings starting after this date"},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"Meetings starting before this date"},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Paginated list of meetings","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Meeting"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"summary":"Create meeting","tags":["Meetings"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMeeting"}}}},"responses":{"201":{"description":"Meeting created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Meeting"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/meetings/{meetingId}":{"get":{"summary":"Get meeting by ID","tags":["Meetings"],"parameters":[{"name":"meetingId","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Meeting details with attendees and duration","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Meeting"}}}}}},"404":{"description":"Meeting not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/conversations/threads":{"get":{"summary":"List email threads","tags":["Conversations"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":25,"maximum":100}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Search by subject"},{"name":"accountId","in":"query","schema":{"type":"integer"},"description":"Filter by account"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["subject","latestMessageAt","createdAt"],"default":"latestMessageAt"}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Paginated list of email threads","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Thread"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"summary":"Create email thread","tags":["Conversations"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateThread"}}}},"responses":{"201":{"description":"Thread created with initial message","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Thread"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/conversations/threads/{threadId}/messages":{"get":{"summary":"Get messages in a thread","description":"Use the numeric thread `id` returned by list_email_threads.","tags":["Conversations"],"parameters":[{"name":"threadId","in":"path","required":true,"description":"Numeric thread ID from list_email_threads `data[].id`.","schema":{"type":"integer"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":25,"maximum":25}}],"responses":{"200":{"description":"Paginated messages in the thread","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Message"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"404":{"description":"Thread not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/issues":{"get":{"summary":"List issues","tags":["Issues"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":25,"maximum":100}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Search by title or identifier"},{"name":"state","in":"query","schema":{"type":"string"}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["title","state","issueCreatedAt","issueUpdatedAt"],"default":"issueUpdatedAt"}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Paginated list of issues","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Issue"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}},"/issues/{issueId}":{"get":{"summary":"Get issue by ID","tags":["Issues"],"parameters":[{"name":"issueId","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Issue details with linked requests and accounts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Issue"}}}}}},"404":{"description":"Issue not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts":{"get":{"summary":"List contacts","tags":["Contacts"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":25,"maximum":100}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Search by name or email"},{"name":"accountId","in":"query","schema":{"type":"integer"},"description":"Filter by account"}],"responses":{"200":{"description":"Paginated list of contacts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"summary":"Create contact","tags":["Contacts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContact"}}}},"responses":{"201":{"description":"Contact created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Account not authorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts/{contactId}":{"patch":{"summary":"Update contact","tags":["Contacts"],"parameters":[{"name":"contactId","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lastSeenAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"integer"}],"nullable":true,"description":"ISO 8601 timestamp or Unix timestamp in seconds or milliseconds for this contact's last activity. Set to null to clear. Cannot be in the future."}}}}}},"responses":{"200":{"description":"Updated contact","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Contact not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tasks":{"get":{"summary":"List tasks","tags":["Tasks"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":25,"maximum":100}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Search by title"},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"priority","in":"query","schema":{"type":"string"}},{"name":"accountId","in":"query","schema":{"type":"integer"},"description":"Filter by linked account"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["title","status","priority","dueAt","createdAt","updatedAt"],"default":"createdAt"}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Paginated list of tasks","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Task"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"summary":"Create task","tags":["Tasks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTask"}}}},"responses":{"201":{"description":"Task created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Task"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tasks/{taskId}":{"get":{"summary":"Get task by ID","tags":["Tasks"],"parameters":[{"name":"taskId","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Task details with linked accounts, issues, requests, meetings, and assignee","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Task"}}}}}},"404":{"description":"Task not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/requests/{requestId}/similar-accounts":{"get":{"summary":"Find accounts likely interested in this request","description":"Given a feature/customer request, returns AI-ranked candidate accounts most likely to also want it. Approach is structured similarity — profiles the accounts already linked to the request (via AccountOnRequest), filters the org's active account pool by MRR proximity / trait overlap / health, then uses gpt-4o-mini to pick and explain a shortlist. Requires the request to have at least one linked account.","tags":["Requests"],"parameters":[{"name":"requestId","in":"path","required":true,"schema":{"type":"integer"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":8,"minimum":1,"maximum":20},"description":"Max candidates to return."}],"responses":{"200":{"description":"Ranked similar accounts with reasoning.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"request":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"notes":{"type":"string","nullable":true}}},"seedAccounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"mrr":{"type":"number","nullable":true}}}},"candidates":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"integer"},"accountName":{"type":"string"},"mrr":{"type":"number","nullable":true},"reasoning":{"type":"string"}}}},"totalEvaluated":{"type":"integer"}}}}}}}},"400":{"description":"Request has no linked accounts yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"AI features are disabled for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/accounts/{accountId}/search":{"get":{"summary":"Search a single account's records","description":"Lexical (ILIKE) search across one account's emails, meetings (incl. transcripts and AI-generated summaries), notes, requests, and linked issues. Returns hits grouped by entity type with snippets — no LLM involved.","tags":["Search"],"parameters":[{"name":"accountId","in":"path","required":true,"schema":{"type":"integer"}},{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"Search query. Case-insensitive substring match."}],"responses":{"200":{"description":"Grouped search results scoped to the account.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"query":{"type":"string"},"totalCount":{"type":"integer"},"account":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}}},"results":{"type":"object","properties":{"emails":{"type":"array","items":{"type":"object"}},"meetings":{"type":"array","items":{"type":"object"}},"notes":{"type":"array","items":{"type":"object"}},"requests":{"type":"array","items":{"type":"object"}},"issues":{"type":"array","items":{"type":"object"}}}}}}}}}}},"400":{"description":"Missing or invalid query.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Account not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/search/ai-chat":{"post":{"summary":"Ask an AI question about a single account","description":"Searches one account's records and synthesizes a natural-language answer with citations using gpt-4o-mini. Use this for questions like \"have we ever talked about X with this account.\" For cross-account questions about who would want a feature, see GET /requests/{requestId}/similar-accounts.","tags":["Search"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query","accountId"],"properties":{"query":{"type":"string","description":"The natural-language question to answer."},"accountId":{"type":"integer","description":"The account to scope the question to."}}}}}},"responses":{"200":{"description":"AI answer with citations referencing the source records.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"query":{"type":"string"},"accountId":{"type":"integer"},"accountName":{"type":"string","nullable":true},"answer":{"type":"string"},"cached":{"type":"boolean"},"citations":{"type":"array","items":{"type":"object","properties":{"ref":{"type":"integer"},"type":{"type":"string"},"id":{"type":"integer"},"accountId":{"type":"integer","nullable":true},"title":{"type":"string"},"snippet":{"type":"string"},"date":{"type":"string","format":"date-time","nullable":true}}}}}}}}}}},"400":{"description":"Missing or invalid query.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"AI search is disabled for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"tags":[{"name":"Accounts","description":"Customer accounts"},{"name":"Requests","description":"Customer requests / feature requests"},{"name":"Meetings","description":"Meeting records and transcripts"},{"name":"Conversations","description":"Email threads and messages"},{"name":"Issues","description":"Linked engineering issues"},{"name":"Contacts","description":"Customer contacts"},{"name":"Tasks","description":"Tasks and action items"},{"name":"Search","description":"Cross-record search and AI Q&A"}]}