{"openapi":"3.1.0","info":{"title":"JNT Planning Proxy API","version":"1.1.0","description":"Planning proxy: Todoist, Google Calendar, FastMail, local files."},"servers":[{"url":"https://hub-api.juniti.si/planningproxy"}],"security":[{"ApiKeyAuth":[]}],"paths":{"/planning/day":{"get":{"operationId":"getPlanningDay","summary":"Get aggregated day plan context","description":"Returns today's JNTPortal work tasks, Todoist non-work tasks, calendar events and free blocks for AI planning.","parameters":[{"name":"date","in":"query","required":false,"description":"Date in yyyy-MM-dd format. Defaults to today.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanningDayResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/planning/week":{"get":{"operationId":"getPlanningWeek","summary":"Get aggregated week plan context","description":"Returns JNTPortal work tasks and Todoist non-work tasks grouped by day, calendar events and capacity estimate for the week.","parameters":[{"name":"start","in":"query","required":false,"description":"Start date (yyyy-MM-dd). Defaults to current Monday.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanningWeekResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/planning/done":{"get":{"operationId":"getPlanningDone","summary":"Get retrospective context — what was done in a period","description":"Returns JNTPortal work log (hours, notes), completed Todoist tasks, past calendar events and files for the given period.","parameters":[{"name":"period","in":"query","required":false,"description":"Period: today, yesterday, this-week, last-week, this-month, last-month. Default: today.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanningDoneResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/todoist/summary":{"get":{"operationId":"getTodoistSummary","summary":"Get Todoist task counts and top tasks","description":"Returns overdue, today, next 7 days counts, high priority count, by-project breakdown and top tasks.","parameters":[{"name":"topTasksLimit","in":"query","required":false,"description":"Max number of top tasks to return. Default: 20.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoistSummaryResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/todoist/tasks":{"get":{"operationId":"getTodoistTasks","summary":"Get paginated Todoist tasks","description":"Returns tasks filtered by scope (today, overdue, next7days), project, label or priority.","parameters":[{"name":"scope","in":"query","required":false,"description":"today | overdue | next7days or any Todoist filter.","schema":{"type":"string"}},{"name":"projectId","in":"query","required":false,"description":"Filter by project ID.","schema":{"type":"string"}},{"name":"priority","in":"query","required":false,"description":"Filter by priority (4=p1, 3=p2, 2=p3, 1=p4).","schema":{"type":"string"}},{"name":"includeDescriptions","in":"query","required":false,"description":"Include task descriptions. Default: false.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number. Default: 1.","schema":{"type":"string"}},{"name":"pageSize","in":"query","required":false,"description":"Items per page (max 100). Default: 50.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskListResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/todoist/tasks/{taskId}":{"get":{"operationId":"getTodoistTaskById","summary":"Get a single Todoist task with full description","description":"Returns full task detail including description, labels, due date and deadline.","parameters":[{"name":"taskId","in":"path","required":true,"description":"Todoist task ID.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoistTask"}}}},"401":{"description":"Unauthorized."},"404":{"description":"Not found."}}}},"/todoist/completed":{"get":{"operationId":"getTodoistCompleted","summary":"Get completed Todoist tasks for a period","description":"Returns tasks completed in the given date range.","parameters":[{"name":"from","in":"query","required":false,"description":"Start date yyyy-MM-dd. Default: today.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"End date yyyy-MM-dd. Default: today.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number. Default: 1.","schema":{"type":"string"}},{"name":"pageSize","in":"query","required":false,"description":"Items per page. Default: 50.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskListResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/calendar/summary":{"get":{"operationId":"getCalendarSummary","summary":"Get calendar summary with busy hours and free blocks","description":"Returns event count, total busy hours per day and free time blocks in work hours.","parameters":[{"name":"from","in":"query","required":false,"description":"Start date yyyy-MM-dd. Default: today.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"End date yyyy-MM-dd. Default: today+6.","schema":{"type":"string"}},{"name":"minFreeSlotMinutes","in":"query","required":false,"description":"Minimum free block duration in minutes. Default: 30.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarSummaryResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/calendar/freebusy":{"get":{"operationId":"getCalendarFreeBusy","summary":"Get free and busy time blocks","description":"Returns merged busy intervals and free blocks within work hours for each day.","parameters":[{"name":"from","in":"query","required":false,"description":"Start date yyyy-MM-dd. Default: today.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"End date yyyy-MM-dd. Default: today+6.","schema":{"type":"string"}},{"name":"minSlotMinutes","in":"query","required":false,"description":"Minimum free block in minutes. Default: 30.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FreeBusyResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/calendar/events":{"get":{"operationId":"getCalendarEvents","summary":"Get paginated calendar events","description":"Returns events from configured calendars in the given date range.","parameters":[{"name":"from","in":"query","required":false,"description":"Start date yyyy-MM-dd. Default: today.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"End date yyyy-MM-dd. Default: today+6.","schema":{"type":"string"}},{"name":"includeDescriptions","in":"query","required":false,"description":"Include event descriptions. Default: false.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number. Default: 1.","schema":{"type":"string"}},{"name":"pageSize","in":"query","required":false,"description":"Items per page. Default: 50.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventListResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/mail/summary":{"get":{"operationId":"getMailSummary","summary":"Get FastMail inbox summary","description":"Returns inbox count, unread count and recent messages. Use for quick mail overview.","parameters":[{"name":"from","in":"query","required":false,"description":"Start date yyyy-MM-dd.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"End date yyyy-MM-dd.","schema":{"type":"string"}},{"name":"recentCount","in":"query","required":false,"description":"Number of recent messages to return. Default: 20.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailSummaryResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/mail/folders":{"get":{"operationId":"getMailFolders","summary":"Get Inbox subfolders (customer folders)","description":"Subfolders of the Inbox — typically one per customer, holding open mails that act as todos. Use the folder id as mailboxId in /mail/messages.","parameters":[{"name":"all","in":"query","required":false,"description":"true = list every mailbox, false (default) = only Inbox subfolders.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailFolderListResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/mail/messages":{"get":{"operationId":"getMailMessages","summary":"Get paginated mail messages","description":"Returns messages from the Inbox or, with mailboxId, from a specific folder (see /mail/folders).","parameters":[{"name":"from","in":"query","required":false,"description":"Start date yyyy-MM-dd.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"End date yyyy-MM-dd.","schema":{"type":"string"}},{"name":"mailboxId","in":"query","required":false,"description":"Folder ID from /mail/folders. Default: Inbox.","schema":{"type":"string"}},{"name":"includeBody","in":"query","required":false,"description":"Include message body. Default: false.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number. Default: 1.","schema":{"type":"string"}},{"name":"pageSize","in":"query","required":false,"description":"Items per page. Default: 50.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailListResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/mail/messages/{messageId}":{"get":{"operationId":"getMailMessageById","summary":"Get a single mail message with full body","description":"Returns the complete message including text body (truncated at maxBytes).","parameters":[{"name":"messageId","in":"path","required":true,"description":"JMAP message ID.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailMessage"}}}},"401":{"description":"Unauthorized."},"404":{"description":"Not found."}}}},"/files/folders":{"get":{"operationId":"getFileFolders","summary":"Get work folders filtered by date","description":"Lists folders from configured root paths. Folder names with dates (yyyy-MM-dd) are filterable by range.","parameters":[{"name":"from","in":"query","required":false,"description":"Start date yyyy-MM-dd.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"End date yyyy-MM-dd.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number. Default: 1.","schema":{"type":"string"}},{"name":"pageSize","in":"query","required":false,"description":"Items per page. Default: 50.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderListResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/files/folders/{folderId}/summary":{"get":{"operationId":"getFolderSummary","summary":"Get readable summary of folder contents","description":"Reads text files in the folder and returns a concatenated summary (max maxBytes).","parameters":[{"name":"folderId","in":"path","required":true,"description":"Base64-encoded folder ID from /files/folders.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderSummaryResponse"}}}},"401":{"description":"Unauthorized."},"404":{"description":"Not found."}}}},"/files/folders/{folderId}/files":{"get":{"operationId":"getFolderFiles","summary":"Get files in a folder","description":"Returns file metadata (name, size, modified date) for all files in the folder.","parameters":[{"name":"folderId","in":"path","required":true,"description":"Base64-encoded folder ID from /files/folders.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderFilesResponse"}}}},"401":{"description":"Unauthorized."},"404":{"description":"Not found."}}}},"/files/{fileId}/content":{"get":{"operationId":"getFileContent","summary":"Get file content with byte limit","description":"Returns raw text content of a file, truncated at maxBytes.","parameters":[{"name":"fileId","in":"path","required":true,"description":"Base64-encoded file ID from /files/folders/{id}/files.","schema":{"type":"string"}},{"name":"maxBytes","in":"query","required":false,"description":"Max bytes to return. Default: 20000.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileContentResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/calendar/list":{"get":{"operationId":"getCalendarList","summary":"Get list of configured calendars","description":"Returns all Google Calendar calendars the proxy is configured to read.","parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarListResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/calendar/events/create":{"post":{"operationId":"createCalendarEvent","summary":"Create a new calendar event","description":"Creates an event on a write-enabled calendar. CalendarId defaults to the first CalendarIdsWrite entry.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarCreateEventRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarEvent"}}}},"400":{"description":"Bad request — no write calendars configured or invalid calendarId."},"401":{"description":"Unauthorized."}}}},"/calendar/events/update/{eventId}":{"put":{"operationId":"updateCalendarEvent","summary":"Update an existing calendar event","description":"Updates fields on an existing event. Only provided fields are changed.","parameters":[{"name":"eventId","in":"path","required":true,"description":"Google Calendar event ID.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarUpdateEventRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarEvent"}}}},"400":{"description":"Bad request."},"401":{"description":"Unauthorized."},"404":{"description":"Not found."}}}},"/calendar/events/delete/{eventId}":{"delete":{"operationId":"deleteCalendarEvent","summary":"Delete a calendar event","description":"Deletes the event from the specified write-enabled calendar.","parameters":[{"name":"eventId","in":"path","required":true,"description":"Google Calendar event ID.","schema":{"type":"string"}},{"name":"calendarId","in":"query","required":false,"description":"Target calendar ID. Defaults to first CalendarIdsWrite entry.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteEventResponse"}}}},"400":{"description":"Bad request."},"401":{"description":"Unauthorized."},"404":{"description":"Not found."}}}},"/todoist/projects":{"get":{"operationId":"getTodoistProjects","summary":"Get all Todoist projects","description":"Returns all projects with ID, name and parentId for hierarchy mapping.","parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectListResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/portal/summary":{"get":{"operationId":"getPortalSummary","summary":"Get JNTPortal work summary","description":"JNTPortal holds all WORK tasks/projects (Todoist = non-work only). Returns open/today/overdue task counts, open project count, work hours today/week/month and top due tasks.","parameters":[{"name":"topTasksLimit","in":"query","required":false,"description":"Max top tasks to return. Default: 20.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalSummaryResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/portal/tasks":{"get":{"operationId":"getPortalTasks","summary":"Get paginated JNTPortal work tasks","description":"Work tasks from JNTPortal DB. Scope: open (default) | today | overdue | week | nodate | finished | all.","parameters":[{"name":"scope","in":"query","required":false,"description":"open | today | overdue | week | nodate | finished | all.","schema":{"type":"string"}},{"name":"projectId","in":"query","required":false,"description":"Filter by JNTPortal project ID.","schema":{"type":"string"}},{"name":"parentTaskId","in":"query","required":false,"description":"Filter subtasks of a task.","schema":{"type":"string"}},{"name":"search","in":"query","required":false,"description":"Search in task name and note.","schema":{"type":"string"}},{"name":"includeNotes","in":"query","required":false,"description":"Include task notes. Default: false.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number. Default: 1.","schema":{"type":"string"}},{"name":"pageSize","in":"query","required":false,"description":"Items per page (max 100). Default: 50.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalTaskListResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/portal/tasks/{taskId}":{"get":{"operationId":"getPortalTaskById","summary":"Get a single JNTPortal task with subtasks","description":"Returns full task detail including note and its subtasks.","parameters":[{"name":"taskId","in":"path","required":true,"description":"JNTPortal task ID (integer).","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalTaskDetailResponse"}}}},"401":{"description":"Unauthorized."},"404":{"description":"Not found."}}}},"/portal/projects":{"get":{"operationId":"getPortalProjects","summary":"Get open JNTPortal projects","description":"Open projects with budget, spent time, billed/not-billed time and status. Source: vProjectOpen.","parameters":[{"name":"customerId","in":"query","required":false,"description":"Filter by customer ID.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Filter by project status name.","schema":{"type":"string"}},{"name":"search","in":"query","required":false,"description":"Search in project or customer name.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number. Default: 1.","schema":{"type":"string"}},{"name":"pageSize","in":"query","required":false,"description":"Items per page (max 100). Default: 50.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalProjectListResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/portal/projects/{projectId}":{"get":{"operationId":"getPortalProjectById","summary":"Get a JNTPortal project with recent work and open tasks","description":"Returns project detail plus recent work entries and open tasks for the project.","parameters":[{"name":"projectId","in":"path","required":true,"description":"JNTPortal project ID (integer).","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalProjectDetailResponse"}}}},"401":{"description":"Unauthorized."},"404":{"description":"Not found."}}}},"/portal/work":{"get":{"operationId":"getPortalWork","summary":"Get JNTPortal work log — what was done","description":"Work entries (hours, notes, project, task) for a period. This is the primary record of performed work.","parameters":[{"name":"from","in":"query","required":false,"description":"Start date yyyy-MM-dd. Default: today.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"End date yyyy-MM-dd. Default: today.","schema":{"type":"string"}},{"name":"projectId","in":"query","required":false,"description":"Filter by project ID.","schema":{"type":"string"}},{"name":"taskId","in":"query","required":false,"description":"Filter by task ID.","schema":{"type":"string"}},{"name":"search","in":"query","required":false,"description":"Search in note, project or task name.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number. Default: 1.","schema":{"type":"string"}},{"name":"pageSize","in":"query","required":false,"description":"Items per page (max 100). Default: 50.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalWorkListResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/portal/work/summary":{"get":{"operationId":"getPortalWorkSummary","summary":"Get aggregated JNTPortal work hours","description":"Sums work hours for a period grouped by project (default), day or customer.","parameters":[{"name":"from","in":"query","required":false,"description":"Start date yyyy-MM-dd. Default: today.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"End date yyyy-MM-dd. Default: today.","schema":{"type":"string"}},{"name":"groupBy","in":"query","required":false,"description":"project | day | customer. Default: project.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalWorkSummaryResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}},"/health":{"get":{"operationId":"getHealth","summary":"Health check","description":"Returns service status and server time.","parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"401":{"description":"Unauthorized — missing or invalid x-api-key header."}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key"}},"schemas":{"TodoistTask":{"type":"object","properties":{"id":{"type":"string","description":"Task ID"},"content":{"type":"string","description":"Task title"},"description":{"type":"string","description":"Full task description"},"priority":{"type":"integer","description":"1=p4 (low) … 4=p1 (urgent)"},"due":{"type":"object","properties":{"date":{"type":"string","description":"Due date yyyy-MM-dd"},"datetime":{"type":"string","description":"Due datetime"}}},"deadline":{"type":"object","properties":{"date":{"type":"string","description":"Deadline date yyyy-MM-dd"}}},"due_date":{"type":"string","description":"Flattened due date yyyy-MM-dd (null if none)"},"deadline_date":{"type":"string","description":"Flattened deadline date yyyy-MM-dd (null if none)"},"labels":{"type":"array","items":{"type":"string"}},"projectId":{"type":"string","description":"Project ID"},"url":{"type":"string","description":"Todoist task URL"}}},"TodoistProject":{"type":"object","properties":{"id":{"type":"string","description":"Project ID"},"name":{"type":"string","description":"Project name"},"parentId":{"type":"string","description":"Parent project ID (null for top-level)"}}},"CalendarEvent":{"type":"object","properties":{"id":{"type":"string","description":"Event ID"},"calendarName":{"type":"string","description":"Calendar display name"},"summary":{"type":"string","description":"Event title"},"description":{"type":"string","description":"Event description"},"location":{"type":"string","description":"Event location"},"start":{"type":"string","description":"Start datetime ISO 8601"},"end":{"type":"string","description":"End datetime ISO 8601"}}},"MailMessage":{"type":"object","properties":{"id":{"type":"string","description":"JMAP message ID"},"from":{"type":"string","description":"Sender (Name <email>)"},"to":{"type":"string","description":"Recipients"},"subject":{"type":"string","description":"Subject"},"receivedAt":{"type":"string","description":"Received datetime ISO 8601"},"preview":{"type":"string","description":"Short preview of body"},"isRead":{"type":"boolean"},"isStarred":{"type":"boolean"},"body":{"type":"string","description":"Full body text (only in /mail/messages/{id})"},"truncated":{"type":"boolean"},"returnedBytes":{"type":"integer"},"totalBytes":{"type":"integer"}}},"FileFolder":{"type":"object","properties":{"id":{"type":"string","description":"Base64 folder ID"},"name":{"type":"string","description":"Folder name"},"path":{"type":"string","description":"Full path"},"detectedDate":{"type":"string","description":"Date detected from folder name (yyyy-MM-dd)"},"fileCount":{"type":"integer"},"totalBytes":{"type":"integer"},"tags":{"type":"array","items":{"type":"string"},"description":"Words extracted from folder name"}}},"FileItem":{"type":"object","properties":{"id":{"type":"string","description":"Base64 file ID"},"name":{"type":"string","description":"File name"},"extension":{"type":"string","description":"File extension"},"sizeBytes":{"type":"integer"},"modifiedAt":{"type":"string","description":"Modified datetime ISO 8601"}}},"ListMeta":{"type":"object","properties":{"source":{"type":"string","description":"Data source"},"type":{"type":"string","description":"Item type"},"count":{"type":"integer","description":"Total items available"},"returned":{"type":"integer","description":"Items in this page"},"page":{"type":"integer"},"pageSize":{"type":"integer"},"hasMore":{"type":"boolean"},"nextEndpoint":{"type":"string","description":"Endpoint hint for next page"}}},"PlanningDayResponse":{"type":"object","properties":{"type":{"type":"string","description":"day-plan-context"},"date":{"type":"string","description":"yyyy-MM-dd"},"generatedAt":{"type":"string","description":"ISO 8601"},"todoist":{"type":"object","properties":{"overdueCount":{"type":"integer"},"todayCount":{"type":"integer"},"highPriorityCount":{"type":"integer"},"topTasks":{"type":"array","items":{"$ref":"#/components/schemas/TodoistTask"}}}},"calendar":{"type":"object","properties":{"eventCount":{"type":"integer"},"busyHours":{"type":"number"},"freeBlocks":{"type":"array","items":{"$ref":"#/components/schemas/FreeBlock"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/CalendarEvent"}}}},"files":{"type":"object","properties":{"foldersTodayCount":{"type":"integer"},"recentFolders":{"type":"array","items":{"$ref":"#/components/schemas/FileFolder"}}}},"recommendationContext":{"type":"object","properties":{"warnings":{"type":"array","items":{"type":"string"}},"hasMore":{"type":"boolean"}}}}},"PlanningWeekResponse":{"type":"object","properties":{"type":{"type":"string","description":"week-plan-context"},"start":{"type":"string","description":"yyyy-MM-dd"},"end":{"type":"string","description":"yyyy-MM-dd"},"generatedAt":{"type":"string","description":"ISO 8601"},"todoist":{"type":"object","properties":{"taskCount":{"type":"integer"},"highPriorityCount":{"type":"integer"},"overdueCount":{"type":"integer"},"byDay":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"yyyy-MM-dd"},"count":{"type":"integer"},"topTasks":{"type":"array","items":{"$ref":"#/components/schemas/TodoistTask"}}}}}}},"calendar":{"type":"object","properties":{"totalBusyHours":{"type":"number"},"eventsByDay":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"yyyy-MM-dd"},"eventCount":{"type":"integer"},"busyHours":{"type":"number"}}}}}},"capacity":{"type":"object","properties":{"estimatedFreeFocusHours":{"type":"number"}}},"risks":{"type":"array","items":{"type":"string"}}}},"PlanningDoneResponse":{"type":"object","properties":{"type":{"type":"string","description":"done-context"},"period":{"type":"string","description":"Period key"},"from":{"type":"string","description":"yyyy-MM-dd"},"to":{"type":"string","description":"yyyy-MM-dd"},"generatedAt":{"type":"string","description":"ISO 8601"},"todoistCompleted":{"type":"object","properties":{"count":{"type":"integer"},"items":{"type":"array","items":{"$ref":"#/components/schemas/TodoistTask"}}}},"calendar":{"type":"object","properties":{"pastEventsCount":{"type":"integer"},"items":{"type":"array","items":{"$ref":"#/components/schemas/CalendarEvent"}}}},"files":{"type":"object","properties":{"folderCount":{"type":"integer"},"items":{"type":"array","items":{"$ref":"#/components/schemas/FileFolder"}}}},"summary":{"type":"object","properties":{"mainProjects":{"type":"array","items":{"type":"string"}}}}}},"TodoistSummaryResponse":{"type":"object","properties":{"source":{"type":"string","description":"todoist"},"overdueCount":{"type":"integer"},"todayCount":{"type":"integer"},"next7DaysCount":{"type":"integer"},"highPriorityCount":{"type":"integer"},"byProject":{"type":"array","items":{"type":"object","properties":{"projectId":{"type":"string"},"projectName":{"type":"string"},"count":{"type":"integer"},"highPriorityCount":{"type":"integer"}}}},"topTasks":{"type":"array","items":{"$ref":"#/components/schemas/TodoistTask"}}}},"CalendarSummaryResponse":{"type":"object","properties":{"source":{"type":"string","description":"google_calendar"},"from":{"type":"string","description":"yyyy-MM-dd"},"to":{"type":"string","description":"yyyy-MM-dd"},"eventCount":{"type":"integer"},"busyHours":{"type":"number"},"days":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"yyyy-MM-dd"},"eventCount":{"type":"integer"},"busyHours":{"type":"number"}}}},"freeBlocks":{"type":"array","items":{"$ref":"#/components/schemas/FreeBlock"}}}},"FreeBusyResponse":{"type":"object","properties":{"source":{"type":"string","description":"google_calendar"},"from":{"type":"string","description":"yyyy-MM-dd"},"to":{"type":"string","description":"yyyy-MM-dd"},"busy":{"type":"array","items":{"$ref":"#/components/schemas/BusyBlock"}},"free":{"type":"array","items":{"$ref":"#/components/schemas/FreeBlock"}}}},"FreeBlock":{"type":"object","properties":{"date":{"type":"string","description":"yyyy-MM-dd"},"start":{"type":"string","description":"ISO 8601"},"end":{"type":"string","description":"ISO 8601"},"durationMinutes":{"type":"integer"}}},"BusyBlock":{"type":"object","properties":{"date":{"type":"string","description":"yyyy-MM-dd"},"start":{"type":"string","description":"ISO 8601"},"end":{"type":"string","description":"ISO 8601"},"durationMinutes":{"type":"integer"},"summary":{"type":"string","description":"Event title if matched"}}},"MailSummaryResponse":{"type":"object","properties":{"source":{"type":"string","description":"fastmail"},"inboxCount":{"type":"integer"},"unreadCount":{"type":"integer"},"returnedCount":{"type":"integer"},"folders":{"type":"array","items":{"$ref":"#/components/schemas/MailFolder"},"description":"Inbox subfolders (customer folders with open mails)"},"recentMessages":{"type":"array","items":{"$ref":"#/components/schemas/MailMessage"}}}},"MailFolder":{"type":"object","properties":{"id":{"type":"string","description":"Mailbox ID — use as mailboxId in /mail/messages"},"name":{"type":"string","description":"Folder name (usually customer name)"},"parentId":{"type":"string","description":"Parent mailbox ID"},"role":{"type":"string","description":"JMAP role (inbox, sent, …) or null for custom folders"},"totalEmails":{"type":"integer"},"unreadEmails":{"type":"integer"}}},"MailFolderListResponse":{"type":"object","properties":{"source":{"type":"string","description":"fastmail"},"scope":{"type":"string","description":"inbox-subfolders | all"},"count":{"type":"integer"},"folders":{"type":"array","items":{"$ref":"#/components/schemas/MailFolder"}}}},"TaskListResponse":{"type":"object","properties":{"source":{"type":"string"},"count":{"type":"integer"},"returned":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"},"hasMore":{"type":"boolean"},"nextEndpoint":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/TodoistTask"}}}},"EventListResponse":{"type":"object","properties":{"source":{"type":"string"},"count":{"type":"integer"},"returned":{"type":"integer"},"hasMore":{"type":"boolean"},"items":{"type":"array","items":{"$ref":"#/components/schemas/CalendarEvent"}}}},"MailListResponse":{"type":"object","properties":{"source":{"type":"string"},"count":{"type":"integer"},"returned":{"type":"integer"},"hasMore":{"type":"boolean"},"items":{"type":"array","items":{"$ref":"#/components/schemas/MailMessage"}}}},"FolderListResponse":{"type":"object","properties":{"source":{"type":"string"},"count":{"type":"integer"},"returned":{"type":"integer"},"hasMore":{"type":"boolean"},"items":{"type":"array","items":{"$ref":"#/components/schemas/FileFolder"}}}},"FolderSummaryResponse":{"type":"object","properties":{"folderId":{"type":"string"},"summary":{"type":"string","description":"Concatenated readable content of text files"},"detectedTopics":{"type":"array","items":{"type":"string"}},"detectedDate":{"type":"string","description":"yyyy-MM-dd"},"filesRead":{"type":"integer"},"truncated":{"type":"boolean"}}},"FolderFilesResponse":{"type":"object","properties":{"folderId":{"type":"string"},"count":{"type":"integer"},"files":{"type":"array","items":{"$ref":"#/components/schemas/FileItem"}}}},"FileContentResponse":{"type":"object","properties":{"fileId":{"type":"string"},"name":{"type":"string","description":"File name"},"content":{"type":"string","description":"Raw file content"},"truncated":{"type":"boolean"},"returnedBytes":{"type":"integer"},"totalBytes":{"type":"integer"}}},"ProjectListResponse":{"type":"object","properties":{"source":{"type":"string"},"count":{"type":"integer"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/TodoistProject"}}}},"CalendarListResponse":{"type":"object","properties":{"source":{"type":"string","description":"google_calendar"},"count":{"type":"integer"},"calendars":{"type":"array","items":{"type":"object"}}}},"CalendarCreateEventRequest":{"type":"object","properties":{"calendarId":{"type":"string","description":"Target calendar ID. Omit to use first CalendarIdsWrite entry."},"summary":{"type":"string","description":"Event title (required)."},"description":{"type":"string","description":"Optional notes."},"location":{"type":"string","description":"Optional location."},"start":{"type":"string","description":"Start time ISO 8601 or date-only for all-day (required)."},"end":{"type":"string","description":"End time ISO 8601 or date-only for all-day (required)."},"allDay":{"type":"boolean","description":"If true, Start/End are date-only."},"attendees":{"type":"array","items":{"type":"string"},"description":"Attendee email addresses."}}},"CalendarUpdateEventRequest":{"type":"object","properties":{"calendarId":{"type":"string","description":"Target calendar ID. Omit to use first CalendarIdsWrite entry."},"summary":{"type":"string","description":"New event title."},"description":{"type":"string","description":"New description."},"location":{"type":"string","description":"New location."},"start":{"type":"string","description":"New start time ISO 8601. Null = keep existing."},"end":{"type":"string","description":"New end time ISO 8601. Null = keep existing."},"allDay":{"type":"boolean","description":"Override all-day flag."},"attendees":{"type":"array","items":{"type":"string"},"description":"Replacement attendee list."}}},"DeleteEventResponse":{"type":"object","properties":{"deleted":{"type":"boolean"},"calendarId":{"type":"string","description":"Calendar the event was deleted from."},"eventId":{"type":"string","description":"Deleted event ID."}}},"PortalTask":{"type":"object","properties":{"id":{"type":"integer","description":"JNTPortal task ID"},"taskName":{"type":"string","description":"Task title"},"projectId":{"type":"integer"},"projectName":{"type":"string","description":"Project name"},"customer":{"type":"string","description":"Customer name"},"parentTaskId":{"type":"integer","description":"Parent task ID for subtasks"},"priority":{"type":"integer"},"isFinished":{"type":"boolean"},"estimatedTime":{"type":"number","description":"Estimated hours"},"estimatedTimeSumAllSubTasks":{"type":"number"},"dueDate":{"type":"string","description":"Due date yyyy-MM-dd (null = no due date)"},"planedTime":{"type":"string","description":"Planned datetime"},"finished":{"type":"string","description":"Finished datetime"},"isRepeated":{"type":"boolean"},"repeatRule":{"type":"string","description":"Repeat rule"},"note":{"type":"string","description":"Task note (truncated unless single-task endpoint)"}}},"PortalProject":{"type":"object","properties":{"id":{"type":"integer","description":"JNTPortal project ID"},"projectName":{"type":"string","description":"Project name"},"parentProjectId":{"type":"integer"},"customer":{"type":"string","description":"Customer name"},"projectStatus":{"type":"string","description":"Status name"},"projectGroup":{"type":"string","description":"Sorted status group"},"budget":{"type":"number"},"estimatedTime":{"type":"number","description":"Estimated hours"},"spentTime":{"type":"number","description":"Work hours spent (chargeable)"},"spentTimeAll":{"type":"number","description":"All hours spent"},"spentBudget":{"type":"number"},"billedTime":{"type":"number"},"notBilledTime":{"type":"number","description":"Hours not yet billed"},"billedValueNeto":{"type":"number"},"hourlyCalculated":{"type":"number","description":"Effective hourly rate"},"alarm":{"type":"string","description":"Budget alarm: Green/Orange/Red/Violet"},"workCount":{"type":"integer"},"taskCountNotFinished":{"type":"integer"},"workMaxDate":{"type":"string","description":"Last work entry date"},"deliveryDeadline":{"type":"string","description":"Delivery deadline"},"note":{"type":"string"}}},"PortalWorkEntry":{"type":"object","properties":{"id":{"type":"integer"},"date":{"type":"string","description":"Work date yyyy-MM-dd"},"timeFrom":{"type":"string","description":"Start datetime"},"timeTo":{"type":"string","description":"End datetime"},"time":{"type":"number","description":"Hours"},"projectId":{"type":"integer"},"projectName":{"type":"string"},"taskId":{"type":"integer"},"taskName":{"type":"string"},"reference":{"type":"string"},"billReference":{"type":"string","description":"Invoice reference (empty = not billed)"},"note":{"type":"string","description":"What was done"}}},"PortalWorkSum":{"type":"object","properties":{"groupKey":{"type":"string","description":"Project name, date or customer depending on groupBy"},"customer":{"type":"string"},"hoursWork":{"type":"number"},"hoursInternal":{"type":"number"},"hoursTotal":{"type":"number"},"entryCount":{"type":"integer"}}},"PortalSummaryResponse":{"type":"object","properties":{"source":{"type":"string","description":"jntportal"},"openTaskCount":{"type":"integer"},"todayTaskCount":{"type":"integer"},"overdueTaskCount":{"type":"integer"},"noDueDateTaskCount":{"type":"integer"},"openProjectCount":{"type":"integer"},"workHoursToday":{"type":"number"},"workHoursThisWeek":{"type":"number"},"workHoursThisMonth":{"type":"number"},"topTasks":{"type":"array","items":{"$ref":"#/components/schemas/PortalTask"}}}},"PortalTaskListResponse":{"type":"object","properties":{"source":{"type":"string","description":"jntportal"},"count":{"type":"integer"},"returned":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"},"hasMore":{"type":"boolean"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PortalTask"}}}},"PortalTaskDetailResponse":{"type":"object","properties":{"source":{"type":"string","description":"jntportal"},"task":{"$ref":"#/components/schemas/PortalTask"},"subTaskCount":{"type":"integer"},"subTasks":{"type":"array","items":{"$ref":"#/components/schemas/PortalTask"}}}},"PortalProjectListResponse":{"type":"object","properties":{"source":{"type":"string","description":"jntportal"},"count":{"type":"integer"},"returned":{"type":"integer"},"hasMore":{"type":"boolean"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PortalProject"}}}},"PortalProjectDetailResponse":{"type":"object","properties":{"source":{"type":"string","description":"jntportal"},"project":{"$ref":"#/components/schemas/PortalProject"},"workEntryCount":{"type":"integer"},"workHoursTotal":{"type":"number"},"recentWork":{"type":"array","items":{"$ref":"#/components/schemas/PortalWorkEntry"}},"openTaskCount":{"type":"integer"},"openTasks":{"type":"array","items":{"$ref":"#/components/schemas/PortalTask"}}}},"PortalWorkListResponse":{"type":"object","properties":{"source":{"type":"string","description":"jntportal"},"from":{"type":"string","description":"yyyy-MM-dd"},"to":{"type":"string","description":"yyyy-MM-dd"},"count":{"type":"integer"},"totalHours":{"type":"number"},"returned":{"type":"integer"},"hasMore":{"type":"boolean"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PortalWorkEntry"}}}},"PortalWorkSummaryResponse":{"type":"object","properties":{"source":{"type":"string","description":"jntportal"},"from":{"type":"string","description":"yyyy-MM-dd"},"to":{"type":"string","description":"yyyy-MM-dd"},"groupBy":{"type":"string","description":"project | day | customer"},"totalHours":{"type":"number"},"count":{"type":"integer"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PortalWorkSum"}}}},"HealthResponse":{"type":"object","properties":{"status":{"type":"string"},"time":{"type":"string","description":"ISO 8601"}}}}}}