openapi: 3.1.0 info: title: Productier API version: 0.1.0 description: Core API contract for Productier workspaces, planning, notes, and focus sessions. servers: - url: http://localhost:8080 paths: /v1/health: get: operationId: getHealth tags: [system] responses: "200": description: Health check content: application/json: schema: $ref: "#/components/schemas/HealthResponse" "503": description: Dependency health check failed content: application/json: schema: $ref: "#/components/schemas/HealthResponse" /v1/metrics: get: operationId: getMetrics tags: [system] responses: "200": description: Runtime request metrics snapshot content: application/json: schema: $ref: "#/components/schemas/MetricsResponse" "401": description: Metrics token missing or invalid content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/metrics/prometheus: get: operationId: getMetricsPrometheus tags: [system] responses: "200": description: Runtime request metrics in Prometheus text format content: text/plain: schema: type: string "401": description: Metrics token missing or invalid content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/workspaces: get: operationId: listWorkspaces tags: [workspaces] responses: "200": description: Workspace list content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/Workspace" /v1/members: get: operationId: listMembers tags: [workspaces] parameters: - name: workspaceSlug in: query required: true schema: type: string responses: "200": description: Workspace members content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/Member" /v1/members/{memberId}: patch: operationId: updateMember tags: [workspaces] parameters: - name: memberId in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateMemberInput" responses: "200": description: Updated member content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Member" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Member not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Business rule conflict content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/invites: get: operationId: listInvites tags: [workspaces] parameters: - name: workspaceSlug in: query required: true schema: type: string responses: "200": description: Workspace invites content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/Invite" post: operationId: createInvite tags: [workspaces] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateInviteInput" responses: "201": description: Created invite content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Invite" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/invites/{token}: get: operationId: getInviteByToken tags: [workspaces] parameters: - name: token in: path required: true schema: type: string responses: "200": description: Invite detail content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Invite" "404": description: Invite not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/invites/{token}/accept: post: operationId: acceptInvite tags: [workspaces] parameters: - name: token in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AcceptInviteInput" responses: "200": description: Accepted invite content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Invite" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Invite not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/invites/{inviteId}/revoke: post: operationId: revokeInvite tags: [workspaces] parameters: - name: inviteId in: path required: true schema: type: string responses: "204": description: Invite revoked "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Invite not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Invite state conflict content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/activity: get: operationId: listActivity tags: [workspaces] parameters: - name: workspaceSlug in: query required: true schema: type: string - name: limit in: query required: false description: Max entries to return (1-40, default 8) schema: type: integer minimum: 1 maximum: 40 - name: type in: query required: false description: Optional inferred activity category filter schema: type: string enum: [task, board, calendar, note, focus, mail, invite, system] - name: q in: query required: false description: Case-insensitive text search over title and detail schema: type: string responses: "200": description: Workspace activity feed content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/ActivityEntry" "400": description: Invalid activity query parameters content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/board-groups: get: operationId: listBoardGroups tags: [board] parameters: - name: workspaceSlug in: query required: true schema: type: string responses: "200": description: Board groups content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/BoardGroup" post: operationId: createBoardGroup tags: [board] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateBoardGroupInput" responses: "201": description: Created board group content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/BoardGroup" /v1/board-groups/{groupId}: patch: operationId: updateBoardGroup tags: [board] parameters: - name: groupId in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateBoardGroupInput" responses: "200": description: Updated board group content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/BoardGroup" /v1/labels: get: operationId: listLabels tags: [labels] parameters: - name: workspaceSlug in: query required: true schema: type: string responses: "200": description: Label list content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/Label" post: operationId: createLabel tags: [labels] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateLabelInput" responses: "201": description: Created label content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Label" /v1/tasks: get: operationId: listTasks tags: [tasks] parameters: - name: workspaceSlug in: query required: true schema: type: string responses: "200": description: Task list content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/Task" post: operationId: createTask tags: [tasks] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateTaskInput" responses: "201": description: Created task content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Task" /v1/calendar/events: get: operationId: listCalendarEvents tags: [calendar] parameters: - name: workspaceSlug in: query required: true schema: type: string responses: "200": description: Calendar events content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/CalendarEvent" post: operationId: createCalendarEvent tags: [calendar] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateCalendarEventInput" responses: "201": description: Created event content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/CalendarEvent" /v1/tasks/{taskId}: patch: operationId: updateTask tags: [tasks] parameters: - name: taskId in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateTaskInput" responses: "200": description: Updated task content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Task" /v1/tasks/{taskId}/attachments: post: operationId: uploadTaskAttachment tags: [tasks] parameters: - name: taskId in: path required: true schema: type: string requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary responses: "201": description: Uploaded task attachment content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Attachment" "400": description: Invalid upload content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Task not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Attachment storage or update failure content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/tasks/{taskId}/attachments/{attachmentId}: delete: operationId: deleteTaskAttachment tags: [tasks] parameters: - name: taskId in: path required: true schema: type: string - name: attachmentId in: path required: true schema: type: string responses: "204": description: Deleted attachment "404": description: Task or attachment not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Attachment delete failure content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/tasks/{taskId}/attachments/{attachmentId}/download: get: operationId: downloadTaskAttachment tags: [tasks] parameters: - name: taskId in: path required: true schema: type: string - name: attachmentId in: path required: true schema: type: string responses: "200": description: Attachment file stream content: application/octet-stream: schema: type: string format: binary "404": description: Task or attachment not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Attachment read failure content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/calendar/events/{eventId}: patch: operationId: updateCalendarEvent tags: [calendar] parameters: - name: eventId in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateCalendarEventInput" responses: "200": description: Updated event content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/CalendarEvent" /v1/notes: get: operationId: listNotes tags: [notes] parameters: - name: workspaceSlug in: query required: true schema: type: string responses: "200": description: Notes list content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/Note" post: operationId: createNote tags: [notes] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateNoteInput" responses: "201": description: Created note content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Note" /v1/notes/{noteId}: patch: operationId: updateNote tags: [notes] parameters: - name: noteId in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateNoteInput" responses: "200": description: Updated note content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Note" /v1/focus/sessions: get: operationId: listFocusSessions tags: [focus] parameters: - name: workspaceSlug in: query required: true schema: type: string responses: "200": description: Focus sessions content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/FocusSession" post: operationId: createFocusSession tags: [focus] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateFocusSessionInput" responses: "201": description: Created focus session content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/FocusSession" /v1/focus/sessions/{sessionId}: patch: operationId: updateFocusSession tags: [focus] parameters: - name: sessionId in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateFocusSessionInput" responses: "200": description: Updated focus session content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/FocusSession" /v1/mailboxes: get: operationId: listMailboxes tags: [mail] parameters: - name: workspaceSlug in: query required: true schema: type: string responses: "200": description: Connected mailboxes content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/Mailbox" post: operationId: connectMailbox tags: [mail] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ConnectMailboxInput" responses: "201": description: Connected mailbox content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Mailbox" "400": description: Invalid mailbox configuration content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/mailboxes/{mailboxId}/sync: post: operationId: syncMailbox tags: [mail] parameters: - name: mailboxId in: path required: true schema: type: string responses: "200": description: Synced mailbox content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Mailbox" "404": description: Mailbox not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "502": description: Mail provider sync failure content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/mail/messages: get: operationId: listMailMessages tags: [mail] parameters: - name: workspaceSlug in: query required: true schema: type: string - name: mailboxId in: query required: false schema: type: string responses: "200": description: Mail messages content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/MailMessage" /v1/mail/messages/{messageId}/create-task: post: operationId: createTaskFromMail tags: [mail] parameters: - name: messageId in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateTaskFromMailInput" responses: "201": description: Created task from mail content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/Task" "400": description: Invalid request content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Message not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Message already linked content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Link operation failure content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /v1/mail/outgoing: get: operationId: listOutgoingMails tags: [mail] parameters: - name: workspaceSlug in: query required: true schema: type: string - name: mailboxId in: query required: false schema: type: string responses: "200": description: Outgoing mail queue content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/OutgoingMail" post: operationId: createOutgoingMail tags: [mail] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateOutgoingMailInput" responses: "201": description: Queued outgoing mail content: application/json: schema: type: object required: [data] properties: data: $ref: "#/components/schemas/OutgoingMail" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Mailbox does not belong to workspace content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Mailbox not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "502": description: Queue delivery upstream failure content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" components: schemas: HealthResponse: type: object required: [ok, mode, timestamp, storage] properties: ok: type: boolean mode: type: string timestamp: type: string format: date-time storage: $ref: "#/components/schemas/HealthStorageStatus" HealthStorageStatus: type: object required: [provider, ok] properties: provider: type: string ok: type: boolean error: type: string MetricsResponse: type: object required: [generatedAt, uptimeSeconds, requestsTotal, statusClassTotals, routes] properties: generatedAt: type: string format: date-time uptimeSeconds: type: integer format: int64 requestsTotal: type: integer format: int64 statusClassTotals: type: object additionalProperties: type: integer format: int64 routes: type: array items: $ref: "#/components/schemas/MetricsRouteStat" MetricsRouteStat: type: object required: [method, path, status, count, avgLatencyMs, maxLatencyMs, lastSeenAt] properties: method: type: string path: type: string status: type: integer count: type: integer format: int64 avgLatencyMs: type: number format: double maxLatencyMs: type: number format: double lastSeenAt: type: string format: date-time ErrorResponse: type: object required: [error] properties: error: $ref: "#/components/schemas/ErrorDetail" ErrorDetail: type: object required: [code, message, requestId] properties: code: type: string message: type: string requestId: type: string BoardGroup: type: object required: [id, workspaceSlug, name, color, order] properties: id: type: string workspaceSlug: type: string name: type: string color: type: string order: type: integer Workspace: type: object required: - id - slug - name - role - createdAt properties: id: type: string slug: type: string name: type: string role: type: string enum: [owner, admin, member] createdAt: type: string format: date-time Member: type: object required: - id - workspaceSlug - name - email - role - status properties: id: type: string workspaceSlug: type: string name: type: string email: type: string role: type: string enum: [owner, admin, member] status: type: string enum: [active, invited, removed] Invite: type: object required: - id - workspaceSlug - email - role - token - createdAt - status properties: id: type: string workspaceSlug: type: string email: type: string format: email role: type: string enum: [owner, admin, member] token: type: string createdAt: type: string format: date-time status: type: string enum: [pending, accepted] ActivityEntry: type: object required: - id - workspaceSlug - title - detail - createdAt properties: id: type: string workspaceSlug: type: string title: type: string detail: type: string createdAt: type: string format: date-time Label: type: object required: [id, workspaceSlug, name, color] properties: id: type: string workspaceSlug: type: string name: type: string color: type: string Attachment: type: object required: [id, name, mimeType, size] properties: id: type: string name: type: string mimeType: type: string size: type: integer dataUrl: type: string TaskComment: type: object required: [id, taskId, author, content, createdAt] properties: id: type: string taskId: type: string author: type: string content: type: string createdAt: type: string format: date-time Task: type: object required: - id - workspaceSlug - boardGroupId - title - status - color - labelIds - attachments - comments - createdAt - updatedAt properties: id: type: string workspaceSlug: type: string boardGroupId: type: string title: type: string description: type: string status: type: string enum: [todo, in_progress, done] color: type: string dueAt: type: string format: date-time scheduledStart: type: string format: date-time scheduledEnd: type: string format: date-time assigneeId: type: string labelIds: type: array items: type: string attachments: type: array items: $ref: "#/components/schemas/Attachment" comments: type: array items: $ref: "#/components/schemas/TaskComment" createdAt: type: string format: date-time updatedAt: type: string format: date-time CreateTaskInput: type: object required: [workspaceSlug, boardGroupId, title] properties: workspaceSlug: type: string boardGroupId: type: string title: type: string description: type: string dueAt: type: string format: date-time color: type: string UpdateTaskInput: type: object properties: title: type: string description: type: string status: type: string enum: [todo, in_progress, done] boardGroupId: type: string color: type: string dueAt: type: string format: date-time scheduledStart: type: string format: date-time scheduledEnd: type: string format: date-time assigneeId: type: string labelIds: type: array items: type: string attachments: type: array items: $ref: "#/components/schemas/Attachment" comments: type: array items: $ref: "#/components/schemas/TaskComment" CalendarEvent: type: object required: - id - workspaceSlug - title - startsAt - endsAt - color - attachments properties: id: type: string workspaceSlug: type: string title: type: string description: type: string startsAt: type: string format: date-time endsAt: type: string format: date-time color: type: string linkedTaskId: type: string attachments: type: array items: $ref: "#/components/schemas/Attachment" CreateCalendarEventInput: type: object required: [workspaceSlug, title, startsAt, endsAt] properties: workspaceSlug: type: string title: type: string description: type: string startsAt: type: string format: date-time endsAt: type: string format: date-time linkedTaskId: type: string color: type: string attachments: type: array items: $ref: "#/components/schemas/Attachment" UpdateCalendarEventInput: type: object properties: title: type: string description: type: string startsAt: type: string format: date-time endsAt: type: string format: date-time linkedTaskId: type: string color: type: string attachments: type: array items: $ref: "#/components/schemas/Attachment" Note: type: object required: - id - workspaceSlug - title - content - updatedAt properties: id: type: string workspaceSlug: type: string title: type: string content: type: string updatedAt: type: string format: date-time CreateNoteInput: type: object required: [workspaceSlug, title, content] properties: workspaceSlug: type: string title: type: string content: type: string UpdateNoteInput: type: object properties: title: type: string content: type: string FocusSession: type: object required: - id - workspaceSlug - mode - startedAt - pausedTotalSeconds - durationSeconds properties: id: type: string workspaceSlug: type: string taskId: type: string mode: type: string enum: [focus, short_break, long_break] startedAt: type: string format: date-time completedAt: type: string format: date-time pausedAt: type: string format: date-time pausedTotalSeconds: type: integer durationSeconds: type: integer CreateFocusSessionInput: type: object required: [workspaceSlug, mode, durationSeconds] properties: workspaceSlug: type: string taskId: type: string mode: type: string enum: [focus, short_break, long_break] durationSeconds: type: integer UpdateFocusSessionInput: type: object properties: completedAt: type: string format: date-time pausedAt: type: string format: date-time pausedTotalSeconds: type: integer MailAddress: type: object required: [name, email] properties: name: type: string email: type: string format: email Mailbox: type: object required: - id - workspaceSlug - label - email - displayName - imapHost - imapPort - imapUsername - imapUseTls - smtpHost - smtpPort - smtpUsername - smtpUseTls - createdAt - updatedAt - syncStatus properties: id: type: string workspaceSlug: type: string label: type: string email: type: string format: email displayName: type: string imapHost: type: string imapPort: type: integer imapUsername: type: string imapUseTls: type: boolean smtpHost: type: string smtpPort: type: integer smtpUsername: type: string smtpUseTls: type: boolean createdAt: type: string format: date-time updatedAt: type: string format: date-time lastSyncedAt: type: string format: date-time syncStatus: type: string enum: [idle, syncing, ready, error] syncError: type: string MailMessage: type: object required: - id - workspaceSlug - mailboxId - remoteUid - messageId - folder - from - to - cc - subject - snippet - textBody - htmlBody - receivedAt - isRead - createdAt - updatedAt properties: id: type: string workspaceSlug: type: string mailboxId: type: string remoteUid: type: integer messageId: type: string folder: type: string from: $ref: "#/components/schemas/MailAddress" to: type: array items: $ref: "#/components/schemas/MailAddress" cc: type: array items: $ref: "#/components/schemas/MailAddress" subject: type: string snippet: type: string textBody: type: string htmlBody: type: string receivedAt: type: string format: date-time isRead: type: boolean linkedTaskId: type: string createdAt: type: string format: date-time updatedAt: type: string format: date-time OutgoingMail: type: object required: - id - workspaceSlug - mailboxId - to - cc - bcc - subject - textBody - htmlBody - status - createdAt - updatedAt properties: id: type: string workspaceSlug: type: string mailboxId: type: string to: type: array items: $ref: "#/components/schemas/MailAddress" cc: type: array items: $ref: "#/components/schemas/MailAddress" bcc: type: array items: $ref: "#/components/schemas/MailAddress" subject: type: string textBody: type: string htmlBody: type: string status: type: string enum: [queued, scheduled, sent, failed] scheduledFor: type: string format: date-time sentAt: type: string format: date-time error: type: string createdAt: type: string format: date-time updatedAt: type: string format: date-time ConnectMailboxInput: type: object required: - workspaceSlug - email - imapHost - imapPassword - smtpHost properties: workspaceSlug: type: string label: type: string email: type: string format: email displayName: type: string imapHost: type: string imapPort: type: integer imapUsername: type: string imapPassword: type: string imapUseTls: type: boolean smtpHost: type: string smtpPort: type: integer smtpUsername: type: string smtpPassword: type: string smtpUseTls: type: boolean CreateOutgoingMailInput: type: object required: [workspaceSlug, mailboxId, to] properties: workspaceSlug: type: string mailboxId: type: string to: type: array items: $ref: "#/components/schemas/MailAddress" cc: type: array items: $ref: "#/components/schemas/MailAddress" bcc: type: array items: $ref: "#/components/schemas/MailAddress" subject: type: string textBody: type: string htmlBody: type: string scheduledFor: type: string format: date-time CreateTaskFromMailInput: type: object required: [boardGroupId] properties: boardGroupId: type: string title: type: string dueAt: type: string format: date-time color: type: string CreateBoardGroupInput: type: object required: [workspaceSlug, name] properties: workspaceSlug: type: string name: type: string color: type: string UpdateBoardGroupInput: type: object properties: name: type: string color: type: string order: type: integer CreateLabelInput: type: object required: [workspaceSlug, name, color] properties: workspaceSlug: type: string name: type: string color: type: string CreateInviteInput: type: object required: [workspaceSlug, email, role] properties: workspaceSlug: type: string email: type: string format: email role: type: string enum: [owner, admin, member] AcceptInviteInput: type: object required: [name, email] properties: name: type: string email: type: string format: email UpdateMemberInput: type: object properties: role: type: string enum: [owner, admin, member] status: type: string enum: [active, removed]