{"openapi":"3.1.0","servers":[{"url":"https://api.modjo.ai//v2"}],"info":{"title":"Modjo Public API","version":"2.0.0","description":"The Modjo Public API lets you programmatically access your Modjo workspace data — calls, users, teams, and webhooks.\n\n### Base URL\n\n```\nhttps://api.modjo.ai//v2\n```\n\n### Getting Started\n\n1. [Create an API key](#tag/Authentication) from your Modjo settings.\n2. Include it as a Bearer token in the `Authorization` header of every request.\n3. Browse the endpoints below to list calls, manage users, configure webhooks, and more.\n\n### Pagination\n\nAll list endpoints return paginated results. Use the `page` (1-based, default: 1) and `size` (default: 25, max: 100) query parameters to navigate through results. Every paginated response includes a `pagination` object with `page`, `size`, and `total` fields.\n\n### Expanding Relations\n\nSome endpoints support a `expand` query parameter that lets you inline related objects instead of receiving only their IDs. Pass a comma-separated list of fields (e.g. `?expand=contacts,deal`). When a relation is expanded, the corresponding ID field is omitted from the response.\n\n### Need Help?\n\nContact your Modjo account manager or reach out to [support@modjo.ai](mailto:support@modjo.ai)."},"security":[{"bearerAuth":[]}],"tags":[{"name":"Authentication","description":"Modjo API authentication is based on an API key that must be included in the request headers.\n\nTo authenticate, add your API key to the `Authorization` header as a Bearer token:\n\n```\nAuthorization: Bearer YOUR_API_KEY\n```\n\n### How to Retrieve Your API Key\n\nBefore generating a new API key, you must have **Administrator** or **Manager** permissions.\n\nFollow these steps to create your API key:\n\n1. **[Log in to Modjo](https://app.modjo.ai)**\n2. **[Go to Settings](https://app.modjo.ai/settings/?utm_source=api-doc)**\n3. **[Access the Integrations section](https://app.modjo.ai/settings/integrations?utm_source=api-doc)**\n4. **[Find the Public API card](https://app.modjo.ai/settings/integrations/modjo_api_key?utm_source=api-doc)**\n5. Create a new API key.\n\nMake sure to keep your API key **secure** and do not share it with unauthorized parties.\n\n### Rate Limiting\n\nThe API enforces a rate limit of **100 requests per minute** per API key. Rate limit information is included in response headers:\n\n- `X-RateLimit-Limit`: Maximum number of requests allowed per window\n- `X-RateLimit-Remaining`: Number of requests remaining in the current window\n- `X-RateLimit-Reset`: Seconds until the rate limit resets\n\nIf you exceed the rate limit, you will receive a `429 Too Many Requests` response."},{"name":"Errors","description":"The API uses conventional HTTP status codes and returns a consistent JSON error body.\n\n### Error Response Format\n\n```json\n{\n  \"code\": \"not_found\",\n  \"message\": \"Call not found\"\n}\n```\n\n### Error Codes\n\n| HTTP Status | Code | Description |\n|---|---|---|\n| 400 | `validation_error` | The request body or query parameters are invalid. The `message` field describes which fields failed validation. |\n| 401 | `missing_api_key` | No `Authorization` header was provided. |\n| 401 | `invalid_api_key` | The API key is invalid, revoked, or the tenant has been deleted. |\n| 404 | `not_found` | The requested resource does not exist. |\n| 409 | `conflict` | The resource already exists (e.g. duplicate email or webhook name). |\n| 410 | `gone` | The resource existed but has been permanently deleted (e.g. a recording removed by data retention policy). |\n| 429 | `rate_limited` | You have exceeded the rate limit. Wait and retry after the `X-RateLimit-Reset` interval. |\n| 500 | `internal_error` | An unexpected error occurred on our side. If this persists, contact support. |"},{"name":"Calls","description":"A call represents a recorded conversation in Modjo (phone call, video meeting, etc.).\n\n### Call Statuses\n\n| Status | Description |\n|---|---|\n| `processing` | The call has been received and is being downloaded, transcribed, or analyzed. |\n| `completed` | The call is fully processed and the transcript is available. |\n| `failed` | Processing failed (e.g. empty recording, damaged file, no speakers detected). |\n\n### Uploading Calls\n\nUse `POST /calls` to upload a call via a publicly accessible recording URL. The call is processed asynchronously — you will receive a UUID immediately and can poll `GET /calls/{id}` until the status changes from `processing` to `completed` or `failed`. Typical processing time is 5 to 30 minutes.\n\n### Expanding Relations\n\nThe list and get endpoints support the `expand` query parameter with the following fields:\n- **contacts** — inline contact details instead of `contactIds`\n- **deal** — inline deal details instead of `dealId`\n- **account** — inline account details instead of `accountId`\n- **users** — inline user details instead of `userIds`\n\n### Downloading Recordings\n\nUse `GET /calls/{id}/recording` to retrieve a signed URL to download the call recording media file. The URL is valid for 1 hour; request a new one once it expires. The recording is only available while the call `recordingRetentionStatus` is `available`."},{"name":"Call Reviews","description":"Call reviews are structured evaluations of a call filled in against a review template. Each review carries an overall rating, per-question answers with individual ratings, and metadata (reviewer, reviewee, whether it was with the help of an AI agent). Use this endpoint to export call reviews."},{"name":"CRM Filling Answers","description":"CRM filling answers represent values that have been pushed to a CRM after a call was processed. Each answer is linked to a specific call and a CRM filling field. Only answers that have been successfully pushed to the CRM are returned."},{"name":"Contacts","description":"Contacts represent external people associated with your calls and deals (e.g. prospects, customers). Use these endpoints to list and search contacts in your workspace."},{"name":"CRM Filling Templates","description":"CRM filling templates define how Modjo automatically fills CRM fields after calls. Each template specifies the language, call duration filters, applicable providers, and which teams and tags it applies to. Templates can be in `pending` (draft) or `published` (active) status."},{"name":"Deals","description":"Deals represent sales opportunities tracked in your CRM. Use these endpoints to list deals and retrieve AI-generated deal summaries."},{"name":"Tags","description":"Tags are labels that can be applied to calls for categorization and filtering. Use this endpoint to list available tags in your workspace."},{"name":"Topics","description":"Topics represent conversation subjects detected in calls (e.g. pricing, competitors). Topics can be grouped into categories. Use this endpoint to list available topics in your workspace."},{"name":"Users","description":"Users represent licensed members of your Modjo workspace. Each user has a unique email address within the tenant. Use these endpoints to list, create, update, or deactivate users, and to manage their team membership programmatically."},{"name":"Teams","description":"Teams let you group users together for organizational purposes (e.g. \"Sales\", \"Customer Success\"). Use these endpoints to manage teams and their membership."},{"name":"Webhooks","description":"Webhooks let you receive real-time notifications when events occur in your Modjo workspace.\n\n### Supported Events\n\n| Event | Description |\n|---|---|\n| `call_created` | Fired when a call has been imported and created in Modjo. |\n| `call_summarized` | Fired when a call has been fully processed and its summary is available. |\n| `call_recording_deleted` | Fired when a call recording has been deleted. |\n| `call_tag_added` | Fired when a tag is added to a call. |\n| `call_tag_removed` | Fired when a tag is removed from a call. |\n| `call_transcribed` | Fired when a call transcription is complete. |\n| `call_transcript_deleted` | Fired when a call transcript has been deleted. |\n\n### Delivery Format\n\nWhen an event fires, Modjo sends a `POST` request to your webhook URL with a JSON payload:\n\n```json\n{\n  \"event\": \"call_summarized\",\n  \"timestamp\": \"2024-06-15T14:30:00.000Z\",\n  \"data\": {\n    \"callId\": 12345\n  }\n}\n```\n\n### Security\n\nEach webhook is assigned a secret token on creation. Modjo includes this token in the `X-Webhook-Secret` header of every delivery request so you can verify the request authenticity.\n\n### Retry Policy\n\nIf your endpoint returns a non-2xx status code, Modjo will retry the delivery with exponential backoff."}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"To retrieve your API key please refer to the [Authentication](#tag/Authentication) section of this documentation."}},"schemas":{"AccountListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Account"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"Account":{"type":"object","properties":{"id":{"type":"number","description":"Account ID","example":1},"name":{"type":"string","description":"Account/company name","example":"Acme Inc."},"crmId":{"type":"string","description":"External CRM identifier","example":"001ABC123"},"crmIdentifier":{"type":"string","nullable":true,"description":"External CRM identifier (unified field)","example":"001ABC123"},"crmLink":{"type":"string","format":"uri","description":"URL to account in external CRM","example":"https://example.my.salesforce.com/001ABC123"},"crm":{"type":"string","enum":["microsoft_dynamics","hubspot","pipedrive","salesforce","sellsy","zoho"],"description":"CRM provider","example":"salesforce"},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp"}},"required":["id","name","crmId","crmIdentifier","crmLink","crm","createdOn","modifiedOn"]},"ErrorResponse":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code (e.g. validation_error, not_found, conflict)","example":"not_found"},"message":{"type":"string","description":"Human-readable error message with details about the failure","example":"The requested resource was not found"}},"required":["code","message"]},"CallReviewListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CallReview"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"CallReview":{"type":"object","properties":{"id":{"type":"number","description":"Unique identifier of the review.","example":1024},"callId":{"type":"number","description":"Identifier of the call being reviewed.","example":55555},"template":{"$ref":"#/components/schemas/CallReviewTemplate"},"revieweeId":{"type":"number","description":"Identifier of the user being reviewed.","example":88},"rating":{"type":"number","nullable":true,"description":"Overall review rating (weighted average of the per-question ratings, on a 0-4 scale). Null when the reviewer left every question as not-applicable.","example":3.2},"isPrivate":{"type":"boolean","description":"When true, the answers are only visible to the reviewer and reviewee inside Modjo. The public API exposes them regardless — treat this flag as guidance for downstream visibility rules.","example":false},"isAiGenerated":{"type":"boolean","description":"When true, the review was authored by an AI agent rather than a human reviewer.","example":false},"createdById":{"type":"number","nullable":true,"description":"Identifier of the reviewer. Null when the review was created without a user context (e.g. AI/API pipelines).","example":42},"createdOn":{"type":"string","nullable":true,"description":"Instant the review was created (ISO 8601).","example":"2026-06-15T14:30:00.000Z"},"modifiedOn":{"type":"string","nullable":true,"description":"Instant the review was last modified (ISO 8601).","example":"2026-06-15T14:35:00.000Z"},"answers":{"type":"array","items":{"$ref":"#/components/schemas/CallReviewAnswer"},"description":"Per-question answers attached to the review."}},"required":["id","callId","template","revieweeId","rating","isPrivate","isAiGenerated","createdById","createdOn","modifiedOn","answers"]},"CallReviewTemplate":{"type":"object","nullable":true,"properties":{"id":{"type":"number","description":"Unique identifier of the template.","example":12},"title":{"type":"string","nullable":true,"description":"Template title. May reference a template that has since been soft-deleted; null if the template row is missing.","example":"Cold Calling"}},"required":["id","title"]},"CallReviewAnswer":{"type":"object","properties":{"id":{"type":"number","description":"Unique identifier of the answer.","example":42},"question":{"$ref":"#/components/schemas/CallReviewAnswerQuestion"},"weight":{"type":"number","description":"Position of the answer's question in the template at review time.","example":0},"rating":{"type":"number","nullable":true,"description":"Per-question rating on a 0-4 scale, or `-1` when the reviewer marked it as not-applicable.","example":3},"feedback":{"type":"string","nullable":true,"description":"Free-text comment the reviewer wrote for the question.","example":"Handled objection cleanly."}},"required":["id","question","weight","rating","feedback"]},"CallReviewAnswerQuestion":{"type":"object","nullable":true,"properties":{"id":{"type":"number","description":"Unique identifier of the question.","example":500},"title":{"type":"string","nullable":true,"description":"Question title. May belong to a template question that has since been soft-deleted; null if the question row is missing.","example":"Intro (timing, why, agenda)"}},"required":["id","title"]},"CallTag":{"type":"object","properties":{"callId":{"type":"number","description":"Call ID","example":1},"tagId":{"type":"number","description":"Tag ID","example":1}},"required":["callId","tagId"]},"AddTagToCallRequest":{"type":"object","properties":{"tagId":{"type":"integer","minimum":0,"exclusiveMinimum":true,"description":"ID of the tag to add to the call","example":1}},"required":["tagId"]},"CallNextStepsResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NextStepItem"},"description":"List of AI-extracted next steps from the call. Empty if no next steps were detected or the call is still processing."}},"required":["data"]},"NextStepItem":{"type":"object","properties":{"title":{"type":"string","description":"Short title of the next step","example":"Schedule follow-up meeting"},"description":{"type":"string","description":"Detailed description of the next step","example":"Set up a 30-minute follow-up call with the prospect to review the proposal by end of week."}},"required":["title","description"]},"NoteListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Note"}}},"required":["data"]},"Note":{"type":"object","properties":{"id":{"type":"number","description":"Note ID","example":1},"title":{"type":"string","nullable":true,"description":"Note title","example":"Follow-up notes"},"date":{"type":"string","description":"Note date in ISO 8601 format","example":"2024-06-15T14:30:00.000Z"},"rawContent":{"nullable":true,"description":"Note content as a rich-text JSON structure"},"status":{"type":"string","enum":["DRAFT","PUBLISHED"],"description":"Note status","example":"PUBLISHED"},"type":{"type":"string","enum":["USER","AI"],"description":"Note type","example":"USER"},"publishedDate":{"type":"string","nullable":true,"description":"Publication timestamp in ISO 8601 format"},"createdOn":{"type":"string","description":"Creation timestamp in ISO 8601 format"},"modifiedOn":{"type":"string","description":"Last modification timestamp in ISO 8601 format"},"createdBy":{"type":"number","nullable":true,"description":"ID of the user who created the note"},"modifiedBy":{"type":"number","nullable":true,"description":"ID of the user who last modified the note"}},"required":["id","title","date","status","type","publishedDate","createdOn","modifiedOn","createdBy","modifiedBy"]},"CallRecording":{"type":"object","properties":{"url":{"type":"string","description":"Signed URL to download the call recording media file. The URL is valid for 1 hour.","example":"https://storage.example.com/recordings/call-123.mp4?signature=abc123"},"expiresAt":{"type":"string","description":"Expiration timestamp of the signed URL in ISO 8601 format. After this time the URL is no longer valid and a new one must be requested.","example":"2024-06-15T15:30:00.000Z"},"mediaType":{"type":"string","enum":["audio","video"],"description":"Type of the recording media file: audio or video","example":"video"}},"required":["url","expiresAt","mediaType"]},"CallExpanded":{"type":"object","properties":{"id":{"type":"number","description":"Call ID","example":1},"name":{"type":"string","description":"Call title","example":"Demo call with Acme Corp"},"date":{"type":"string","nullable":true,"description":"Call date in ISO 8601 format","example":"2024-06-15T14:30:00.000Z"},"duration":{"type":"number","nullable":true,"description":"Call duration in seconds","example":1800},"direction":{"type":"string","nullable":true,"description":"Call direction: inbound or outbound","example":"outbound"},"language":{"type":"string","nullable":true,"description":"Detected language code (ISO 639-1)","example":"en"},"status":{"type":"string","description":"Public status: processing, completed, failed","example":"completed"},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp in ISO 8601 format","example":"2024-06-15T14:30:00.000Z"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp in ISO 8601 format","example":"2024-06-15T15:00:00.000Z"},"phoneProviderCallId":{"type":"string","description":"External identifier of the call from the phone provider (e.g. Aircall, Ringover, etc.).","example":"aircall-1234567890"},"recordingRetentionStatus":{"type":"string","enum":["available","deleted"],"description":"Retention status of the call recording: \"available\" if the recording is kept, \"deleted\" if it has been deleted for data retention reasons.","example":"available"},"transcriptRetentionStatus":{"type":"string","enum":["available","deleted"],"description":"Retention status of the call transcript: \"available\" if the transcript is kept, \"deleted\" if it has been deleted for data retention reasons.","example":"available"},"contacts":{"type":"array","items":{"$ref":"#/components/schemas/ContactSummary"},"description":"Expanded contact objects. Present when expand=contacts is set."},"contactIds":{"type":"array","items":{"type":"number"},"description":"Contact IDs. Present when contacts are not expanded."},"deal":{"type":"object","nullable":true,"properties":{"id":{"type":"number","description":"Deal ID","example":100},"name":{"type":"string","description":"Deal name","example":"Acme Corp - Enterprise Plan"},"status":{"type":"string","nullable":true,"description":"Deal status","example":"open"},"stage":{"type":"string","nullable":true,"description":"Deal stage","example":"Negotiation"},"amount":{"type":"number","nullable":true,"description":"Deal amount in the deal currency","example":50000},"currency":{"type":"string","nullable":true,"description":"Deal currency code","example":"EUR"},"closeDate":{"type":"string","nullable":true,"description":"Expected close date in ISO 8601 format","example":"2024-09-30"}},"required":["id","name","status","stage","amount","currency","closeDate"],"description":"Expanded deal object. Present when expand=deal is set."},"dealId":{"type":"number","nullable":true,"description":"Deal ID. Present when deal is not expanded.","example":100},"account":{"type":"object","nullable":true,"properties":{"id":{"type":"number","description":"Account ID","example":200},"name":{"type":"string","description":"Account name","example":"Acme Corp"}},"required":["id","name"],"description":"Expanded account object. Present when expand=account is set."},"accountId":{"type":"number","nullable":true,"description":"Account ID. Present when account is not expanded.","example":200},"users":{"type":"array","items":{"$ref":"#/components/schemas/UserSummary"},"description":"Expanded user objects. Present when expand=users is set."},"userIds":{"type":"array","items":{"type":"number"},"description":"User IDs. Present when users are not expanded."},"crmActivity":{"$ref":"#/components/schemas/CrmActivity"}},"required":["id","name","date","duration","direction","language","status","createdOn","modifiedOn","phoneProviderCallId","recordingRetentionStatus","transcriptRetentionStatus","crmActivity"]},"ContactSummary":{"type":"object","properties":{"id":{"type":"number","description":"Contact ID","example":10},"name":{"type":"string","nullable":true,"description":"Contact name","example":"John Smith"},"email":{"type":"string","nullable":true,"description":"Contact email","example":"john@prospect.com"},"phoneNumber":{"type":"string","nullable":true,"description":"Contact phone number","example":"+33612345678"},"jobTitle":{"type":"string","nullable":true,"description":"Contact job title","example":"VP of Sales"}},"required":["id","name","email","phoneNumber","jobTitle"]},"UserSummary":{"type":"object","properties":{"id":{"type":"number","description":"User ID","example":42},"email":{"type":"string","description":"User email","example":"jane.doe@company.com"},"firstName":{"type":"string","nullable":true,"description":"User first name","example":"Jane"},"lastName":{"type":"string","nullable":true,"description":"User last name","example":"Doe"}},"required":["id","email","firstName","lastName"]},"CrmActivity":{"type":"object","nullable":true,"properties":{"crmId":{"type":"string","description":"Identifier of the activity record in the external CRM","example":"00T1234567ABC"},"crmOrigin":{"type":"string","enum":["created_by_modjo","found_in_crm","provided_by_provider"],"description":"How the activity was logged in the CRM: created_by_modjo, found_in_crm, or provided_by_provider","example":"created_by_modjo"}},"required":["crmId","crmOrigin"],"description":"CRM activity record linked to this call. Null if the call has not been synced to a CRM."},"TranscriptResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TranscriptBlock"}}},"required":["data"]},"TranscriptBlock":{"type":"object","properties":{"startTime":{"type":"number","description":"Block start time in seconds from the beginning of the call","example":0},"endTime":{"type":"number","description":"Block end time in seconds from the beginning of the call","example":12.5},"content":{"type":"string","description":"Transcript text content for this block","example":"Hi, thanks for joining the call today."},"speaker":{"type":"object","properties":{"id":{"type":"number","description":"Speaker ID","example":1},"name":{"type":"string","nullable":true,"description":"Speaker display name","example":"Jane Doe"},"type":{"type":"string","enum":["user","contact","unknown"],"description":"Speaker type: user (internal team member), contact (external participant), or unknown","example":"user"}},"required":["id","name","type"],"description":"Speaker who said this block"}},"required":["startTime","endTime","content","speaker"]},"CrmFillingAnswerListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CrmFillingAnswer"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"CrmFillingAnswer":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","description":"Answer UUID","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901"},"callId":{"type":"integer","description":"ID of the call this answer belongs to","example":12345},"crmFillingFieldUuid":{"type":"string","format":"uuid","description":"UUID of the CRM filling field this answer is for","example":"f1e2d3c4-b5a6-7890-abcd-ef1234567890"},"value":{"nullable":true,"description":"Value that was pushed to the CRM. Type depends on the CRM field type.","example":"Follow up next Tuesday"},"crmId":{"type":"string","nullable":true,"description":"CRM record ID this answer was pushed to","example":"006xx000001abc"},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp (ISO 8601)","example":"2024-06-15T14:30:00.000Z"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp (ISO 8601)","example":"2024-06-15T15:00:00.000Z"}},"required":["uuid","callId","crmFillingFieldUuid","crmId","createdOn","modifiedOn"]},"CallSummaryListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CallSummary"}}},"required":["data"]},"CallSummary":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","description":"Summary answer UUID","example":"c3d4e5f6-a7b8-9012-cdef-123456789012"},"templateUuid":{"type":"string","format":"uuid","description":"UUID of the summary template used to generate this summary","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"templateTitle":{"type":"string","description":"Title of the summary template","example":"Meeting Summary"},"templateLength":{"type":"string","enum":["short","detailed","adjusted"],"description":"Length setting of the template: short, detailed, or adjusted (adapts to call duration)","example":"detailed"},"answer":{"type":"string","nullable":true,"description":"The AI-generated summary text. Null if the summary has not been generated yet.","example":"The team discussed Q3 targets and agreed to increase outbound outreach by 20%."},"language":{"type":"string","nullable":true,"description":"Language of the summary (BCP 47)","example":"en-US"},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp (ISO 8601)","example":"2024-06-15T14:30:00.000Z"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp (ISO 8601)","example":"2024-06-15T15:00:00.000Z"}},"required":["uuid","templateUuid","templateTitle","templateLength","answer","language","createdOn","modifiedOn"]},"CallTagsResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}}},"required":["data"]},"Tag":{"type":"object","properties":{"id":{"type":"number","description":"Tag ID","example":1},"name":{"type":"string","description":"Tag name","example":"Competitor mention"},"color":{"type":"string","description":"Tag color","example":"#FF5733"},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp"}},"required":["id","name","color","createdOn","modifiedOn"]},"CallExpandedListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CallExpanded"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"UploadCallResponse":{"type":"object","properties":{"callId":{"type":"string","format":"uuid","description":"UUID of the created call. Use with GET /calls/{id} to poll for processing status.","example":"550e8400-e29b-41d4-a716-446655440000"},"status":{"type":"string","enum":["processing"],"description":"Call is queued for async processing"}},"required":["callId","status"]},"UploadCallRequest":{"type":"object","properties":{"downloadMediaUrl":{"type":"string","format":"uri","description":"Publicly accessible recording URL. Modjo will download the file from this URL.","example":"https://storage.example.com/recordings/call-123.mp3"},"name":{"type":"string","description":"Call title. If omitted, auto-generated from participant names.","example":"Demo call with Acme Corp"},"date":{"type":"string","format":"date-time","description":"Call start datetime in ISO 8601 format","example":"2024-06-15T14:30:00.000Z"},"direction":{"type":"string","enum":["inbound","outbound"],"default":"outbound","description":"Call direction. Defaults to outbound.","example":"outbound"},"duration":{"type":"number","minimum":0,"description":"Call duration in seconds. Can be 0 or omitted.","example":1800},"participants":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"Participant email address","example":"jane.doe@company.com"},"name":{"type":"string","description":"Participant display name","example":"Jane Doe"},"type":{"type":"string","enum":["user","contact"],"description":"Participant type: \"user\" for internal team members, \"contact\" for external participants","example":"user"}},"required":["email","type"]},"minItems":1,"description":"List of call participants. At least one participant of type \"user\" must map to a licensed user"},"tags":{"type":"array","items":{"type":"string"},"description":"Tag names to attach to the call","example":["demo","enterprise"]},"account":{"type":"object","properties":{"crm":{"type":"string","description":"CRM provider name (e.g. salesforce, hubspot)","example":"salesforce"},"crmId":{"type":"string","description":"CRM account ID","example":"001ABC123"}},"required":["crm","crmId"],"description":"Link the call to a CRM account directly"},"deal":{"type":"object","properties":{"crm":{"type":"string","description":"CRM provider name (e.g. salesforce, hubspot)","example":"salesforce"},"crmId":{"type":"string","description":"CRM deal/opportunity ID","example":"006DEF456"}},"required":["crm","crmId"],"description":"Link the call to a CRM deal directly"}},"required":["downloadMediaUrl","date","participants"]},"ContactListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"Contact":{"type":"object","properties":{"id":{"type":"number","description":"Contact ID","example":1},"name":{"type":"string","nullable":true,"description":"Contact name","example":"John Doe"},"email":{"type":"string","nullable":true,"format":"email","description":"Contact email address","example":"john.doe@example.com"},"phoneNumber":{"type":"string","nullable":true,"description":"Contact phone number","example":"+1234567890"},"jobTitle":{"type":"string","nullable":true,"description":"Job title","example":"Sales Manager"},"crmPersonId":{"type":"string","nullable":true,"description":"External CRM person identifier","example":"003ABC123"},"crmIdentifier":{"type":"string","nullable":true,"description":"External CRM identifier (unified field)","example":"003ABC123"},"crmLink":{"type":"string","nullable":true,"description":"URL to contact in external CRM","example":"https://example.my.salesforce.com/003ABC123"},"crm":{"type":"string","nullable":true,"enum":["microsoft_dynamics","hubspot","pipedrive","salesforce","sellsy","zoho",null],"description":"CRM provider","example":"salesforce"},"accountId":{"type":"number","nullable":true,"description":"Associated account ID","example":42},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp"}},"required":["id","name","email","phoneNumber","jobTitle","crmPersonId","crmIdentifier","crmLink","crm","accountId","createdOn","modifiedOn"]},"CrmFillingTemplateListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CrmFillingTemplate"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"CrmFillingTemplate":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","description":"Template UUID","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"title":{"type":"string","description":"Template title","example":"Post-call CRM update"},"status":{"type":"string","enum":["pending","published"],"description":"Template status. `pending` means in draft, `published` means active.","example":"published"},"language":{"type":"string","description":"Language code (BCP 47)","example":"en-US"},"callDurationMin":{"type":"integer","nullable":true,"description":"Minimum call duration filter (seconds)","example":60},"callDurationMax":{"type":"integer","nullable":true,"description":"Maximum call duration filter (seconds)","example":3600},"providers":{"type":"array","items":{"type":"string"},"description":"List of call providers this template applies to","example":["aircall","hubspot"]},"teamIds":{"type":"array","items":{"type":"integer"},"description":"IDs of teams this template is assigned to","example":[1,2]},"tagIds":{"type":"array","items":{"type":"integer"},"description":"IDs of tags this template is filtered by","example":[10,20]},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp (ISO 8601)","example":"2024-06-15T14:30:00.000Z"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp (ISO 8601)","example":"2024-06-15T15:00:00.000Z"}},"required":["uuid","title","status","language","callDurationMin","callDurationMax","providers","teamIds","tagIds","createdOn","modifiedOn"]},"CrmFillingFieldListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CrmFillingField"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"CrmFillingField":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","description":"Field UUID","example":"f1e2d3c4-b5a6-7890-abcd-ef1234567890"},"order":{"type":"integer","description":"Display order of the field within the template","example":1},"prompt":{"type":"string","description":"AI prompt used to extract the field value from the call","example":"What was the next step agreed upon?"},"crm":{"type":"string","enum":["hubspot","pipedrive","salesforce","zoho","sellsy","microsoft_dynamics"],"description":"Target CRM system","example":"salesforce"},"entityType":{"type":"string","enum":["account","contact","lead","deal","lookup"],"description":"CRM entity type this field maps to","example":"deal"},"fieldId":{"type":"string","description":"CRM field identifier","example":"NextStep__c"},"fieldLabel":{"type":"string","description":"Human-readable CRM field label","example":"Next Step"},"fieldKey":{"type":"string","description":"CRM field key","example":"NextStep__c"},"fieldType":{"type":"string","enum":["string","textarea","number","date","boolean","enum"],"description":"Data type of the CRM field","example":"string"},"isActive":{"type":"boolean","description":"Whether the field is currently active","example":true},"isAutoPush":{"type":"boolean","description":"Whether the field value is automatically pushed to the CRM","example":false},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp (ISO 8601)","example":"2024-06-15T14:30:00.000Z"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp (ISO 8601)","example":"2024-06-15T15:00:00.000Z"}},"required":["uuid","order","prompt","crm","entityType","fieldId","fieldLabel","fieldKey","fieldType","isActive","isAutoPush","createdOn","modifiedOn"]},"TagListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"DealListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Deal"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"Deal":{"type":"object","properties":{"id":{"type":"number","description":"Deal ID","example":1},"name":{"type":"string","description":"Deal name","example":"Acme Corp - Enterprise Plan"},"crmId":{"type":"string","description":"External CRM identifier","example":"006ABC123"},"crmIdentifier":{"type":"string","nullable":true,"description":"External CRM identifier (unified field)","example":"006ABC123"},"crmLink":{"type":"string","format":"uri","description":"URL to deal in external CRM","example":"https://example.my.salesforce.com/006ABC123"},"crm":{"type":"string","enum":["microsoft_dynamics","hubspot","pipedrive","salesforce","sellsy","zoho"],"description":"CRM provider","example":"salesforce"},"status":{"type":"string","nullable":true,"enum":["Open","Closed won","Closed lost","Closed","Deleted",null],"description":"Deal status","example":"Open"},"stage":{"type":"string","nullable":true,"description":"Deal stage","example":"Negotiation"},"closeDate":{"type":"string","nullable":true,"description":"Expected close date","example":"2024-09-30"},"amount":{"type":"number","nullable":true,"description":"Deal amount in the deal currency","example":50000},"currency":{"type":"string","nullable":true,"description":"Deal currency code","example":"EUR"},"probability":{"type":"number","nullable":true,"description":"Probability of closing (0-100)","example":75},"lossReason":{"type":"string","nullable":true,"description":"Reason for loss, if applicable"},"source":{"type":"string","nullable":true,"description":"Deal source","example":"Inbound"},"accountId":{"type":"number","nullable":true,"description":"Associated account ID","example":42},"ownerId":{"type":"number","nullable":true,"description":"Owner user ID","example":7},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp"}},"required":["id","name","crmId","crmIdentifier","crmLink","crm","status","stage","closeDate","amount","currency","probability","lossReason","source","accountId","ownerId","createdOn","modifiedOn"]},"DealSummaryContent":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Content type","example":"bulletpoint"},"value":{"type":"string","description":"Content value","example":"The prospect is interested in the enterprise plan."}},"required":["type","value"]},"description":"Summary content items"},"language":{"type":"string","description":"Language of the summary","example":"en"}},"required":["data","language"]},"TeamListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Team"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"Team":{"type":"object","properties":{"id":{"type":"number","description":"Team ID","example":1},"name":{"type":"string","description":"Team name","example":"Sales"},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp in ISO 8601 format","example":"2024-06-15T14:30:00.000Z"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp in ISO 8601 format","example":"2024-06-15T15:00:00.000Z"}},"required":["id","name","createdOn","modifiedOn"]},"CreateTeamRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Team name","example":"Sales"}},"required":["name"]},"UpdateTeamRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Team name","example":"Sales"}},"required":["name"]},"TeamMembersListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TeamMember"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"TeamMember":{"type":"object","properties":{"id":{"type":"number","description":"User ID","example":1},"email":{"type":"string","description":"User email address","example":"john@example.com"},"firstName":{"type":"string","nullable":true,"description":"User first name"},"lastName":{"type":"string","nullable":true,"description":"User last name"},"phoneNumber":{"type":"string","nullable":true,"description":"User phone number","example":"+33612345678"},"jobTitle":{"type":"string","nullable":true,"description":"User job title","example":"Account Executive"},"jobDepartment":{"type":"string","nullable":true,"description":"User job department","example":"Sales"},"role":{"type":"string","description":"User role: user, manager, or admin","example":"user"},"timezone":{"type":"string","nullable":true,"description":"IANA timezone identifier","example":"Europe/Paris"},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp in ISO 8601 format","example":"2024-06-15T14:30:00.000Z"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp in ISO 8601 format","example":"2024-06-15T15:00:00.000Z"}},"required":["id","email","firstName","lastName","phoneNumber","jobTitle","jobDepartment","role","timezone","createdOn","modifiedOn"]},"TopicListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Topic"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"Topic":{"type":"object","properties":{"id":{"type":"number","description":"Topic ID","example":1},"name":{"type":"string","description":"Topic name","example":"Pricing discussion"},"slug":{"type":"string","nullable":true,"description":"Topic slug","example":"pricing-discussion"},"color":{"type":"string","nullable":true,"description":"Topic color","example":"#4287f5"},"saidBy":{"type":"string","nullable":true,"enum":["user","contact",null],"description":"Filter for who said the topic","example":"user"},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp"}},"required":["id","name","slug","color","saidBy","createdOn","modifiedOn"]},"UserListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/User"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"User":{"type":"object","properties":{"id":{"type":"number","description":"User ID","example":1},"email":{"type":"string","description":"User email address","example":"john@example.com"},"firstName":{"type":"string","nullable":true,"description":"User first name"},"lastName":{"type":"string","nullable":true,"description":"User last name"},"phoneNumber":{"type":"string","nullable":true,"description":"User phone number","example":"+33612345678"},"jobTitle":{"type":"string","nullable":true,"description":"User job title","example":"Account Executive"},"jobDepartment":{"type":"string","nullable":true,"description":"User job department","example":"Sales"},"role":{"type":"string","description":"User role: user, manager, or admin","example":"user"},"timezone":{"type":"string","nullable":true,"description":"IANA timezone identifier","example":"Europe/Paris"},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp in ISO 8601 format","example":"2024-06-15T14:30:00.000Z"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp in ISO 8601 format","example":"2024-06-15T15:00:00.000Z"}},"required":["id","email","firstName","lastName","phoneNumber","jobTitle","jobDepartment","role","timezone","createdOn","modifiedOn"]},"CreateUserRequest":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"User email address","example":"jane.doe@company.com"},"firstName":{"type":"string","minLength":1,"description":"User first name","example":"Jane"},"lastName":{"type":"string","minLength":1,"description":"User last name","example":"Doe"},"phoneNumber":{"type":"string","description":"User phone number","example":"+33612345678"},"jobTitle":{"type":"string","description":"User job title","example":"Account Executive"},"jobDepartment":{"type":"string","description":"User job department","example":"Sales"},"role":{"type":"string","enum":["user","manager","admin"],"default":"user","description":"User role. Defaults to \"user\".","example":"user"},"timezone":{"type":"string","description":"IANA timezone identifier","example":"Europe/Paris"}},"required":["email","firstName","lastName"]},"UpdateUserRequest":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"User email address","example":"jane.doe@company.com"},"firstName":{"type":"string","nullable":true,"minLength":1,"description":"User first name","example":"Jane"},"lastName":{"type":"string","nullable":true,"minLength":1,"description":"User last name","example":"Doe"},"phoneNumber":{"type":"string","nullable":true,"description":"User phone number","example":"+33612345678"},"jobTitle":{"type":"string","nullable":true,"description":"User job title","example":"Account Executive"},"jobDepartment":{"type":"string","nullable":true,"description":"User job department","example":"Sales"},"role":{"type":"string","enum":["user","manager","admin"],"description":"User role","example":"user"},"timezone":{"type":"string","nullable":true,"description":"IANA timezone identifier","example":"Europe/Paris"}}},"UserTeam":{"type":"object","properties":{"userId":{"type":"number","description":"User ID","example":1},"teamId":{"type":"number","description":"Team ID","example":1}},"required":["userId","teamId"]},"AddTeamToUserRequest":{"type":"object","properties":{"teamId":{"type":"integer","minimum":0,"exclusiveMinimum":true,"description":"ID of the team to add the user to","example":1}},"required":["teamId"]},"WebhookListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"pagination":{"type":"object","properties":{"page":{"type":"number","description":"Current page number","example":1},"size":{"type":"number","description":"Items per page","example":25},"total":{"type":"number","description":"Total number of items","example":100}},"required":["page","size","total"]}},"required":["data","pagination"]},"Webhook":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","description":"Webhook UUID","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","description":"Webhook name","example":"My Webhook"},"url":{"type":"string","description":"Webhook delivery URL","example":"https://example.com/webhook"},"events":{"type":"array","items":{"anyOf":[{"type":"string","enum":["call_created","call_summarized","call_recording_deleted","call_tag_added","call_tag_removed","call_transcribed","call_transcript_deleted"]},{"type":"string"}]},"description":"Subscribed event names","example":["call_summarized"]},"createdOn":{"type":"string","nullable":true,"description":"Creation timestamp in ISO 8601 format","example":"2024-06-15T14:30:00.000Z"},"modifiedOn":{"type":"string","nullable":true,"description":"Last modification timestamp in ISO 8601 format","example":"2024-06-15T15:00:00.000Z"}},"required":["uuid","name","url","events","createdOn","modifiedOn"]},"CreateWebhookRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Webhook name. Must be unique within the tenant.","example":"Call Summary Notifications"},"url":{"type":"string","format":"uri","description":"HTTPS URL where event payloads will be delivered","example":"https://example.com/webhooks/modjo"},"events":{"type":"array","items":{"anyOf":[{"type":"string","enum":["call_created","call_summarized","call_recording_deleted","call_tag_added","call_tag_removed","call_transcribed","call_transcript_deleted"]},{"type":"string"}]},"minItems":1,"description":"List of event names to subscribe to. At least one event is required.","example":["call_summarized"]}},"required":["name","url","events"]},"UpdateWebhookRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Webhook name. Must be unique within the tenant.","example":"Call Summary Notifications"},"url":{"type":"string","format":"uri","description":"HTTPS URL where event payloads will be delivered","example":"https://example.com/webhooks/modjo"},"events":{"type":"array","items":{"anyOf":[{"type":"string","enum":["call_created","call_summarized","call_recording_deleted","call_tag_added","call_tag_removed","call_transcribed","call_transcript_deleted"]},{"type":"string"}]},"minItems":1,"description":"List of event names to subscribe to. At least one event is required.","example":["call_summarized"]}}}},"parameters":{}},"paths":{"/accounts":{"get":{"tags":["Accounts"],"summary":"List accounts","description":"Returns a paginated list of accounts. Supports filtering by account name.","parameters":[{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Filter by account name"},"required":false,"description":"Filter by account name","name":"name","in":"query"}],"responses":{"200":{"description":"Paginated list of accounts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountListResponse"}}}}}}},"/accounts/{id}":{"get":{"tags":["Accounts"],"summary":"Get an account","description":"Returns a single account by ID.","parameters":[{"schema":{"type":"integer","description":"Account ID","example":1},"required":true,"description":"Account ID","name":"id","in":"path"}],"responses":{"200":{"description":"Account details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"404":{"description":"Account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/call-reviews":{"get":{"tags":["Call Reviews"],"summary":"List call reviews","description":"Returns a paginated list of call reviews with their per-question answers, ordered by creation date descending. Optionally filter by `createdOn` date range.","parameters":[{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Inclusive lower bound on `createdOn` (ISO 8601). Filters reviews created at or after this instant.","example":"2026-01-01T00:00:00.000Z"},"required":false,"description":"Inclusive lower bound on `createdOn` (ISO 8601). Filters reviews created at or after this instant.","name":"startDateTime","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Inclusive upper bound on `createdOn` (ISO 8601). Filters reviews created at or before this instant.","example":"2026-12-31T23:59:59.999Z"},"required":false,"description":"Inclusive upper bound on `createdOn` (ISO 8601). Filters reviews created at or before this instant.","name":"endDateTime","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"default":"desc","description":"Sort direction on `createdOn`. Defaults to `desc` (newest first). Use `asc` for forward-only incremental syncs.","example":"desc"},"required":false,"description":"Sort direction on `createdOn`. Defaults to `desc` (newest first). Use `asc` for forward-only incremental syncs.","name":"order","in":"query"}],"responses":{"200":{"description":"Paginated list of call reviews","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallReviewListResponse"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/calls/{id}/tags":{"post":{"tags":["Calls"],"summary":"Add a tag to a call","description":"Adds a tag to a call. If the tag is already associated with the call, the operation is idempotent and returns the existing association.","parameters":[{"schema":{"type":"string","description":"Call ID (positive integer) or UUID","example":"1"},"required":true,"description":"Call ID (positive integer) or UUID","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTagToCallRequest"}}}},"responses":{"201":{"description":"Tag added to call","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallTag"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Call or tag not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"tags":["Calls"],"summary":"List tags for a call","description":"Returns all tags associated with a call. Accepts both integer ID and UUID.","parameters":[{"schema":{"type":"string","description":"Call ID (positive integer) or UUID","example":"1"},"required":true,"description":"Call ID (positive integer) or UUID","name":"id","in":"path"}],"responses":{"200":{"description":"List of tags for the call","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallTagsResponse"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Call not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/calls/{id}/next-steps":{"get":{"tags":["Calls"],"summary":"Get call next steps","description":"Returns AI-extracted next steps (action items) from a call. Returns an empty list if the call is still processing or no next steps were detected.","parameters":[{"schema":{"type":"string","description":"Call ID (positive integer) or UUID","example":"1"},"required":true,"description":"Call ID (positive integer) or UUID","name":"id","in":"path"}],"responses":{"200":{"description":"List of next steps extracted from the call","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallNextStepsResponse"}}}},"404":{"description":"Call not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/calls/{id}/notes":{"get":{"tags":["Calls"],"summary":"Get call notes","description":"Returns the notes for a call. Only published notes are returned.","parameters":[{"schema":{"type":"string","description":"Call ID (positive integer) or UUID","example":"1"},"required":true,"description":"Call ID (positive integer) or UUID","name":"id","in":"path"}],"responses":{"200":{"description":"Call notes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteListResponse"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Call not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/calls/{id}/recording":{"get":{"tags":["Calls"],"summary":"Get call recording URL","description":"Returns a signed URL to download the call recording media file. The URL is valid for 1 hour; request a new one once it expires. Returns 410 if the recording has been deleted for data retention reasons, 404 if the call does not exist or the recording is not available yet. Accepts both integer ID and UUID.","parameters":[{"schema":{"type":"string","description":"Call ID (positive integer) or UUID","example":"1"},"required":true,"description":"Call ID (positive integer) or UUID","name":"id","in":"path"}],"responses":{"200":{"description":"Call recording URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallRecording"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Call not found or recording not available","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Call recording has been deleted for data retention reasons","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/calls/{id}":{"get":{"tags":["Calls"],"summary":"Get a call","description":"Returns a single call by ID. Accepts both integer ID and UUID. Use the expand query param to include related entities inline.","parameters":[{"schema":{"type":"string","description":"Call ID (positive integer) or UUID","example":"1"},"required":true,"description":"Call ID (positive integer) or UUID","name":"id","in":"path"},{"schema":{"type":"string","description":"Comma-separated list of relations to expand. Allowed values: contacts, deal, account, users","example":"contacts,deal"},"required":false,"description":"Comma-separated list of relations to expand. Allowed values: contacts, deal, account, users","name":"expand","in":"query"}],"responses":{"200":{"description":"Call details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallExpanded"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Call not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/calls/{id}/transcript":{"get":{"tags":["Calls"],"summary":"Get call transcript","description":"Returns the transcript for a call. Returns an empty data array while the call status is \"processing\". Accepts both integer ID and UUID.","parameters":[{"schema":{"type":"string","description":"Call ID (positive integer) or UUID","example":"1"},"required":true,"description":"Call ID (positive integer) or UUID","name":"id","in":"path"}],"responses":{"200":{"description":"Call transcript","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscriptResponse"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Call not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/calls/{id}/crm-filling-answers":{"get":{"tags":["CRM Filling Answers"],"summary":"List CRM filling answers for a call","description":"Returns a paginated list of CRM filling answers that have been pushed to the CRM for a specific call.","parameters":[{"schema":{"type":"string","description":"Call ID (positive integer) or UUID","example":"1"},"required":true,"description":"Call ID (positive integer) or UUID","name":"id","in":"path"},{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"}],"responses":{"200":{"description":"Paginated list of CRM filling answers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmFillingAnswerListResponse"}}}},"404":{"description":"Call not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/calls/{id}/summaries":{"get":{"tags":["Calls"],"summary":"List call summaries","description":"Returns all AI-generated summaries for a call. Each summary corresponds to a summary template configured in the workspace.","parameters":[{"schema":{"type":"string","description":"Call ID (positive integer) or UUID","example":"1"},"required":true,"description":"Call ID (positive integer) or UUID","name":"id","in":"path"}],"responses":{"200":{"description":"List of call summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallSummaryListResponse"}}}},"404":{"description":"Call not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/calls":{"get":{"tags":["Calls"],"summary":"List calls","description":"Returns a paginated list of calls. Supports filtering by date range, user, deal, and account. Use the expand query param to include related entities inline.","parameters":[{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"},{"schema":{"type":"string","description":"Comma-separated list of relations to expand. Allowed values: contacts, deal, account, users","example":"contacts,deal"},"required":false,"description":"Comma-separated list of relations to expand. Allowed values: contacts, deal, account, users","name":"expand","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Filter calls starting from this ISO 8601 date"},"required":false,"description":"Filter calls starting from this ISO 8601 date","name":"from","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Filter calls ending at this ISO 8601 date"},"required":false,"description":"Filter calls ending at this ISO 8601 date","name":"to","in":"query"},{"schema":{"type":"integer","description":"Filter by user ID"},"required":false,"description":"Filter by user ID","name":"user_id","in":"query"},{"schema":{"type":"integer","description":"Filter by deal ID"},"required":false,"description":"Filter by deal ID","name":"deal_id","in":"query"},{"schema":{"type":"integer","description":"Filter by account ID"},"required":false,"description":"Filter by account ID","name":"account_id","in":"query"}],"responses":{"200":{"description":"Paginated list of calls","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallExpandedListResponse"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Calls"],"summary":"Upload a call","description":"Upload a call to Modjo via a recording URL. Modjo will download the recording asynchronously. The call becomes visible within a few seconds. Typical total processing time: 5-30 minutes. The callId in the response is a UUID, usable with GET /v1/calls/:id.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadCallRequest"}}}},"responses":{"202":{"description":"Call accepted for processing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadCallResponse"}}}},"400":{"description":"Invalid request. At least one participant of type \"user\" mapping to a licensed user is required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/calls/{id}/tags/{tagId}":{"delete":{"tags":["Calls"],"summary":"Remove a tag from a call","description":"Removes a tag from a call. Returns 204 on success, 404 if the call, tag, or association does not exist.","parameters":[{"schema":{"type":"string","description":"Call ID (positive integer) or UUID","example":"1"},"required":true,"description":"Call ID (positive integer) or UUID","name":"id","in":"path"},{"schema":{"type":"integer","description":"Tag ID","example":1},"required":true,"description":"Tag ID","name":"tagId","in":"path"}],"responses":{"204":{"description":"Tag removed from call"},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Call, tag, or association not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/contacts":{"get":{"tags":["Contacts"],"summary":"List contacts","description":"Returns a paginated list of contacts. Supports filtering by contact name.","parameters":[{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Filter by contact name"},"required":false,"description":"Filter by contact name","name":"name","in":"query"}],"responses":{"200":{"description":"Paginated list of contacts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactListResponse"}}}}}}},"/contacts/{id}":{"get":{"tags":["Contacts"],"summary":"Get a contact","description":"Returns a single contact by ID.","parameters":[{"schema":{"type":"integer","description":"Contact ID","example":1},"required":true,"description":"Contact ID","name":"id","in":"path"}],"responses":{"200":{"description":"Contact details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"404":{"description":"Contact not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/crm-filling-templates":{"get":{"tags":["CRM Filling Templates"],"summary":"List CRM filling templates","description":"Returns a paginated list of CRM filling templates. Supports filtering by status.","parameters":[{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"},{"schema":{"type":"string","enum":["pending","published"],"description":"Filter by template status","example":"published"},"required":false,"description":"Filter by template status","name":"status","in":"query"}],"responses":{"200":{"description":"Paginated list of CRM filling templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmFillingTemplateListResponse"}}}}}}},"/crm-filling-templates/{uuid}":{"get":{"tags":["CRM Filling Templates"],"summary":"Get a CRM filling template","description":"Returns a single CRM filling template by UUID.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Template UUID","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Template UUID","name":"uuid","in":"path"}],"responses":{"200":{"description":"CRM filling template details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmFillingTemplate"}}}},"404":{"description":"CRM filling template not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/crm-filling-templates/{uuid}/fields":{"get":{"tags":["CRM Filling Templates"],"summary":"List fields of a CRM filling template","description":"Returns a paginated list of fields belonging to a CRM filling template.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Template UUID","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Template UUID","name":"uuid","in":"path"},{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"}],"responses":{"200":{"description":"Paginated list of CRM filling template fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmFillingFieldListResponse"}}}},"404":{"description":"CRM filling template not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/tags":{"get":{"tags":["Tags"],"summary":"List tags","description":"Returns a paginated list of tags.","parameters":[{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"}],"responses":{"200":{"description":"Paginated list of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}}}}},"/deals":{"get":{"tags":["Deals"],"summary":"List deals","description":"Returns a paginated list of deals. Supports filtering by deal name, account ID, and status.","parameters":[{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Filter by deal name"},"required":false,"description":"Filter by deal name","name":"name","in":"query"},{"schema":{"type":"integer","description":"Filter by account ID"},"required":false,"description":"Filter by account ID","name":"account_id","in":"query"},{"schema":{"type":"string","enum":["Open","Closed won","Closed lost","Closed","Deleted"],"description":"Filter by deal status (e.g. Open, Closed won, Closed lost)"},"required":false,"description":"Filter by deal status (e.g. Open, Closed won, Closed lost)","name":"status","in":"query"}],"responses":{"200":{"description":"Paginated list of deals","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealListResponse"}}}}}}},"/deals/{id}/summary":{"get":{"tags":["Deals"],"summary":"Get deal summary","description":"Returns the AI-generated summary for a deal. Returns 404 if the deal does not exist or has no summary.","parameters":[{"schema":{"type":"integer","description":"Deal ID","example":1},"required":true,"description":"Deal ID","name":"id","in":"path"}],"responses":{"200":{"description":"Deal summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealSummaryContent"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Deal or summary not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/teams":{"get":{"tags":["Teams"],"summary":"List teams","description":"Returns a paginated list of teams. Supports filtering by team name.","parameters":[{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Filter by team name"},"required":false,"description":"Filter by team name","name":"name","in":"query"}],"responses":{"200":{"description":"Paginated list of teams","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamListResponse"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Teams"],"summary":"Create a team","description":"Creates a new team.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamRequest"}}}},"responses":{"201":{"description":"Team created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/teams/{id}":{"get":{"tags":["Teams"],"summary":"Get a team","description":"Returns a single team by ID.","parameters":[{"schema":{"type":"integer","description":"Team ID","example":1},"required":true,"description":"Team ID","name":"id","in":"path"}],"responses":{"200":{"description":"Team details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Team not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Teams"],"summary":"Update a team","description":"Updates an existing team name.","parameters":[{"schema":{"type":"integer","description":"Team ID","example":1},"required":true,"description":"Team ID","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamRequest"}}}},"responses":{"200":{"description":"Team updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Team not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Teams"],"summary":"Delete a team","description":"Soft-deletes a team by ID.","parameters":[{"schema":{"type":"integer","description":"Team ID","example":1},"required":true,"description":"Team ID","name":"id","in":"path"}],"responses":{"204":{"description":"Team deleted"},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Team not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/teams/{id}/members":{"get":{"tags":["Teams"],"summary":"List team members","description":"Returns a paginated list of users belonging to a team.","parameters":[{"schema":{"type":"integer","description":"Team ID","example":1},"required":true,"description":"Team ID","name":"id","in":"path"},{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"}],"responses":{"200":{"description":"Paginated list of team members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMembersListResponse"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Team not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/topics":{"get":{"tags":["Topics"],"summary":"List topics","description":"Returns a paginated list of topics.","parameters":[{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"}],"responses":{"200":{"description":"Paginated list of topics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicListResponse"}}}}}}},"/users":{"get":{"tags":["Users"],"summary":"List users","description":"Returns a paginated list of users. Supports filtering by email.","parameters":[{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"},{"schema":{"type":"string","format":"email","description":"Filter by exact email address"},"required":false,"description":"Filter by exact email address","name":"email","in":"query"}],"responses":{"200":{"description":"Paginated list of users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserListResponse"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Users"],"summary":"Create a user","description":"Creates a new user. Email must be unique within the tenant.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}}},"responses":{"201":{"description":"User created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A user with this email already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/users/{id}":{"get":{"tags":["Users"],"summary":"Get a user","description":"Returns a single user by ID.","parameters":[{"schema":{"type":"integer","description":"User ID","example":1},"required":true,"description":"User ID","name":"id","in":"path"}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Users"],"summary":"Update a user","description":"Partially updates an existing user. Only provided fields are updated.","parameters":[{"schema":{"type":"integer","description":"User ID","example":1},"required":true,"description":"User ID","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}}},"responses":{"200":{"description":"User updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A user with this email already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Users"],"summary":"Delete a user","description":"Soft-deletes a user by ID.","parameters":[{"schema":{"type":"integer","description":"User ID","example":1},"required":true,"description":"User ID","name":"id","in":"path"}],"responses":{"204":{"description":"User deleted"},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/users/{id}/teams":{"post":{"tags":["Users"],"summary":"Add a user to a team","description":"Adds a user to a team. If the user is already a member of the team, the operation is idempotent and returns the existing membership.","parameters":[{"schema":{"type":"integer","description":"User ID","example":1},"required":true,"description":"User ID","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTeamToUserRequest"}}}},"responses":{"201":{"description":"User added to team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserTeam"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"User or team not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/users/{id}/teams/{teamId}":{"delete":{"tags":["Users"],"summary":"Remove a user from a team","description":"Removes a user from a team. Returns 204 on success, 404 if the user, team, or membership does not exist.","parameters":[{"schema":{"type":"integer","description":"User ID","example":1},"required":true,"description":"User ID","name":"id","in":"path"},{"schema":{"type":"integer","description":"Team ID","example":1},"required":true,"description":"Team ID","name":"teamId","in":"path"}],"responses":{"204":{"description":"User removed from team"},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"User, team, or membership not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhooks","description":"Returns a paginated list of webhooks.","parameters":[{"schema":{"type":"integer","description":"Page number (1-based)","example":1},"required":false,"description":"Page number (1-based)","name":"page","in":"query"},{"schema":{"type":"integer","description":"Number of items per page","example":25},"required":false,"description":"Number of items per page","name":"size","in":"query"}],"responses":{"200":{"description":"Paginated list of webhooks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookListResponse"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Webhooks"],"summary":"Create a webhook","description":"Creates a new webhook. Name must be unique within the tenant.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"}}}},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A webhook with this name already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/webhooks/{uuid}":{"get":{"tags":["Webhooks"],"summary":"Get a webhook","description":"Returns a single webhook by UUID.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Webhook UUID","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Webhook UUID","name":"uuid","in":"path"}],"responses":{"200":{"description":"Webhook details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Webhooks"],"summary":"Update a webhook","description":"Partially updates an existing webhook. Only provided fields are updated.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Webhook UUID","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Webhook UUID","name":"uuid","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequest"}}}},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A webhook with this name already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","description":"Soft-deletes a webhook by UUID.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Webhook UUID","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Webhook UUID","name":"uuid","in":"path"}],"responses":{"204":{"description":"Webhook deleted"},"401":{"description":"Authentication failed. The API key is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the X-RateLimit-Reset interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}