{"openapi":"3.0.0","info":{"title":"BaseOS API Documentation","version":"1.0.0","description":"API documentation for the BaseOS platform. All endpoints require API key authentication via the Authorization header.","contact":{"name":"API Support"}},"servers":[{"url":"http://localhost:3000","description":"API Server"}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API Key authentication. Format: Bearer <api_key>"}},"schemas":{"Error":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Error message"}},"required":["success","error"]},"Success":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object"}},"required":["success"]},"QuoteStatus":{"type":"string","enum":["DRAFT","SENT","ACCEPTED","REJECTED","EXPIRED"]},"QuoteItem":{"type":"object","properties":{"id":{"type":"integer","example":1},"quoteId":{"type":"integer","example":1},"itemId":{"type":"integer","nullable":true,"example":1},"name":{"type":"string","example":"Web Development Service"},"description":{"type":"string","nullable":true,"example":"Custom web development"},"quantity":{"type":"number","example":1},"unitPrice":{"type":"number","example":1000},"discount":{"type":"number","example":0},"tax":{"type":"number","nullable":true,"example":0},"setupFee":{"type":"number","example":0},"subtotal":{"type":"number","example":1000}},"required":["name","quantity","unitPrice"]},"Quote":{"type":"object","properties":{"id":{"type":"integer","example":1},"organizationId":{"type":"integer","example":1},"clientId":{"type":"integer","example":1},"title":{"type":"string","example":"Website Development Quote"},"quoteNumber":{"type":"string","example":"Q-1-2024-0001"},"publicToken":{"type":"string","example":"abc123def456"},"status":{"$ref":"#/components/schemas/QuoteStatus"},"subtotal":{"type":"number","example":1000},"tax":{"type":"number","nullable":true,"example":0},"total":{"type":"number","example":1000},"currencyId":{"type":"integer","example":1},"validUntil":{"type":"string","format":"date-time","example":"2024-12-31T23:59:59Z"},"notes":{"type":"string","nullable":true,"example":"Additional notes"},"contractId":{"type":"integer","nullable":true},"projectId":{"type":"integer","nullable":true},"invoiceId":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"items":{"type":"array","items":{"$ref":"#/components/schemas/QuoteItem"}}},"required":["id","organizationId","clientId","title","quoteNumber","status","subtotal","total","currencyId","validUntil"]},"CreateQuoteItem":{"type":"object","properties":{"itemId":{"type":"integer","nullable":true,"example":1},"name":{"type":"string","example":"Web Development Service"},"description":{"type":"string","nullable":true,"example":"Custom web development"},"quantity":{"type":"number","example":1},"unitPrice":{"type":"number","example":1000},"discount":{"type":"number","example":0},"tax":{"type":"number","nullable":true,"example":0},"setupFee":{"type":"number","example":0}},"required":["name","quantity","unitPrice"]},"CreateQuoteRequest":{"type":"object","properties":{"clientId":{"type":"integer","nullable":true,"example":1,"description":"Existing client target. Required when opportunityId is not provided."},"opportunityId":{"type":"integer","nullable":true,"example":77,"description":"Sales opportunity/deal target. Quotes for leads must be created from an opportunity; leadId is not accepted here."},"title":{"type":"string","example":"Website Development Quote"},"currencyId":{"type":"integer","nullable":true,"example":1,"description":"Currency id. Ignored when opportunityId is provided because the quote inherits the opportunity currency."},"currencyCode":{"type":"string","nullable":true,"example":"USD","description":"Currency code alternative for API clients. Ignored when opportunityId is provided."},"validUntil":{"type":"string","format":"date-time","example":"2024-12-31T23:59:59Z"},"notes":{"type":"string","nullable":true,"example":"Additional notes"},"items":{"type":"array","items":{"$ref":"#/components/schemas/CreateQuoteItem"}}},"required":["title","validUntil","items"]},"UpdateQuoteRequest":{"type":"object","properties":{"title":{"type":"string","example":"Updated Quote Title"},"status":{"$ref":"#/components/schemas/QuoteStatus"},"currencyId":{"type":"integer","example":1},"validUntil":{"type":"string","format":"date-time","example":"2024-12-31T23:59:59Z"},"notes":{"type":"string","nullable":true},"items":{"type":"array","items":{"$ref":"#/components/schemas/CreateQuoteItem"}}}},"QuotesListResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"quotes":{"type":"array","items":{"$ref":"#/components/schemas/Quote"}},"pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"limit":{"type":"integer","example":10},"total":{"type":"integer","example":100},"totalPages":{"type":"integer","example":10}}}}}}},"QuoteResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"quote":{"$ref":"#/components/schemas/Quote"}}}}},"Client":{"type":"object","properties":{"id":{"type":"integer","example":1},"organizationId":{"type":"integer","example":1},"userId":{"type":"integer","nullable":true,"example":1},"name":{"type":"string","example":"John Doe"},"email":{"type":"string","nullable":true,"example":"john.doe@example.com"},"phone":{"type":"string","nullable":true,"example":"+1234567890"},"avatar":{"type":"string","nullable":true,"example":"https://example.com/avatar.jpg"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"user":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"John Doe"},"email":{"type":"string","example":"john.doe@example.com"},"phone":{"type":"string","nullable":true},"avatar":{"type":"string","nullable":true}}},"organization":{"type":"object","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Acme Corp"}}},"projects":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Project Name"},"description":{"type":"string","nullable":true},"status":{"type":"string","example":"ACTIVE"},"startDate":{"type":"string","format":"date-time","nullable":true},"endDate":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"tickets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":1},"subject":{"type":"string","example":"Ticket Subject"},"status":{"type":"string","example":"OPEN"},"priority":{"type":"string","example":"MEDIUM"},"departmentId":{"type":"integer","nullable":true},"projectId":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"lastReply":{"type":"string","format":"date-time","nullable":true},"department":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Support"}}},"project":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Project Name"}}}}}},"_count":{"type":"object","properties":{"projects":{"type":"integer","example":5},"tickets":{"type":"integer","example":10}}}},"required":["id","organizationId","name"]},"CreateClientRequest":{"type":"object","properties":{"name":{"type":"string","example":"John Doe"},"email":{"type":"string","nullable":true,"example":"john.doe@example.com"},"phone":{"type":"string","nullable":true,"example":"+1234567890"},"avatar":{"type":"string","nullable":true,"example":"https://example.com/avatar.jpg"},"userId":{"type":"integer","nullable":true,"example":1}},"required":["name"]},"UpdateClientRequest":{"type":"object","properties":{"name":{"type":"string","example":"John Doe Updated"},"email":{"type":"string","nullable":true,"example":"john.doe.updated@example.com"},"phone":{"type":"string","nullable":true,"example":"+1234567891"},"avatar":{"type":"string","nullable":true,"example":"https://example.com/avatar-updated.jpg"},"userId":{"type":"integer","nullable":true,"example":1}}},"ClientsListResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"clients":{"type":"array","items":{"$ref":"#/components/schemas/Client"}},"pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"limit":{"type":"integer","example":10},"total":{"type":"integer","example":100},"totalPages":{"type":"integer","example":10}}}}}}},"ClientResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"client":{"$ref":"#/components/schemas/Client"}}}}},"TicketPriority":{"type":"string","enum":["LOW","MEDIUM","HIGH","URGENT"]},"SupportTicketStatus":{"type":"string","enum":["NEW","OPEN","ASSIGNED","IN_PROGRESS","AWAITING_CUSTOMER","ON_HOLD","RESOLVED","CLOSED","REOPENED","CANCELED","MERGED"]},"PublicationContentType":{"type":"string","enum":["TEXT","VIDEO","GALLERY","LINK","CUSTOM","DISCUSSION"]},"TicketMessageContent":{"type":"object","properties":{"id":{"type":"integer","example":1},"messageId":{"type":"integer","example":1},"type":{"$ref":"#/components/schemas/PublicationContentType"},"content":{"type":"string","example":"<p>We found the root cause and applied a fix.</p>"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","messageId","type","content","createdAt","updatedAt"]},"TicketMessage":{"type":"object","properties":{"id":{"type":"integer","example":1},"ticketId":{"type":"integer","example":1},"organizationId":{"type":"integer","nullable":true,"example":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"organization":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Acme Inc"}}},"content":{"type":"array","items":{"$ref":"#/components/schemas/TicketMessageContent"}}},"required":["id","ticketId","createdAt","updatedAt"]},"Ticket":{"type":"object","properties":{"id":{"type":"integer","example":1},"subject":{"type":"string","example":"Integration issue with billing webhook"},"departmentId":{"type":"integer","nullable":true,"example":2},"status":{"$ref":"#/components/schemas/SupportTicketStatus"},"priority":{"$ref":"#/components/schemas/TicketPriority"},"clientId":{"type":"integer","nullable":true,"example":14},"projectId":{"type":"integer","nullable":true,"example":8},"email":{"type":"string","nullable":true,"example":"client@example.com"},"message":{"type":"string","nullable":true,"example":"<p>The webhook is returning 500 for paid invoices.</p>"},"lastReply":{"type":"string","format":"date-time","nullable":true},"organizationId":{"type":"integer","nullable":true,"example":1},"assignedToUserMembershipId":{"type":"integer","nullable":true,"example":17},"last24hNotificationSent":{"type":"string","format":"date-time","nullable":true},"last72hNotificationSent":{"type":"string","format":"date-time","nullable":true},"isPinned":{"type":"boolean","example":false},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"organization":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Acme Inc"}}},"department":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":2},"name":{"type":"string","example":"Support"},"description":{"type":"string","nullable":true,"example":"Technical support and incidents"}}},"client":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":14},"name":{"type":"string","example":"Jane Doe"},"email":{"type":"string","nullable":true,"example":"jane@example.com"},"phone":{"type":"string","nullable":true,"example":"+5511999999999"}}},"project":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":8},"name":{"type":"string","example":"ERP rollout"},"description":{"type":"string","nullable":true,"example":"Implementation and support project"},"status":{"type":"string","example":"ACTIVE"}}},"assignedToUserMembership":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":17},"user":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":7},"name":{"type":"string","example":"Support Agent"},"email":{"type":"string","nullable":true,"example":"agent@example.com"},"avatar":{"type":"string","nullable":true,"example":"https://example.com/avatar.png"}}}}},"messages":{"type":"array","items":{"$ref":"#/components/schemas/TicketMessage"}}},"required":["id","subject","status","priority","createdAt","updatedAt"]},"CreateTicketRequest":{"type":"object","properties":{"subject":{"type":"string","example":"Integration issue with billing webhook"},"departmentId":{"type":"integer","nullable":true,"example":2},"priority":{"$ref":"#/components/schemas/TicketPriority"},"clientId":{"type":"integer","nullable":true,"example":14},"projectId":{"type":"integer","nullable":true,"example":8},"email":{"type":"string","nullable":true,"example":"client@example.com"},"message":{"type":"string","example":"<p>The webhook is returning 500 for paid invoices.</p>"}},"required":["subject","message"]},"UpdateTicketRequest":{"type":"object","properties":{"subject":{"type":"string","example":"Updated issue title"},"departmentId":{"type":"integer","nullable":true,"example":2},"priority":{"$ref":"#/components/schemas/TicketPriority"},"status":{"$ref":"#/components/schemas/SupportTicketStatus"},"clientId":{"type":"integer","nullable":true,"example":14},"email":{"type":"string","nullable":true,"example":"client@example.com"},"assignedToUserMembershipId":{"type":"integer","nullable":true,"example":17}}},"AddTicketMessageRequest":{"type":"object","properties":{"content":{"type":"string","example":"<p>We found the root cause and applied a fix.</p>"},"type":{"$ref":"#/components/schemas/PublicationContentType"}},"required":["content"]},"TicketsListResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"tickets":{"type":"array","items":{"$ref":"#/components/schemas/Ticket"}},"pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"limit":{"type":"integer","example":10},"total":{"type":"integer","example":42},"totalPages":{"type":"integer","example":5}}}}}}},"TicketResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"ticket":{"$ref":"#/components/schemas/Ticket"}}}}},"TicketMessageResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"$ref":"#/components/schemas/TicketMessage"}}}}},"DeleteTicketResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"deleted":{"type":"boolean","example":true}}}}},"ItemType":{"type":"string","enum":["SERVICE","PHYSICAL_PRODUCT","LICENSE_SAAS","SUBSCRIPTION","DIGITAL_CONTENT"]},"UnitOfMeasure":{"type":"string","enum":["HOUR","MONTH","SPRINT","UNIT","TOKEN","LICENSE","USER_SLOT"]},"BillingModel":{"type":"string","enum":["FIXED_PRICE","TIME_AND_MATERIALS","RECURRING"]},"ProvisioningStrategy":{"type":"string","enum":["NONE","GITHUB_ACCESS","SAAS_INSTANCE","LMS_ACCESS","PROJECT_CREATION"]},"RenewalType":{"type":"string","enum":["NONE","EXTEND_EXPIRY","CREATE_NEW_RESET","CREATE_NEW_ROLLOVER"]},"Item":{"type":"object","properties":{"id":{"type":"integer","example":1},"organizationId":{"type":"integer","example":1},"categoryId":{"type":"integer","nullable":true,"example":1},"name":{"type":"string","example":"Web Development Service"},"description":{"type":"string","nullable":true,"example":"Custom web development service"},"type":{"$ref":"#/components/schemas/ItemType"},"unitOfMeasure":{"$ref":"#/components/schemas/UnitOfMeasure"},"billingModel":{"$ref":"#/components/schemas/BillingModel"},"internalCost":{"type":"number","example":50},"basePrice":{"type":"number","example":100},"setupFee":{"type":"number","example":0},"currencyId":{"type":"integer","example":1},"provisioningStrategy":{"$ref":"#/components/schemas/ProvisioningStrategy"},"renewalType":{"$ref":"#/components/schemas/RenewalType"},"metadata":{"type":"object","nullable":true},"isActive":{"type":"boolean","example":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"category":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Services"},"description":{"type":"string","nullable":true}}},"currency":{"type":"object","properties":{"id":{"type":"integer","example":1},"code":{"type":"string","example":"USD"},"name":{"type":"string","example":"US Dollar"},"symbol":{"type":"string","example":"$"}}},"basePrices":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":1},"itemId":{"type":"integer","example":1},"currencyId":{"type":"integer","example":1},"price":{"type":"number","example":100},"effectiveDate":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"currency":{"type":"object","properties":{"id":{"type":"integer","example":1},"code":{"type":"string","example":"USD"},"name":{"type":"string","example":"US Dollar"}}}}}}},"required":["id","organizationId","name","type","unitOfMeasure","billingModel","internalCost","basePrice","currencyId","provisioningStrategy","renewalType","isActive"]},"CreateItemRequest":{"type":"object","properties":{"name":{"type":"string","example":"Web Development Service"},"description":{"type":"string","nullable":true,"example":"Custom web development service"},"type":{"$ref":"#/components/schemas/ItemType"},"unitOfMeasure":{"$ref":"#/components/schemas/UnitOfMeasure"},"billingModel":{"$ref":"#/components/schemas/BillingModel"},"internalCost":{"type":"number","example":50},"basePrice":{"type":"number","example":100},"setupFee":{"type":"number","example":0},"currencyId":{"type":"integer","example":1},"categoryId":{"type":"integer","nullable":true,"example":1},"provisioningStrategy":{"$ref":"#/components/schemas/ProvisioningStrategy"},"renewalType":{"$ref":"#/components/schemas/RenewalType"},"metadata":{"type":"object","nullable":true}},"required":["name","type","unitOfMeasure","billingModel","internalCost","basePrice","currencyId"]},"UpdateItemRequest":{"type":"object","properties":{"name":{"type":"string","example":"Updated Web Development Service"},"description":{"type":"string","nullable":true},"type":{"$ref":"#/components/schemas/ItemType"},"unitOfMeasure":{"$ref":"#/components/schemas/UnitOfMeasure"},"billingModel":{"$ref":"#/components/schemas/BillingModel"},"internalCost":{"type":"number","example":50},"basePrice":{"type":"number","example":120},"setupFee":{"type":"number","example":0},"currencyId":{"type":"integer","example":1},"categoryId":{"type":"integer","nullable":true,"example":1},"provisioningStrategy":{"$ref":"#/components/schemas/ProvisioningStrategy"},"renewalType":{"$ref":"#/components/schemas/RenewalType"},"metadata":{"type":"object","nullable":true},"isActive":{"type":"boolean","example":true}}},"ItemsListResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Item"}},"pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"limit":{"type":"integer","example":10},"total":{"type":"integer","example":100},"totalPages":{"type":"integer","example":10}}}}}}},"ItemResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"item":{"$ref":"#/components/schemas/Item"}}}}},"StripeWebhookEvent":{"type":"object","properties":{"id":{"type":"string","example":"evt_1234567890"},"object":{"type":"string","example":"event"},"api_version":{"type":"string","example":"2023-10-16"},"created":{"type":"integer","example":1698765432},"type":{"type":"string","example":"invoice.paid"},"data":{"type":"object","properties":{"object":{"$ref":"#/components/schemas/StripeInvoicePaidEvent"}}}},"required":["id","type","data"]},"StripeInvoicePaidEvent":{"type":"object","properties":{"id":{"type":"string","example":"in_1234567890"},"object":{"type":"string","example":"invoice"},"amount_paid":{"type":"integer","description":"Amount paid in cents","example":10000},"amount_due":{"type":"integer","description":"Amount due in cents","example":0},"currency":{"type":"string","example":"usd"},"customer":{"type":"string","example":"cus_1234567890"},"invoice_pdf":{"type":"string","nullable":true,"example":"https://pay.stripe.com/invoice/xxx"},"hosted_invoice_url":{"type":"string","nullable":true,"example":"https://invoice.stripe.com/i/xxx"},"status":{"type":"string","example":"paid"},"subtotal":{"type":"integer","description":"Subtotal in cents","example":10000},"tax":{"type":"integer","nullable":true,"description":"Tax amount in cents","example":null},"created":{"type":"integer","example":1698765432},"due_date":{"type":"integer","nullable":true,"example":1698765432},"metadata":{"type":"object","properties":{"organizationId":{"type":"string","example":"123"},"clientId":{"type":"string","nullable":true,"example":"456"},"clientInvoiceId":{"type":"string","nullable":true,"example":"789"},"projectId":{"type":"string","nullable":true,"example":"101"},"notes":{"type":"string","nullable":true,"example":"Additional notes"}}},"status_transitions":{"type":"object","properties":{"paid_at":{"type":"integer","nullable":true,"example":1698765432}}},"payment_intent":{"type":"string","nullable":true,"example":"pi_1234567890"},"lines":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"il_1234567890"},"description":{"type":"string","example":"Service Subscription"},"amount":{"type":"integer","description":"Amount in cents","example":10000},"quantity":{"type":"integer","example":1},"price":{"type":"object","properties":{"unit_amount":{"type":"integer","description":"Unit amount in cents","example":10000}}}}}}}}},"required":["id","amount_paid","currency"]},"WebhookSuccessResponse":{"type":"object","properties":{"message":{"type":"string","example":"ok"}},"required":["message"]},"WebhookErrorResponse":{"type":"object","properties":{"error":{"type":"string","example":"Error message"}},"required":["error"]},"ProjectStatus":{"type":"string","enum":["ACTIVE","INACTIVE","COMPLETED","CANCELLED"]},"ProjectType":{"type":"string","enum":["DEVELOPMENT","IMPLEMENTATION","CONSULTING","MAINTENANCE","OPERATIONS","TRAINING","RESEARCH","MIGRATION","SUPPORT"]},"TaskPriority":{"type":"string","enum":["LOW","MEDIUM","HIGH","URGENT"]},"Project":{"type":"object","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Website Redesign"},"description":{"type":"string","nullable":true},"status":{"$ref":"#/components/schemas/ProjectStatus"},"type":{"allOf":[{"$ref":"#/components/schemas/ProjectType"}],"nullable":true},"startDate":{"type":"string","format":"date-time","nullable":true},"endDate":{"type":"string","format":"date-time","nullable":true},"clientId":{"type":"integer","nullable":true},"organizationId":{"type":"integer"},"folderId":{"type":"integer","nullable":true},"templateId":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateProjectRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","example":"Website Redesign"},"description":{"type":"string"},"status":{"$ref":"#/components/schemas/ProjectStatus"},"type":{"$ref":"#/components/schemas/ProjectType"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"clientId":{"type":"integer","nullable":true},"folderId":{"type":"integer","nullable":true},"templateId":{"type":"integer"}}},"UpdateProjectRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string","nullable":true},"status":{"$ref":"#/components/schemas/ProjectStatus"},"startDate":{"type":"string","format":"date-time","nullable":true},"endDate":{"type":"string","format":"date-time","nullable":true},"clientId":{"type":"integer","nullable":true},"folderId":{"type":"integer","nullable":true}}},"ProjectResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"project":{"$ref":"#/components/schemas/Project"}}}}},"ProjectsListResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"projects":{"type":"array","items":{"$ref":"#/components/schemas/Project"}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}}}}}}},"Task":{"type":"object","properties":{"id":{"type":"integer","example":1},"title":{"type":"string","example":"Implement login page"},"description":{"type":"string","nullable":true},"startDate":{"type":"string","format":"date-time","nullable":true},"dueDate":{"type":"string","format":"date-time","nullable":true},"priority":{"$ref":"#/components/schemas/TaskPriority"},"estimatedHours":{"type":"number","nullable":true},"actualHours":{"type":"number","nullable":true},"projectId":{"type":"integer"},"statusId":{"type":"integer"},"organizationId":{"type":"integer"},"order":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateTaskRequest":{"type":"object","required":["title"],"properties":{"title":{"type":"string","example":"Implement login page"},"description":{"type":"string"},"startDate":{"type":"string","format":"date-time"},"dueDate":{"type":"string","format":"date-time"},"priority":{"$ref":"#/components/schemas/TaskPriority"},"estimatedHours":{"type":"number"},"statusId":{"type":"integer"},"assigneeIds":{"type":"array","items":{"type":"integer"}},"tagIds":{"type":"array","items":{"type":"integer"}},"ticketId":{"type":"integer"},"parentTaskId":{"type":"integer"}}},"UpdateTaskRequest":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string","nullable":true},"startDate":{"type":"string","format":"date-time","nullable":true},"dueDate":{"type":"string","format":"date-time","nullable":true},"priority":{"$ref":"#/components/schemas/TaskPriority"},"estimatedHours":{"type":"number","nullable":true},"actualHours":{"type":"number","nullable":true},"statusId":{"type":"integer"},"assigneeIds":{"type":"array","items":{"type":"integer"}},"tagIds":{"type":"array","items":{"type":"integer"}}}},"TaskResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"task":{"$ref":"#/components/schemas/Task"}}}}},"TasksListResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"tasks":{"type":"array","items":{"$ref":"#/components/schemas/Task"}}}}}},"Activity":{"type":"object","properties":{"id":{"type":"integer","example":77},"type":{"type":"string","enum":["CALL","EMAIL","MEETING","TASK","NOTE","FOLLOW_UP"]},"status":{"type":"string","enum":["PLANNED","COMPLETED","CANCELED"]},"title":{"type":"string","example":"Discovery call"},"description":{"type":"string","nullable":true},"dueAt":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"ownerMembershipId":{"type":"integer","nullable":true},"leadId":{"type":"integer","nullable":true},"opportunityId":{"type":"integer","nullable":true},"clientId":{"type":"integer","nullable":true},"contactId":{"type":"integer","nullable":true,"description":"Read-only. The CRM record this activity was filed under, resolved from the link you gave."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateActivityRequest":{"type":"object","properties":{"title":{"type":"string","example":"Discovery call"},"type":{"type":"string","enum":["CALL","EMAIL","MEETING","TASK","NOTE","FOLLOW_UP"]},"description":{"type":"string","nullable":true},"dueAt":{"type":"string","format":"date-time","nullable":true},"ownerMembershipId":{"type":"integer","nullable":true},"leadId":{"type":"integer","nullable":true},"opportunityId":{"type":"integer","nullable":true},"clientId":{"type":"integer","nullable":true},"contactId":{"type":"integer","nullable":true,"description":"A CRM record id, when the activity is about a person or company directly rather than a lead or a deal."}},"required":["title","type"]},"UpdateContactRequest":{"type":"object","description":"Partial update - only the fields present in the body are written. Send\nnull to clear a nullable field; omit it to leave it untouched.\n\nIdentifiers are replaced BY TYPE: sending `email` swaps the contact's\ne-mail addresses and leaves its phone alone, and `\"email\": null`\nclears them. A value already held by another contact is refused with\n409 rather than moved, because moving it would silently blank it on\nthe record that had it.\n\n`type` cannot be changed here. A person is not turned into a company\nby an edit - the two have different relationships hanging off them.\n","properties":{"name":{"type":"string","description":"Unlike POST, this renames the contact outright. An explicit statement about one record, not a side effect of a sync."},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"domain":{"type":"string","nullable":true},"taxId":{"type":"string","nullable":true},"externalId":{"type":"string","nullable":true},"jobTitle":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"lifecycleStatus":{"type":"string","nullable":true},"ownerMembershipId":{"type":"integer","nullable":true},"tags":{"type":"array","items":{"type":"string"},"description":"The COMPLETE tag list. Omit to leave tags untouched; send [] to clear them."}}},"ContactIdentifier":{"type":"object","properties":{"type":{"type":"string","enum":["EMAIL","PHONE","DOMAIN","TAX_ID","EXTERNAL_ID"],"example":"EMAIL"},"value":{"type":"string","description":"The normalized form actually stored - e-mails lower-cased, phones reduced to digits, domains stripped of scheme and www.","example":"ada@example.com"}}},"ContactOwner":{"type":"object","nullable":true,"properties":{"membershipId":{"type":"integer","example":9},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true}}},"ContactTag":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"}}},"Contact":{"type":"object","properties":{"id":{"type":"integer","example":20},"type":{"type":"string","enum":["PERSON","COMPANY"]},"name":{"type":"string","example":"Ada Lovelace"},"description":{"type":"string","nullable":true},"lifecycleStatus":{"type":"string","nullable":true,"enum":["subscriber","lead","prospect","opportunity","customer","churned","disqualified"]},"source":{"type":"string","nullable":true},"jobTitle":{"type":"string","nullable":true},"email":{"type":"string","nullable":true,"description":"Convenience field - the first EMAIL identifier. The full list is in identifiers."},"phone":{"type":"string","nullable":true,"description":"Convenience field - the first PHONE identifier."},"identifiers":{"type":"array","items":{"$ref":"#/components/schemas/ContactIdentifier"}},"ownerMembershipId":{"type":"integer","nullable":true},"owner":{"$ref":"#/components/schemas/ContactOwner"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/ContactTag"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ContactListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"contacts":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}}}}}}},"ContactResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"contact":{"$ref":"#/components/schemas/Contact"},"created":{"type":"boolean","description":"true when a new record was minted, false when an existing one was matched by identifier and updated."}}}}},"UpsertContactRequest":{"type":"object","description":"At least one identifier (email, phone, domain, taxId, externalId) is\nrequired - it is what the endpoint resolves on. A body without one is\nrefused rather than always creating, because a retried request would\nthen mint a second copy of the same contact.\n","properties":{"type":{"type":"string","enum":["PERSON","COMPANY"],"example":"PERSON"},"name":{"type":"string","description":"Used as the display name when a record is created. On a match it is IGNORED unless the stored name is a placeholder (the record's own e-mail or phone) - a sync must not revert a name corrected by hand. Use PATCH to rename.","example":"Ada Lovelace"},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"domain":{"type":"string","nullable":true},"taxId":{"type":"string","nullable":true},"externalId":{"type":"string","nullable":true,"description":"The id this contact has in YOUR system. The most reliable key to sync on, since it does not change when the person changes jobs."},"jobTitle":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"lifecycleStatus":{"type":"string","nullable":true,"enum":["subscriber","lead","prospect","opportunity","customer","churned","disqualified"]},"ownerMembershipId":{"type":"integer","nullable":true},"tags":{"type":"array","items":{"type":"string"},"description":"The COMPLETE tag list for this contact - tags not listed are removed. Omit the field to leave tags untouched; send [] to clear them. Unknown names are created."}},"required":["type","name"]},"AccountType":{"type":"string","enum":["BANK","CREDIT_CARD","DEBT","CASH","INVESTMENT","OTHER"]},"BalanceAccountNature":{"type":"string","enum":["ASSET","LIABILITY","EQUITY"]},"FinancialTransactionType":{"type":"string","enum":["INCOME","EXPENSE","TRANSFER"]},"FinancialBusinessEventType":{"type":"string","enum":["OPERATING_INCOME","OPERATING_EXPENSE","OWNER_CONTRIBUTION","PRO_LABORE","SHAREHOLDER_LOAN_IN","SHAREHOLDER_LOAN_REPAYMENT","SHAREHOLDER_LOAN_CONVERSION","DIVIDEND_DECLARATION","DIVIDEND_PAYMENT","TRANSFER","ADJUSTMENT"]},"CashFlowBucket":{"type":"string","enum":["OPERATING","INVESTING","FINANCING"]},"CurrencySummary":{"type":"object","properties":{"id":{"type":"integer","example":1},"code":{"type":"string","example":"USD"},"symbol":{"type":"string","nullable":true,"example":"$"}},"required":["id"]},"FinancialCategorySummary":{"type":"object","properties":{"id":{"type":"integer","example":12},"name":{"type":"string","example":"Software subscriptions"},"type":{"$ref":"#/components/schemas/FinancialTransactionType"}},"required":["id","name","type"]},"ClientSummary":{"type":"object","properties":{"id":{"type":"integer","example":10},"name":{"type":"string","example":"Acme Corp"},"email":{"type":"string","nullable":true,"example":"finance@acme.com"}},"required":["id","name"]},"ProjectSummary":{"type":"object","properties":{"id":{"type":"integer","example":22},"name":{"type":"string","example":"ERP rollout"}},"required":["id","name"]},"InvoiceSummary":{"type":"object","properties":{"id":{"type":"integer","example":31},"invoiceNumber":{"type":"string","example":"INV-2026-0031"},"status":{"type":"string","example":"PAID"}},"required":["id","invoiceNumber"]},"AccountSummary":{"type":"object","properties":{"id":{"type":"integer","example":8},"name":{"type":"string","example":"Main Bank Account"},"type":{"$ref":"#/components/schemas/AccountType"},"isActive":{"type":"boolean","example":true},"last4Digits":{"type":"string","nullable":true,"example":"1234"}},"required":["id","name","type","isActive"]},"FinancialTransaction":{"type":"object","properties":{"id":{"type":"integer","example":15},"organizationId":{"type":"integer","example":1},"type":{"$ref":"#/components/schemas/FinancialTransactionType"},"amount":{"type":"number","example":249.9},"currencyId":{"type":"integer","example":1},"categoryId":{"type":"integer","nullable":true,"example":12},"clientId":{"type":"integer","nullable":true,"example":10},"projectId":{"type":"integer","nullable":true,"example":22},"invoiceId":{"type":"integer","nullable":true,"example":31},"accountId":{"type":"integer","nullable":true,"example":8},"toAccountId":{"type":"integer","nullable":true,"example":9},"affectsProfit":{"type":"boolean","example":true},"businessEventType":{"allOf":[{"$ref":"#/components/schemas/FinancialBusinessEventType"}],"nullable":true},"cashFlowBucket":{"allOf":[{"$ref":"#/components/schemas/CashFlowBucket"}],"nullable":true},"description":{"type":"string","nullable":true,"example":"March software payment"},"transactionDate":{"type":"string","format":"date-time","example":"2026-03-13T12:00:00.000Z"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"category":{"allOf":[{"$ref":"#/components/schemas/FinancialCategorySummary"}],"nullable":true},"client":{"allOf":[{"$ref":"#/components/schemas/ClientSummary"}],"nullable":true},"project":{"allOf":[{"$ref":"#/components/schemas/ProjectSummary"}],"nullable":true},"invoice":{"allOf":[{"$ref":"#/components/schemas/InvoiceSummary"}],"nullable":true},"account":{"allOf":[{"$ref":"#/components/schemas/AccountSummary"}],"nullable":true},"toAccount":{"allOf":[{"$ref":"#/components/schemas/AccountSummary"}],"nullable":true},"currency":{"allOf":[{"$ref":"#/components/schemas/CurrencySummary"}],"nullable":true}},"required":["id","organizationId","type","amount","currencyId","affectsProfit","transactionDate","createdAt","updatedAt"]},"Account":{"type":"object","properties":{"id":{"type":"integer","example":8},"organizationId":{"type":"integer","example":1},"name":{"type":"string","example":"Main Bank Account"},"type":{"$ref":"#/components/schemas/AccountType"},"accountingNature":{"$ref":"#/components/schemas/BalanceAccountNature"},"currencyId":{"type":"integer","example":1},"description":{"type":"string","nullable":true,"example":"Primary operating account"},"isActive":{"type":"boolean","example":true},"isPrimary":{"type":"boolean","example":false},"creditLimit":{"type":"number","nullable":true,"example":10000},"initialBalance":{"type":"number","example":5000},"expirationDate":{"type":"string","format":"date-time","nullable":true},"last4Digits":{"type":"string","nullable":true,"example":"1234"},"metadata":{"type":"object","nullable":true,"additionalProperties":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"currency":{"allOf":[{"$ref":"#/components/schemas/CurrencySummary"}],"nullable":true}},"required":["id","organizationId","name","type","accountingNature","currencyId","isActive","isPrimary","initialBalance","createdAt","updatedAt"]},"AccountWithBalance":{"allOf":[{"$ref":"#/components/schemas/Account"},{"type":"object","properties":{"balance":{"type":"number","example":7340.15},"availableCredit":{"type":"number","nullable":true,"example":3200},"recentTransactions":{"type":"array","items":{"$ref":"#/components/schemas/FinancialTransaction"}}},"required":["balance"]}]},"CreateAccountRequest":{"type":"object","properties":{"name":{"type":"string","example":"Main Bank Account"},"type":{"$ref":"#/components/schemas/AccountType"},"currencyId":{"type":"integer","example":1},"accountingNature":{"$ref":"#/components/schemas/BalanceAccountNature"},"description":{"type":"string","nullable":true,"example":"Main operating bank account"},"creditLimit":{"type":"number","nullable":true,"example":10000},"initialBalance":{"type":"number","nullable":true,"example":5000},"expirationDate":{"type":"string","format":"date","nullable":true},"last4Digits":{"type":"string","nullable":true,"example":"1234"},"metadata":{"type":"object","nullable":true,"additionalProperties":true}},"required":["name","type","currencyId"]},"CreateTransactionRequest":{"type":"object","properties":{"type":{"$ref":"#/components/schemas/FinancialTransactionType"},"amount":{"type":"number","example":249.9},"currencyId":{"type":"integer","example":1},"categoryId":{"type":"integer","nullable":true,"example":12},"clientId":{"type":"integer","nullable":true,"example":10},"projectId":{"type":"integer","nullable":true,"example":22},"invoiceId":{"type":"integer","nullable":true,"example":31},"accountId":{"type":"integer","nullable":true,"example":8},"toAccountId":{"type":"integer","nullable":true,"example":9},"affectsProfit":{"type":"boolean","nullable":true,"example":true},"businessEventType":{"allOf":[{"$ref":"#/components/schemas/FinancialBusinessEventType"}],"nullable":true},"cashFlowBucket":{"allOf":[{"$ref":"#/components/schemas/CashFlowBucket"}],"nullable":true},"description":{"type":"string","nullable":true,"example":"March payroll transfer"},"transactionDate":{"type":"string","format":"date","example":"2026-03-13"}},"required":["type","amount","currencyId","transactionDate"]},"AccountResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"account":{"$ref":"#/components/schemas/AccountWithBalance"}}}},"required":["success","data"]},"AccountsListResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"accounts":{"type":"array","items":{"$ref":"#/components/schemas/AccountWithBalance"}}}}},"required":["success","data"]},"TransactionResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"transaction":{"$ref":"#/components/schemas/FinancialTransaction"}}}},"required":["success","data"]},"TransactionsListResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"transactions":{"type":"array","items":{"$ref":"#/components/schemas/FinancialTransaction"}},"pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"limit":{"type":"integer","example":50},"total":{"type":"integer","example":125},"totalPages":{"type":"integer","example":3}},"required":["page","limit","total","totalPages"]}}}},"required":["success","data"]},"UpdateLeadRequest":{"type":"object","description":"Partial update - only the fields present in the body are written. Send null to clear a nullable field; omit it to leave it untouched.","properties":{"name":{"type":"string","example":"Ada Lovelace"},"company":{"type":"string","nullable":true},"jobTitle":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true,"description":"Contact fields are written through the linked CRM person record, so the lead columns stay a mirror of it. The stored phone may be canonicalized (country code prepended)."},"sourceId":{"type":"integer","nullable":true,"description":"Takes precedence over sourceName when both are provided."},"sourceName":{"type":"string","nullable":true,"description":"Resolved case-insensitively against the organization's sources. Returns 400 if it does not match an existing source."},"campaignId":{"type":"integer","nullable":true},"ownerMembershipId":{"type":"integer","nullable":true},"score":{"type":"integer","nullable":true},"estimatedValue":{"type":"number","nullable":true},"notes":{"type":"string","nullable":true},"status":{"type":"string","enum":["NEW","CONTACTED","QUALIFIED","UNQUALIFIED","LOST","CONVERTED"],"description":"CONVERTED cannot be set directly - a lead becomes CONVERTED by converting it to a client, which links the client record. Sending it returns 400.","example":"QUALIFIED"},"lostReason":{"type":"string","nullable":true},"whatsappOptIn":{"type":"boolean","description":"Two-way consent switch. true records a SUBSCRIBED row (marketing templates allowed); false records UNSUBSCRIBED, which also cancels that contact's messages still waiting in the send queue. Omit to leave consent unchanged. Must be a real JSON boolean - strings like \"true\" return 400. Ignored when the lead has no resolvable phone.","example":false},"optInSource":{"type":"string","nullable":true,"description":"Provenance recorded on the consent row (e.g. \"portal:unsubscribe\", \"form:123\"). Defaults to \"lead_update\".","example":"portal:unsubscribe"}}},"CreateLeadRequest":{"type":"object","properties":{"name":{"type":"string","example":"Ada Lovelace"},"company":{"type":"string","nullable":true,"example":"Analytical Engines Ltd"},"jobTitle":{"type":"string","nullable":true,"example":"Founder"},"email":{"type":"string","nullable":true,"example":"ada@example.com"},"phone":{"type":"string","nullable":true,"example":"+18095550000"},"sourceId":{"type":"integer","nullable":true,"description":"Lead source id. Takes precedence over sourceName when both are provided.","example":1},"sourceName":{"type":"string","nullable":true,"description":"Lead source name, matched case-insensitively against the organization's sources. Used to resolve the source when sourceId is omitted. Returns 400 if the name does not match an existing source.","example":"Website"},"campaignId":{"type":"integer","nullable":true,"example":1},"ownerMembershipId":{"type":"integer","nullable":true,"example":9},"score":{"type":"integer","nullable":true,"example":80},"estimatedValue":{"type":"number","nullable":true,"example":2500},"notes":{"type":"string","nullable":true,"example":"Captured from partner integration"},"metadata":{"type":"object","nullable":true,"additionalProperties":true,"example":{"externalId":"lead_123","form":"demo-request"}},"whatsappOptIn":{"type":"boolean","nullable":true,"description":"Set true only when the contact gave explicit WhatsApp marketing consent (e.g. a checked opt-in box). When true and a phone is present, records a SUBSCRIBED consent row so a compliant marketing-template first-touch may be sent. Leads without opt-in are never cold-messaged. Must be a real JSON boolean - strings like \"true\" or numbers return 400. If no phone can be resolved for the lead the opt-in is ignored and no consent row is written, while the lead is still created.","example":true},"optInSource":{"type":"string","nullable":true,"description":"Provenance recorded on the consent row when whatsappOptIn is true (e.g. \"form:123\", \"ad:meta-q3\"). Defaults to \"lead_capture\" when omitted. Ignored when whatsappOptIn is not true.","example":"form:123"}},"required":["name"]},"LeadCrmRecord":{"type":"object","nullable":true,"properties":{"id":{"type":"integer","example":20},"displayName":{"type":"string","example":"Ada Lovelace"}}},"Lead":{"type":"object","properties":{"id":{"type":"integer","example":10},"name":{"type":"string","example":"Ada Lovelace"},"company":{"type":"string","nullable":true,"example":"Analytical Engines Ltd"},"jobTitle":{"type":"string","nullable":true,"example":"Founder"},"email":{"type":"string","nullable":true,"example":"ada@example.com"},"phone":{"type":"string","nullable":true,"example":"+18095550000"},"status":{"type":"string","example":"NEW"},"score":{"type":"integer","example":80},"estimatedValue":{"type":"number","nullable":true,"example":2500},"notes":{"type":"string","nullable":true},"metadata":{"type":"object","nullable":true,"additionalProperties":true},"personRecordId":{"type":"integer","nullable":true,"example":20},"companyRecordId":{"type":"integer","nullable":true,"example":30},"personRecord":{"$ref":"#/components/schemas/LeadCrmRecord"},"companyRecord":{"$ref":"#/components/schemas/LeadCrmRecord"},"lostReason":{"type":"string","nullable":true},"sourceId":{"type":"integer","nullable":true},"campaignId":{"type":"integer","nullable":true},"ownerMembershipId":{"type":"integer","nullable":true},"convertedClientId":{"type":"integer","nullable":true,"description":"Set once the lead became a client. Its presence is what makes the status CONVERTED."},"convertedAt":{"type":"string","format":"date-time","nullable":true},"source":{"type":"object","nullable":true,"description":"Only present on the read endpoints.","properties":{"id":{"type":"integer"},"name":{"type":"string"}}},"campaign":{"type":"object","nullable":true,"description":"Only present on the read endpoints.","properties":{"id":{"type":"integer"},"name":{"type":"string"}}},"owner":{"type":"object","nullable":true,"description":"Only present on the read endpoints. membershipId is the value to send back as ownerMembershipId.","properties":{"membershipId":{"type":"integer"},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true}}},"tags":{"type":"array","description":"Only present on the read endpoints.","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"}}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"LeadResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"lead":{"$ref":"#/components/schemas/Lead"}}}},"required":["success","data"]},"LeadListResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"leads":{"type":"array","items":{"$ref":"#/components/schemas/Lead"}},"pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"limit":{"type":"integer","example":25},"total":{"type":"integer","example":137},"totalPages":{"type":"integer","example":6}}}}}},"required":["success","data"]},"Opportunity":{"type":"object","properties":{"id":{"type":"integer","example":42},"title":{"type":"string","example":"Website redesign"},"status":{"type":"string","enum":["OPEN","WON","LOST"]},"value":{"type":"number","example":45000},"currencyId":{"type":"integer"},"probability":{"type":"integer","example":60},"probabilityIsManual":{"type":"boolean","description":"While true, moving the deal to another stage does not change its probability."},"stageId":{"type":"integer"},"stageEnteredAt":{"type":"string","format":"date-time"},"expectedCloseDate":{"type":"string","format":"date-time","nullable":true},"wonAt":{"type":"string","format":"date-time","nullable":true},"lostAt":{"type":"string","format":"date-time","nullable":true},"lostReason":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"ownerMembershipId":{"type":"integer","nullable":true},"leadId":{"type":"integer","nullable":true},"clientId":{"type":"integer","nullable":true},"quoteId":{"type":"integer","nullable":true},"personRecordId":{"type":"integer","nullable":true},"companyRecordId":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateOpportunityRequest":{"type":"object","properties":{"title":{"type":"string","example":"Website redesign"},"stageId":{"type":"integer","nullable":true,"description":"Defaults to the first stage of the organization's pipeline."},"value":{"type":"number","nullable":true},"currencyId":{"type":"integer","nullable":true},"probability":{"type":"integer","nullable":true},"expectedCloseDate":{"type":"string","format":"date-time","nullable":true},"notes":{"type":"string","nullable":true},"ownerMembershipId":{"type":"integer","nullable":true},"leadId":{"type":"integer","nullable":true,"description":"The lead this deal came from. Its owner, source, campaign and estimated value are inherited when not given explicitly. A lead can only have one open deal."},"clientId":{"type":"integer","nullable":true},"personRecordId":{"type":"integer","nullable":true},"companyRecordId":{"type":"integer","nullable":true},"campaignId":{"type":"integer","nullable":true},"sourceId":{"type":"integer","nullable":true}},"required":["title"]},"EnrollRequest":{"type":"object","description":"Exactly one of leadIds or contactIds, matching what the workflow runs on.","properties":{"leadIds":{"type":"array","items":{"type":"integer"},"description":"Lead ids, for a workflow whose trigger object is `lead`."},"contactIds":{"type":"array","items":{"type":"integer"},"description":"CRM person record ids, for a workflow whose trigger object is `person`."}}},"EnrollResult":{"type":"object","properties":{"workflowId":{"type":"integer","example":12},"subject":{"type":"string","enum":["lead","person"]},"enrolled":{"type":"integer","example":2},"skipped":{"type":"integer","example":1},"results":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","description":"The lead or contact id you sent."},"status":{"type":"string","enum":["enrolled","skipped"]},"runId":{"type":"integer","nullable":true,"description":"The run created","when enrolled.":null},"reason":{"type":"string","nullable":true,"enum":["not_found","opted_out","already_enrolled"],"description":"Why this one got no run. `already_enrolled` is the idempotent no-op, not a failure."}}}}}}}},"security":[{"ApiKeyAuth":[]}],"paths":{"/api/v1/accounts/{id}":{"get":{"summary":"Get customer account by ID","tags":["Customer Accounts"],"operationId":"getAccountById"},"put":{"summary":"Update customer account","tags":["Customer Accounts"],"operationId":"updateAccountById"},"delete":{"summary":"Delete customer account","tags":["Customer Accounts"],"operationId":"deleteAccountById"}},"/api/v1/accounts":{"get":{"summary":"List customer accounts","description":"Canonical customer-account endpoint. /api/v1/clients remains available as a legacy-compatible alias.","tags":["Customer Accounts"],"operationId":"listAccounts"},"post":{"summary":"Create customer account","description":"Canonical create endpoint. Accepts the same payload as legacy /api/v1/clients and returns customerAccount/customerAccountId.","tags":["Customer Accounts"],"operationId":"createAccount"}},"/api/v1/activities/{id}":{"get":{"summary":"Get one activity","tags":["Activities"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"The activity"},"401":{"description":"Missing or invalid API key"},"404":{"description":"No such activity in this organization"}},"operationId":"getActivityById"},"patch":{"summary":"Complete or cancel an activity","tags":["Activities"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["PLANNED","COMPLETED","CANCELED"],"description":"COMPLETED stamps completedAt; anything else clears it."}},"required":["status"]}}}},"responses":{"200":{"description":"The updated activity"},"400":{"description":"Invalid payload"},"401":{"description":"Missing or invalid API key"},"404":{"description":"No such activity in this organization"}},"operationId":"updateActivityById"}},"/api/v1/activities":{"get":{"summary":"List activities","tags":["Activities"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"in":"query","name":"type","schema":{"type":"string","enum":["CALL","EMAIL","MEETING","TASK","NOTE","FOLLOW_UP"]}},{"in":"query","name":"status","schema":{"type":"string","enum":["PLANNED","COMPLETED","CANCELED"]}},{"in":"query","name":"ownerMembershipId","description":"A membership id, or the literal \"unassigned\".","schema":{"type":"string"}},{"in":"query","name":"leadId","schema":{"type":"integer"}},{"in":"query","name":"opportunityId","schema":{"type":"integer"}},{"in":"query","name":"clientId","schema":{"type":"integer"}},{"in":"query","name":"contactId","schema":{"type":"integer"}},{"in":"query","name":"dueBefore","description":"Combine with status=PLANNED for \"what is overdue\".","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"dueAfter","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"updatedSince","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"createdSince","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"sort","schema":{"type":"string","enum":["dueAt","createdAt","updatedAt","completedAt","id"],"default":"dueAt"}},{"in":"query","name":"order","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Activities page"},"400":{"description":"A query parameter could not be parsed"},"401":{"description":"Missing or invalid API key"}},"operationId":"listActivities"},"post":{"summary":"Log an activity","tags":["Activities"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateActivityRequest"}}}},"responses":{"201":{"description":"Activity created"},"400":{"description":"Invalid payload"},"401":{"description":"Missing or invalid API key"}},"operationId":"createActivity"}},"/api/v1/clients/{id}":{"get":{"summary":"Get client by ID","description":"Retrieve a single client by its ID. Returns full client details including user, organization, projects, and tickets information.","tags":["Clients"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Client ID"}],"responses":{"200":{"description":"Client retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientResponse"}}}},"400":{"description":"Invalid client ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"getClientById"},"put":{"summary":"Update client","description":"Update an existing client. All fields are optional. Email uniqueness is enforced within the organization.","tags":["Clients"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Client ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateClientRequest"},"example":{"name":"John Doe Updated","email":"john.doe.updated@example.com","phone":"+1234567891"}}}},"responses":{"200":{"description":"Client updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Client or user not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"updateClientById"},"delete":{"summary":"Delete client","description":"Delete a client by ID. Cannot delete clients with associated projects or tickets.","tags":["Clients"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Client ID"}],"responses":{"200":{"description":"Client deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"integer","example":1},"message":{"type":"string","example":"Client deleted successfully"}}}}}}}},"400":{"description":"Invalid client ID or client cannot be deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"deleteClientById"}},"/api/v1/clients":{"get":{"summary":"List clients with pagination and search filters","description":"Retrieve a paginated list of clients for the authenticated organization. Supports searching by name, email, and phone.","tags":["Clients"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number for pagination"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":10},"description":"Number of items per page"},{"in":"query","name":"search","schema":{"type":"string"},"description":"Search in client name, email, and phone"}],"responses":{"200":{"description":"Successful response with clients list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientsListResponse"}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"listClients"},"post":{"summary":"Create a new client","description":"Create a new client in the authenticated organization. Name is required, all other fields are optional.","tags":["Clients"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClientRequest"},"example":{"name":"John Doe","email":"john.doe@example.com","phone":"+1234567890","avatar":"https://example.com/avatar.jpg","userId":1}}}},"responses":{"200":{"description":"Client created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"createClient"}},"/api/v1/contacts/{id}":{"get":{"summary":"Read one CRM contact","description":"The same contact the list returns, so a caller needs one mapper rather\nthan two.\n\nA contact of another organization, and a record that is not a PERSON or\nCOMPANY (a deal, an internal record), both answer 404. They are the same\nanswer on purpose: distinguishing them would let a caller probe which\nids exist in someone else's account.\n","tags":["CRM Contacts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"The contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"400":{"description":"Malformed id"},"401":{"description":"Unauthorized - invalid or missing API key"},"403":{"description":"The CRM module is not active for this organization"},"404":{"description":"No such contact in this organization"}},"operationId":"getContactById"},"patch":{"summary":"Update a CRM contact","description":"Partially update a PERSON or COMPANY record owned by the authenticated organization. Changes to a person's name, e-mail or phone propagate to the leads that mirror it, and a record.updated workflow trigger fires after the write.","tags":["CRM Contacts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateContactRequest"}}}},"responses":{"200":{"description":"The updated contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"400":{"description":"Malformed id or field"},"401":{"description":"Unauthorized - invalid or missing API key"},"403":{"description":"The CRM module is not active for this organization"},"404":{"description":"No such contact in this organization"},"409":{"description":"An identifier in the body already belongs to another contact"}},"operationId":"updateContactById"}},"/api/v1/contacts":{"get":{"summary":"List CRM contacts (people and companies)","description":"The canonical identity layer of the CRM: the records that leads,\nconversations, opportunities and clients all point at. Only PERSON and\nCOMPANY records are ever returned - deal records belong to the\nopportunities resource.\n\nAt most ONE identifier filter (email, phone, domain, taxId, externalId)\nper request; values are normalized before matching, so an address sent\nin any casing finds its contact.\n","tags":["CRM Contacts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":25,"maximum":100}},{"in":"query","name":"type","schema":{"type":"string","enum":["PERSON","COMPANY"]}},{"in":"query","name":"lifecycleStatus","schema":{"type":"string"}},{"in":"query","name":"source","schema":{"type":"string"}},{"in":"query","name":"ownerMembershipId","description":"A membership id, or the literal \"unassigned\" for contacts nobody owns.","schema":{"type":"string"}},{"in":"query","name":"tag","description":"Tag name or slug, matched on the slug (casing and spacing forgiven).","schema":{"type":"string"}},{"in":"query","name":"email","schema":{"type":"string"}},{"in":"query","name":"phone","schema":{"type":"string"}},{"in":"query","name":"domain","schema":{"type":"string"}},{"in":"query","name":"taxId","schema":{"type":"string"}},{"in":"query","name":"externalId","schema":{"type":"string"}},{"in":"query","name":"updatedSince","description":"ISO-8601. Incremental sync - contacts touched at or after this instant.","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"createdSince","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"sort","schema":{"type":"string","enum":["updatedAt","createdAt","displayName","id"],"default":"updatedAt"}},{"in":"query","name":"order","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"A page of contacts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactListResponse"}}}},"400":{"description":"A malformed or ambiguous query parameter, named in the message"},"401":{"description":"Unauthorized - invalid or missing API key"},"403":{"description":"The CRM module is not active for this organization"}},"operationId":"listContacts"},"post":{"summary":"Create or update a CRM contact, resolved by identifier","description":"An upsert keyed on identity, not on our primary key. The identifiers in\nthe body are normalized and looked up first; a match updates that\ncontact (200) and no match creates one (201). Contacts are NEVER matched\nby name - two different customers sharing a name must not become one\nrecord.\n","tags":["CRM Contacts"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertContactRequest"}}}},"responses":{"200":{"description":"An existing contact was matched by identifier and updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"201":{"description":"A new contact was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"400":{"description":"Missing name/type, no identifier, or an unusable value"},"401":{"description":"Unauthorized - invalid or missing API key"},"403":{"description":"The CRM module is not active for this organization"},"409":{"description":"The identifier already belongs to a record of another type"}},"operationId":"createContact"}},"/api/v1/events":{"post":{"summary":"Ingest product events","description":"Record business events emitted by a product (signup, subscription started/canceled, churn, revenue, feature usage). Feeds the PRODUCT dashboard (MRR, signups, churn). Accepts a single event object or a batch via `{ \"events\": [...] }` (max 500 per request). Supply an `externalId` to make delivery idempotent — a repeated id is a no-op.\n","tags":["Product Events"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProductEvent"},{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/ProductEvent"}}},"required":["events"]}]},"examples":{"signup":{"summary":"A single signup","value":{"name":"user_signed_up","distinctId":"user_123","email":"ada@example.com","externalId":"evt_abc"}},"batch":{"summary":"A batch with a paid subscription","value":{"events":[{"name":"user_signed_up","distinctId":"user_123"},{"name":"subscription_started","distinctId":"user_123","amountUsd":29,"currency":"USD"}]}}}}}},"responses":{"202":{"description":"Events accepted for ingestion","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"accepted":{"type":"integer","example":2},"duplicates":{"type":"integer","example":0},"eventIds":{"type":"array","items":{"type":"integer"}}}}}}}}},"400":{"description":"Invalid request body or event payload"},"401":{"description":"Unauthorized - Invalid or missing API key"}},"operationId":"createEvent"}},"/api/v1/financial/accounts/{id}":{"get":{"summary":"Get financial account by ID","description":"Retrieve a single account, including its calculated balance and optionally its most recent transactions.","tags":["Financial Accounts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Account ID"},{"in":"query","name":"includeTransactions","schema":{"type":"boolean","default":false},"description":"Include recent transactions for this account"},{"in":"query","name":"transactionLimit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of recent transactions to include"}],"responses":{"200":{"description":"Account retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountResponse"}}}},"400":{"description":"Invalid account ID or query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"getFinancialAccountById"}},"/api/v1/financial/accounts":{"get":{"summary":"List financial accounts","description":"Retrieve financial accounts for the authenticated organization, including their calculated balances.","tags":["Financial Accounts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"type","schema":{"$ref":"#/components/schemas/AccountType"},"description":"Filter by account type"},{"in":"query","name":"includeInactive","schema":{"type":"boolean","default":false},"description":"Include inactive accounts in the response"}],"responses":{"200":{"description":"Accounts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountsListResponse"}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"listFinancialAccounts"},"post":{"summary":"Create a financial account","description":"Create a new account for the authenticated organization. Credit card accounts require a positive credit limit.","tags":["Financial Accounts"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountRequest"},"example":{"name":"Main Bank Account","type":"BANK","currencyId":1,"accountingNature":"ASSET","description":"Primary operating bank account","initialBalance":2500,"metadata":{"bank":"Inter"}}}}},"responses":{"200":{"description":"Account created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Currency not found for this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"createFinancialAccount"}},"/api/v1/financial/transactions/{id}":{"get":{"summary":"Get financial transaction by ID","description":"Retrieve a single financial transaction for the authenticated organization.","tags":["Financial Transactions"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Transaction ID"}],"responses":{"200":{"description":"Transaction retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"400":{"description":"Invalid transaction ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Transaction not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"getFinancialTransactionById"}},"/api/v1/financial/transactions":{"get":{"summary":"List financial transactions","description":"Retrieve financial transactions for the authenticated organization with pagination and optional filters.","tags":["Financial Transactions"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":50},"description":"Number of items per page"},{"in":"query","name":"type","schema":{"$ref":"#/components/schemas/FinancialTransactionType"},"description":"Filter by transaction type"},{"in":"query","name":"categoryId","schema":{"type":"integer"},"description":"Filter by financial category"},{"in":"query","name":"clientId","schema":{"type":"integer"},"description":"Filter by client"},{"in":"query","name":"projectId","schema":{"type":"integer"},"description":"Filter by project"},{"in":"query","name":"accountId","schema":{"type":"integer"},"description":"Filter by source or destination account"},{"in":"query","name":"currencyId","schema":{"type":"integer"},"description":"Filter by currency"},{"in":"query","name":"startDate","schema":{"type":"string","format":"date"},"description":"Filter transactions on or after this date"},{"in":"query","name":"endDate","schema":{"type":"string","format":"date"},"description":"Filter transactions on or before this date"}],"responses":{"200":{"description":"Transactions retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionsListResponse"}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"listFinancialTransactions"},"post":{"summary":"Create a financial transaction","description":"Create a financial transaction for the authenticated organization. Transfer transactions require both source and destination accounts.","tags":["Financial Transactions"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTransactionRequest"},"example":{"type":"EXPENSE","amount":249.9,"currencyId":1,"categoryId":12,"accountId":8,"description":"March software subscription","transactionDate":"2026-03-13"}}}},"responses":{"200":{"description":"Transaction created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Related resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"createFinancialTransaction"}},"/api/v1/items/{id}":{"get":{"summary":"Get item by ID","description":"Retrieve a single item by its ID. Returns full item details including category, currency, and base prices.","tags":["Items"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Item ID"}],"responses":{"200":{"description":"Item retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemResponse"}}}},"400":{"description":"Invalid item ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Item not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"getItemById"},"put":{"summary":"Update item","description":"Update an existing item. All fields are optional. Enum values must be valid if provided.","tags":["Items"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Item ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateItemRequest"},"example":{"name":"Updated Web Development Service","basePrice":120,"isActive":true}}}},"responses":{"200":{"description":"Item updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Item, currency, or category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"updateItemById"},"delete":{"summary":"Delete item","description":"Delete an item by ID. Cannot delete items with associated contract items, invoice items, entitlements, or quote items.","tags":["Items"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Item ID"}],"responses":{"200":{"description":"Item deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"integer","example":1},"message":{"type":"string","example":"Item deleted successfully"}}}}}}}},"400":{"description":"Invalid item ID or item cannot be deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Item not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"deleteItemById"}},"/api/v1/items":{"get":{"summary":"List items with pagination and filters","description":"Retrieve a paginated list of items for the authenticated organization. Supports filtering by type, category, active status, provisioning strategy, and search terms.","tags":["Items"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number for pagination"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":10},"description":"Number of items per page"},{"in":"query","name":"type","schema":{"$ref":"#/components/schemas/ItemType"},"description":"Filter by item type"},{"in":"query","name":"categoryId","schema":{"type":"integer"},"description":"Filter by category ID"},{"in":"query","name":"isActive","schema":{"type":"boolean"},"description":"Filter by active status"},{"in":"query","name":"provisioningStrategy","schema":{"$ref":"#/components/schemas/ProvisioningStrategy"},"description":"Filter by provisioning strategy"},{"in":"query","name":"search","schema":{"type":"string"},"description":"Search in item name and description"}],"responses":{"200":{"description":"Successful response with items list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemsListResponse"}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"listItems"},"post":{"summary":"Create a new item","description":"Create a new item in the authenticated organization. All required fields must be provided.","tags":["Items"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateItemRequest"},"example":{"name":"Web Development Service","description":"Custom web development service","type":"SERVICE","unitOfMeasure":"HOUR","billingModel":"TIME_AND_MATERIALS","internalCost":50,"basePrice":100,"setupFee":0,"currencyId":1,"categoryId":1,"provisioningStrategy":"NONE","renewalType":"NONE"}}}},"responses":{"200":{"description":"Item created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Currency or category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"createItem"}},"/api/v1/leads/{id}":{"get":{"summary":"Read one growth lead","description":"The full lead, with its source, campaign, owner and tags resolved — the\nsame shape the list endpoint returns, so a caller does not need a second\nmapper for the detail view.\n\nA lead of another organization and a deleted lead both answer 404. They\nare the same answer on purpose: distinguishing them would let a caller\nprobe which ids exist in someone else's account.\n","tags":["Growth Leads"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"example":10}],"responses":{"200":{"description":"The lead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadResponse"}}}},"400":{"description":"Malformed id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Lead not found in this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"getLeadById"},"patch":{"summary":"Update a growth lead","description":"Partially update a lead owned by the authenticated organization. Contact changes propagate to the linked CRM person record, and a record.updated workflow trigger fires after the write.","tags":["Growth Leads"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Lead id returned by POST /api/v1/leads","example":10}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLeadRequest"},"examples":{"qualify":{"summary":"Move the lead forward and assign an owner","value":{"status":"QUALIFIED","score":90,"ownerMembershipId":9}},"revokeConsent":{"summary":"Record a WhatsApp opt-out and suppress queued sends","value":{"whatsappOptIn":false,"optInSource":"portal:unsubscribe"}},"clearField":{"summary":"Clear a nullable field","value":{"notes":null}}}}}},"responses":{"200":{"description":"Lead updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Lead not found in this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"updateLeadById"}},"/api/v1/leads":{"post":{"summary":"Create a growth lead","description":"Create a lead for the authenticated organization and automatically link it to CRM person/company records.","tags":["Growth Leads"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLeadRequest"},"examples":{"bySourceId":{"summary":"Attribute the lead using a source id","value":{"name":"Ada Lovelace","company":"Analytical Engines Ltd","jobTitle":"Founder","email":"ada@example.com","phone":"+18095550000","sourceId":1,"ownerMembershipId":9,"score":80,"estimatedValue":2500,"notes":"Captured from partner integration","metadata":{"externalId":"lead_123"}}},"bySourceName":{"summary":"Attribute the lead using a source name (resolved to its id)","value":{"name":"Ada Lovelace","email":"ada@example.com","sourceName":"Website","notes":"Captured from partner integration"}},"withWhatsAppOptIn":{"summary":"Record explicit WhatsApp marketing consent","value":{"name":"Ada Lovelace","phone":"+18095550000","sourceName":"Website","whatsappOptIn":true,"optInSource":"form:123"}}}}}},"responses":{"201":{"description":"Lead created and linked to CRM records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Duplicate lead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"createLead"},"get":{"summary":"List growth leads","description":"Paginated list of the authenticated organization's leads, newest change\nfirst. Deleted leads are never returned — the CRM hides them rather than\ndestroying them, and a sync that saw them would resurrect every contact\nthe customer removed.\n\nEvery filter is validated: a parameter that cannot be parsed answers 400\nand names itself, instead of being dropped. A dropped filter returns the\nwhole base and looks like a successful sync.\n","tags":["Growth Leads"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"in":"query","name":"status","schema":{"type":"string","enum":["NEW","CONTACTED","QUALIFIED","UNQUALIFIED","LOST","CONVERTED"]}},{"in":"query","name":"sourceId","schema":{"type":"integer"}},{"in":"query","name":"campaignId","schema":{"type":"integer"}},{"in":"query","name":"ownerMembershipId","description":"A membership id, or the literal \"unassigned\" for leads nobody owns. Omit for any owner.","schema":{"type":"string","example":"unassigned"}},{"in":"query","name":"tag","description":"Tag name or slug. Matched on the slug, so casing and inner spacing are forgiven.","schema":{"type":"string","example":"hot lead"}},{"in":"query","name":"updatedSince","description":"ISO-8601. Incremental sync — rows whose updatedAt is at or after this instant.","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"createdSince","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"sort","schema":{"type":"string","enum":["updatedAt","createdAt","id"],"default":"updatedAt"}},{"in":"query","name":"order","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Page of leads","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadListResponse"}}}},"400":{"description":"Invalid query parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"listLeads"}},"/api/v1/opportunities/{id}":{"get":{"summary":"Get one opportunity","tags":["Opportunities"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"The opportunity"},"401":{"description":"Missing or invalid API key"},"404":{"description":"No such opportunity in this organization"}},"operationId":"getOpportunityById"},"patch":{"summary":"Update, move or close an opportunity","tags":["Opportunities"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Partial update - only the fields present are written.","properties":{"title":{"type":"string"},"value":{"type":"number"},"currencyId":{"type":"integer"},"probability":{"type":"integer","minimum":0,"maximum":100},"expectedCloseDate":{"type":"string","format":"date-time","nullable":true},"notes":{"type":"string","nullable":true},"ownerMembershipId":{"type":"integer","nullable":true},"personRecordId":{"type":"integer","nullable":true},"companyRecordId":{"type":"integer","nullable":true},"stageId":{"type":"integer","description":"Moves the deal. Cannot be combined with a WON or LOST status - closing already moves it to the terminal stage."},"status":{"type":"string","enum":["OPEN","WON","LOST"]},"lostReason":{"type":"string","description":"Required when status is LOST. One of the values listed in the error message when omitted."}}}}}},"responses":{"200":{"description":"The updated opportunity"},"400":{"description":"Invalid payload","or LOST without a loss reason":null},"401":{"description":"Missing or invalid API key"},"404":{"description":"No such opportunity in this organization"}},"operationId":"updateOpportunityById"}},"/api/v1/opportunities":{"get":{"summary":"List opportunities","tags":["Opportunities"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"in":"query","name":"status","schema":{"type":"string","enum":["OPEN","WON","LOST"]}},{"in":"query","name":"stageId","schema":{"type":"integer"}},{"in":"query","name":"ownerMembershipId","description":"A membership id, or the literal \"unassigned\".","schema":{"type":"string"}},{"in":"query","name":"leadId","schema":{"type":"integer"}},{"in":"query","name":"clientId","schema":{"type":"integer"}},{"in":"query","name":"personRecordId","schema":{"type":"integer"}},{"in":"query","name":"companyRecordId","schema":{"type":"integer"}},{"in":"query","name":"campaignId","schema":{"type":"integer"}},{"in":"query","name":"sourceId","schema":{"type":"integer"}},{"in":"query","name":"closedSince","description":"Won or lost at or after this instant - the incremental read for a revenue sync.","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"updatedSince","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"createdSince","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"sort","schema":{"type":"string","enum":["updatedAt","createdAt","value","expectedCloseDate","id"],"default":"updatedAt"}},{"in":"query","name":"order","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Opportunities page"},"400":{"description":"A query parameter could not be parsed"},"401":{"description":"Missing or invalid API key"}},"operationId":"listOpportunities"},"post":{"summary":"Create an opportunity","tags":["Opportunities"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOpportunityRequest"}}}},"responses":{"201":{"description":"Opportunity created"},"400":{"description":"Invalid payload"},"401":{"description":"Missing or invalid API key"}},"operationId":"createOpportunity"}},"/api/v1/projects/{id}":{"get":{"summary":"Get project by ID","description":"Retrieve a single project by its ID for the authenticated organization.","tags":["Projects"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Project retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid project ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"getProjectById"},"put":{"summary":"Update project","description":"Update an existing project. All fields are optional.","tags":["Projects"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectRequest"}}}},"responses":{"200":{"description":"Project updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"updateProjectById"},"delete":{"summary":"Delete project","description":"Delete a project. Projects with associated tickets cannot be deleted.","tags":["Projects"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Project deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"deleteProjectById"}},"/api/v1/projects/{projectId}/tasks":{"get":{"summary":"List tasks for a project","description":"Retrieve tasks for a project with optional filters by status, assignee, and search term.","tags":["Tasks"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"projectId","required":true,"schema":{"type":"integer"}},{"in":"query","name":"statusId","schema":{"type":"integer"}},{"in":"query","name":"assigneeMembershipId","schema":{"type":"integer"}},{"in":"query","name":"search","schema":{"type":"string"}},{"in":"query","name":"archived","description":"Whether archived tasks are included. Defaults to `live`.","schema":{"type":"string","enum":["live","archived","all"]}}],"responses":{"200":{"description":"Successful response with tasks list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TasksListResponse"}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"getProjectTaskByProjectid"},"post":{"summary":"Create a task in a project","description":"Create a new task in the specified project. Title is required.","tags":["Tasks"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"projectId","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskRequest"}}}},"responses":{"200":{"description":"Task created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"createProjectTaskByProjectid"}},"/api/v1/projects":{"get":{"summary":"List projects with pagination and filters","description":"Retrieve a paginated list of projects for the authenticated organization. Supports filtering by status, client, type, and search term.","tags":["Projects"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":10}},{"in":"query","name":"status","schema":{"$ref":"#/components/schemas/ProjectStatus"}},{"in":"query","name":"clientId","schema":{"type":"integer"}},{"in":"query","name":"type","schema":{"$ref":"#/components/schemas/ProjectType"}},{"in":"query","name":"search","schema":{"type":"string"}}],"responses":{"200":{"description":"Successful response with projects list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsListResponse"}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"listProjects"},"post":{"summary":"Create a new project","description":"Create a project in the authenticated organization. Name is required.","tags":["Projects"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}}},"responses":{"200":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"createProject"}},"/api/v1/quotes/{id}":{"get":{"summary":"Get quote by ID","description":"Retrieve a single quote by its ID. Returns full quote details including items, client, and currency information.","tags":["Quotes"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Quote ID"}],"responses":{"200":{"description":"Quote retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"400":{"description":"Invalid quote ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Quote not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"getQuoteById"},"put":{"summary":"Update quote","description":"Update an existing quote. All fields are optional. Cannot update quotes that have been converted to contracts, projects, or invoices.","tags":["Quotes"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Quote ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateQuoteRequest"},"example":{"title":"Updated Quote Title","status":"SENT","notes":"Updated notes"}}}},"responses":{"200":{"description":"Quote updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"400":{"description":"Invalid request data or quote cannot be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Quote not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"updateQuoteById"},"delete":{"summary":"Delete quote","description":"Delete a quote by ID. Cannot delete quotes that have been converted to contracts, projects, or invoices.","tags":["Quotes"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Quote ID"}],"responses":{"200":{"description":"Quote deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"integer","example":1},"message":{"type":"string","example":"Quote deleted successfully"}}}}}}}},"400":{"description":"Invalid quote ID or quote cannot be deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Quote not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"deleteQuoteById"}},"/api/v1/quotes":{"get":{"summary":"List quotes with pagination and filters","description":"Retrieve a paginated list of quotes for the authenticated organization. Supports filtering by status, client, and search terms.","tags":["Quotes"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number for pagination"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":10},"description":"Number of items per page"},{"in":"query","name":"status","schema":{"$ref":"#/components/schemas/QuoteStatus"},"description":"Filter by quote status"},{"in":"query","name":"clientId","schema":{"type":"integer"},"description":"Filter by client ID"},{"in":"query","name":"search","schema":{"type":"string"},"description":"Search in quote title and quote number"}],"responses":{"200":{"description":"Successful response with quotes list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotesListResponse"}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"listQuotes"},"post":{"summary":"Create a new quote","description":"Create a new quote with items. Provide either clientId for an existing client or opportunityId for a sales opportunity/deal. Quotes are not created directly from leadId; convert the lead to an opportunity first. The quote will be created in DRAFT status and totals are calculated automatically.","tags":["Quotes"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateQuoteRequest"},"example":{"opportunityId":77,"title":"Website Development Quote","currencyCode":"usd","validUntil":"2024-12-31T23:59:59Z","notes":"This is a custom quote for website development","items":[{"name":"Web Development Service","description":"Custom web development","quantity":1,"unitPrice":1000,"discount":0,"tax":0,"setupFee":0}]}}}},"responses":{"200":{"description":"Quote created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"createQuote"}},"/api/v1/tasks/{id}":{"get":{"summary":"Get task by ID","description":"Retrieve a single task by its ID for the authenticated organization.","tags":["Tasks"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Task retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskResponse"}}}},"400":{"description":"Invalid task ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Task not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"getTaskById"},"put":{"summary":"Update task","description":"Update an existing task. All fields are optional.","tags":["Tasks"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTaskRequest"}}}},"responses":{"200":{"description":"Task updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Task not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"updateTaskById"},"delete":{"summary":"Delete task","description":"Soft-delete a task and its subtasks by moving them to trash.","tags":["Tasks"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Task deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Task not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"deleteTaskById"}},"/api/v1/tickets/{id}/messages":{"post":{"summary":"Add message to ticket","description":"Add an internal agent message to an existing ticket. This also updates the ticket workflow status when needed and triggers email reply delivery for email-based tickets.","tags":["Tickets"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Ticket ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTicketMessageRequest"},"example":{"content":"<p>We found the root cause and applied a fix. Please confirm.</p>","type":"TEXT"}}}},"responses":{"200":{"description":"Message added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketMessageResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Ticket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"createTicketMessageById"}},"/api/v1/tickets/{id}":{"get":{"summary":"Get ticket by ID","description":"Retrieve a single ticket by its ID, including its message history, relations, and assignee information.","tags":["Tickets"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Ticket ID"}],"responses":{"200":{"description":"Ticket retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponse"}}}},"400":{"description":"Invalid ticket ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Ticket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"getTicketById"},"put":{"summary":"Update ticket","description":"Update an existing ticket. Supports subject, department, priority, status, client, email, and assignment changes. Status transitions are validated using the ticket workflow rules.","tags":["Tickets"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Ticket ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTicketRequest"},"example":{"status":"IN_PROGRESS","priority":"HIGH","departmentId":2,"assignedToUserMembershipId":17}}}},"responses":{"200":{"description":"Ticket updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Ticket or related resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"updateTicketById"},"delete":{"summary":"Delete ticket","description":"Delete a ticket by ID from the authenticated organization.","tags":["Tickets"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"Ticket ID"}],"responses":{"200":{"description":"Ticket deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteTicketResponse"}}}},"400":{"description":"Invalid ticket ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Ticket not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"deleteTicketById"}},"/api/v1/tickets":{"get":{"summary":"List tickets with pagination and filters","description":"Retrieve a paginated list of tickets for the authenticated organization. Supports filtering by status, priority, department, client, assignment, and search term.","tags":["Tickets"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number for pagination"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":10},"description":"Number of items per page"},{"in":"query","name":"status","schema":{"$ref":"#/components/schemas/SupportTicketStatus"},"description":"Filter by ticket status"},{"in":"query","name":"priority","schema":{"$ref":"#/components/schemas/TicketPriority"},"description":"Filter by ticket priority"},{"in":"query","name":"departmentId","schema":{"type":"integer"},"description":"Filter by department ID"},{"in":"query","name":"clientId","schema":{"type":"integer"},"description":"Filter by client ID"},{"in":"query","name":"assignedToUserMembershipId","schema":{"oneOf":[{"type":"integer"},{"type":"string","enum":["null"]}]},"description":"Filter by assigned membership ID. Use `null` to return unassigned tickets."},{"in":"query","name":"search","schema":{"type":"string"},"description":"Search in ticket subject, email, and message"}],"responses":{"200":{"description":"Successful response with tickets list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketsListResponse"}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"listTickets"},"post":{"summary":"Create a new ticket","description":"Create a new support ticket in the authenticated organization with an initial message. You must provide a client or an email. If `projectId` is provided and `clientId` is omitted, the project client is used automatically.","tags":["Tickets"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTicketRequest"},"example":{"subject":"Integration issue with billing webhook","message":"<p>The webhook is returning 500 for paid invoices.</p>","priority":"HIGH","departmentId":2,"clientId":14,"projectId":8}}}},"responses":{"200":{"description":"Ticket created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Related resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"createTicket"}},"/api/v1/timeline":{"get":{"summary":"Read the interaction timeline of a contact, lead or opportunity","tags":["Activities"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"contactId","description":"A CRM record id. At least one of contactId, leadId or opportunityId is required.","schema":{"type":"integer"}},{"in":"query","name":"leadId","schema":{"type":"integer"}},{"in":"query","name":"opportunityId","schema":{"type":"integer"}},{"in":"query","name":"category","description":"Repeatable. Filters to these interaction categories.","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200,"default":100}}],"responses":{"200":{"description":"The timeline","newest first":null},"400":{"description":"No subject given","or a parameter could not be parsed":null},"401":{"description":"Missing or invalid API key"}},"operationId":"listTimeline"}},"/api/v1/workflows/{id}/enroll":{"post":{"summary":"Enroll leads or contacts into a published workflow","description":"Starts the workflow for each subject, exactly as the CRM's bulk-enroll button does. Safe to retry: a subject already in this workflow comes back as `already_enrolled` rather than starting a second run.\n","tags":["Workflows"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollRequest"}}}},"responses":{"200":{"description":"Every subject got a verdict — see `results`."},"400":{"description":"Invalid payload","or the wrong subject type for this workflow":null},"401":{"description":"Missing or invalid API key"},"403":{"description":"The organization does not have workflow automations"},"404":{"description":"No such workflow in this organization"},"409":{"description":"The workflow exists but is not published and active"}},"operationId":"createWorkflowEnrollById"}},"/api/stripe/webhook/{organizationId}":{"post":{"summary":"Stripe webhook endpoint for invoice.paid events","description":"Webhook endpoint to receive Stripe events, specifically for invoice.paid events.\nWhen a Stripe invoice is paid, this endpoint will:\n1. Create or update a ClientInvoice record\n2. Register the payment\n3. Create a FinancialTransaction entry in the accounting system\n\nThe webhook signature must be verified using the Stripe webhook secret configured\nin the organization's Stripe integration settings.\n","tags":["Finance","Webhooks"],"parameters":[{"in":"path","name":"organizationId","required":true,"schema":{"type":"integer"},"description":"Organization ID"},{"in":"header","name":"stripe-signature","required":false,"schema":{"type":"string"},"description":"Stripe webhook signature header sent automatically by Stripe with each webhook request.\nThis header is used to verify the authenticity of the webhook. The webhook secret\nmust be configured in the integration settings to enable signature verification.\n"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeWebhookEvent"},"examples":{"invoicePaid":{"summary":"Invoice Paid Event","value":{"id":"evt_1234567890","object":"event","api_version":"2023-10-16","created":1698765432,"type":"invoice.paid","data":{"object":{"id":"in_1234567890","object":"invoice","amount_paid":10000,"amount_due":0,"currency":"usd","customer":"cus_1234567890","invoice_pdf":"https://pay.stripe.com/invoice/xxx","hosted_invoice_url":"https://invoice.stripe.com/i/xxx","status":"paid","subtotal":10000,"tax":null,"created":1698765432,"due_date":1698765432,"metadata":{"organizationId":"123","clientId":"456","clientInvoiceId":"789"},"status_transitions":{"paid_at":1698765432},"payment_intent":"pi_1234567890","lines":{"data":[{"id":"il_1234567890","description":"Service Subscription","amount":10000,"quantity":1,"price":{"unit_amount":10000}}]}}}}}}}}},"responses":{"200":{"description":"Webhook processed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSuccessResponse"},"example":{"message":"ok"}}}},"400":{"description":"Bad request - Invalid payload, signature verification failed, or webhook processing failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookErrorResponse"},"examples":{"invalidOrganization":{"value":{"error":"Invalid organization ID"}},"signatureVerificationFailed":{"value":{"error":"Webhook signature verification failed: No signatures found matching the expected signature"}},"processingFailed":{"value":{"error":"Could not identify organization from webhook"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookErrorResponse"},"example":{"error":"Internal server error"}}}}},"operationId":"createStripeWebhookByOrganizationid"}}},"tags":[{"name":"Financial Accounts","description":"Manage organization accounts such as bank, cash, debt, or credit card accounts."},{"name":"Financial Transactions","description":"Create and query financial transactions for the authenticated organization."}]}