{"openapi":"3.1.0","info":{"title":"NovumOS","description":"Block-based kanban where agents are first-class users.","version":"0.0.0"},"paths":{"/v1/auth/google/start":{"get":{"tags":["auth"],"summary":"Google Start","operationId":"google_start_v1_auth_google_start_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/auth/google/callback":{"get":{"tags":["auth"],"summary":"Google Callback","description":"Complete the Authorization-Code + PKCE flow Google bounced back to us.\n\nSpec §4.1.1. Every failure path is a ``302`` to the SPA login with an\n``?oauth_error=`` reason (never a JSON error body) so the user lands\nsomewhere usable. On success we mint the same session state as the\nemail/password path and bounce to ``{app_base_url}{return_to}``.\n\nCSRF is intentionally *not* enforced on this GET — the signed, single-use\n``state`` carried in the ``novumos_oauth`` flow cookie is the CSRF defense.","operationId":"google_callback_v1_auth_google_callback_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/auth/csrf":{"get":{"tags":["auth"],"summary":"Csrf Token","description":"Issue a CSRF token cookie (double-submit). Safe to call before login.","operationId":"csrf_token_v1_auth_csrf_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Csrf Token V1 Auth Csrf Get"}}}}},"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/auth/signup":{"post":{"tags":["auth"],"summary":"Signup","operationId":"signup_v1_auth_signup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/auth/verify-email":{"post":{"tags":["auth"],"summary":"Verify Email","operationId":"verify_email_v1_auth_verify_email_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/auth/login":{"post":{"tags":["auth"],"summary":"Login","operationId":"login_v1_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/auth/logout":{"post":{"tags":["auth"],"summary":"Logout","operationId":"logout_v1_auth_logout_post","responses":{"204":{"description":"Successful Response"}},"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/auth/password-reset/request":{"post":{"tags":["auth"],"summary":"Password Reset Request","operationId":"password_reset_request_v1_auth_password_reset_request_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordResetRequest"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/auth/password-reset/confirm":{"post":{"tags":["auth"],"summary":"Password Reset Confirm","operationId":"password_reset_confirm_v1_auth_password_reset_confirm_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordResetConfirmRequest"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/auth/resend-verification":{"post":{"tags":["auth"],"summary":"Resend Verification","operationId":"resend_verification_v1_auth_resend_verification_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResendVerificationRequest"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/me":{"get":{"tags":["me"],"summary":"Get Me","operationId":"get_me_v1_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/me/memberships":{"get":{"tags":["me"],"summary":"List My Memberships","operationId":"list_my_memberships_v1_me_memberships_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_MembershipResponse_"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/me/profile":{"get":{"tags":["me"],"summary":"Get My Profile","operationId":"get_my_profile_v1_me_profile_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponse"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]},"patch":{"tags":["me"],"summary":"Update My Profile","operationId":"update_my_profile_v1_me_profile_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/me/password":{"post":{"tags":["me"],"summary":"Change My Password","operationId":"change_my_password_v1_me_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/me/password/set":{"post":{"tags":["me"],"summary":"Set My Initial Password","operationId":"set_my_initial_password_v1_me_password_set_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPasswordRequest"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/me/sessions":{"get":{"tags":["me"],"summary":"List My Sessions","operationId":"list_my_sessions_v1_me_sessions_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_UserSessionResponse_"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]},"delete":{"tags":["me"],"summary":"Revoke All My Sessions","operationId":"revoke_all_my_sessions_v1_me_sessions_delete","responses":{"204":{"description":"Successful Response"}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/me/sessions/{session_id}":{"delete":{"tags":["me"],"summary":"Revoke My Session","operationId":"revoke_my_session_v1_me_sessions__session_id__delete","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/me/preferences":{"get":{"tags":["me"],"summary":"Get My Preferences","operationId":"get_my_preferences_v1_me_preferences_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPreferencesResponse"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]},"patch":{"tags":["me"],"summary":"Update My Preferences","operationId":"update_my_preferences_v1_me_preferences_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePreferencesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPreferencesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/me/surveys":{"get":{"tags":["me"],"summary":"Get My Survey Eligibility","description":"Which triggered surveys may interrupt this person right now (§25.9).\n\nLives under ``/v1/me`` rather than ``/v1/feedback`` because the answer is a\nfact about the *caller* — their frequency caps, their activity, their\nworkspace — and because the write half (``PATCH /v1/me/preferences``) is\nalready here. Keeping the read and the write on the same resource is what\nstops the cap from acquiring two homes.\n\nThe org half of the NPS decision is evaluated against the request's\nworkspace context, so this takes ``get_workspace_principal`` rather than\n``get_principal`` (§4.8): the active workspace is a property of the REQUEST,\nand one account may hold memberships in several. Its sibling\n``/me/preferences`` correctly does not — a preference is user-global —\nwhich is exactly the distinction that makes the choice worth stating.\nA principal with no workspace simply isn't NPS-eligible.\n\nNothing here reads another user's or another org's rows: the preferences\nblob comes off the caller's own ``User`` and the activity count is filtered\non both ``org_id`` and the caller's ``user_id``.","operationId":"get_my_survey_eligibility_v1_me_surveys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SurveyEligibilityResponse"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}]}},"/v1/me/invitations":{"get":{"tags":["invitations"],"summary":"List My Invitations","description":"Live invitations addressed to the signed-in account, across every workspace.\n\nThis is the in-app half of §4.8's \"if the address already has an account,\nthe invitation surfaces in-app on their next load *and* by email\" — the\nemail can be lost, filtered, or read on a phone, and the invitation still\nhas to be findable. Each row carries ``org_name`` because the caller does\nnot belong to the inviting workspace and has no other way to learn what they\nare being asked to join.\n\nOnly pending, unexpired invitations appear; the list never offers something\naccept would refuse.","operationId":"list_my_invitations_v1_me_invitations_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_InvitationResponse_"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/invitations/{invitation_id}:accept":{"post":{"tags":["invitations"],"summary":"Accept Invitation","description":"Accept an invitation — the moment the membership and the seat exist (§4.8).\n\nRequires being signed in as the invited address; anything else is ``404``,\nnever ``403``, so a guessed id tells a stranger nothing. Returns the\nmembership just created, which is what the client needs to switch into the\nnew workspace.\n\n``402 plan_limit_reached`` when accepting would breach the workspace's free\n-tier seat cap: pending invitations hold no seat, so the cap is only truly\ndecidable here, inside the per-org seat lock.","operationId":"accept_invitation_v1_invitations__invitation_id__accept_post","parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/invitations/{invitation_id}:decline":{"post":{"tags":["invitations"],"summary":"Decline Invitation","description":"Decline an invitation. Terminal, and it never touched a seat (§4.8).\n\nSame authorization as accept. Declining is deliberately a real, recorded\naction rather than an ignore: the workspace's admin sees the pending row\nclear, and the ``(org_id, lower(email))`` uniqueness slot frees up so they\ncan invite again later.","operationId":"decline_invitation_v1_invitations__invitation_id__decline_post","parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/notifications":{"get":{"tags":["notifications"],"summary":"Get Notifications","description":"List the caller's notifications, newest first (spec §22.2).","operationId":"get_notifications_v1_notifications_get","parameters":[{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Org Id"}},{"name":"unread","in":"query","required":false,"schema":{"type":"boolean","description":"Only return unread notifications.","default":false,"title":"Unread"},"description":"Only return unread notifications."},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Notifications V1 Notifications Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/notifications/count":{"get":{"tags":["notifications"],"summary":"Get Unread Count","description":"Unread notification count for the caller (spec §22.2).","operationId":"get_unread_count_v1_notifications_count_get","parameters":[{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnreadCountResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/notifications/{notification_id}:read":{"post":{"tags":["notifications"],"summary":"Mark Notification Read","description":"Mark one of the caller's notifications read. 404 if it isn't theirs.","operationId":"mark_notification_read_v1_notifications__notification_id__read_post","parameters":[{"name":"notification_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Notification Id"}},{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/notifications:readAll":{"post":{"tags":["notifications"],"summary":"Mark All Notifications Read","description":"Mark every unread notification for the caller read (spec §22.2).","operationId":"mark_all_notifications_read_v1_notifications_readAll_post","parameters":[{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Mark All Notifications Read V1 Notifications Readall Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/feedback":{"post":{"tags":["feedback"],"summary":"Submit Feedback","description":"Submit one feedback report (spec §25.4).\n\nThe share-link refusal, the workspace resolution and the hourly caps all run\nin ``require_submit_context`` — a dependency, so they run before the body is\nvalidated (see the module docstring). It hands back the resolved ``org_id``,\nwhich is what the row is stamped with.\n\n``surface`` is derived from HOW the caller authenticated, not claimed by\nthem: an integration token is the ``api`` surface, a browser session is\n``web``. (``mcp`` is set by the §25.11 tools.)","operationId":"submit_feedback_v1_feedback_post","parameters":[{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The workspace this call acts in. Browser sessions may name any org the user is a live member of; integration tokens stay pinned to their own.","title":"Org Id"},"description":"The workspace this call acts in. Browser sessions may name any org the user is a live member of; integration tokens stay pinned to their own."},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFeedbackRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"get":{"tags":["feedback"],"summary":"List Own Feedback","description":"List the caller's OWN submissions, newest first (spec §25.4).","operationId":"list_own_feedback_v1_feedback_get","parameters":[{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by feedback type.","title":"Type"},"description":"Filter by feedback type."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by triage status.","title":"Status"},"description":"Filter by triage status."},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The workspace this call acts in. Browser sessions may name any org the user is a live member of; integration tokens stay pinned to their own.","title":"Org Id"},"description":"The workspace this call acts in. Browser sessions may name any org the user is a live member of; integration tokens stay pinned to their own."},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Own Feedback V1 Feedback Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/feedback/screenshots:presign":{"post":{"tags":["feedback"],"summary":"Presign Feedback Screenshot","description":"Mint a presigned POST for a feedback screenshot (spec §25.4).\n\nBody: ``{filename, content_type, size_bytes?}``. Returns the standard file\nenvelope plus ``upload_url`` + ``upload_url_fields`` + ``upload_url_method``\n(POST — the multipart form is what carries the ``content-length-range``\npolicy). The client posts the bytes straight to S3, calls\n``POST /v1/feedback/screenshots/{id}:commit`` below to flip the row to\n``available``, and then passes the id as ``screenshot_file_id`` on\n``POST /v1/feedback``.\n\nOrdering is ``submit_feedback``'s, because it is the same dependency: the\nshare-link refusal, the workspace resolution and the hourly cap all run in\n``require_screenshot_presign_context`` — before the body is validated, which\nis what makes the cap count malformed requests too.\n\nThe ``org_id`` the row is stamped with is the one the dependency RESOLVED,\nnot ``principal.org_id``. ``?org_id=`` hints are honored here as everywhere\non this router, so the principal's org is the cookie's possibly-stale active\nworkspace; stamping from it would file the object under one org while the\nrequest ran scoped to another.","operationId":"presign_feedback_screenshot_v1_feedback_screenshots_presign_post","parameters":[{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The workspace this call acts in. Browser sessions may name any org the user is a live member of; integration tokens stay pinned to their own.","title":"Org Id"},"description":"The workspace this call acts in. Browser sessions may name any org the user is a live member of; integration tokens stay pinned to their own."},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFeedbackScreenshotUploadRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Presign Feedback Screenshot V1 Feedback Screenshots Presign Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/feedback/screenshots/{file_id}:commit":{"post":{"tags":["feedback"],"summary":"Commit Feedback Screenshot","description":"Finalize a feedback screenshot upload (spec §25.4, NOV-442 review F1).\n\nThe screenshot's own commit rather than the shared ``POST\n/v1/files/{id}:commit``, because the two legs of one chain have to agree\nabout which workspace they are in. The presign resolves ``?org_id=`` and\nstamps the row with the SELECTED workspace; the shared route resolves its\norg from ``principal.org_id``, which for a browser session is the cookie's\npossibly-stale active org. For a multi-workspace user those differ, and the\nchain died at this step — presign 201 in B, commit 404 in A, the row left\n``pending`` forever with its object orphaned in S3. Mounting the commit on\n``/v1/feedback/*`` puts it behind the same resolution as its siblings, so\nthe disagreement cannot arise.\n\nThe alternative — teaching the shared route to take the hint — was\ndeliberately not taken: it would extend ``?org_id=`` workspace selection\nover the entire file surface to fix one route. This one accepts the hint\nonly for rows the feedback presign minted (anything else is a 404, in\n:func:`app.services.files.commit_feedback_screenshot_for_principal`).\n\nRate limit: its own ``feedback_upload_commit`` per-user window — see\n``require_screenshot_commit_context`` for why it is a third key rather than\na second charge against the presign's.\n\nPast_due: this path is the §25.4 carve-out from the §18.8 write-block, and\nsince NOV-442's review it is the ONLY commit path that carries one. The\nshared route went back to being blocked for every producer, screenshots\nincluded — a read-only workspace finishes its screenshot here.","operationId":"commit_feedback_screenshot_v1_feedback_screenshots__file_id__commit_post","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The workspace this call acts in. Browser sessions may name any org the user is a live member of; integration tokens stay pinned to their own.","title":"Org Id"},"description":"The workspace this call acts in. Browser sessions may name any org the user is a live member of; integration tokens stay pinned to their own."},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Commit Feedback Screenshot V1 Feedback Screenshots  File Id  Commit Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/feedback/{feedback_id}":{"get":{"tags":["feedback"],"summary":"Get Own Feedback","description":"One of the caller's own submissions. Someone else's → 404, never 403.","operationId":"get_own_feedback_v1_feedback__feedback_id__get","parameters":[{"name":"feedback_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feedback Id"}},{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The workspace this call acts in. Browser sessions may name any org the user is a live member of; integration tokens stay pinned to their own.","title":"Org Id"},"description":"The workspace this call acts in. Browser sessions may name any org the user is a live member of; integration tokens stay pinned to their own."},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/email-outbox/{outbox_id}:requeue":{"post":{"tags":["email-outbox"],"summary":"Requeue Email Outbox Endpoint","description":"Re-drive one failed row. Owner/admin only; repeated requests are safe.","operationId":"requeue_email_outbox_endpoint_v1_orgs__org_id__email_outbox__outbox_id__requeue_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"outbox_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Outbox Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailOutboxRequeueResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs":{"get":{"tags":["orgs"],"summary":"List Orgs","operationId":"list_orgs_v1_orgs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_OrganizationResponse_"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]},"post":{"tags":["orgs"],"summary":"Create Org","operationId":"create_org_v1_orgs_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrganizationRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/orgs/{org_id}":{"get":{"tags":["orgs"],"summary":"Get Org","operationId":"get_org_v1_orgs__org_id__get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"patch":{"tags":["orgs"],"summary":"Update Org","operationId":"update_org_v1_orgs__org_id__patch","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}:switch":{"post":{"tags":["orgs"],"summary":"Switch Org","description":"Set ``org_id`` as the caller's active org and re-issue the session cookie.\n\nNOV-119: the org switcher was purely client-side (localStorage + the\n``/v1/orgs/{org_id}`` URL path hint). That left the session cookie's\n``org_id`` claim stale, so requests to routes with no org_id in the path\nresolved to the *old* (or no) org. This server-side switch re-stamps the\ncookie with the selected org so the active-org choice is durable across the\nwhole API surface, not just org-scoped paths.\n\nNOV-527 (§4.8): the switch now also persists ``user_sessions.active_org_id``,\nso the choice survives a reload instead of depending on a cookie the client\ncannot read. The distinction that matters: this endpoint sets the DEFAULT\nworkspace for the next fresh page load; the ``X-Novum-Org`` header is what\nmakes an individual request act elsewhere. A tab that switches workspaces\nmust not silently retarget every OTHER tab's writes, which is exactly what\nre-stamping a process-global cookie would do on its own.\n\n``require_org_access`` gates on real membership in ``org_id`` (404 for\nnon-members, never leaking org existence), so a caller can only switch into\nan org they actually belong to. The re-issued cookie carries that org's\nreal role. No-op cookie-wise for integration tokens (single-org by\ndefinition) — they get the org body back without a cookie.","operationId":"switch_org_v1_orgs__org_id__switch_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/members":{"get":{"tags":["orgs"],"summary":"List Members","operationId":"list_members_v1_orgs__org_id__members_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_MembershipResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["orgs"],"summary":"Add Member","operationId":"add_member_v1_orgs__org_id__members_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddMemberRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/members/{user_id}:resend-invite":{"post":{"tags":["orgs"],"summary":"Resend Member Invite","description":"Resend the verification / invite email for an org member.\n\nAdmin/owner-only. The endpoint inspects the target user's state and\npicks the right email template:\n  - email_verified=False → mint a fresh verification token and send\n    the `send_invite_new_user` template (the user finishes verifying\n    + setting up their account from the link).\n  - email_verified=True (already verified, just hasn't logged in\n    yet) → send `send_invite_existing_user` so they get a nudge with\n    a link back to the workspace.\n\nRate limit: once per minute per (org, target user). Returns 429 with\na clear retry message past that ceiling. Distinct from the\nuser-self path at `/v1/auth/resend-verification` (NOV-83 ticket).","operationId":"resend_member_invite_v1_orgs__org_id__members__user_id__resend_invite_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/members/{user_id}":{"patch":{"tags":["orgs"],"summary":"Update Member Role","operationId":"update_member_role_v1_orgs__org_id__members__user_id__patch","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMembershipRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["orgs"],"summary":"Remove Member","operationId":"remove_member_v1_orgs__org_id__members__user_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/members/me":{"delete":{"tags":["orgs"],"summary":"Leave Org","description":"Leave this workspace (§4.8 invariant 6, \"leaving is self-service\").\n\nThe counterpart to ``DELETE /{org_id}/members/{user_id}``: that one is an\nadmin removing somebody else and is owner/admin-only, which is precisely why\na member invited into a client's workspace previously had no way out. This\none takes no role — every member may leave — but the sole remaining owner\ngets a ``409`` and has to transfer ownership first, because §4.4's \"there is\nalways ≥1 owner\" must hold through every path.\n\nDeclared BEFORE the ``/{user_id}`` route: ``me`` is not a UUID, so without\nthis ordering FastAPI would try the parameterized route first and reject the\nliteral at path-parsing time.","operationId":"leave_org_v1_orgs__org_id__members_me_delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/invitations":{"post":{"tags":["orgs"],"summary":"Create Invitation","description":"Invite an email address into this workspace. Owner/admin only.\n\nThe consented replacement for ``POST /{org_id}/members`` on the human path\n(§4.8 invariant 5): this writes a *pending invitation*, not a membership, so\nnobody's account acquires a second employer without their say-so. No seat is\nconsumed here — that happens at accept.\n\nStatus codes carry the outcome: **201** for a new invitation, **200** for a\nresend of a live one (the token is rotated, so the previous link dies) and\nfor the \"they're already a member\" no-op, which per §4.8 is a no-op rather\nthan a duplicate row or an error.\n\nThe response is identical whether or not the address has a NovumOS account —\ninviting somebody must not become a way to test which addresses are\nregistered.","operationId":"create_invitation_v1_orgs__org_id__invitations_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInvitationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/InvitationResponse"},{"$ref":"#/components/schemas/AlreadyMemberResponse"}],"title":"Response Create Invitation V1 Orgs  Org Id  Invitations Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"get":{"tags":["orgs"],"summary":"List Invitations","description":"List this workspace's invitations. Owner/admin only.\n\nDefaults to the pending slice — the actionable one. ``?status=`` selects one\nother state, and ``?status=all`` returns the full history (terminal rows are\nkept forever). Admin-only because the list is a directory of addresses the\nworkspace has approached.","operationId":"list_invitations_v1_orgs__org_id__invitations_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"default":"pending","title":"Status"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_InvitationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/invitations/{invitation_id}":{"delete":{"tags":["orgs"],"summary":"Revoke Invitation","description":"Withdraw a pending invitation. Owner/admin only.\n\nTerminal and seatless — a revoked invitation never created a membership, so\nit never held a seat to release. The emailed token stops resolving the\nmoment the row leaves ``pending``.","operationId":"revoke_invitation_v1_orgs__org_id__invitations__invitation_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/integrations":{"get":{"tags":["orgs"],"summary":"List Integrations","operationId":"list_integrations_v1_orgs__org_id__integrations_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_IntegrationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["orgs"],"summary":"Create Integration","operationId":"create_integration_v1_orgs__org_id__integrations_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/integrations/{integration_id}":{"delete":{"tags":["orgs"],"summary":"Revoke Integration","description":"Revoke (hard-delete) an integration token (NOV-190 / spec §4.5).\n\nWorks for BOTH agent tokens (``user_id`` set) and raw tokens\n(``user_id IS NULL``). Org-scoped — an integration in another org 404s, so\nthere is no cross-tenant revoke. Revoking an agent's last token leaves the\nagent User / Membership / seat intact; killing the agent itself is a member\ndelete, not a token revoke.\n\nHARD delete, deliberately: ``AuditMixin`` carries ``in_trash`` / ``archived``\nflags, but the token-auth lookup (``_principal_from_integration_token``)\ndoes NOT filter on them — a soft-deleted row would still authenticate. Hard\ndelete is the only way to actually disable the credential. No seat\nrecompute: a token is not a seat (spec §18.1).","operationId":"revoke_integration_v1_orgs__org_id__integrations__integration_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Integration Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/agents":{"post":{"tags":["orgs"],"summary":"Connect Agent","description":"Atomically connect an agent: User(kind='agent') + Membership + Integration.\n\nThe agent appears in assignee pickers and shows up with the\nsparkle badge on its avatar disc (NOV-92). The integration's\nbearer token is shown once in the response — the admin pastes it\ninto the agent runtime; we never serve it again.","operationId":"connect_agent_v1_orgs__org_id__agents_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectAgentRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectAgentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/agents/{agent_user_id}/tokens":{"post":{"tags":["orgs"],"summary":"Add Agent Token","description":"Mint an ADDITIONAL credential for an existing agent (NOV-190 / spec §4.2, §4.5).\n\nTokens are children of an agent: an agent can own several (rotation, a\nmulti-Lambda fleet). The new ``Integration`` carries ``user_id=agent_user_id``\nso bearer-auth resolves to the same agent identity as its first token. The\nplaintext token is shown once.\n\nNO seat recompute: adding a token to an existing agent does not change the\nbillable count — the agent already counts as its (possibly free) seat; a\ntoken is a credential, not a member (spec §18.1). So this path skips the\nseat lock / recompute / Stripe sync that ``connect_agent`` runs.\n\nThe target must be a ``User(kind='agent')`` with a Membership in THIS org,\nor we 404 (no existence leak across tenants).","operationId":"add_agent_token_v1_orgs__org_id__agents__agent_user_id__tokens_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"agent_user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddAgentTokenRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/agents/{agent_user_id}:pause":{"post":{"tags":["orgs"],"summary":"Pause Agent","description":"Kill switch — pause an agent instantly (NOV-264 / spec §4.7).\n\nThin caller over :func:`app.services.agent_admin.pause_agent_for_principal`\n(shared with the ``pause_agent`` MCP tool). Available on ALL plans — safety\nis never paywalled. Owner/admin only.","operationId":"pause_agent_v1_orgs__org_id__agents__agent_user_id__pause_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"agent_user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/PauseAgentRequest"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentKillSwitchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/agents/{agent_user_id}:resume":{"post":{"tags":["orgs"],"summary":"Resume Agent","description":"Reverse a pause — re-admit the agent (NOV-264 / spec §4.7).\n\nThin caller over :func:`app.services.agent_admin.resume_agent_for_principal`\n(shared with the ``resume_agent`` MCP tool). Owner/admin only.","operationId":"resume_agent_v1_orgs__org_id__agents__agent_user_id__resume_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"agent_user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentKillSwitchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/agents/{agent_user_id}:revoke_tokens":{"post":{"tags":["orgs"],"summary":"Revoke Agent Tokens","description":"Hard kill — irreversibly delete ALL of an agent's tokens (NOV-264 / spec §4.7).\n\nUnlike :pause (reversible), this removes credentials outright: every\n``Integration`` the agent owns in this org is hard-deleted (same rationale as\n``revoke_integration`` — a soft-deleted row would still authenticate). It\ndoes NOT set paused/disabled and does NOT recompute seats (a token is not a\nseat, spec §18.1). Owner/admin only.","operationId":"revoke_agent_tokens_v1_orgs__org_id__agents__agent_user_id__revoke_tokens_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"agent_user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeAgentTokensResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/agents/{agent_user_id}/budget":{"get":{"tags":["orgs"],"summary":"Get Agent Budget","description":"Read an agent's budget caps + read-only kill-switch state + live usage.\n\nThin caller over :func:`app.services.agent_admin.get_agent_budget_for_principal`\n(shared with the ``get_agent_budget`` MCP tool). GATED to Scale/Agency\n(entitlement checked before the owner/admin role check); owner/admin only;\nthe target must be a ``kind='agent'`` member of this org. ``board_id`` absent\n= the org-wide budget (unchanged); present = the per-board override (NOV-271).","operationId":"get_agent_budget_v1_orgs__org_id__agents__agent_user_id__budget_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"agent_user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent User Id"}},{"name":"board_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentBudgetResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"put":{"tags":["orgs"],"summary":"Set Agent Budget","description":"Set an agent's caps (PUT-replace; ``null`` clears a cap).\n\nThin caller over :func:`app.services.agent_admin.set_agent_budget_for_principal`\n(shared with the ``set_agent_budget`` MCP tool). GATED to Scale/Agency;\nowner/admin only; agent-target only. Writes an ``agent.budget_updated`` audit\nrow. Validation (``null`` or ``>=0``) is enforced by the request schema.\n``board_id`` absent = the org-wide budget (unchanged); present = the per-board\noverride (NOV-271; enforces writes/day only, per-board req/s deferred).","operationId":"set_agent_budget_v1_orgs__org_id__agents__agent_user_id__budget_put","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"agent_user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent User Id"}},{"name":"board_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentBudgetUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentBudgetResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/agents/activity":{"get":{"tags":["orgs"],"summary":"Get Org Agents Activity","description":"All-agents org (or per-client-board) activity rollup (NOV-266 / spec §4.7 ledger).\n\nThin caller over :func:`app.services.agent_admin.get_agent_activity_for_principal`\nwith ``agent_user_id=None`` (the all-agents rollup — no agent-target guard).\nShared with the ``get_agent_activity`` MCP tool. GATED to Scale/Agency;\nowner/admin only.","operationId":"get_org_agents_activity_v1_orgs__org_id__agents_activity_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"24h","title":"Window"}},{"name":"board_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Limit"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentActivityResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/agents/{agent_user_id}/activity":{"get":{"tags":["orgs"],"summary":"Get Agent Activity","description":"Per-agent buyer-facing activity ledger — summary + reverse-chron feed (spec §4.7).\n\nThin caller over :func:`app.services.agent_admin.get_agent_activity_for_principal`\n(shared with the ``get_agent_activity`` MCP tool). GATED to Scale/Agency;\nowner/admin only; the target must resolve to a ``kind='agent'`` member of this\norg. ``window`` is ``24h`` or ``7d`` (400 otherwise); ``board_id`` scopes to\none client board.","operationId":"get_agent_activity_v1_orgs__org_id__agents__agent_user_id__activity_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"agent_user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent User Id"}},{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"24h","title":"Window"}},{"name":"board_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Limit"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentActivityResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/presence/agents":{"get":{"tags":["orgs"],"summary":"List Live Agents","description":"Snapshot of agent Users with a live WS connection in ``org_id``.\n\nThe frontend's live-agents badge hits this on mount to hydrate before\nits WS opens (and starts streaming ``presence.agent.connected`` /\n``.disconnected`` events). Membership in ``org_id`` is the gate for the\nbaseline roles — every member sees the same snapshot.\n\nNOV-531 (§4.4): agents are Users (§4.5), so a presence roster IS a member\nroster. It is narrowed by the same directory rule as\n``GET /v1/orgs/{id}/members`` — a guest sees only the agents they share a\nreachable board with, never the org's whole agent fleet.","operationId":"list_live_agents_v1_orgs__org_id__presence_agents_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AgentPresence_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/domains":{"get":{"tags":["orgs"],"summary":"List Domains","operationId":"list_domains_v1_orgs__org_id__domains_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_DomainClaimResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["orgs"],"summary":"Claim Domain","operationId":"claim_domain_v1_orgs__org_id__domains_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainClaimRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainClaimResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/domains/{domain}:verify":{"post":{"tags":["orgs"],"summary":"Verify Domain","description":"Check the org's DNS TXT record and stamp verification on success (§4.3.1).\n\nOwner/admin only. Looks up `_novumos-verify.<domain>` and compares each TXT\nvalue against the claim's verification_code (exact, case-sensitive). On a\nmatch: stamp verified_at, write a `domain.verified` audit event. On any miss\nor DNS failure: leave the claim unverified and return it (never 5xx).\n`google_workspace` claims use the same DNS-TXT check in v1.","operationId":"verify_domain_v1_orgs__org_id__domains__domain__verify_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainClaimResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/domains/{domain}":{"delete":{"tags":["orgs"],"summary":"Release Domain","description":"Release this org's claim on `domain` (NOV-603, §4.3.1).\n\nOwner/admin only, and scoped to `(org_id, domain)` — a member of org A can\nnever delete org B's claim; a claim that isn't this org's is a `404`, not a\n`403`, so the endpoint doesn't confirm the row exists elsewhere.\n\nReleasing a VERIFIED claim does **not** remove members who already\nauto-joined: they are members of the org on their own account now, and\nsilently ejecting people because an admin tidied up a DNS record would be a\nfar bigger surprise than leaving them. It only stops FUTURE auto-joins, and\nfrees the domain for another org to verify.","operationId":"release_domain_v1_orgs__org_id__domains__domain__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/billing":{"get":{"tags":["billing"],"summary":"Get Billing","description":"Return the org's billing status object (spec §18.9).\n\nOwner-only. ``billable_seats`` and the humans/agents ``seat_breakdown`` are\nrecomputed **live** via :func:`seat_breakdown` — never the stale\n``billing_seats`` cache; the total derives from the breakdown's counts so\nthey agree by construction (the first-agent-free math is server-side). On\na free org, ``current_period_end``/``cancel_at_period_end`` are null and\n``has_payment_method`` is always false (spec §18.9 invariant), even if the\norg retains a ``stripe_customer_id`` from a prior Pro subscription (§18.7\nonly clears the subscription id on cancel). On Pro, ``has_payment_method``\nis derived offline from the Stripe customer id; no live Stripe call is made.","operationId":"get_billing_v1_orgs__org_id__billing_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/billing:checkout":{"post":{"tags":["billing"],"summary":"Checkout","description":"Start a Stripe Checkout to upgrade the org to Pro (spec §18.6 / §18.5).\n\nOwner-only (``admin`` is not sufficient — §18.1). Accepts an optional\n``{\"interval\": \"annual\"|\"monthly\"}`` body (NOV-242) selecting the billing\ncadence; an omitted body defaults to ``annual`` (the promoted option, §18.1).\nReturns a ``{\"checkout_url\": …}`` the owner is redirected to. Errors:\n\n* ``409`` if the org is already Pro (nothing to check out).\n* ``503 billing_unconfigured`` if Stripe isn't configured (dev has no keys),\n  surfaced by :func:`~app.core.stripe_client.get_stripe`.\n\nThe plan flip to Pro is **webhook-driven** (``checkout.session.completed`` →\n§18.7), never set here. The router stays thin; the Customer-create /\nsession-create logic lives in :func:`create_checkout_session`.","operationId":"checkout_v1_orgs__org_id__billing_checkout_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CheckoutRequest"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/billing:portal":{"post":{"tags":["billing"],"summary":"Portal","description":"Open a Stripe Customer Portal session for the org (spec §18.6).\n\nOwner-only (``admin`` is not sufficient — §18.1). Returns a\n``{\"portal_url\": …}`` the owner is redirected to. Errors:\n\n* ``409 no_subscription`` if the org has no ``stripe_customer_id`` (must\n  complete Checkout first to create the Stripe Customer).\n* ``503 billing_unconfigured`` if Stripe isn't configured (dev has no keys),\n  surfaced by :func:`~app.core.stripe_client.get_stripe`.\n\nThe router stays thin; the portal session logic lives in\n:func:`create_portal_session`.","operationId":"portal_v1_orgs__org_id__billing_portal_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/automations":{"get":{"tags":["automations"],"summary":"List Automations Endpoint","description":"List the org's automations, newest first (keyset pagination). Admin/owner-only.","operationId":"list_automations_endpoint_v1_orgs__org_id__automations_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AutomationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["automations"],"summary":"Create Automation Endpoint","description":"Create an automation rule (§20.8). Admin/owner-only.\n\nThe body's ``trigger`` / ``actions`` are validated (event_type ∈\nKNOWN_EVENT_TYPES; non-empty actions with known ``type``) — the schema rejects\na malformed body with 422 before the service, which re-validates for parity\nwith the MCP path. A ``notify`` action's ``params`` may set ``recipient``\n(``owner`` default | ``assignees``) and ``channels`` (any of ``comment``\ndefault | ``in_app`` | ``email``); unknown values are rejected at write time\n(422). Omitting both keys preserves the historical comment-to-owner behavior.","operationId":"create_automation_endpoint_v1_orgs__org_id__automations_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAutomationRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/automations/{automation_id}":{"get":{"tags":["automations"],"summary":"Get Automation Endpoint","description":"Fetch one automation. Admin/owner-only. Cross-org → ``404`` (no leak).","operationId":"get_automation_endpoint_v1_orgs__org_id__automations__automation_id__get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"automation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Automation Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"patch":{"tags":["automations"],"summary":"Update Automation Endpoint","description":"Update / toggle an automation (§20.8). Admin/owner-only.\n\nOnly the fields the client sent are changed (``model_dump(exclude_unset=True)``\nforwards an explicit ``null`` but not an absent key). ``is_active`` supports the\nenable/disable toggle.","operationId":"update_automation_endpoint_v1_orgs__org_id__automations__automation_id__patch","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"automation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Automation Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutomationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["automations"],"summary":"Delete Automation Endpoint","description":"Delete an automation (§20.8). Admin/owner-only. Cross-org → ``404``.","operationId":"delete_automation_endpoint_v1_orgs__org_id__automations__automation_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"automation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Automation Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/automations/{automation_id}/runs":{"get":{"tags":["automations"],"summary":"List Automation Runs Endpoint","description":"List one automation's run ledger, newest first (§20.8). Admin/owner-only.","operationId":"list_automation_runs_endpoint_v1_orgs__org_id__automations__automation_id__runs_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"automation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Automation Id"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AutomationRunResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/automations/{automation_id}/runs/{run_id}:replay":{"post":{"tags":["automations"],"summary":"Replay Automation Run Endpoint","description":"Re-arm a terminal-failed run (§20.6.2). Admin/owner-only.\n\nResets the run to ``pending`` + ``next_retry_at=now()`` in place (dedup_key\npreserved, NO new row); a non-terminal-failed run → ``409``; a run under\nanother automation/org → ``404``. The executor (NOV-281) drains the reset run.","operationId":"replay_automation_run_endpoint_v1_orgs__org_id__automations__automation_id__runs__run_id__replay_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"automation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Automation Id"}},{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationRunResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/playbooks":{"get":{"tags":["playbooks"],"summary":"List Playbooks Endpoint","description":"List the org's Playbooks, newest first (keyset pagination). Admin/owner-only.","operationId":"list_playbooks_endpoint_v1_orgs__org_id__playbooks_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_PlaybookResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["playbooks"],"summary":"Create Playbook Endpoint","description":"Create a Playbook (§23.4). Admin/owner-only.\n\nThe body's ``steps`` (non-empty, each with a ``prompt_md``) and ``output_target``\n(``append_body`` | ``replace_body``) are validated — the schema rejects a\nmalformed body with 422 before the service, which re-validates for parity with\nthe MCP path. ``on_success_move_to`` is the column a card advances to on success.","operationId":"create_playbook_endpoint_v1_orgs__org_id__playbooks_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlaybookRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaybookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/playbooks/{playbook_id}":{"get":{"tags":["playbooks"],"summary":"Get Playbook Endpoint","description":"Fetch one Playbook. Admin/owner-only. Cross-org → ``404`` (no leak).","operationId":"get_playbook_endpoint_v1_orgs__org_id__playbooks__playbook_id__get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"playbook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Playbook Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaybookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"patch":{"tags":["playbooks"],"summary":"Update Playbook Endpoint","description":"Update a Playbook (§23.4). Admin/owner-only.\n\nOnly the fields the client sent are changed (``model_dump(exclude_unset=True)``\nforwards an explicit ``null`` but not an absent key). ``steps`` / ``output_target``\nare re-validated.","operationId":"update_playbook_endpoint_v1_orgs__org_id__playbooks__playbook_id__patch","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"playbook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Playbook Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePlaybookRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaybookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["playbooks"],"summary":"Delete Playbook Endpoint","description":"Delete a Playbook (§23.4). Admin/owner-only. Cross-org → ``404``.","operationId":"delete_playbook_endpoint_v1_orgs__org_id__playbooks__playbook_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"playbook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Playbook Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/ai-run-usage":{"get":{"tags":["autopilot"],"summary":"List Ai Run Usage Endpoint","description":"List the org's Autopilot run history, newest first (§23.6). Admin/owner-gated.\n\nOptional ``board_id`` / ``column_id`` / ``playbook_id`` narrow the feed to a\nsingle board, Autopilot column, or Playbook.","operationId":"list_ai_run_usage_endpoint_v1_orgs__org_id__ai_run_usage_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"board_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"}},{"name":"column_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"}},{"name":"playbook_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Playbook Id"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AiRunUsageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/import-jobs":{"post":{"tags":["import-jobs"],"summary":"Create Import Job Endpoint","description":"Create + start an import (spec §21.9). Admin/owner-only.\n\n``notion_api`` (default): body carries the transient Notion ``token`` (§21.10 —\nbody only, never a query string) plus ``database_id`` / ``whole_workspace`` and\noptional ``column_property``; the token is registered in the process-local store\nso the worker can claim it. ``export_file`` (NOV-297): body carries ``file_id``\nof a committed upload (from ``:upload`` → ``:commit``; usable as soon as the\nfile is ``status=available``) plus optional ``column_property``. Returns the\njob WITHOUT any token.","operationId":"create_import_job_endpoint_v1_orgs__org_id__import_jobs_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateImportJobRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"get":{"tags":["import-jobs"],"summary":"List Import Jobs Endpoint","description":"List the org's import jobs, newest first (keyset pagination). Admin/owner-only.","operationId":"list_import_jobs_endpoint_v1_orgs__org_id__import_jobs_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ImportJobResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/import-jobs:upload":{"post":{"tags":["import-jobs"],"summary":"Create Import Upload Endpoint","description":"Mint a presigned POST for a Notion export ``.zip`` (NOV-297). Admin/owner-only.\n\nReturns the standard file envelope (``upload_url`` + form fields). Flow:\n``:upload`` → PUT bytes to S3 → ``POST /v1/files/{id}:commit`` → ``POST\n.../import-jobs`` with ``source=export_file`` + this ``file_id`` (the file is\nusable as soon as ``:commit`` returns ``status=available``). Only\n``application/zip`` is accepted (415 otherwise).","operationId":"create_import_upload_endpoint_v1_orgs__org_id__import_jobs_upload_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateImportUploadRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Import Upload Endpoint V1 Orgs  Org Id  Import Jobs Upload Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/import-jobs/{job_id}":{"get":{"tags":["import-jobs"],"summary":"Get Import Job Endpoint","description":"Return one import job's status/counts/error_log/board_id (the wizard polls this).\n\nAdmin/owner-only. A job in another org is a ``404`` (org-scoping, no leak).","operationId":"get_import_job_endpoint_v1_orgs__org_id__import_jobs__job_id__get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/import-jobs/{job_id}:cancel":{"post":{"tags":["import-jobs"],"summary":"Cancel Import Job Endpoint","description":"Cancel a queued/running import (spec §21.9). Admin/owner-only.\n\nTerminal job → ``409 conflict``. A queued/running job is landed in ``failed``\n(no ``cancelled`` status) and its transient token dropped so an unclaimed job\nnever runs. Cancelling an already-running job is best-effort — the runner does\nnot poll for cancellation.","operationId":"cancel_import_job_endpoint_v1_orgs__org_id__import_jobs__job_id__cancel_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/orgs/{org_id}/import-jobs:databases":{"post":{"tags":["import-jobs"],"summary":"List Databases Endpoint","description":"List the Notion databases the token can see, to pick from (spec §21.9/§21.10).\n\nAdmin/owner-only. The transient token is carried in the request body (never a\nURL/query string — proxies log those) and is used once to build the Notion\nsource, then dropped; nothing is persisted. Returns ``[{id, title}]``.","operationId":"list_databases_endpoint_v1_orgs__org_id__import_jobs_databases_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDatabasesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDatabasesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards":{"get":{"tags":["boards"],"summary":"List Boards","operationId":"list_boards_v1_boards_get","parameters":[{"name":"archived","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Archived"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_BoardResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["boards"],"summary":"Create Board","operationId":"create_board_v1_boards_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBoardRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}]}},"/v1/boards/{board_id}":{"get":{"tags":["boards"],"summary":"Get Board","operationId":"get_board_v1_boards__board_id__get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","description":"NOV-459 (§7.1): also return ARCHIVED property definitions in the ``properties`` map, each tagged ``\"archived\": true``. Archived definitions are hidden by default — the map is the board's live schema. Deleting a ``unique_id`` property archives rather than removes it, preserving its id, prefix and numbering; re-adding the same name reinstates it. Use this to discover what is archived, then reinstate it (PATCH with a body under that name) or delete it permanently (POST /v1/boards/{board_id}/properties:purge). Handing this response's ``properties`` map straight back to PATCH is safe: an entry echoed with ``\"archived\": true`` stays archived, so a read-modify-write that edits one property does not reinstate the rest. Reinstating is therefore always explicit — send a body under the archived name WITHOUT the flag.","default":false,"title":"Include Archived"},"description":"NOV-459 (§7.1): also return ARCHIVED property definitions in the ``properties`` map, each tagged ``\"archived\": true``. Archived definitions are hidden by default — the map is the board's live schema. Deleting a ``unique_id`` property archives rather than removes it, preserving its id, prefix and numbering; re-adding the same name reinstates it. Use this to discover what is archived, then reinstate it (PATCH with a body under that name) or delete it permanently (POST /v1/boards/{board_id}/properties:purge). Handing this response's ``properties`` map straight back to PATCH is safe: an entry echoed with ``\"archived\": true`` stays archived, so a read-modify-write that edits one property does not reinstate the rest. Reinstating is therefore always explicit — send a body under the archived name WITHOUT the flag."},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"patch":{"tags":["boards"],"summary":"Update Board","operationId":"update_board_v1_boards__board_id__patch","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBoardRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["boards"],"summary":"Delete Board","operationId":"delete_board_v1_boards__board_id__delete","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/properties:purge":{"post":{"tags":["boards"],"summary":"Purge Board Property","description":"PERMANENTLY delete an archived property definition (NOV-459, §7.1).\n\nIRREVERSIBLE, and the only irreversible operation on a board's property\nschema. Deleting a ``unique_id`` property via ``PATCH /v1/boards/{id}`` with\n``{\"properties\": {\"ID\": null}}`` ARCHIVES it — the definition, its id, its\nprefix and its numbering all survive, and re-adding the same name reinstates\nevery one of them. This endpoint destroys that. Once purged, re-adding the\nname mints a brand-new property, and the name becomes free for any type.\n\nValues already stored on cards under the purged name are NOT deleted; only\nthe definition is. 404 if the board has no property under that name, 422 if\nit has a LIVE one (archive it first). Manager role required.","operationId":"purge_board_property_v1_boards__board_id__properties_purge_post","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeBoardPropertyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/query":{"post":{"tags":["boards"],"summary":"Query Board","description":"The primary board read — a page of cards in the spec §8 list envelope.\n\nNOV-457: the service still assembles the envelope as a dict (the MCP\n``list_cards`` wrapper and the public-board payload both consume it in that\nform), so the router validates it into the declared model. The published\nOpenAPI schema is then the same object the response is serialized from.","operationId":"query_board_v1_boards__board_id__query_post","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardQueryRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_CardResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/labels":{"get":{"tags":["boards"],"summary":"List Board Labels","description":"The board's label vocabulary — ``{name, color, count}``, most-used first.\n\nNOV-437: Labels are a card BUILT-IN (``card.labels``). A board-schema\n``multi_select`` named \"Labels\" *can* be created — only ``Status`` is\nreserved — but the built-in shadows it on the card read, so nothing else on\nthe API exposes \"which labels does this board actually use\". This feeds the\ncard-detail label picker and the board's\nLabels filter; without it both offered an empty list and every reuse became\na fresh typo/color variant.\n\nAggregated over the board's non-archived cards. Names merge case- and\nspace-insensitively; a name used with several colors reports its\nmost-used color, and ``count`` is the number of distinct CARDS carrying the\nname (across all its colors). The board-query ``contains`` filter folds names\nthe same way, so a value taken from here matches every spelling variant on\nthe board. Same 404-on-no-access contract as every other board endpoint.","operationId":"list_board_labels_v1_boards__board_id__labels_get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":100,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_BoardLabelResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/columns":{"get":{"tags":["boards"],"summary":"List Columns","operationId":"list_columns_v1_boards__board_id__columns_get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_BoardColumnResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["boards"],"summary":"Create Column","operationId":"create_column_v1_boards__board_id__columns_post","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateColumnRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardColumnResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/columns/{column_id}":{"patch":{"tags":["boards"],"summary":"Update Column","operationId":"update_column_v1_boards__board_id__columns__column_id__patch","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"column_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Column Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateColumnRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardColumnResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["boards"],"summary":"Delete Column","operationId":"delete_column_v1_boards__board_id__columns__column_id__delete","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"column_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Column Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/property-types":{"get":{"tags":["boards"],"summary":"List Property Types","description":"Filter+sort vocabulary metadata for the frontend (NOV-73).\n\nReturns a static map of property type → allowed operators, plus the\nmax filter nesting depth. The frontend derives its filter-builder UI\nfrom this so the operator list never drifts from the backend\ntranslator's truth.\n\nAuthenticated callers only (any role): operator lists are not org-\nsensitive, but we don't want unauthenticated clients sniffing the\nsurface area.","operationId":"list_property_types_v1_property_types_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Property Types V1 Property Types Get"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}]}},"/v1/board-templates":{"get":{"tags":["boards"],"summary":"List Board Templates","description":"List curated board-template presets (NOV-350 / §7.8).\n\nEach entry carries a ``key``, display ``name``, one-line ``description``,\n``property_validation`` mode, and a preview of the columns + properties the\npreset would create. To instantiate one, POST /v1/boards with the ``template``\nkey. The catalogue is static (org-agnostic); authenticated callers only —\nsame gate as /property-types. Uses the standard list envelope so clients\nread every list surface uniformly; the whole catalogue always fits one page\n(``has_more`` is always false).","operationId":"list_board_templates_v1_board_templates_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_BoardTemplateResponse_"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}]}},"/v1/boards/{board_id}/access":{"get":{"tags":["board-access"],"summary":"Get Board Access","operationId":"get_board_access_v1_boards__board_id__access_get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardAccessListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["board-access"],"summary":"Post Board Access","operationId":"post_board_access_v1_boards__board_id__access_post","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantBoardAccessRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardGrantResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/access/{user_id}":{"patch":{"tags":["board-access"],"summary":"Patch Board Access","operationId":"patch_board_access_v1_boards__board_id__access__user_id__patch","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBoardAccessRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardGrantResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["board-access"],"summary":"Delete Board Access","operationId":"delete_board_access_v1_boards__board_id__access__user_id__delete","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/access:reclaim":{"post":{"tags":["board-access"],"summary":"Reclaim Board Access","description":"Org-owner-only governance action: add (or raise to) the owner's manager\ngrant. Non-owners get a uniform ``403`` (the service closes the existence\noracle before any board load). See ``reclaim_board``.","operationId":"reclaim_board_access_v1_boards__board_id__access_reclaim_post","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardGrantResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/invitations":{"post":{"tags":["board-access"],"summary":"Create Board Invitation","description":"Invite an email address straight to **this board**. Board manager only.\n\nOne operator action for \"share this board with my client's reviewer\": it\nmints a pending **guest** invitation carrying the board grant, so accepting\ncreates the membership and the ``board_grants`` row in the same transaction\nand the invitee lands on a workspace where the board is already there —\ninstead of the empty workspace §4.4 describes.\n\nBoard ``manager`` is the gate (§4.6's sharing capability), **not** org\nadmin: a ``member`` who runs one client's board can bring that client onto\nit without being made an administrator of the whole workspace. A ``guest``\ncannot — an external collaborator must not be able to staff, or spend the\nseats of, a workspace they do not pay for (``403``).\n\nStatus codes carry the outcome: **201** for a new invitation, **200** for a\nresend of a live one to the same board (the token is rotated, so the\nprevious link dies), and **200** with the ``invitation_noop`` shape when the\naddress already holds a membership — in which case the board grant is\napplied immediately and rides along on the response, because the operator's\nintent (\"share this board with them\") is satisfiable right now without an\ninvitation. A pending invitation for a *different* board, or a workspace\ninvitation, is a ``409``: the two are different offers and neither may\nsilently overwrite the other.\n\nThis is **not** a share link. A share link (``POST\n/v1/boards/{id}/share-links``) is seatless, identity-free and read-only —\nthe free way to let a client watch a board. This creates a real account with\nattribution and comment/edit rights. §4.6 keeps both, and they are not\ninterchangeable.","operationId":"create_board_invitation_v1_boards__board_id__invitations_post","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBoardInvitationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/InvitationResponse"},{"$ref":"#/components/schemas/AlreadyMemberResponse"}],"title":"Response Create Board Invitation V1 Boards  Board Id  Invitations Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"get":{"tags":["board-access"],"summary":"List Board Invitations","description":"Invitations sent to this board. Board manager only.\n\nDefaults to the pending slice — what the share dialog shows next to the\npeople who already have access, so an operator can tell \"invited, waiting\"\napart from \"in\". ``?status=all`` returns the history.","operationId":"list_board_invitations_v1_boards__board_id__invitations_get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"default":"pending","title":"Status"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_InvitationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/invitations/{invitation_id}":{"delete":{"tags":["board-access"],"summary":"Revoke Board Invitation","description":"Withdraw a pending invitation to this board. Board manager only.\n\nExists alongside the admin-gated workspace revoke because the manager who\nsent it may not be an org admin, and whoever can send has to be able to take\nit back. Terminal and seatless — and since the grant materializes only at\naccept, a revoked invitation leaves no board access behind.","operationId":"revoke_board_invitation_v1_boards__board_id__invitations__invitation_id__delete","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/share-links":{"post":{"tags":["share-links"],"summary":"Create Board Share Link","operationId":"create_board_share_link_v1_boards__board_id__share_links_post","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateShareLinkRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareLinkCreatedResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"get":{"tags":["share-links"],"summary":"List Board Share Links","operationId":"list_board_share_links_v1_boards__board_id__share_links_get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ShareLinkResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["share-links"],"summary":"Revoke All Board Share Links","description":"Revoke every active link on the board — the NOV-219 kill-switch.\n\nManager-gated. Returns the links revoked by this call (empty when the board\nhad no active links). Closing external access here never touches the board's\n``visibility`` or internal access.","operationId":"revoke_all_board_share_links_v1_boards__board_id__share_links_delete","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ShareLinkResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/share-links/{link_id}":{"delete":{"tags":["share-links"],"summary":"Revoke Board Share Link","operationId":"revoke_board_share_link_v1_boards__board_id__share_links__link_id__delete","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"link_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Link Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareLinkResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/public/config":{"get":{"tags":["public"],"summary":"Get Public Config","description":"Publish the runtime policy an unauthenticated client needs (NOV-512).\n\nDeliberately NOT folded into ``/healthz``: that route is ops/meta (liveness,\nbuild sha, migration state) and this is a product contract the SPA reads on\nthe signup and password-reset forms. Keeping them apart also keeps this one\ninside ``/v1``, so it carries the same ``X-Board-Version`` gate and the same\nversioning promise as every other client-facing read.\n\nThe handler resolves no principal and reads no org-scoped table: the\nresponse is identical for every caller on a deploy and can never leak\ntenant data. (The app-level dependencies — ``enforce_billing_writable`` and\nfriends — do take a ``db`` session, but the Session is lazy and their org\nlookups are gated on ``principal.org_id``, which is ``None`` for anonymous\ntraffic: no query runs, no connection is checked out.)\nValues come from :func:`app.services.auth.password_policy`, the same\nfunction ``validate_password_strength`` validates through — so an operator\nwho overrides ``PASSWORD_MIN_LENGTH`` moves the client's rules with the\nserver's instead of leaving them stale.","operationId":"get_public_config_v1_public_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicConfigResponse"}}}}},"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/public/boards/{board_id}":{"get":{"tags":["public"],"summary":"Get Public Board","description":"Read a shared board (board-scoped): metadata, columns, non-archived cards.\n\nProgrammatic / back-compat surface — the token rides as the ``token`` query\nparam and the path pins the board. Kept for callers that already hold a\nboard id; the client-facing web route uses the token-only sibling below.","operationId":"get_public_board_v1_public_boards__board_id__get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Public Board V1 Public Boards  Board Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/public/share/{token}":{"get":{"tags":["public"],"summary":"Get Public Board By Token","description":"Resolve a share-link ``token`` and serve ITS bound board (token-only, NOV-200).\n\nThe client-facing share URL is ``{app_base_url}/share/{token}`` (a web route\nrendering the read-only board); this endpoint backs it. The token resolver\nis board-agnostic — it resolves the raw token via the ``last4`` index +\nargon2 verify and returns a principal carrying the bound ``board_id`` — so\nwe serve the principal's OWN board with no board id in the URL.\n\n404 (never reveal) when the token is absent, malformed, unknown, expired, or\nrevoked. The bound org is set as the tenant scope so the board/card queries\nare org-filtered; board *access* is still granted only on the bound board by\n``require_board_access`` inside :func:`_public_board_payload`.","operationId":"get_public_board_by_token_v1_public_share__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Public Board By Token V1 Public Share  Token  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/public/invitations/{token}":{"get":{"tags":["public"],"summary":"Get Invitation By Token","description":"Resolve an emailed invitation token to its preview (unauthenticated, §4.8).\n\nBacks the ``{app_base_url}/invitations/{token}`` deep link the invitation\nemail carries. The recipient has to be able to see *which workspace is\nasking* before deciding whether to sign in — or create an account at all —\nso this read cannot require a session. It is unauthenticated but not\nunauthorized: the token IS the credential, argon2id-hashed at rest and\nresolvable only while the invitation is pending.\n\n404 — never a distinguishable error — when the token is absent, malformed,\nunknown, expired, revoked, or already used. All six look identical, so the\nendpoint is not an oracle for guessing tokens, and the payload deliberately\nsays nothing about whether the invited address has an account: presenting a\nvalid token must not become account enumeration either.\n\nAccepting still requires signing in as the invited address\n(``POST /v1/invitations/{id}:accept``). This endpoint only tells the SPA\nwhich invitation to accept and whom to ask the visitor to sign in as.","operationId":"get_invitation_by_token_v1_public_invitations__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationPreviewResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/public/boards/{board_id}/cards/{card_id}/comments":{"post":{"tags":["public"],"summary":"Create Public Comment","description":"Post a comment through a ``commenter`` share link.\n\n``require_board_access(min_role='commenter')`` rejects a ``viewer`` link with\n403 and a cross-board token with 404. The card must live on the bound board.\nThe comment is authored anonymously (no User, no seat).\n\nThe app-level ``enforce_billing_writable`` dependency falls out at its \"no\nprincipal\" gate for a share-link token (it isn't a bearer), so the §18.8\nread-only-when-past_due invariant is enforced here explicitly: a past_due org\nrefuses this write with the same ``402 billing_past_due`` an internal write\nreturns. Checked after the role gate so a ``viewer`` link still 403s (and an\nunauthorized caller never learns the org's billing state).","operationId":"create_public_comment_v1_public_boards__board_id__cards__card_id__comments_post","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"card_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Card Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCommentRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/public/boards/{board_id}/agent-activity":{"get":{"tags":["public"],"summary":"Get Public Agent Activity","description":"Client-shareable, read-only agent-activity report for a shared board (NOV-271).\n\nBoard-scoped surface: the token rides as ``?token=`` and the path pins the\nboard. A viewer OR commenter token for THIS board sees the all-agents rollup;\na cross-board / expired / revoked token 404s (existence hidden); an\nun-entitled org 403s ``governance_not_entitled`` AFTER the board gate. GATED\nto the Scale/Agency tier (the agency's entitlement). ``window`` is ``24h`` or\n``7d`` (400 otherwise).","operationId":"get_public_agent_activity_v1_public_boards__board_id__agent_activity_get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"24h","title":"Window"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Limit"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentActivityResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/public/share/{token}/agent-activity":{"get":{"tags":["public"],"summary":"Get Public Agent Activity By Token","description":"Token-only sibling of :func:`get_public_agent_activity` (NOV-200 pattern).\n\nResolves the share-link ``token`` board-agnostically and serves the report\nfor ITS bound board — no board id in the URL, mirroring\n:func:`get_public_board_by_token`. Same gates, same 404-on-invalid-token\ncontract.","operationId":"get_public_agent_activity_by_token_v1_public_share__token__agent_activity_get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}},{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"24h","title":"Window"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Limit"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentActivityResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cards":{"post":{"tags":["cards"],"summary":"Create Card","operationId":"create_card_v1_cards_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCardRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}]}},"/v1/cards/{card_id}":{"get":{"tags":["cards"],"summary":"Get Card","operationId":"get_card_v1_cards__card_id__get","parameters":[{"name":"card_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Card Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"patch":{"tags":["cards"],"summary":"Update Card","description":"Patch a card. ``If-Match: \"v17\"`` against the etag honored (spec §8.1).\n\n``Prefer: merge-properties`` (spec §7.3, NOV-352): ``properties`` merges\nkey-by-key instead of replacing the map, and array-typed properties\n(``multi_select`` / ``people`` / ``files`` per the board schema)\nelement-UNION with the stored value — deduped by option id/name, user id,\nor file id/url/name — so concurrent agent appends never clobber each\nother. Explicit removal per key: ``{\"add\": [...], \"remove\": [...]}``\n(either optional). Without the header, writes replace (Notion default).","operationId":"update_card_v1_cards__card_id__patch","parameters":[{"name":"card_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Card Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCardRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["cards"],"summary":"Delete Card","description":"Soft-archive a card. ``If-Match: \"v17\"`` honored when supplied (spec §8.1).","operationId":"delete_card_v1_cards__card_id__delete","parameters":[{"name":"card_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Card Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/cards/{card_id}/audit":{"get":{"tags":["cards"],"summary":"List Card Audit","operationId":"list_card_audit_v1_cards__card_id__audit_get","parameters":[{"name":"card_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Card Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_CardAuditEntry_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/cards/{card_id}/autopilot-runs":{"get":{"tags":["cards"],"summary":"List Card Autopilot Runs","description":"Autopilot runs that wrote content on this card, newest first (§25.9).\n\nGated on **board access**, not the org admin role — unlike\n``GET /v1/orgs/{org_id}/ai-run-usage``, which is the governance feed and\ncarries token counts and dollar costs. This route carries neither, and it\nexists so the §25.9 Autopilot thumbs can sit next to the content on the card\nfor whoever is reading it.\n\n**Not cursor-paginated, but ``has_more`` is still honest.** The row cap is\nfixed and ``next_cursor`` is always null — there is no second page to ask\nfor. ``has_more`` reports whether the cap truncated anything, because it is\na claim about the data rather than about the wire shape, and an envelope\nthat says a list is complete when it is not is worse than one with no\npagination fields at all.","operationId":"list_card_autopilot_runs_v1_cards__card_id__autopilot_runs_get","parameters":[{"name":"card_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Card Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10,"minimum":1,"default":10,"title":"Limit"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AutopilotRunProvenanceResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/cards/{card_id}:move":{"post":{"tags":["cards"],"summary":"Move Card","description":"Move a card. ``If-Match: \"v17\"`` against the etag honored (spec §8.1).","operationId":"move_card_v1_cards__card_id__move_post","parameters":[{"name":"card_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Card Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveCardRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/cards:batchUpdate":{"post":{"tags":["cards"],"summary":"Batch Update Cards","description":"Transactional bulk ops. ``Prefer: merge-properties`` applies the same\nper-key merge + array element-union semantics as ``PATCH /v1/cards/{id}``\n(spec §7.3) to every ``set`` op in the batch.","operationId":"batch_update_cards_v1_cards_batchUpdate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpdateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}]}},"/v1/cards/{card_id}/agent_activity":{"post":{"tags":["cards"],"summary":"Set Card Agent Activity","description":"Publish an agent's current claim on a card (NOV-91).\n\nLast-write-wins. The server stamps ``started_at`` to drive the\n10-minute lazy expiry on read. Broadcasts\n``card.agent_activity.set`` so the kanban board's WS subscribers\nflip the agent-motion frame on within ~200ms.","operationId":"set_card_agent_activity_v1_cards__card_id__agent_activity_post","parameters":[{"name":"card_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Card Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetAgentActivityRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["cards"],"summary":"Clear Card Agent Activity","description":"Clear an agent's claim on a card (NOV-91).\n\nIdempotent — re-clearing an already-empty field is a no-op\n(no realtime event fires). The next card mutation also clears the\nfield automatically; this DELETE is the explicit \"I'm done\" path.","operationId":"clear_card_agent_activity_v1_cards__card_id__agent_activity_delete","parameters":[{"name":"card_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Card Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/columns/{column_id}:claim-next":{"post":{"tags":["leases"],"summary":"Claim Next","description":"Lease the next eligible card in a column.\n\nOn success returns ``200`` with the lease + full card. When the queue is\ndrained (or the column's ``concurrency_limit`` is reached) returns ``200``\n``{object:\"lease\", card:null}`` (a single content-type, cheap to busy-poll) —\nnever a ``204``/``404`` (spec §7.5.3).\n\nAn optional ``Idempotency-Key`` header makes the claim safe to retry after a\ndropped response: a retry with the SAME key returns the SAME lease (never a\nsecond one) or replays the original ``no_work`` (NOV-259, spec §7.5.4).","operationId":"claim_next_v1_boards__board_id__columns__column_id__claim_next_post","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"column_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Column Id"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency-Key"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ClaimNextRequest"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/leases/{lease_id}:heartbeat":{"post":{"tags":["leases"],"summary":"Renew Lease","description":"Extend a held lease's TTL + stamp its heartbeat. ``:heartbeat`` is an\nalias of ``:renew`` (same handler). ``409 lease_lost`` if the caller no\nlonger holds the active lease (spec §7.5.3).","operationId":"renew_lease_v1_leases__lease_id__heartbeat_post","parameters":[{"name":"lease_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Lease Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenewLeaseRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaseResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/leases/{lease_id}:renew":{"post":{"tags":["leases"],"summary":"Renew Lease","description":"Extend a held lease's TTL + stamp its heartbeat. ``:heartbeat`` is an\nalias of ``:renew`` (same handler). ``409 lease_lost`` if the caller no\nlonger holds the active lease (spec §7.5.3).","operationId":"renew_lease_v1_leases__lease_id__renew_post","parameters":[{"name":"lease_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Lease Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenewLeaseRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaseResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/leases/{lease_id}:complete":{"post":{"tags":["leases"],"summary":"Complete Lease","description":"Complete a held lease: optionally patch the card, advance it to the\ncontract's ``on_success_column_id``, release the lease. Idempotent on a\ncompleted lease with the same token; ``409 lease_lost`` on a stale token\n(spec §7.5.3).\n\nThe ``properties`` patch applies MERGE semantics (spec §7.3, NOV-352):\nkeys merge instead of replacing the map, and array-typed properties\n(``multi_select`` / ``people`` / ``files``) element-union with the stored\nvalue — an agent's result tags never wipe tags already on the card.\nPer-key ``{\"add\": [...], \"remove\": [...]}`` is honored.","operationId":"complete_lease_v1_leases__lease_id__complete_post","parameters":[{"name":"lease_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Lease Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteLeaseRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/leases/{lease_id}:fail":{"post":{"tags":["leases"],"summary":"Fail Lease","description":"Release a held lease as failed; requeue with backoff while attempts\nremain, else dead-letter in place. Idempotent on an already-failed lease\nwith the same token; ``409 lease_lost`` on a stale token (spec §7.5.3).","operationId":"fail_lease_v1_leases__lease_id__fail_post","parameters":[{"name":"lease_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Lease Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FailLeaseRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaseResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/leases/{lease_id}":{"get":{"tags":["leases"],"summary":"Get Lease","description":"Fetch one lease. Gated on board READ access via the lease's card — a\nnon-grantee of a restricted board (or a cross-org caller) gets ``404\nobject_not_found`` (existence never revealed). A read: never past_due-blocked\n(spec §7.5.3 observability).","operationId":"get_lease_v1_leases__lease_id__get","parameters":[{"name":"lease_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Lease Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaseResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/leases":{"get":{"tags":["leases"],"summary":"List Board Leases","description":"List a board's leases (Notion-shape envelope). Requires board READ access\n(viewer+); a non-grantee of a restricted board 404s. ``state`` is one of\n``active`` (default — currently held), ``expired`` (lapsed, awaiting the\nreaper — \"who is stuck\"), or ``all`` (full history incl. released); an\nunknown value is ``422``. ``column_id`` narrows to one column's queue.\nOrdered soonest-to-expire first. A read: never past_due-blocked.","operationId":"list_board_leases_v1_boards__board_id__leases_get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"column_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"}},{"name":"state","in":"query","required":false,"schema":{"type":"string","default":"active","title":"State"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_LeaseResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/columns/{column_id}/contract":{"get":{"tags":["leases"],"summary":"Get Column Contract","description":"Read a column's job contract (the durable-work queue config). MANAGER-only\n— a non-manager board role is ``403``; a missing/cross-org board or a column\nnot on this board is ``404`` (existence never revealed). Returns the fields as\nstored (a column with no contract reads back as the empty shape). A read:\nnever past_due-blocked (spec §7.5.3 admin).","operationId":"get_column_contract_v1_boards__board_id__columns__column_id__contract_get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"column_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Column Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobContractResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"put":{"tags":["leases"],"summary":"Set Column Contract","description":"Write a column's job contract (full replace). MANAGER-only (same 404/403\ncontract as the GET). Rejects a malformed ``input_schema``/``output_schema``\nor an off-board ``on_success_column_id``/``on_failure_column_id`` with ``422\ninvalid_contract``, and an unknown field with ``422`` (extra keys forbidden).\nEmits ``column.contract.updated``. The app-level past_due guard already blocks\nthis PUT for a delinquent org (spec §7.5.3 admin).","operationId":"set_column_contract_v1_boards__board_id__columns__column_id__contract_put","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"column_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Column Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobContractRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobContractResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/card-templates":{"post":{"tags":["card-templates"],"summary":"Create Template","operationId":"create_template_v1_card_templates_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCardTemplateRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardTemplateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}]}},"/v1/boards/{board_id}/card-templates":{"get":{"tags":["card-templates"],"summary":"List Templates","operationId":"list_templates_v1_boards__board_id__card_templates_get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_CardTemplateResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/card-templates/{template_id}":{"get":{"tags":["card-templates"],"summary":"Get Template","operationId":"get_template_v1_card_templates__template_id__get","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Template Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardTemplateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"patch":{"tags":["card-templates"],"summary":"Update Template","operationId":"update_template_v1_card_templates__template_id__patch","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Template Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCardTemplateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardTemplateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["card-templates"],"summary":"Delete Template","operationId":"delete_template_v1_card_templates__template_id__delete","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Template Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/cards/{card_id}:make-recurring":{"post":{"tags":["card-templates"],"summary":"Make Card Recurring","operationId":"make_card_recurring_v1_cards__card_id__make_recurring_post","parameters":[{"name":"card_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Card Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MakeRecurringRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardTemplateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/comments":{"get":{"tags":["comments"],"summary":"List Comments","description":"List comments on a card.\n\nAccepts ``block_id`` as a Notion-shape alias for ``card_id`` (NOV-63 B5).\nNotion's API uses ``GET /v1/comments?block_id=<page_id>`` to list\npage-level comments — content-forge does this verbatim. We treat the\ntwo parameters as equivalent so a Notion-shape client works unchanged.\nIf both are present, ``card_id`` wins.","operationId":"list_comments_v1_comments_get","parameters":[{"name":"card_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Card Id"}},{"name":"block_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Block Id"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Comments V1 Comments Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["comments"],"summary":"Create Comment","operationId":"create_comment_v1_comments_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}]}},"/v1/comments/{comment_id}":{"patch":{"tags":["comments"],"summary":"Update Comment","description":"Patch a comment. ``If-Match: \"v17\"`` against the etag honored (spec §8.1).","operationId":"update_comment_v1_comments__comment_id__patch","parameters":[{"name":"comment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Comment Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCommentRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["comments"],"summary":"Delete Comment","description":"Soft-archive a comment. ``If-Match: \"v17\"`` honored when supplied.","operationId":"delete_comment_v1_comments__comment_id__delete","parameters":[{"name":"comment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Comment Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/databases/{database_id}":{"get":{"tags":["notion-compat"],"summary":"Get Database","operationId":"get_database_v1_databases__database_id__get","parameters":[{"name":"database_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Database Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"patch":{"tags":["notion-compat"],"summary":"Update Database","operationId":"update_database_v1_databases__database_id__patch","parameters":[{"name":"database_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Database Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBoardRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/databases/{database_id}/query":{"post":{"tags":["notion-compat"],"summary":"Query Database","operationId":"query_database_v1_databases__database_id__query_post","parameters":[{"name":"database_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Database Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardQueryRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_CardResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/data_sources/{data_source_id}":{"get":{"tags":["notion-compat"],"summary":"Get Data Source","operationId":"get_data_source_v1_data_sources__data_source_id__get","parameters":[{"name":"data_source_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Data Source Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataSourceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/data_sources/{data_source_id}/query":{"post":{"tags":["notion-compat"],"summary":"Query Data Source","operationId":"query_data_source_v1_data_sources__data_source_id__query_post","parameters":[{"name":"data_source_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Data Source Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardQueryRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_CardResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/pages":{"post":{"tags":["notion-compat"],"summary":"Create Page","operationId":"create_page_v1_pages_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCardRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}]}},"/v1/pages/{page_id}":{"get":{"tags":["notion-compat"],"summary":"Get Page","operationId":"get_page_v1_pages__page_id__get","parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"patch":{"tags":["notion-compat"],"summary":"Update Page","description":"Update a card via the Notion-shape `PATCH /v1/pages/{id}` alias.\n\nPromotes built-in Notion properties (Status, Assignees, Due, Labels) to\nfirst-class card columns before delegating (NOV-63 B6). Unknown\nproperty names pass through unchanged.\n\nNOV-82: a Status property write resolves to the named board column and\nmoves the card via the canonical move path. A name that matches no\ncolumn on the card's board is rejected as 400. The single emitted event\nis ``card.moved`` — the legacy ``card.status_changed`` event is gone\n(the column move IS the status change).","operationId":"update_page_v1_pages__page_id__patch","parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCardRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/pages/{page_id}/properties/{prop_id}":{"get":{"tags":["notion-compat"],"summary":"Get Page Property","operationId":"get_page_property_v1_pages__page_id__properties__prop_id__get","parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"prop_id","in":"path","required":true,"schema":{"type":"string","title":"Prop Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyItemResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/blocks/{parent_id}/children":{"get":{"tags":["blocks"],"summary":"List Block Children","description":"Fetch a card's body tree, recursing up to ``depth`` levels (spec §6.4).","operationId":"list_block_children_v1_blocks__parent_id__children_get","parameters":[{"name":"parent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Parent Id"}},{"name":"depth","in":"query","required":false,"schema":{"type":"integer","maximum":10,"minimum":1,"default":1,"title":"Depth"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Block Children V1 Blocks  Parent Id  Children Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"patch":{"tags":["blocks"],"summary":"Append Block Children","description":"Append a run of blocks under ``parent_id`` (card or block).\n\nOptional ``after`` selects a sibling to insert AFTER (Notion shape);\notherwise blocks land at the end.\n\nNOV-168: an optional ``Idempotency-Key`` header makes the append safe to\nretry. Absent ⇒ today's behavior (append normally). Present ⇒ a replay\nwith the same key returns the original response without re-appending.","operationId":"append_block_children_v1_blocks__parent_id__children_patch","parameters":[{"name":"parent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Parent Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppendBlocksRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Append Block Children V1 Blocks  Parent Id  Children Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/blocks/{block_id}":{"patch":{"tags":["blocks"],"summary":"Update Block","description":"Modify a block. ``If-Match`` is ACCEPTED but ADVISORY (NOV-169, spec §8.1).\n\nBody blocks are server-authoritative last-write-wins: a stale/wrong\n``If-Match`` never 412s, the write merges. The header is still read and\nforwarded for back-compat (the frontend keeps sending it until P4/NOV-170);\n``update_block_for_principal`` parses-and-ignores it.","operationId":"update_block_v1_blocks__block_id__patch","parameters":[{"name":"block_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Block Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlockRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Update Block V1 Blocks  Block Id  Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["blocks"],"summary":"Delete Block","description":"Soft-archive a block + its descendants.","operationId":"delete_block_v1_blocks__block_id__delete","parameters":[{"name":"block_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Block Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/blocks/{block_id}:move":{"post":{"tags":["blocks"],"summary":"Move Block","description":"Re-parent and/or reorder a block (NOV-498, spec §8.2).\n\nMirrors ``POST /v1/cards/{id}:move``. Returns the moved block's envelope —\nthe same shape ``PATCH /v1/blocks/{id}`` returns.\n\nNo ``If-Match`` here, unlike the card ``:move``: the body surface resolves\nlast-write-wins and never 412s (§8.1), and this endpoint postdates that\ndecision, so there is no legacy header to parse-and-ignore.","operationId":"move_block_v1_blocks__block_id__move_post","parameters":[{"name":"block_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Block Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveBlockRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Move Block V1 Blocks  Block Id  Move Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/files:upload":{"post":{"tags":["files"],"summary":"Presign Upload","description":"Mint a presigned PUT URL for a card attachment.\n\nBody: ``{card_id, filename, content_type, size_bytes?}``. Returns the\nfile envelope plus ``upload_url`` + ``upload_url_expires_in``. The\nclient then PUTs the bytes to ``upload_url`` (NOT through us — direct\nto S3) and calls ``:commit`` once done.","operationId":"presign_upload_v1_files_upload_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFileUploadRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Presign Upload V1 Files Upload Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}]}},"/v1/files/{file_id}:commit":{"post":{"tags":["files"],"summary":"Commit File","description":"Finalize an upload: HeadObject the bytes + flip status to available.","operationId":"commit_file_v1_files__file_id__commit_post","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Commit File V1 Files  File Id  Commit Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/files/{file_id}":{"get":{"tags":["files"],"summary":"Get File","description":"Metadata + presigned GET URL for an ``available`` file.","operationId":"get_file_v1_files__file_id__get","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get File V1 Files  File Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["files"],"summary":"Delete File","description":"Soft-archive a file + fire `card.updated` webhook for the removal.","operationId":"delete_file_v1_files__file_id__delete","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/cards/{card_id}/attachments":{"get":{"tags":["files"],"summary":"List Card Attachments","description":"Notion-shape list of a card's `available` attachments.","operationId":"list_card_attachments_v1_cards__card_id__attachments_get","parameters":[{"name":"card_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Card Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Card Attachments V1 Cards  Card Id  Attachments Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/orgs":{"get":{"tags":["admin"],"summary":"List Admin Orgs","operationId":"list_admin_orgs_v1_admin_orgs_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AdminOrgRow_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/orgs/{org_id}":{"get":{"tags":["admin"],"summary":"Get Admin Org","operationId":"get_admin_org_v1_admin_orgs__org_id__get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOrgRow"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/billing/orgs":{"get":{"tags":["admin"],"summary":"List Admin Billing Orgs","description":"Per-org billing state across all tenants (spec §18.10).\n\nPaginated + searchable (name/slug). ``?status=past_due`` is the\nfailed-payment list. ``billable_seats`` is recomputed LIVE; revenue is a\nper-kind estimate (``humans × $1 + billable_agents × $1`` at the annual\nmonthly-equivalent display rates — NOV-370) on Pro, 0 on free; ``drift`` is\nthe reconciliation descriptor recorded by the daily cron.","operationId":"list_admin_billing_orgs_v1_admin_billing_orgs_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AdminBillingOrgRow_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/orgs/{org_id}/grants":{"post":{"tags":["admin"],"summary":"Create Org Grant","operationId":"create_org_grant_v1_admin_orgs__org_id__grants_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantOrgCompRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgGrantRow"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"get":{"tags":["admin"],"summary":"List Org Grants","operationId":"list_org_grants_v1_admin_orgs__org_id__grants_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"include_history","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Include History"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_OrgGrantRow_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/orgs/{org_id}/grants/{grant_id}":{"delete":{"tags":["admin"],"summary":"Revoke Org Grant","operationId":"revoke_org_grant_v1_admin_orgs__org_id__grants__grant_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"grant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Grant Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/RevokeOrgGrantRequest"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgGrantRow"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/users":{"get":{"tags":["admin"],"summary":"List Admin Users","operationId":"list_admin_users_v1_admin_users_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AdminUserRow_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/users/{user_id}":{"get":{"tags":["admin"],"summary":"Get Admin User","operationId":"get_admin_user_v1_admin_users__user_id__get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserRow"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/audit":{"get":{"tags":["admin"],"summary":"List Admin Audit","operationId":"list_admin_audit_v1_admin_audit_get","parameters":[{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Org Id"}},{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"}},{"name":"event_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type"}},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Since"}},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Until"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AdminAuditRow_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/admins":{"get":{"tags":["admin"],"summary":"List Platform Admins Short","operationId":"list_platform_admins_short_v1_admin_admins_get","parameters":[{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Page Size"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_PlatformAdminRow_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["admin"],"summary":"Grant Platform Admin Short","operationId":"grant_platform_admin_short_v1_admin_admins_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantPlatformAdminRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformAdminRow"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/admin/platform-admins":{"get":{"tags":["admin"],"summary":"List Platform Admins","operationId":"list_platform_admins_v1_admin_platform_admins_get","parameters":[{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Page Size"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_PlatformAdminRow_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["admin"],"summary":"Grant Platform Admin","operationId":"grant_platform_admin_v1_admin_platform_admins_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantPlatformAdminRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformAdminRow"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/admin/admins/{user_id}":{"delete":{"tags":["admin"],"summary":"Revoke Platform Admin Short","operationId":"revoke_platform_admin_short_v1_admin_admins__user_id__delete","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/platform-admins/{user_id}":{"delete":{"tags":["admin"],"summary":"Revoke Platform Admin","operationId":"revoke_platform_admin_v1_admin_platform_admins__user_id__delete","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/feedback":{"get":{"tags":["admin"],"summary":"List Admin Feedback","description":"Cross-org triage list, EVERY filter applied server-side (§25.7).\n\nMulti-value filters are repeated parameters, not comma-joined lists:\n``?type=bug_report&type=idea&status=new``. A comma-joined encoding would\nhave to pick a separator that no enum value can contain and then defend\nthat choice forever; repetition is what HTTP already means by \"several of\nthese\", and FastAPI parses it natively.\n\n``sort`` is ``created_time`` | ``rating`` | ``status`` and ``order`` is\n``asc`` | ``desc`` (default ``created_time``/``desc``, the inbox reading).\nEach key names the response field it sorts on. ``status`` sorts by\nthe triage lifecycle, not the alphabet — see the service.","operationId":"list_admin_feedback_v1_admin_feedback_get","parameters":[{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable. Filter by feedback type.","title":"Type"},"description":"Repeatable. Filter by feedback type."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable. Filter by status.","title":"Status"},"description":"Repeatable. Filter by status."},{"name":"jira_status","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable. Filter by Jira sync state.","title":"Jira Status"},"description":"Repeatable. Filter by Jira sync state."},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable. Filter by bug severity.","title":"Severity"},"description":"Repeatable. Filter by bug severity."},{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Org Id"}},{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"}},{"name":"submitted_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Submitted From"}},{"name":"submitted_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Submitted To"}},{"name":"rating_min","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rating Min"}},{"name":"rating_max","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rating Max"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"created_time","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","default":"desc","title":"Order"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AdminFeedbackRow_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/feedback/count":{"get":{"tags":["admin"],"summary":"Count Admin Feedback","description":"``{new: n}`` — the §25.7.1 nav-badge probe, polled every 60 s.\n\nA plain ``COUNT`` behind the same filter helper the list uses, which is what\nmakes a deep-linked dashboard tile's number agree with the table it opens.\n\n``?status=`` is deliberately absent from the signature rather than accepted\nand ignored: the endpoint counts ``new`` by definition, and a parameter that\nsilently does nothing is worse than one that isn't there.","operationId":"count_admin_feedback_v1_admin_feedback_count_get","parameters":[{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable. Filter by feedback type.","title":"Type"},"description":"Repeatable. Filter by feedback type."},{"name":"jira_status","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable. Filter by Jira sync state.","title":"Jira Status"},"description":"Repeatable. Filter by Jira sync state."},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable. Filter by bug severity.","title":"Severity"},"description":"Repeatable. Filter by bug severity."},{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Org Id"}},{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"}},{"name":"submitted_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Submitted From"}},{"name":"submitted_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Submitted To"}},{"name":"rating_min","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rating Min"}},{"name":"rating_max","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rating Max"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminFeedbackCount"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/feedback/stats":{"get":{"tags":["admin"],"summary":"Admin Feedback Stats","description":"Date-ranged rollups AND the three daily series (§25.7).\n\nThe series are the point. A rollup tells you where you are; only the daily\nline tells you that last Tuesday's deploy doubled the bug rate — so\n``daily.volume`` / ``daily.nps`` / ``daily.autopilot_rating`` are always\npresent, gap-filled across every day in the range including the zeros.\n\nWith no ``submitted_from`` / ``submitted_to`` the range defaults to the last\n30 days, and the resolved window is echoed back as ``range_start`` /\n``range_end`` so a reader never has to infer which range produced the\nnumbers.","operationId":"admin_feedback_stats_v1_admin_feedback_stats_get","parameters":[{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable. Filter by feedback type.","title":"Type"},"description":"Repeatable. Filter by feedback type."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable. Filter by status.","title":"Status"},"description":"Repeatable. Filter by status."},{"name":"jira_status","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable. Filter by Jira sync state.","title":"Jira Status"},"description":"Repeatable. Filter by Jira sync state."},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable. Filter by bug severity.","title":"Severity"},"description":"Repeatable. Filter by bug severity."},{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Org Id"}},{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"}},{"name":"submitted_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Submitted From"}},{"name":"submitted_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Submitted To"}},{"name":"rating_min","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rating Min"}},{"name":"rating_max","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rating Max"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminFeedbackStats"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/feedback/{feedback_id}":{"get":{"tags":["admin"],"summary":"Get Admin Feedback","description":"One report in full, with a short-TTL presigned screenshot GET (§25.7).\n\nThe screenshot URL forces ``Content-Disposition: attachment`` — a security\ncontrol, not a UX choice (§25.16 A05); see\n:func:`app.services.files.presign_admin_screenshot_download`.\n\nReading a ``new`` row does NOT triage it. §25.7.1's auto-triage is a PATCH\nthe detail page issues, which is what makes it audited and what makes it\ncorrectly unavailable to ``platform_support``.","operationId":"get_admin_feedback_v1_admin_feedback__feedback_id__get","parameters":[{"name":"feedback_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feedback Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminFeedbackDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"patch":{"tags":["admin"],"summary":"Update Admin Feedback","description":"Set ``status`` and/or ``admin_notes`` (§25.7).\n\nAlso the §25.7.1 auto-triage call: the detail page PATCHes ``new →\ntriaged`` on open, which is why that transition is audited like any other\nand why ``platform_support`` — refused at :func:`_require_mutator` — cannot\nsilently drain the queue by browsing it.\n\nA no-op PATCH (both fields already at the submitted values) returns the row\nunchanged and writes NO audit row. An audit trail whose entries do not\ncorrespond to changes is a trail nobody can reason about.","operationId":"update_admin_feedback_v1_admin_feedback__feedback_id__patch","parameters":[{"name":"feedback_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feedback Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFeedbackRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminFeedbackDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/feedback:bulkUpdate":{"post":{"tags":["admin"],"summary":"Bulk Update Admin Feedback","description":"One status across up to 200 ids, in ONE transaction (§25.7).\n\nTriaging a screenful must be one request, not N parallel PATCHes — each of\nwhich would be its own transaction, so a failure halfway through would leave\nthe operator looking at a half-triaged page with no way to tell which half.\nHere every row lands or none does: the single ``db.commit()`` at the end is\nthe whole of it, and any raise before it leaves the session for ``get_db``\nto close and roll back.\n\nOne audit row per **changed** id — not per submitted id. An id that already\nholds the target status is an idempotent no-op and writes nothing, which is\nwhat keeps \"count the audit rows\" a valid way to ask what a bulk call did.","operationId":"bulk_update_admin_feedback_v1_admin_feedback_bulkUpdate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUpdateFeedbackRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/admin/feedback/{feedback_id}:file-issue":{"post":{"tags":["admin"],"summary":"File Feedback Issue","description":"Promote a `skipped` row into the Jira queue (§25.7).\n\nThe NPS comment that turned out to be a bug. Idempotent no-op when the row\nis already ``synced``.","operationId":"file_feedback_issue_v1_admin_feedback__feedback_id__file_issue_post","parameters":[{"name":"feedback_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feedback Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminFeedbackDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/feedback/{feedback_id}:retry-jira":{"post":{"tags":["admin"],"summary":"Retry Feedback Jira","description":"Re-drive a `failed` row (§25.7).\n\nMechanically identical to ``:file-issue`` — both put the row back in the\nworker's queue — but a DISTINCT endpoint and a distinct audit event,\nbecause the two answer different operator questions (\"this survey response\nis actually a bug\" vs \"Jira was down, try again\") and §25.7 names them\nseparately. Collapsing them would make the audit trail unable to say which\nhappened.","operationId":"retry_feedback_jira_v1_admin_feedback__feedback_id__retry_jira_post","parameters":[{"name":"feedback_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feedback Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminFeedbackDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/admin/feedback:bulkFileIssue":{"post":{"tags":["admin"],"summary":"Bulk File Feedback Issues","description":"Re-drive up to 200 `skipped` / `failed` rows into Jira, in one transaction.\n\n**This endpoint is a spec delta** — see the module docstring. §25.7 gives\nonly the per-row ``:file-issue``, which is a fine answer to \"this one survey\nresponse is actually a bug\" and no answer at all to the situation we are\nactually shipping into: Jira deliberately unconfigured, the §25.6 worker\nfail-softing every row to ``skipped``, and a backlog that grows for as long\nas the API token is missing. When the token lands, the recovery has to be\none request.\n\nSame cap, same single transaction, same ``feedback.issue_filed`` event as\nthe per-row form — it is the bulk shape of an operation §25.7 already\nsanctions, not a new capability. ``synced`` and ``pending`` rows are\nidempotent no-ops (see :func:`_redrive_jira`), so the natural recovery\ngesture — select everything, re-drive — is safe to repeat.","operationId":"bulk_file_feedback_issues_v1_admin_feedback_bulkFileIssue_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkFileIssueRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/admin/feedback/{feedback_id}:reply":{"post":{"tags":["admin"],"summary":"Reply To Feedback","description":"Email the submitter through the §22.7 durable outbox (§25.8).\n\nNever sent inline on the request thread: the operator gets one fast 200 and\nthe SES call, its retries and its dead-lettering all happen out-of-band —\nwhich is why the response says ``queued`` rather than ``sent``.\n\nRequires a submitter with ``kind='human'`` and a deliverable address,\notherwise 400. All three refusals are real cases, not defensive padding: an\nagent files reports through §25.11 and has no inbox; a §25.10 erasure NULLs\n``user_id`` and leaves a row nobody can be written back to; and a service\nprincipal never had a user at all.\n\nThe message is HTML-escaped in the template\n(:func:`app.services.email._feedback_reply_html`) — paperlives interpolated\nthe raw operator string into ``<p>{message}</p>``, an HTML-injection bug we\ndo not reproduce.","operationId":"reply_to_feedback_v1_admin_feedback__feedback_id__reply_post","parameters":[{"name":"feedback_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feedback Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackReplyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackReplyResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/search":{"post":{"tags":["search"],"summary":"Search","description":"Full-text search across the caller's org (spec §8.2).\n\nNOV-457: the service still assembles the Notion-shape envelope as a dict —\nthe MCP wrapper consumes it in that form — so the router validates it into\nthe declared model. That is deliberate: the published schema is then the\nsame object the response is serialized from, rather than a promise made\nalongside an untyped blob.","operationId":"search_v1_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_SearchHitResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}]}},"/v1/orgs/{org_id}/export":{"get":{"tags":["export"],"summary":"Export Org","description":"Export the entire workspace as one JSON document (owner/admin only).\n\nKeeps the plain ``get_principal`` gate on purpose (§4.8): the workspace is\nalready named in the path, and ``build_org_export`` binds the tenant scope\nto it and probes membership itself. Layering ``X-Novum-Org`` on top of a\npath that already says which workspace it means could only ever contradict\nit — the board-level sibling below, which has no org in its path, is the one\nthat takes the header.","operationId":"export_org_v1_orgs__org_id__export_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/boards/{board_id}/export":{"get":{"tags":["export"],"summary":"Export Board","description":"Export a single board (columns + cards + block bodies + comments).","operationId":"export_board_v1_boards__board_id__export_get","parameters":[{"name":"board_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Board Id"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."},{"name":"X-Novum-Org","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Optional. Selects the workspace this request acts in. An integration token is **pinned** to its own workspace — a conflicting value is `404`. For a browser session the value is re-checked against live membership on every request: it can only ever narrow to a workspace you already belong to, never widen. Omit it to act in the session's active workspace."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/webhooks":{"get":{"tags":["webhooks"],"summary":"List Webhooks","description":"List webhooks visible to the caller's org. Newest first.","operationId":"list_webhooks_v1_webhooks_get","parameters":[{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_WebhookResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"post":{"tags":["webhooks"],"summary":"Create Webhook","operationId":"create_webhook_v1_webhooks_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}],"parameters":[{"name":"X-Board-Version","in":"header","required":true,"schema":{"type":"string","default":"2026-06-19"},"description":"Required on every `/v1` request. Send `2026-06-19`. The middleware validates *presence*, not the value, so an older pinned date keeps working; `Notion-Version` is accepted as a Notion-SDK compatibility fallback when this header is absent."}]}},"/v1/webhooks/{webhook_id}":{"get":{"tags":["webhooks"],"summary":"Get Webhook","operationId":"get_webhook_v1_webhooks__webhook_id__get","parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Webhook Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"patch":{"tags":["webhooks"],"summary":"Update Webhook","operationId":"update_webhook_v1_webhooks__webhook_id__patch","parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Webhook Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]},"delete":{"tags":["webhooks"],"summary":"Delete Webhook","operationId":"delete_webhook_v1_webhooks__webhook_id__delete","parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Webhook Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/webhooks/{webhook_id}:rotate-secret":{"post":{"tags":["webhooks"],"summary":"Rotate Webhook Secret","description":"Mint a new secret. Old one is unusable from the next request on.\n\nReturns the new plaintext exactly once. There's a brief window between\nrotation and the receiver knowing about the new key, during which\nin-flight deliveries (already signed with the OLD secret) keep flowing.\nThat's intentional — pending rows were signed before rotation and the\nreceiver should still accept them; in steady state new events use the\nnew key.","operationId":"rotate_webhook_secret_v1_webhooks__webhook_id__rotate_secret_post","parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Webhook Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/webhooks/{webhook_id}/deliveries":{"get":{"tags":["webhooks"],"summary":"List Deliveries","operationId":"list_deliveries_v1_webhooks__webhook_id__deliveries_get","parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Webhook Id"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Page Size"}},{"name":"start_cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_WebhookDeliveryResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/webhooks/{webhook_id}/deliveries/{delivery_id}:replay":{"post":{"tags":["webhooks"],"summary":"Replay Delivery","description":"Re-enqueue a past delivery. Same event_id so receivers dedup correctly.","operationId":"replay_delivery_v1_webhooks__webhook_id__deliveries__delivery_id__replay_post","parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Webhook Id"}},{"name":"delivery_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Delivery Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"IntegrationToken":[]}]}},"/v1/sse/notifications":{"get":{"tags":["realtime"],"summary":"Notifications Sse","description":"Stream the caller's PRIVATE notifications over SSE (spec §22.3, NOV-362).\n\nThe SSE fallback for ``/v1/ws/notifications`` — same auth model, same\nper-user channel derived from the authenticated principal (never a\nclient-supplied id), for environments where WebSockets are blocked. 401 if\nanonymous; 404 if the principal has no attached user (no inbox), mirroring\nthe REST posture (defense-in-depth: the auth layer already rejects\nuserless integration tokens, NOV-299, so real tokens land on 401 first).\nOrg-bound integration tokens receive ONLY their org's frames\n(``user_frame_permitted``); credentials are re-validated mid-stream every\n``USER_CHANNEL_REAUTH_INTERVAL_S`` and the stream ends with\n``subscription.closed`` (``unauthorized``) once they no longer resolve.","operationId":"notifications_sse_v1_sse_notifications_get","parameters":[{"name":"token","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sse":{"get":{"tags":["realtime"],"summary":"Board Sse","description":"Stream a board's realtime events over SSE (spec §22.3, NOV-28).\n\nNOV-392 / spec §9.2: ``?last_sequence=N`` resumes a reconnecting client by\nreplaying events with ``sequence > N`` before live streaming starts — full\nparity with the ``/v1/ws`` gateway (the SSE path previously had ZERO replay\nand silently lost every event created during a reconnect gap). If ``N``\npredates the retention window the server emits a ``snapshot_required`` frame\nand closes, and the client falls back to a full REST refetch.","operationId":"board_sse_v1_sse_get","parameters":[{"name":"board_id","in":"query","required":true,"schema":{"type":"string","title":"Board Id"}},{"name":"token","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token"}},{"name":"last_sequence","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Last Sequence"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/healthz":{"get":{"tags":["meta"],"summary":"Health","operationId":"health_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"object","title":"Response Health Healthz Get"}}}}}}}},"components":{"schemas":{"AccessUser":{"properties":{"object":{"type":"string","title":"Object","default":"user"},"id":{"type":"string","format":"uuid","title":"Id"},"kind":{"type":"string","title":"Kind"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name"},"avatar":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Avatar"}},"additionalProperties":false,"type":"object","required":["id","kind"],"title":"AccessUser","description":"The grantee, shaped like the Notion person reference (§5.1)."},"ActiveWorkspaceResponse":{"properties":{"object":{"type":"string","title":"Object","default":"active_workspace"},"id":{"type":"string","format":"uuid","title":"Id"},"slug":{"type":"string","title":"Slug"}},"type":"object","required":["id","slug"],"title":"ActiveWorkspaceResponse","description":"The workspace a fresh page load lands in (§4.8, NOV-534).\n\nDeliberately just the identity of the workspace: the id the SPA binds to\n``X-Novum-Org`` and the slug it navigates to, so learning where to land\ncosts no second id-to-slug round trip. Everything else about the workspace\nalready comes from ``GET /v1/orgs``."},"AddAgentTokenRequest":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name"},"role":{"type":"string","enum":["member","admin"],"title":"Role","default":"member"}},"type":"object","required":["name"],"title":"AddAgentTokenRequest","description":"Body for POST /v1/orgs/{org_id}/agents/{agent_user_id}/tokens (NOV-190).\n\nMints an additional Integration (credential) owned by an EXISTING agent —\nthe rotation / multi-Lambda-fleet case (spec §4.2, §4.5). Tokens are\nchildren of an agent; adding one does not add a seat (the agent already\ncounts), so there is no billing recompute."},"AddMemberRequest":{"properties":{"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role","default":"member"}},"type":"object","required":["email"],"title":"AddMemberRequest"},"AdminAuditRow":{"properties":{"object":{"type":"string","title":"Object","default":"audit_event"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Org Id"},"actor_kind":{"type":"string","title":"Actor Kind"},"actor_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Actor Id"},"event_type":{"type":"string","title":"Event Type"},"target_kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Kind"},"target_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target Id"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"occurred_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Occurred At"}},"type":"object","required":["id","actor_kind","event_type","created_at"],"title":"AdminAuditRow"},"AdminBillingOrgRow":{"properties":{"object":{"type":"string","title":"Object","default":"billing_org"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"name":{"type":"string","title":"Name"},"slug":{"type":"string","title":"Slug"},"plan":{"type":"string","title":"Plan","default":"free"},"status":{"type":"string","title":"Status","default":"active"},"billable_seats":{"type":"integer","title":"Billable Seats","default":0},"monthly_revenue_usd":{"type":"integer","title":"Monthly Revenue Usd","default":0},"stripe_customer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Customer Id"},"stripe_subscription_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Subscription Id"},"current_period_end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Current Period End"},"cancel_at_period_end":{"type":"boolean","title":"Cancel At Period End","default":false},"seats_synced_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Seats Synced At"},"drift":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Drift"}},"type":"object","required":["org_id","name","slug"],"title":"AdminBillingOrgRow","description":"One row of the admin billing overview (spec §18.10).\n\n``billable_seats`` is recomputed LIVE via ``count_billable_seats`` —\nnever the stale ``billing_seats`` cache. ``monthly_revenue_usd`` is a\nper-kind estimate on Pro (``humans × $1 + billable_agents × $1`` at the\nannual monthly-equivalent display rates — NOV-370), ``0`` on free. ``drift``\nis the reconciliation-cron descriptor (``None`` when reconciled)."},"AdminFeedbackCount":{"properties":{"object":{"type":"string","title":"Object","default":"feedback_count"},"new":{"type":"integer","title":"New","default":0},"poll_interval_seconds":{"type":"integer","title":"Poll Interval Seconds"}},"type":"object","required":["poll_interval_seconds"],"title":"AdminFeedbackCount","description":"``GET /v1/admin/feedback/count`` — the §25.7.1 nav-badge probe."},"AdminFeedbackDetail":{"properties":{"object":{"type":"string","title":"Object","default":"feedback"},"id":{"type":"string","format":"uuid","title":"Id"},"reference":{"type":"string","title":"Reference"},"type":{"type":"string","title":"Type"},"status":{"type":"string","title":"Status"},"severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"exit_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exit Reason"},"rating":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rating"},"surface":{"type":"string","title":"Surface"},"route":{"type":"string","title":"Route"},"content_preview":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Preview"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"org_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Name"},"org_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Slug"},"org_plan":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Plan"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"},"submitter_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Submitter Email"},"submitter_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Submitter Name"},"principal_kind":{"type":"string","title":"Principal Kind"},"jira_status":{"type":"string","title":"Jira Status"},"jira_issue_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jira Issue Key"},"jira_issue_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jira Issue Url"},"has_screenshot":{"type":"boolean","title":"Has Screenshot","default":false},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"expected":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expected"},"org_billing_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Billing Status"},"org_billing_seats":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Org Billing Seats"},"context":{"additionalProperties":true,"type":"object","title":"Context"},"admin_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Admin Notes"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"card_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Card Id"},"automation_run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Automation Run Id"},"app_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"App Version"},"api_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Version"},"jira_attempts":{"type":"integer","title":"Jira Attempts","default":0},"jira_next_attempt_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Jira Next Attempt At"},"jira_last_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jira Last Error"},"screenshot_file_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Screenshot File Id"},"screenshot_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screenshot Url"},"screenshot_url_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Screenshot Url Expires At"}},"type":"object","required":["id","reference","type","status","surface","route","org_id","principal_kind","jira_status","created_time"],"title":"AdminFeedbackDetail","description":"The full row plus everything the §25.7 detail page reads.\n\n``screenshot_url`` is a short-TTL presigned GET forced to\n``Content-Disposition: attachment`` (§25.7 / §25.16 A05) and is ``None``\nwhen there is no screenshot, when the upload never committed, or when the\n§25.3 prune has already dropped the object."},"AdminFeedbackRow":{"properties":{"object":{"type":"string","title":"Object","default":"feedback"},"id":{"type":"string","format":"uuid","title":"Id"},"reference":{"type":"string","title":"Reference"},"type":{"type":"string","title":"Type"},"status":{"type":"string","title":"Status"},"severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"exit_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exit Reason"},"rating":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rating"},"surface":{"type":"string","title":"Surface"},"route":{"type":"string","title":"Route"},"content_preview":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Preview"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"org_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Name"},"org_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Slug"},"org_plan":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Plan"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"},"submitter_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Submitter Email"},"submitter_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Submitter Name"},"principal_kind":{"type":"string","title":"Principal Kind"},"jira_status":{"type":"string","title":"Jira Status"},"jira_issue_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jira Issue Key"},"jira_issue_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jira Issue Url"},"has_screenshot":{"type":"boolean","title":"Has Screenshot","default":false},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At"}},"type":"object","required":["id","reference","type","status","surface","route","org_id","principal_kind","jira_status","created_time"],"title":"AdminFeedbackRow","description":"One feedback row as the §25.7 triage list shows it."},"AdminFeedbackStats":{"properties":{"object":{"type":"string","title":"Object","default":"feedback_stats"},"range_start":{"type":"string","format":"date-time","title":"Range Start"},"range_end":{"type":"string","format":"date-time","title":"Range End"},"total":{"type":"integer","title":"Total","default":0},"volume_by_type":{"additionalProperties":{"type":"integer"},"type":"object","title":"Volume By Type"},"counts_by_status":{"additionalProperties":{"type":"integer"},"type":"object","title":"Counts By Status"},"nps":{"$ref":"#/components/schemas/NpsRollup"},"autopilot":{"$ref":"#/components/schemas/AutopilotRollup"},"unresolved_bugs_by_severity":{"additionalProperties":{"type":"integer"},"type":"object","title":"Unresolved Bugs By Severity"},"jira_sync_failures":{"type":"integer","title":"Jira Sync Failures","default":0},"top_orgs":{"items":{"$ref":"#/components/schemas/OrgVolumeRow"},"type":"array","title":"Top Orgs"},"top_routes":{"items":{"$ref":"#/components/schemas/RouteVolumeRow"},"type":"array","title":"Top Routes"},"response_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Response Rate"},"daily":{"$ref":"#/components/schemas/FeedbackDailySeries"}},"type":"object","required":["range_start","range_end"],"title":"AdminFeedbackStats","description":"``GET /v1/admin/feedback/stats`` (§25.7).\n\n``response_rate`` is the share of rows in the range that have left ``new``\n— the operator's own SLA proxy, and the reason it sits next to the volume\nnumbers rather than inside ``counts_by_status`` where it would have to be\nrecomputed by every reader."},"AdminOrgRow":{"properties":{"object":{"type":"string","title":"Object","default":"organization"},"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"slug":{"type":"string","title":"Slug"},"primary_domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Domain"},"billing_plan":{"type":"string","title":"Billing Plan","default":"free"},"billing_status":{"type":"string","title":"Billing Status","default":"active"},"billing_seats":{"type":"integer","title":"Billing Seats","default":0},"member_count":{"type":"integer","title":"Member Count","default":0},"board_count":{"type":"integer","title":"Board Count","default":0},"last_active_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Active At"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["id","name","slug"],"title":"AdminOrgRow"},"AdminUserRow":{"properties":{"object":{"type":"string","title":"Object","default":"user"},"id":{"type":"string","format":"uuid","title":"Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"avatar_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Avatar Url"},"email_verified":{"type":"boolean","title":"Email Verified","default":false},"disabled":{"type":"boolean","title":"Disabled","default":false},"signup_source":{"type":"string","title":"Signup Source","default":"email"},"last_login_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Login At"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"orgs":{"items":{"$ref":"#/components/schemas/MembershipResponse"},"type":"array","title":"Orgs"}},"type":"object","required":["id"],"title":"AdminUserRow"},"AgentActivity":{"properties":{"agent_name":{"type":"string","title":"Agent Name"},"doing":{"type":"string","title":"Doing"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"}},"additionalProperties":false,"type":"object","required":["agent_name","doing"],"title":"AgentActivity","description":"NOV-86 / NOV-91: \"an agent is working on this card right now\" payload.\n\nStored as ``cards.agent_activity`` JSONB. Set via\n``POST /v1/cards/{id}/agent_activity``, cleared via the matching\nDELETE, the next mutation on the card, or a 10-minute TTL on read\n(NOV-91 lifecycle).\n\nThe model is strict (``extra=\"forbid\"`` + required fields) but\n``started_at`` is optional so legacy blobs written before NOV-91\ndon't fail validation. The outer ``CardResponse.agent_activity``\nvalidator silently downgrades a malformed stored blob to ``None``\nso a bad write from the agent runtime can't 500 every card read."},"AgentActivityEntry":{"properties":{"object":{"type":"string","title":"Object","default":"agent_activity_entry"},"action":{"type":"string","title":"Action"},"label":{"type":"string","title":"Label"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"card_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Card Id"},"outcome":{"type":"string","title":"Outcome"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["action","label","outcome","created_at"],"title":"AgentActivityEntry","description":"One reverse-chron feed row — a single successful agent action."},"AgentActivityResponse":{"properties":{"object":{"type":"string","title":"Object","default":"agent_activity"},"agent_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Agent User Id"},"summary":{"$ref":"#/components/schemas/AgentActivitySummary"},"entries":{"items":{"$ref":"#/components/schemas/AgentActivityEntry"},"type":"array","title":"Entries"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["summary","entries"],"title":"AgentActivityResponse","description":"Response for the per-agent and all-agents activity endpoints (spec §4.7 ledger).\n\n``agent_user_id`` is set for the per-agent view and ``None`` for the org-wide\nrollup. ``entries`` is the cursor-paginated feed; ``next_cursor`` is present\nonly when ``has_more``."},"AgentActivitySummary":{"properties":{"object":{"type":"string","title":"Object","default":"agent_activity_summary"},"by_action":{"additionalProperties":{"type":"integer"},"type":"object","title":"By Action"},"errors":{"type":"integer","title":"Errors"},"window":{"type":"string","title":"Window"}},"type":"object","required":["by_action","errors","window"],"title":"AgentActivitySummary","description":"Rollup line for the activity drawer — \"47 drafts, 3 card-moves, 0 errors · 24h\".\n\n``by_action`` maps a human label (``draft`` / ``card-move`` / ``card-create``\n/ ``card-update``) to its count within ``window``. ``errors`` = ledger\nfailures (0 in MVP) PLUS ``agent.request_denied`` budget denials in-window\n(see :func:`app.services.agent_ledger.agent_activity_summary`)."},"AgentBudgetResponse":{"properties":{"object":{"type":"string","title":"Object","default":"agent_budget"},"agent_user_id":{"type":"string","format":"uuid","title":"Agent User Id"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"writes_per_day":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Writes Per Day"},"requests_per_sec":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Requests Per Sec"},"auto_pause":{"type":"boolean","title":"Auto Pause","default":false},"paused":{"type":"boolean","title":"Paused"},"paused_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paused Reason"},"paused_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Paused At"},"usage":{"$ref":"#/components/schemas/AgentBudgetUsage"}},"type":"object","required":["agent_user_id","paused","usage"],"title":"AgentBudgetResponse","description":"Response for GET / PUT of an agent's budget (spec §4.7 budgets).\n\nSurfaces the two caps plus the read-only kill-switch state (``paused`` /\n``paused_reason`` / ``paused_at`` — the kill switch is mutated only via\n:pause / :resume, but is DISCOVERABLE here per the team-lead ruling) and live\ncounter ``usage``. ``board_id`` is ``null`` for the ORG-WIDE budget and set\nfor a per-board override (NOV-271)."},"AgentBudgetUpdateRequest":{"properties":{"writes_per_day":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Writes Per Day"},"requests_per_sec":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Requests Per Sec"},"auto_pause":{"type":"boolean","title":"Auto Pause","default":false}},"type":"object","title":"AgentBudgetUpdateRequest","description":"Body for PUT /v1/orgs/{org_id}/agents/{agent_user_id}/budget.\n\nPUT-replace semantics: each cap is set to the supplied value; a field set to\n``null`` (or omitted) CLEARS that cap (unlimited / fall back to the flat\nintegration limit). Each must be ``null`` or a non-negative int (``ge=0``);\na negative value fails validation (422). This never touches paused /\nprovenance — that is the kill switch's job (:pause / :resume).\n\n``auto_pause`` (NOV-272) toggles whether tripping this row's writes/day cap\nauto-pauses the agent (its own kill switch). PUT-replace like the caps:\nomitted / ``false`` clears it. It is the one non-cap governance knob set here\nbecause it is a property of the budget, not a manual pause action."},"AgentBudgetUsage":{"properties":{"object":{"type":"string","title":"Object","default":"agent_budget_usage"},"writes_24h":{"type":"integer","title":"Writes 24H"},"requests_last_sec":{"type":"integer","title":"Requests Last Sec"}},"type":"object","required":["writes_24h","requests_last_sec"],"title":"AgentBudgetUsage","description":"Live per-agent counter usage, read from the limiter's Redis windows.\n\nBoth counts come from :func:`app.core.rate_limit.peek_window_count` (read-only\n— surfacing them never consumes budget), and both fail open to ``0`` when\nRedis is unset/unreachable."},"AgentKillSwitchResponse":{"properties":{"object":{"type":"string","title":"Object","default":"agent_kill_switch"},"agent_user_id":{"type":"string","format":"uuid","title":"Agent User Id"},"paused":{"type":"boolean","title":"Paused"},"paused_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Paused At"},"paused_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paused Reason"}},"type":"object","required":["agent_user_id","paused"],"title":"AgentKillSwitchResponse","description":"Response for :pause / :resume (spec §4.7 kill switch).\n\nMirrors the reversible ``agent_budgets`` kill-switch columns so the caller\n(UI / MCP wrapper) can render the new paused state without a re-read."},"AgentPresence":{"properties":{"object":{"type":"string","title":"Object","default":"agent_presence"},"user_id":{"type":"string","title":"User Id"},"display_name":{"type":"string","title":"Display Name"}},"type":"object","required":["user_id","display_name"],"title":"AgentPresence","description":"One live-agent row, returned by GET /v1/orgs/{org_id}/presence/agents."},"AiRunUsageResponse":{"properties":{"object":{"type":"string","title":"Object","default":"ai_run_usage"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"card_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Card Id"},"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"playbook_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Playbook Id"},"automation_run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Automation Run Id"},"model":{"type":"string","title":"Model"},"step_count":{"type":"integer","title":"Step Count"},"tokens_in":{"type":"integer","title":"Tokens In"},"tokens_out":{"type":"integer","title":"Tokens Out"},"cost_estimate_usd":{"type":"string","title":"Cost Estimate Usd"},"status":{"type":"string","title":"Status"},"created_time":{"type":"string","format":"date-time","title":"Created Time"}},"type":"object","required":["id","org_id","board_id","card_id","column_id","playbook_id","automation_run_id","model","step_count","tokens_in","tokens_out","cost_estimate_usd","status","created_time"],"title":"AiRunUsageResponse","description":"One metered Autopilot run in the run-history feed (spec §23.6)."},"AlreadyMemberResponse":{"properties":{"object":{"type":"string","title":"Object","default":"invitation_noop"},"already_member":{"type":"boolean","title":"Already Member","default":true},"membership":{"$ref":"#/components/schemas/MembershipResponse"},"board_grant":{"anyOf":[{"$ref":"#/components/schemas/BoardGrantResponse"},{"type":"null"}]}},"type":"object","required":["membership"],"title":"AlreadyMemberResponse","description":"The §4.8 \"an invitation to an existing member is a no-op\" outcome.\n\nReturned (HTTP **200**, not 201) when the invited address already holds a\nlive membership in the workspace. No invitation row is written and no seat\nmoves — the spec calls this \"a no-op, not a duplicate row\", so it is neither\nan error nor a second invitation. The existing membership rides along so the\ncaller can render \"they're already in\" without a follow-up request."},"AppendBlocksRequest":{"properties":{"children":{"items":{"$ref":"#/components/schemas/BlockInput"},"type":"array","maxItems":100,"minItems":1,"title":"Children"},"after":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"After"}},"additionalProperties":false,"type":"object","required":["children"],"title":"AppendBlocksRequest","description":"`PATCH /v1/blocks/{parent_id}/children` body."},"AuthSessionResponse":{"properties":{"object":{"type":"string","title":"Object","default":"auth_session"},"user":{"$ref":"#/components/schemas/UserResponse"},"memberships":{"items":{"$ref":"#/components/schemas/MembershipResponse"},"type":"array","title":"Memberships"}},"type":"object","required":["user","memberships"],"title":"AuthSessionResponse","description":"Returned by login / verify-email: who you are + your orgs."},"AutomationResponse":{"properties":{"object":{"type":"string","title":"Object","default":"automation"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"name":{"type":"string","title":"Name"},"is_active":{"type":"boolean","title":"Is Active"},"trigger":{"additionalProperties":true,"type":"object","title":"Trigger"},"conditions":{"items":{},"type":"array","title":"Conditions"},"actions":{"items":{},"type":"array","title":"Actions"},"run_as_agent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Run As Agent Id"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"}},"type":"object","required":["id","org_id","board_id","name","is_active","trigger","conditions","actions","run_as_agent_id","created_time","last_edited_time"],"title":"AutomationResponse"},"AutomationRunResponse":{"properties":{"object":{"type":"string","title":"Object","default":"automation_run"},"id":{"type":"string","format":"uuid","title":"Id"},"automation_id":{"type":"string","format":"uuid","title":"Automation Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"card_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Card Id"},"source_sequence":{"type":"integer","title":"Source Sequence"},"status":{"type":"string","title":"Status"},"attempts":{"type":"integer","title":"Attempts"},"next_retry_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Next Retry At"},"chain_depth":{"type":"integer","title":"Chain Depth"},"action_results":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Action Results"},"created_time":{"type":"string","format":"date-time","title":"Created Time"}},"type":"object","required":["id","automation_id","org_id","card_id","source_sequence","status","attempts","next_retry_at","chain_depth","action_results","created_time"],"title":"AutomationRunResponse"},"AutopilotRollup":{"properties":{"up":{"type":"integer","title":"Up","default":0},"down":{"type":"integer","title":"Down","default":0},"ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ratio"},"responses":{"type":"integer","title":"Responses","default":0}},"type":"object","title":"AutopilotRollup","description":"Thumbs up/down over the range. ``ratio`` is up / (up + down)."},"AutopilotRunProvenanceResponse":{"properties":{"object":{"type":"string","title":"Object","default":"autopilot_run_provenance"},"id":{"type":"string","format":"uuid","title":"Id"},"automation_run_id":{"type":"string","format":"uuid","title":"Automation Run Id"},"playbook_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Playbook Id"},"model":{"type":"string","title":"Model"},"status":{"type":"string","title":"Status"},"created_time":{"type":"string","format":"date-time","title":"Created Time"}},"type":"object","required":["id","automation_run_id","playbook_id","model","status","created_time"],"title":"AutopilotRunProvenanceResponse","description":"One Autopilot run that wrote content on a card (NOV-447, §25.9 / §23).\n\nThe card-reader's view of a run, served by\n``GET /v1/cards/{card_id}/autopilot-runs`` to anyone who can read the card.\nWhat it leaves out is the point: ``tokens_in`` / ``tokens_out`` /\n``cost_estimate_usd`` are on :class:`AiRunUsageResponse` and stay behind the\nadmin/owner gate on ``/v1/orgs/{org_id}/ai-run-usage``, because what a run\n*cost* is governance data and what a run *wrote* is card data. ``model`` is\nhere deliberately — \"written by claude-haiku on Tuesday\" is provenance the\nreader is entitled to, and it is not a spend figure.\n\n``automation_run_id`` is non-null by construction (the query filters it),\nbecause it is the whole point: it is what makes the §25.9\n``autopilot_rating`` joinable back against ``ai_run_usage``."},"BatchOp":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"op":{"type":"string","enum":["set","move","delete"],"title":"Op"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties"},"assignees":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Assignees"},"due_date":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Due Date"},"labels":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Labels"},"remove_labels":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Remove Labels"},"is_archived":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Archived"},"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"position":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Position"}},"additionalProperties":false,"type":"object","required":["id","op"],"title":"BatchOp"},"BatchOpResult":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"op":{"type":"string","enum":["set","move","delete"],"title":"Op"},"ok":{"type":"boolean","title":"Ok"},"card":{"anyOf":[{"$ref":"#/components/schemas/CardResponse"},{"type":"null"}]},"error":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Error"}},"additionalProperties":false,"type":"object","required":["id","op","ok"],"title":"BatchOpResult"},"BatchUpdateRequest":{"properties":{"ops":{"items":{"$ref":"#/components/schemas/BatchOp"},"type":"array","maxItems":200,"minItems":1,"title":"Ops"}},"additionalProperties":false,"type":"object","required":["ops"],"title":"BatchUpdateRequest"},"BatchUpdateResponse":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/BatchOpResult"},"type":"array","title":"Results"}},"additionalProperties":false,"type":"object","required":["results"],"title":"BatchUpdateResponse"},"BillingResponse":{"properties":{"object":{"type":"string","title":"Object","default":"billing"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"plan":{"type":"string","title":"Plan"},"status":{"type":"string","title":"Status"},"billable_seats":{"type":"integer","title":"Billable Seats"},"seat_breakdown":{"$ref":"#/components/schemas/SeatBreakdown"},"free_caps":{"$ref":"#/components/schemas/FreeCaps"},"current_period_end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Current Period End"},"cancel_at_period_end":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cancel At Period End"},"has_payment_method":{"type":"boolean","title":"Has Payment Method","default":false},"governance_enabled":{"type":"boolean","title":"Governance Enabled","default":false}},"type":"object","required":["org_id","plan","status","billable_seats","seat_breakdown","free_caps"],"title":"BillingResponse","description":"Billing status object for ``GET /v1/orgs/{org_id}/billing`` (spec §18.9).\n\n``billable_seats`` is the **live** count (``count_billable_seats``), never\nthe denormalized ``billing_seats`` cache. ``seat_breakdown`` is the\nserver-computed humans/agents split (the first-agent-free math lives there,\nnot the client — NOV-189). On a free org ``current_period_end`` and\n``cancel_at_period_end`` are null and ``has_payment_method`` is false."},"BlockInput":{"properties":{"object":{"type":"string","title":"Object","default":"block"},"type":{"type":"string","title":"Type"}},"additionalProperties":true,"type":"object","required":["type"],"title":"BlockInput","description":"One node in a `PATCH /v1/blocks/{id}/children` request body.\n\nMatches Notion's append-children shape: ``{\"object\": \"block\", \"type\":\n\"paragraph\", \"paragraph\": {...}}``. ``object`` is optional — clients\nsometimes omit it."},"BlockParent":{"properties":{"type":{"type":"string","title":"Type"},"card_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Card Id"},"block_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Block Id"}},"additionalProperties":false,"type":"object","required":["type"],"title":"BlockParent","description":"Parent reference for a block — either the card or another block."},"BoardAccessListResponse":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"visibility":{"type":"string","title":"Visibility"},"workspace_access":{"type":"string","title":"Workspace Access","default":"edit"},"permissions":{"additionalProperties":{"type":"string"},"type":"object","title":"Permissions"},"your_role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Your Role"},"can_manage":{"type":"boolean","title":"Can Manage","default":false},"results":{"items":{"$ref":"#/components/schemas/BoardGrantResponse"},"type":"array","title":"Results"}},"additionalProperties":false,"type":"object","required":["visibility","results"],"title":"BoardAccessListResponse","description":"List of grants plus the board's access posture (§4.6).\n\nIncludes the board's ``visibility`` (NOV-195) and the ``workspace_access`` /\n``permissions`` configuration (NOV-216) so a sharing client — REST or an MCP\nagent — has the full picture in one call.\n\nNOV-218: also carries the CALLER's effective board role (``your_role``) and a\nderived ``can_manage`` flag, so a client can gate manage affordances on the\nbackend's real board-role resolution instead of approximating from org role.\n``your_role`` is one of ``viewer``/``commenter``/``editor``/``manager`` (or\n``None`` when the caller has no access — in practice never ``None`` here,\nsince listing already requires viewer); ``can_manage`` is exactly\n``role_satisfies(your_role, \"manager\")``."},"BoardColumnResponse":{"properties":{"object":{"type":"string","title":"Object","default":"board_column"},"id":{"type":"string","format":"uuid","title":"Id"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"name":{"type":"string","title":"Name"},"color":{"type":"string","title":"Color"},"role":{"type":"string","title":"Role"},"position":{"type":"number","title":"Position"},"is_default":{"type":"boolean","title":"Is Default"},"status_group":{"type":"string","title":"Status Group"},"autopilot":{"type":"boolean","title":"Autopilot","default":false},"playbook_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Playbook Id"},"autopilot_label_gate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Autopilot Label Gate"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"},"etag":{"type":"integer","title":"Etag"}},"additionalProperties":false,"type":"object","required":["id","board_id","name","color","role","position","is_default","status_group","created_time","last_edited_time","etag"],"title":"BoardColumnResponse"},"BoardGrantResponse":{"properties":{"object":{"type":"string","title":"Object","default":"board_grant"},"id":{"type":"string","format":"uuid","title":"Id"},"user":{"$ref":"#/components/schemas/AccessUser"},"role":{"type":"string","title":"Role"},"granted_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Granted By"},"granted_at":{"type":"string","format":"date-time","title":"Granted At"}},"additionalProperties":false,"type":"object","required":["id","user","role","granted_at"],"title":"BoardGrantResponse"},"BoardLabelResponse":{"properties":{"object":{"type":"string","title":"Object","default":"board_label"},"name":{"type":"string","title":"Name"},"color":{"type":"string","title":"Color"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["name","color","count"],"title":"BoardLabelResponse","description":"One entry in a board's label vocabulary (NOV-437 / §7).\n\nLabels are a card built-in, not a board schema property. Nothing stops\nsomeone creating a ``multi_select`` property named \"Labels\" — only ``Status``\nis reserved (``app/services/properties.py``) — but the built-in shadows it on\nthe card read, so a schema entry can never describe a card's actual labels.\nGET /v1/boards/{id}/labels aggregates the labels\nactually in use on the board's non-archived cards: one entry per distinct\nname (merged case-insensitively), carrying the name's most-used ``color``\nand the total ``count`` across every color it has been written with."},"BoardQueryRequest":{"properties":{"filter":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Filter"},"sorts":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Sorts"},"page_size":{"type":"integer","title":"Page Size","default":25},"start_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},"additionalProperties":false,"type":"object","title":"BoardQueryRequest"},"BoardResponse":{"properties":{"object":{"type":"string","title":"Object","default":"board"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"name":{"type":"string","title":"Name"},"slug":{"type":"string","title":"Slug"},"description":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Description"},"icon":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Icon"},"cover":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Cover"},"default_view_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Default View Id"},"status_groups":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Status Groups"},"properties":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Properties"},"visibility":{"type":"string","title":"Visibility","default":"org"},"workspace_access":{"type":"string","title":"Workspace Access","default":"edit"},"permissions":{"additionalProperties":{"type":"string"},"type":"object","title":"Permissions"},"property_validation":{"type":"string","title":"Property Validation","default":"permissive"},"has_active_share_links":{"type":"boolean","title":"Has Active Share Links","default":false},"is_archived":{"type":"boolean","title":"Is Archived"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"},"etag":{"type":"integer","title":"Etag"}},"additionalProperties":false,"type":"object","required":["id","org_id","name","slug","status_groups","is_archived","created_time","last_edited_time","etag"],"title":"BoardResponse"},"BoardTemplateColumnPreview":{"properties":{"name":{"type":"string","title":"Name"},"status_group":{"type":"string","title":"Status Group"},"color":{"type":"string","title":"Color"},"role":{"type":"string","title":"Role"}},"type":"object","required":["name","status_group","color","role"],"title":"BoardTemplateColumnPreview","description":"One column in a board-template discovery preview (NOV-350 / §7.8)."},"BoardTemplatePropertyPreview":{"properties":{"name":{"type":"string","title":"Name"},"type":{"type":"string","title":"Type"},"show_on_card":{"type":"boolean","title":"Show On Card","default":false},"options":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Options"}},"type":"object","required":["name","type"],"title":"BoardTemplatePropertyPreview","description":"One property in a board-template discovery preview (NOV-350 / §7.8)."},"BoardTemplateResponse":{"properties":{"object":{"type":"string","title":"Object","default":"board_template"},"key":{"type":"string","title":"Key"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"property_validation":{"type":"string","title":"Property Validation"},"columns":{"items":{"$ref":"#/components/schemas/BoardTemplateColumnPreview"},"type":"array","title":"Columns"},"properties":{"items":{"$ref":"#/components/schemas/BoardTemplatePropertyPreview"},"type":"array","title":"Properties"}},"type":"object","required":["key","name","description","property_validation"],"title":"BoardTemplateResponse","description":"A board-template preset as exposed by GET /v1/board-templates and the\n``list_board_templates`` MCP tool (NOV-350 / §7.8). A curated preview —\nthe actual instantiation happens via POST /v1/boards ``template``."},"BulkFileIssueRequest":{"properties":{"ids":{"items":{"type":"string","format":"uuid"},"type":"array","minItems":1,"title":"Ids"}},"additionalProperties":false,"type":"object","required":["ids"],"title":"BulkFileIssueRequest","description":"``POST /v1/admin/feedback:bulkFileIssue`` — re-drive ≤ 200 rows into Jira.\n\nThe spec delta this ticket carries (see the router docstring): §25.7 gives\nonly a per-row ``:file-issue``, and production accumulates ``skipped`` rows\nfor as long as Jira stays unconfigured. Recovering those one click at a\ntime is not a recovery path."},"BulkResult":{"properties":{"object":{"type":"string","title":"Object","default":"bulk_result"},"requested":{"type":"integer","title":"Requested","default":0},"updated":{"type":"integer","title":"Updated","default":0},"unchanged":{"type":"integer","title":"Unchanged","default":0},"not_found":{"type":"integer","title":"Not Found","default":0},"updated_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Updated Ids"},"not_found_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Not Found Ids"}},"type":"object","title":"BulkResult","description":"What a bulk call actually did — never just ``{\"ok\": true}``.\n\nThe three buckets are disjoint and together account for every submitted id,\nwhich is the property that makes the response auditable: ``updated`` rows\nchanged and wrote an audit row, ``unchanged`` rows matched but already held\nthe target state (idempotent no-ops, no audit row), and ``not_found`` ids\nmatched nothing at all. A caller that submitted 200 ids and reads back 40\nupdated needs to know which of the other two buckets the remaining 160 fell\ninto — \"40 updated\" alone cannot distinguish a no-op from a typo."},"BulkUpdateFeedbackRequest":{"properties":{"ids":{"items":{"type":"string","format":"uuid"},"type":"array","minItems":1,"title":"Ids"},"status":{"type":"string","title":"Status"}},"additionalProperties":false,"type":"object","required":["ids","status"],"title":"BulkUpdateFeedbackRequest","description":"``POST /v1/admin/feedback:bulkUpdate`` — one status across ≤ 200 ids."},"CardAuditActor":{"properties":{"kind":{"type":"string","title":"Kind"},"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Id"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"CardAuditActor","description":"Actor inline-expansion for card audit entries."},"CardAuditEntry":{"properties":{"object":{"type":"string","title":"Object","default":"audit_entry"},"id":{"type":"string","format":"uuid","title":"Id"},"event_type":{"type":"string","title":"Event Type"},"actor":{"$ref":"#/components/schemas/CardAuditActor"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata"},"created_time":{"type":"string","format":"date-time","title":"Created Time"}},"additionalProperties":false,"type":"object","required":["id","event_type","actor","metadata","created_time"],"title":"CardAuditEntry","description":"One row of card audit_log, with the actor joined into display form."},"CardResponse":{"properties":{"object":{"type":"string","title":"Object","default":"card"},"id":{"type":"string","format":"uuid","title":"Id"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"title":{"type":"string","title":"Title"},"properties":{"additionalProperties":true,"type":"object","title":"Properties"},"position":{"type":"number","title":"Position"},"assignees":{"items":{"type":"string"},"type":"array","title":"Assignees"},"due_date":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Due Date"},"labels":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Labels"},"is_archived":{"type":"boolean","title":"Is Archived"},"agent_activity":{"anyOf":[{"$ref":"#/components/schemas/AgentActivity"},{"type":"null"}]},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"},"body_last_edited_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Body Last Edited Time"},"etag":{"type":"integer","title":"Etag"},"attachment_count":{"type":"integer","title":"Attachment Count","default":0},"unique_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unique Id"}},"additionalProperties":false,"type":"object","required":["id","board_id","title","properties","position","assignees","labels","is_archived","created_time","last_edited_time","etag"],"title":"CardResponse"},"CardTemplateResponse":{"properties":{"object":{"type":"string","title":"Object","default":"card_template"},"id":{"type":"string","format":"uuid","title":"Id"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"title":{"type":"string","title":"Title"},"properties":{"additionalProperties":true,"type":"object","title":"Properties"},"body_blocks":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Body Blocks"},"assignees":{"items":{"type":"string"},"type":"array","title":"Assignees"},"labels":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Labels"},"recurrence_rule":{"additionalProperties":true,"type":"object","title":"Recurrence Rule"},"next_materialization_at":{"type":"string","format":"date-time","title":"Next Materialization At"},"until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Until"},"count_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Count Remaining"},"is_active":{"type":"boolean","title":"Is Active"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"},"etag":{"type":"integer","title":"Etag"}},"additionalProperties":false,"type":"object","required":["id","board_id","title","properties","body_blocks","assignees","labels","recurrence_rule","next_materialization_at","is_active","created_time","last_edited_time","etag"],"title":"CardTemplateResponse"},"ChangePasswordRequest":{"properties":{"current_password":{"type":"string","minLength":1,"title":"Current Password"},"new_password":{"type":"string","minLength":1,"title":"New Password"}},"type":"object","required":["current_password","new_password"],"title":"ChangePasswordRequest"},"CheckoutRequest":{"properties":{"interval":{"type":"string","enum":["annual","monthly"],"title":"Interval","default":"annual"}},"type":"object","title":"CheckoutRequest","description":"Body for ``POST /v1/orgs/{org_id}/billing:checkout`` (spec §18.6, NOV-242).\n\n``interval`` selects the billing cadence for the Pro subscription: ``\"annual\"``\n(the promoted default — §18.1) or ``\"monthly\"`` (the deliberate premium). It\ndetermines which of the four per-kind Stripe prices Checkout uses. The body is\noptional on the wire; an omitted body defaults to annual."},"CheckoutResponse":{"properties":{"checkout_url":{"type":"string","title":"Checkout Url"}},"type":"object","required":["checkout_url"],"title":"CheckoutResponse","description":"Response for ``POST /v1/orgs/{org_id}/billing:checkout`` (spec §18.6).\n\nThe owner is redirected to ``checkout_url`` (a Stripe-hosted Checkout\nSession) to enter payment details. The plan flip to Pro is **webhook-driven**\n(``checkout.session.completed`` → §18.7), never set by this endpoint — the\nredirect can be lost, the webhook can't."},"ClaimNextRequest":{"properties":{"lease_ttl_seconds":{"anyOf":[{"type":"integer","maximum":86400.0,"minimum":1.0},{"type":"null"}],"title":"Lease Ttl Seconds"}},"additionalProperties":false,"type":"object","title":"ClaimNextRequest","description":"Body for ``POST /v1/boards/{board_id}/columns/{column_id}:claim-next``.\n\n``lease_ttl_seconds`` overrides the column contract's TTL for this claim\n(and every subsequent renew defaults to it). Absent → the contract's\n``lease_ttl_seconds`` else the platform default."},"ClaimResponse":{"properties":{"object":{"type":"string","title":"Object","default":"lease"},"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Id"},"card_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Card Id"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"lease_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lease Token"},"attempt":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Attempt"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"card":{"anyOf":[{"$ref":"#/components/schemas/CardResponse"},{"type":"null"}]}},"type":"object","title":"ClaimResponse","description":"``:claim-next`` result. All lease fields are Optional so the drained-queue\ncase serializes as ``{object:\"lease\", card:null}`` with a single\ncontent-type (spec §7.5.3)."},"CommentResponse":{"properties":{"object":{"type":"string","title":"Object","default":"comment"},"id":{"type":"string","format":"uuid","title":"Id"},"card_id":{"type":"string","format":"uuid","title":"Card Id"},"author_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Author User Id"},"body":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Body"},"is_archived":{"type":"boolean","title":"Is Archived"},"is_edited":{"type":"boolean","title":"Is Edited"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"},"etag":{"type":"integer","title":"Etag"},"parent":{"additionalProperties":true,"type":"object","title":"Parent","readOnly":true},"created_by":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Created By","readOnly":true},"rich_text":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Rich Text","readOnly":true}},"additionalProperties":false,"type":"object","required":["id","card_id","body","is_archived","is_edited","created_time","last_edited_time","etag","parent","created_by","rich_text"],"title":"CommentResponse"},"CompleteLeaseRequest":{"properties":{"lease_token":{"type":"string","maxLength":64,"minLength":1,"title":"Lease Token"},"output":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Output"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties"}},"additionalProperties":false,"type":"object","required":["lease_token"],"title":"CompleteLeaseRequest","description":"Body for ``POST /v1/leases/{lease_id}:complete``.\n\n``output`` is stored on the lease row (validated against the column's\n``output_schema`` in P1). ``properties`` is an optional card field-patch\napplied through the normal card update path before the card is advanced to\n``on_success_column_id``."},"CompleteResponse":{"properties":{"object":{"type":"string","title":"Object","default":"lease"},"id":{"type":"string","format":"uuid","title":"Id"},"card_id":{"type":"string","format":"uuid","title":"Card Id"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"lease_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lease Token"},"attempt":{"type":"integer","title":"Attempt"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"claimed_at":{"type":"string","format":"date-time","title":"Claimed At"},"last_heartbeat_at":{"type":"string","format":"date-time","title":"Last Heartbeat At"},"released_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Released At"},"release_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Release Reason"},"not_before":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Not Before"},"deadlettered":{"type":"boolean","title":"Deadlettered","default":false},"card":{"$ref":"#/components/schemas/CardResponse"}},"type":"object","required":["id","card_id","board_id","attempt","expires_at","claimed_at","last_heartbeat_at","card"],"title":"CompleteResponse","description":"``:complete`` result — the released lease plus the updated card (which has\nbeen advanced to ``on_success_column_id`` when the contract sets one)."},"ConnectAgentRequest":{"properties":{"display_name":{"type":"string","maxLength":200,"minLength":1,"title":"Display Name"},"role":{"type":"string","title":"Role","default":"member"},"avatar_url":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Avatar Url"},"runtime_url":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Runtime Url"}},"type":"object","required":["display_name"],"title":"ConnectAgentRequest","description":"Body for POST /v1/orgs/{org_id}/agents."},"ConnectAgentResponse":{"properties":{"object":{"type":"string","title":"Object","default":"agent_connection"},"agent":{"$ref":"#/components/schemas/UserResponse"},"membership":{"$ref":"#/components/schemas/MembershipResponse"},"integration":{"$ref":"#/components/schemas/CreateIntegrationResponse"},"agent_dispatch_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Dispatch Secret"}},"type":"object","required":["agent","membership","integration"],"title":"ConnectAgentResponse","description":"Response on agent creation.\n\nThe integration's plaintext token is included exactly once — the admin\nmust capture it now or rotate. Subsequent reads only see ``last_4``."},"CreateAutomationRequest":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"trigger":{"additionalProperties":true,"type":"object","title":"Trigger"},"conditions":{"items":{},"type":"array","title":"Conditions"},"actions":{"items":{},"type":"array","title":"Actions"},"run_as_agent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Run As Agent Id"}},"type":"object","required":["name","trigger","actions"],"title":"CreateAutomationRequest","description":"Body for ``POST /v1/orgs/{org_id}/automations`` (§20.8)."},"CreateBoardInvitationRequest":{"properties":{"email":{"type":"string","title":"Email"},"board_role":{"type":"string","title":"Board Role","default":"commenter"}},"additionalProperties":false,"type":"object","required":["email"],"title":"CreateBoardInvitationRequest","description":"Invite an email address **straight to one board** (NOV-532, §4.6/§4.8).\n\nThe one-action form of \"share this board with my client's reviewer\": it\nmints a ``guest`` invitation that carries the board grant, so accepting\nlands the person on a workspace where that board is already there instead of\nthe empty workspace §4.4 describes.\n\nThere is no org-role field on purpose. A board invitation always mints a\n**guest** — the board-scoped, external-collaborator role. Someone who should\nsee the whole workspace is a member, and that is the workspace invite\n(``POST /v1/orgs/{id}/invitations``), a different decision made in a\ndifferent place by an admin.\n\n``board_role`` is one of ``viewer`` | ``commenter`` | ``editor``.\n``manager`` is not invitable — see\n:data:`app.models.invitation.VALID_INVITATION_BOARD_ROLES`."},"CreateBoardRequest":{"properties":{"name":{"type":"string","title":"Name"},"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug"},"description":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Description"},"icon":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Icon"},"cover":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Cover"},"status_groups":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Status Groups"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties"},"create_default_columns":{"type":"boolean","title":"Create Default Columns","default":true},"visibility":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Visibility"},"workspace_access":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace Access"},"permissions":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Permissions"},"property_validation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Validation"},"template":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Template"},"unique_id_prefix":{"anyOf":[{"type":"string","maxLength":16},{"type":"null"}],"title":"Unique Id Prefix"}},"additionalProperties":false,"type":"object","required":["name"],"title":"CreateBoardRequest"},"CreateCardRequest":{"properties":{"board_id":{"type":"string","format":"uuid","title":"Board Id"},"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"title":{"type":"string","title":"Title"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties"},"position":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Position"},"assignees":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Assignees"},"due_date":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Due Date"},"labels":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Labels"}},"additionalProperties":false,"type":"object","required":["board_id","title"],"title":"CreateCardRequest","description":"POST /v1/cards body.\n\nNOV-104: no ``body_blocks`` field. Cards are created empty; clients\nfollow up with ``PATCH /v1/blocks/{card_id}/children`` to seed body\ncontent. The pre-NOV-104 one-shot seed field was always asymmetric\n(POST accepted it, PATCH rejected it) and the JSONB cache it wrote to\nis gone.\n\nNOV-379: ``column_id`` is optional — when omitted (or explicitly\n``null``) the card lands on the board's default column so it is visible\non the kanban board from birth. A column-less card only results from a\nboard that has no columns."},"CreateCardTemplateRequest":{"properties":{"board_id":{"type":"string","format":"uuid","title":"Board Id"},"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"title":{"type":"string","title":"Title"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties"},"body_blocks":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Body Blocks"},"assignees":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Assignees"},"labels":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Labels"},"recurrence_rule":{"additionalProperties":true,"type":"object","title":"Recurrence Rule"},"next_materialization_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Next Materialization At"},"until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Until"},"count":{"anyOf":[{"type":"integer","maximum":10000.0,"minimum":1.0},{"type":"null"}],"title":"Count"}},"additionalProperties":false,"type":"object","required":["board_id","title","recurrence_rule"],"title":"CreateCardTemplateRequest"},"CreateColumnRequest":{"properties":{"name":{"type":"string","title":"Name"},"status_group":{"type":"string","title":"Status Group"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"position":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Position"}},"additionalProperties":false,"type":"object","required":["name","status_group"],"title":"CreateColumnRequest"},"CreateCommentRequest":{"properties":{"card_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Card Id"},"body":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Body"}},"additionalProperties":true,"type":"object","title":"CreateCommentRequest","description":"Comment-create accepts both native and Notion-shape payloads (NOV-63 B5).\n\nNative:    ``{\"card_id\": \"<uuid>\", \"body\": [<block>, …]}``\nNotion:    ``{\"parent\": {\"page_id\": \"<uuid>\"}, \"rich_text\": [<rt>, …]}``\n\nThe Notion-shape input is normalized at validation time:\n\n- ``parent.page_id`` → ``card_id``\n- ``rich_text`` segments concatenated into a single paragraph block\n  ``[{\"object\": \"block\", \"type\": \"paragraph\", \"paragraph\":\n  {\"rich_text\": [...], \"color\": \"default\"}}]``.\n\nMixed payloads (both shapes present) prefer the native fields and log\nnothing — the API is permissive on extras because pydantic discards\nthem once normalization completes."},"CreateDomainClaimRequest":{"properties":{"domain":{"type":"string","title":"Domain"},"verification_type":{"type":"string","title":"Verification Type","default":"dns_txt"},"allowlist":{"items":{"type":"string"},"type":"array","title":"Allowlist","default":[]},"blocklist":{"items":{"type":"string"},"type":"array","title":"Blocklist","default":[]}},"type":"object","required":["domain"],"title":"CreateDomainClaimRequest"},"CreateFeedbackRequest":{"properties":{"type":{"type":"string","title":"Type"},"route":{"type":"string","title":"Route"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"expected":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expected"},"severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"exit_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exit Reason"},"rating":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rating"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"card_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Card Id"},"automation_run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Automation Run Id"},"context":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Context"},"screenshot_file_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Screenshot File Id"},"app_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"App Version"}},"additionalProperties":false,"type":"object","required":["type","route"],"title":"CreateFeedbackRequest","description":"Body for ``POST /v1/feedback`` (spec §25.4)."},"CreateFeedbackScreenshotUploadRequest":{"properties":{"filename":{"type":"string","maxLength":255,"minLength":1,"title":"Filename"},"content_type":{"type":"string","maxLength":255,"minLength":1,"title":"Content Type"},"size_bytes":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Size Bytes"}},"additionalProperties":false,"type":"object","required":["filename","content_type"],"title":"CreateFeedbackScreenshotUploadRequest","description":"Body for ``POST /v1/feedback/screenshots:presign`` (NOV-442, spec §25.4).\n\nDeliberately NOT a reuse of\n:class:`~app.schemas.file.CreateFileUploadRequest`: that one requires a\n``card_id``, and a feedback screenshot is card-less by construction. The\nthree fields it does share carry the same wire meaning and the same column\nwidths.\n\nNo ``org_id`` — the org comes from the principal (§25.10). ``content_type``\nis a plain ``str`` rather than a ``Literal`` of the four allowed types for\nthe same reason the submission body keeps its enums loose: the allow-list\nlives in :func:`app.services.files._validate_screenshot_content_type`, which\nanswers ``415 unsupported_content_type`` — the §13.1 shape for a rejected\nupload type — where a Literal would answer 422 and split the rule across two\nlayers. ``size_bytes`` is a hint: the real ceiling is the\n``content-length-range`` in the S3 policy, which the client cannot lie past."},"CreateFileUploadRequest":{"properties":{"card_id":{"type":"string","format":"uuid","title":"Card Id"},"filename":{"type":"string","maxLength":255,"minLength":1,"title":"Filename"},"content_type":{"type":"string","maxLength":255,"minLength":1,"title":"Content Type"},"size_bytes":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Size Bytes"}},"additionalProperties":false,"type":"object","required":["card_id","filename","content_type"],"title":"CreateFileUploadRequest","description":"`POST /v1/files:upload` body."},"CreateImportJobRequest":{"properties":{"source":{"type":"string","enum":["notion_api","export_file"],"title":"Source","default":"notion_api"},"token":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Token"},"file_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"File Id"},"database_id":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Database Id"},"column_property":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Column Property"},"whole_workspace":{"type":"boolean","title":"Whole Workspace","default":false}},"type":"object","title":"CreateImportJobRequest","description":"Body for ``POST /v1/orgs/{org_id}/import-jobs`` (spec §21.9 / §21.10).\n\nTwo transports, selected by ``source``:\n\n* **``notion_api``** (default) — ``token`` is the Notion internal-integration\n  token, a transient secret carried ONLY in this request body (never a query\n  string / URL, which proxies log; §21.10). ``file_id`` is forbidden. Two\n  sub-modes: single-DB (``database_id`` names the one database; optional\n  ``column_property`` names the Notion status/select property whose options\n  become columns — blank ⇒ auto-detect) or whole-workspace\n  (``whole_workspace: true`` — walk ALL shared databases → one board each with\n  best-effort inter-DB relation links; ``database_id`` omitted).\n* **``export_file``** (NOV-297) — import a previously-uploaded Notion export\n  ``.zip``. ``file_id`` names the committed File\n  (upload → commit → create; usable as soon as the file is ``status=available``;\n  see the ``:upload`` endpoint). ``token``/``database_id``/``whole_workspace``\n  are forbidden;\n  ``column_property`` is an optional per-database column-driver hint. Always a\n  whole-file import (one board per database in the export).\n\nThese seed the job's ``cursor_state`` exactly as the runner reads it."},"CreateImportUploadRequest":{"properties":{"filename":{"type":"string","maxLength":255,"minLength":1,"title":"Filename"},"content_type":{"type":"string","maxLength":255,"minLength":1,"title":"Content Type","default":"application/zip"},"size_bytes":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Size Bytes"}},"type":"object","required":["filename"],"title":"CreateImportUploadRequest","description":"Body for ``POST /v1/orgs/{org_id}/import-jobs:upload`` (NOV-297, §21.10).\n\nMints a presigned POST for the Notion export ``.zip``. ``content_type`` MUST\nbe ``application/zip`` (415 otherwise). ``size_bytes`` is an optional presign\nhint; the server caps via the configured upload limit regardless. The client\nPUTs the bytes, calls the existing ``POST /v1/files/{id}:commit``, then creates\nthe import job with ``source=export_file`` + this ``file_id`` (importable as\nsoon as the file is ``status=available``)."},"CreateIntegrationRequest":{"properties":{"name":{"type":"string","title":"Name"},"role":{"type":"string","enum":["member","admin"],"title":"Role","default":"member"}},"type":"object","required":["name"],"title":"CreateIntegrationRequest"},"CreateIntegrationResponse":{"properties":{"object":{"type":"string","title":"Object","default":"integration"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"name":{"type":"string","title":"Name"},"last_4":{"type":"string","title":"Last 4"},"role":{"type":"string","title":"Role","default":"member"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"},"created_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created Time"},"token":{"type":"string","title":"Token"}},"type":"object","required":["id","org_id","name","last_4","token"],"title":"CreateIntegrationResponse","description":"Response on creation includes the plaintext token — shown once."},"CreateInvitationRequest":{"properties":{"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role","default":"member"}},"additionalProperties":false,"type":"object","required":["email"],"title":"CreateInvitationRequest","description":"Invite an email address into a workspace (NOV-529, spec §4.8).\n\n``role`` is the org role the invitee will hold *once they accept* — the same\nladder as ``AddMemberRequest`` (``owner`` | ``admin`` | ``member`` |\n``guest``). Nothing here consumes a seat: seats move at accept."},"CreateOrganizationRequest":{"properties":{"name":{"type":"string","title":"Name"},"slug":{"type":"string","title":"Slug"},"primary_domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Domain"}},"type":"object","required":["name","slug"],"title":"CreateOrganizationRequest"},"CreatePlaybookRequest":{"properties":{"name":{"type":"string","title":"Name"},"steps":{"items":{},"type":"array","title":"Steps"},"output_target":{"type":"string","title":"Output Target","default":"append_body"},"on_success_move_to":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"On Success Move To"}},"type":"object","required":["name","steps"],"title":"CreatePlaybookRequest","description":"Body for ``POST /v1/orgs/{org_id}/playbooks`` (§23.4)."},"CreateShareLinkRequest":{"properties":{"role":{"type":"string","title":"Role","default":"viewer"},"label":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Label"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"}},"additionalProperties":false,"type":"object","title":"CreateShareLinkRequest","description":"Create a board share link (NOV-199, spec §4.6).\n\n``role`` is capped at ``commenter`` — a share link never edits structure or\nmanages access. ``label`` is an optional human tag for the management list\n(e.g. \"Client: Acme\"). ``expires_at`` is an optional hard expiry; omit for a\nlink that lives until revoked."},"CreateWebhookRequest":{"properties":{"url":{"type":"string","title":"Url"},"event_types":{"items":{"type":"string"},"type":"array","title":"Event Types"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"notion_handshake":{"type":"boolean","title":"Notion Handshake","default":false}},"type":"object","required":["url"],"title":"CreateWebhookRequest"},"CreateWebhookResponse":{"properties":{"object":{"type":"string","title":"Object","default":"webhook"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"url":{"type":"string","title":"Url"},"event_types":{"items":{"type":"string"},"type":"array","title":"Event Types"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"is_active":{"type":"boolean","title":"Is Active"},"secret_last4":{"type":"string","title":"Secret Last4"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"},"secret":{"type":"string","title":"Secret"}},"type":"object","required":["id","org_id","url","event_types","board_id","is_active","secret_last4","created_time","last_edited_time","secret"],"title":"CreateWebhookResponse","description":"Same as WebhookResponse plus the plaintext secret — returned ONCE."},"DailyAutopilotPoint":{"properties":{"date":{"type":"string","format":"date","title":"Date"},"up":{"type":"integer","title":"Up","default":0},"down":{"type":"integer","title":"Down","default":0},"average":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Average"}},"type":"object","required":["date"],"title":"DailyAutopilotPoint"},"DailyNpsPoint":{"properties":{"date":{"type":"string","format":"date","title":"Date"},"score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score"},"responses":{"type":"integer","title":"Responses","default":0}},"type":"object","required":["date"],"title":"DailyNpsPoint"},"DailyVolumePoint":{"properties":{"date":{"type":"string","format":"date","title":"Date"},"count":{"type":"integer","title":"Count","default":0}},"type":"object","required":["date"],"title":"DailyVolumePoint"},"DataSourceColumn":{"properties":{"object":{"type":"string","title":"Object","default":"board_column"},"id":{"type":"string","format":"uuid","title":"Id"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"name":{"type":"string","title":"Name"},"color":{"type":"string","title":"Color"},"position":{"type":"number","title":"Position"},"is_default":{"type":"boolean","title":"Is Default"},"status_group":{"type":"string","title":"Status Group"},"role":{"type":"string","title":"Role"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"},"etag":{"type":"integer","title":"Etag"}},"additionalProperties":false,"type":"object","required":["id","board_id","name","color","position","is_default","status_group","role","created_time","last_edited_time","etag"],"title":"DataSourceColumn","description":"One column inside a data_source response. Mirrors BoardColumnResponse."},"DataSourceResponse":{"properties":{"object":{"type":"string","title":"Object","default":"data_source"},"id":{"type":"string","format":"uuid","title":"Id"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"columns":{"items":{"$ref":"#/components/schemas/DataSourceColumn"},"type":"array","title":"Columns"},"status_groups":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Status Groups"}},"additionalProperties":false,"type":"object","required":["id","board_id","columns","status_groups"],"title":"DataSourceResponse","description":"Notion's `data_source` concept = board.columns + status_groups bundled.\n\nFor v0 the data_source id equals the board id (we collapse Notion's\ndatabase/data_source split — see spec §5.4)."},"DatabaseResponse":{"properties":{"object":{"type":"string","title":"Object","default":"database"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"name":{"type":"string","title":"Name"},"slug":{"type":"string","title":"Slug"},"description":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Description"},"icon":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Icon"},"cover":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Cover"},"default_view_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Default View Id"},"status_groups":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Status Groups"},"properties":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Properties"},"visibility":{"type":"string","title":"Visibility","default":"org"},"workspace_access":{"type":"string","title":"Workspace Access","default":"edit"},"permissions":{"additionalProperties":{"type":"string"},"type":"object","title":"Permissions"},"property_validation":{"type":"string","title":"Property Validation","default":"permissive"},"has_active_share_links":{"type":"boolean","title":"Has Active Share Links","default":false},"is_archived":{"type":"boolean","title":"Is Archived"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"},"etag":{"type":"integer","title":"Etag"}},"additionalProperties":false,"type":"object","required":["id","org_id","name","slug","status_groups","is_archived","created_time","last_edited_time","etag"],"title":"DatabaseResponse","description":"Notion-compat wrapper for a Board. Identical payload except `object`."},"DomainClaimResponse":{"properties":{"object":{"type":"string","title":"Object","default":"domain_claim"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"domain":{"type":"string","title":"Domain"},"verification_type":{"type":"string","title":"Verification Type"},"verification_code":{"type":"string","title":"Verification Code"},"verified":{"type":"boolean","title":"Verified","default":false},"verified_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Verified At"},"allowlist":{"items":{"type":"string"},"type":"array","title":"Allowlist","default":[]},"blocklist":{"items":{"type":"string"},"type":"array","title":"Blocklist","default":[]},"verification_status":{"type":"string","enum":["pending","failed","verified"],"title":"Verification Status","default":"pending"},"last_checked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Checked At"},"expected_record":{"anyOf":[{"$ref":"#/components/schemas/ExpectedDnsRecord"},{"type":"null"}]}},"type":"object","required":["id","org_id","domain","verification_type","verification_code"],"title":"DomainClaimResponse"},"EmailOutboxRequeueResponse":{"properties":{"object":{"type":"string","title":"Object","default":"email_outbox"},"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status"},"attempts":{"type":"integer","title":"Attempts"},"next_attempt_at":{"type":"string","format":"date-time","title":"Next Attempt At"},"requeued":{"type":"boolean","title":"Requeued"}},"type":"object","required":["id","status","attempts","next_attempt_at","requeued"],"title":"EmailOutboxRequeueResponse","description":"Safe operator-facing state; recipient address and payload stay private."},"ExpectedDnsRecord":{"properties":{"object":{"type":"string","title":"Object","default":"expected_dns_record"},"type":{"type":"string","title":"Type","default":"TXT"},"host":{"type":"string","title":"Host"},"value":{"type":"string","title":"Value"}},"type":"object","required":["host","value"],"title":"ExpectedDnsRecord","description":"The exact DNS record an admin must publish to verify ownership (§4.3.1)."},"FailLeaseRequest":{"properties":{"lease_token":{"type":"string","maxLength":64,"minLength":1,"title":"Lease Token"},"reason":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Reason"},"requeue":{"type":"boolean","title":"Requeue","default":true}},"additionalProperties":false,"type":"object","required":["lease_token"],"title":"FailLeaseRequest","description":"Body for ``POST /v1/leases/{lease_id}:fail``."},"FeedbackDailySeries":{"properties":{"volume":{"items":{"$ref":"#/components/schemas/DailyVolumePoint"},"type":"array","title":"Volume"},"nps":{"items":{"$ref":"#/components/schemas/DailyNpsPoint"},"type":"array","title":"Nps"},"autopilot_rating":{"items":{"$ref":"#/components/schemas/DailyAutopilotPoint"},"type":"array","title":"Autopilot Rating"}},"type":"object","title":"FeedbackDailySeries","description":"The three §25.7 daily series.\n\nThese are the point of the endpoint. A rollup tells you where you are; only\nthe series tells you that last Tuesday's deploy doubled the bug rate. Every\nday in the requested range is present, including the zero days — a gap-free\naxis is what makes a drop visible, and a client that has to synthesize the\nmissing days will get it wrong differently from the next client."},"FeedbackReplyRequest":{"properties":{"message":{"type":"string","maxLength":5000,"minLength":1,"title":"Message"}},"additionalProperties":false,"type":"object","required":["message"],"title":"FeedbackReplyRequest","description":"``POST /v1/admin/feedback/{id}:reply`` — email the submitter (§25.8)."},"FeedbackReplyResult":{"properties":{"object":{"type":"string","title":"Object","default":"feedback_reply"},"queued":{"type":"boolean","title":"Queued","default":true},"to_address":{"type":"string","title":"To Address"},"reference":{"type":"string","title":"Reference"}},"type":"object","required":["to_address","reference"],"title":"FeedbackReplyResult","description":"The reply was ENQUEUED, not sent — §22.7 is a durable outbox.\n\nNamed ``queued`` rather than ``sent`` on purpose: the SES call happens\nout-of-band in the outbox worker, and a response claiming \"sent\" would be a\nlie the operator could act on."},"FeedbackResponse":{"properties":{"object":{"type":"string","title":"Object","default":"feedback"},"id":{"type":"string","format":"uuid","title":"Id"},"reference":{"type":"string","title":"Reference"},"type":{"type":"string","title":"Type"},"status":{"type":"string","title":"Status"},"surface":{"type":"string","title":"Surface"},"severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"exit_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exit Reason"},"rating":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rating"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"expected":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expected"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"card_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Card Id"},"automation_run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Automation Run Id"},"route":{"type":"string","title":"Route"},"screenshot_file_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Screenshot File Id"},"app_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"App Version"},"api_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Version"},"created_time":{"type":"string","format":"date-time","title":"Created Time"}},"additionalProperties":false,"type":"object","required":["id","reference","type","status","surface","route","created_time"],"title":"FeedbackResponse","description":"One feedback row as its submitter sees it (spec §25.4).\n\n``org_id`` / ``user_id`` are omitted for the same reason\n:class:`~app.schemas.notification.NotificationResponse` omits them: the\ncaller IS the owner, so echoing the ownership keys back adds nothing and\nonly widens the surface.\n\n**No ``jira_*`` field at all.** Not the issue key or URL (§25.9: the user\nnever sees an internal issue id — it leaks backlog structure and means\nnothing to a customer), not ``jira_last_error`` (platform-admin-only,\n§25.10), and — since NOV-443 — not ``jira_status`` either. A submitter has\nno use for the state of an integration they cannot see, and every value it\ncan take is either uninformative or actively misleading: ``pending`` reads\nas \"not dealt with yet\", ``skipped`` and ``failed`` describe OUR\nmisconfiguration and OUR outage as though they were something that happened\nto the report. The report is durable in either case (§25.6), which is the\nonly fact the submitter needs, and the ``FB-`` reference is how they quote\nit. The ``jira_*`` columns belong to the §25.7 admin schemas.\n\n``context`` is likewise withheld — it is scrubbed diagnostic state for an\noperator, and re-serving it would hand a client back the server-side\nsnapshot (plan, seat counts) it never supplied."},"FreeCaps":{"properties":{"max_human_seats":{"type":"integer","title":"Max Human Seats"},"max_agents":{"type":"integer","title":"Max Agents"},"max_guests":{"type":"integer","title":"Max Guests","default":0}},"type":"object","required":["max_human_seats","max_agents"],"title":"FreeCaps","description":"Free-tier caps surfaced to the client (spec §18.1 / §18.9).\n\nMirrors ``settings.free_max_human_seats`` / ``free_max_agents`` so the\nfrontend can render the upgrade prompt without hardcoding 5/1. Boards are\nuncapped on Free (NOV-242), so there is no board field.\n\n``max_guests`` (NOV-533, §18.14) is the third Free cap — the one the\n``402 plan_limit_reached`` with ``limit.resource=\"guests\"`` actually cites.\nUnlike its two siblings it is **dynamic**: the guest allowance is\n``max(humans, max_human_seats)``, so a grandfathered Free org with 8 humans\ngets 8 guest slots, not 5. It equals ``seat_breakdown.guest_allowance`` by\nconstruction (both come from the one server-side formula). On **Pro** it is\nstill reported — guests there are counted, never capped — so read it as\n\"the free guest allowance\", which is what caps Free and what bills beyond\non Pro."},"GrantBoardAccessRequest":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"role":{"type":"string","title":"Role"}},"additionalProperties":false,"type":"object","required":["user_id","role"],"title":"GrantBoardAccessRequest"},"GrantOrgCompRequest":{"properties":{"grant_type":{"type":"string","title":"Grant Type"},"reason":{"type":"string","minLength":1,"title":"Reason"},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key"},"free_seat_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Seat Count"},"percent_off":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Percent Off"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"}},"type":"object","required":["grant_type","reason"],"title":"GrantOrgCompRequest","description":"Create-grant request body (POST /v1/admin/orgs/{org_id}/grants).\n\n``grant_type`` selects the per-type spec; the optional fields are validated\nper type by the service (``app/services/grants.py``):\n\n* ``free_seats``        → ``free_seat_count`` required (>= 1).\n* ``percent_off_coupon``→ ``percent_off`` required (1..100).\n* ``comped_subscription``→ always 100% off (``percent_off`` forced to 100).\n* ``plan_override``     → no extra fields.\n\n``idempotency_key`` dedupes a retried create; the server generates a UUID\nwhen absent. ``reason`` is REQUIRED (every comp is auditable)."},"GrantPlatformAdminRequest":{"properties":{"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"role":{"type":"string","title":"Role","default":"support"}},"type":"object","title":"GrantPlatformAdminRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ImportJobResponse":{"properties":{"object":{"type":"string","title":"Object","default":"import_job"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"source":{"type":"string","title":"Source"},"status":{"type":"string","title":"Status"},"attempts":{"type":"integer","title":"Attempts"},"counts":{"additionalProperties":true,"type":"object","title":"Counts"},"error_log":{"items":{},"type":"array","title":"Error Log"},"last_page":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Page"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"}},"type":"object","required":["id","org_id","source","status","attempts","created_time","last_edited_time"],"title":"ImportJobResponse","description":"Status object for an ``ImportJob`` (spec §21.9). NEVER carries the token.\n\n``counts`` (boards/columns/cards/blocks) drives the wizard's progress bar and\n``error_log`` explains a ``partial``/``failed`` run; ``board_id`` is null until\nthe worker creates the board and is the deep-link target on success.\n``last_page`` is the runner's incremental resume marker\n(``cursor_state.last_page``) surfaced for the live \"importing card N…\" line —\nthe raw ``cursor_state`` (which also holds the target ``database_id`` /\n``column_property``) is intentionally NOT echoed; only this progress field is."},"IntegrationResponse":{"properties":{"object":{"type":"string","title":"Object","default":"integration"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"name":{"type":"string","title":"Name"},"last_4":{"type":"string","title":"Last 4"},"role":{"type":"string","title":"Role","default":"member"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"},"created_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created Time"}},"type":"object","required":["id","org_id","name","last_4"],"title":"IntegrationResponse"},"InvitationPreviewResponse":{"properties":{"object":{"type":"string","title":"Object","default":"invitation_preview"},"invitation_id":{"type":"string","format":"uuid","title":"Invitation Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"org_name":{"type":"string","title":"Org Name"},"org_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Slug"},"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role"},"board_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board Name"},"board_role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board Role"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"}},"type":"object","required":["invitation_id","org_id","org_name","email","role","expires_at"],"title":"InvitationPreviewResponse","description":"What an emailed invitation token resolves to, before anyone signs in.\n\nBacks ``GET /v1/public/invitations/{token}``, which the ``/invitations/\n{token}`` deep link in the invite email lands on: it tells the SPA which\nworkspace is asking, which address the invitation is addressed to (so the\nsign-in/sign-up form can be pre-filled and the \"wrong account\" case can be\nexplained), and the invitation id to accept by. It carries no member\ndirectory, no org id beyond what the invitee is being offered, and nothing\nabout whether the address already has an account — presenting a valid token\nmust not become an account-enumeration oracle."},"InvitationResponse":{"properties":{"object":{"type":"string","title":"Object","default":"invitation"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"org_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Name"},"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role"},"status":{"type":"string","title":"Status"},"invited_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Invited By User Id"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"board_role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board Role"},"board_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Board Name"},"last4":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last4"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"created_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created Time"},"accepted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Accepted At"},"declined_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Declined At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"}},"type":"object","required":["id","org_id","email","role","status"],"title":"InvitationResponse","description":"One invitation, as the inviting workspace and the invitee both see it.\n\nDeliberately **never** carries the token — the raw token exists exactly once,\nin the email that was sent, and is not recoverable afterwards (only its\nargon2id hash is stored). ``last4`` is included so an admin can correlate a\nrow with a support request without the token being disclosed, mirroring\n``ShareLinkResponse``.\n\n``org_name`` is populated on the invitee-facing reads\n(``GET /v1/me/invitations``, accept/decline) because an invitee looking at a\nworkspace they have not joined has no other way to learn what they are being\nasked to join; the admin-facing list leaves it ``None`` (the caller already\nknows which workspace they are in)."},"JobContractRequest":{"properties":{"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled"},"lease_ttl_seconds":{"anyOf":[{"type":"integer","maximum":86400.0,"minimum":1.0},{"type":"null"}],"title":"Lease Ttl Seconds"},"max_attempts":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":1.0},{"type":"null"}],"title":"Max Attempts"},"concurrency_limit":{"anyOf":[{"type":"integer","maximum":10000.0,"minimum":1.0},{"type":"null"}],"title":"Concurrency Limit"},"backoff_seconds":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Backoff Seconds"},"on_success_column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"On Success Column Id"},"on_failure_column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"On Failure Column Id"},"input_schema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Input Schema"},"output_schema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Output Schema"}},"additionalProperties":false,"type":"object","title":"JobContractRequest","description":"Body for ``PUT /v1/boards/{board_id}/columns/{column_id}/contract`` — the\ncolumn job-contract admin write (NOV-260, spec §7.5.3 admin / cards-as-jobs\n§4.6 / §9). Every field is Optional; the caller sends only the ones it wants\nto set.\n\n``extra=\"forbid\"`` rejects any unknown key: a typo'd contract field (say\n``lease_ttl`` instead of ``lease_ttl_seconds``) is a configuration error, not\na silently-ignored no-op, so it surfaces as a ``422`` at the write boundary\nrather than quietly failing to take effect.\n\nPUT is a full replace: the service stores exactly the fields the caller\nprovided (see :func:`app.services.leases.set_column_contract_for_principal`).\nType/range checks live here; the cross-field write validation (well-formed\nJSON Schemas, on-board column references) lives in the service."},"JobContractResponse":{"properties":{"object":{"type":"string","title":"Object","default":"job_contract"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"column_id":{"type":"string","format":"uuid","title":"Column Id"},"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled"},"lease_ttl_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lease Ttl Seconds"},"max_attempts":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Attempts"},"concurrency_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Concurrency Limit"},"backoff_seconds":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Backoff Seconds"},"on_success_column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"On Success Column Id"},"on_failure_column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"On Failure Column Id"},"input_schema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Input Schema"},"output_schema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Output Schema"}},"type":"object","required":["board_id","column_id"],"title":"JobContractResponse","description":"The column's stored job contract on the wire (NOV-260, spec §7.5.3 admin).\n\nReturned by ``GET``/``PUT /v1/boards/{board_id}/columns/{column_id}/contract``.\nEchoes the fields as STORED on ``board_columns.job_contract`` — a field the\ncolumn never set reads back as ``null`` (the read side, not this response,\napplies platform defaults). A column with no contract at all serializes as\nthe empty shape (every field ``null``), so a fresh column and a\nfully-cleared one look identical (both \"not a queue\")."},"LeaseResponse":{"properties":{"object":{"type":"string","title":"Object","default":"lease"},"id":{"type":"string","format":"uuid","title":"Id"},"card_id":{"type":"string","format":"uuid","title":"Card Id"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"lease_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lease Token"},"attempt":{"type":"integer","title":"Attempt"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"claimed_at":{"type":"string","format":"date-time","title":"Claimed At"},"last_heartbeat_at":{"type":"string","format":"date-time","title":"Last Heartbeat At"},"released_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Released At"},"release_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Release Reason"},"not_before":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Not Before"},"deadlettered":{"type":"boolean","title":"Deadlettered","default":false}},"type":"object","required":["id","card_id","board_id","attempt","expires_at","claimed_at","last_heartbeat_at"],"title":"LeaseResponse","description":"The lease row on the wire — no nested card. Returned by ``:renew`` and\n``:fail``."},"ListDatabasesRequest":{"properties":{"token":{"type":"string","minLength":1,"title":"Token"}},"type":"object","required":["token"],"title":"ListDatabasesRequest","description":"Body for ``POST /v1/orgs/{org_id}/import-jobs:databases`` (spec §21.9/§21.10).\n\nToken-in-body (not a GET query string) so the transient Notion secret is\nnever written to an access log. The token is used once to list the databases\nthe integration can see and is then dropped — never stored."},"ListDatabasesResponse":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/NotionDatabaseSummary"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ListDatabasesResponse","description":"Envelope for the transient-token database listing (spec §21.9)."},"LoginRequest":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"}},"type":"object","required":["email","password"],"title":"LoginRequest"},"MakeRecurringRequest":{"properties":{"recurrence_rule":{"additionalProperties":true,"type":"object","title":"Recurrence Rule"},"until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Until"},"count":{"anyOf":[{"type":"integer","maximum":10000.0,"minimum":1.0},{"type":"null"}],"title":"Count"},"next_materialization_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Next Materialization At"}},"additionalProperties":false,"type":"object","required":["recurrence_rule"],"title":"MakeRecurringRequest","description":"POST /v1/cards/{id}:make-recurring body.\n\nTurns an existing card into a template anchored at the existing card's\ndue_date.start (or `next_materialization_at` if provided). The original\ncard is left in place — the template emits future occurrences."},"MembershipResponse":{"properties":{"object":{"type":"string","title":"Object","default":"membership"},"id":{"type":"string","format":"uuid","title":"Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"role":{"type":"string","title":"Role"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"kind":{"type":"string","title":"Kind","default":"human"},"joined_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Joined At"},"last_signed_in_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Signed In At"}},"type":"object","required":["id","user_id","org_id","role"],"title":"MembershipResponse"},"MoveBlockRequest":{"properties":{"parent":{"$ref":"#/components/schemas/BlockParent"},"after":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"After"}},"additionalProperties":false,"type":"object","required":["parent"],"title":"MoveBlockRequest","description":"`POST /v1/blocks/{block_id}:move` body (NOV-498).\n\nMirrors ``POST /v1/cards/{id}:move``. ``parent`` names the destination —\nanother block in the same card, or the card itself (top level). ``after``\nnames the sibling to land behind.\n\n**``after=None`` means FIRST**, which is the OPPOSITE of ``after`` on\n``AppendBlocksRequest`` above (there it means \"at the end\", Notion's\nbehaviour). The asymmetry is deliberate and documented in spec §8.2:\n\"make this the first child\" has no other spelling, while \"make it last\" is\njust ``after=<current last sibling>``."},"MoveCardRequest":{"properties":{"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"position":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Position"}},"additionalProperties":false,"type":"object","title":"MoveCardRequest"},"NotificationPreferencesResponse":{"properties":{"email":{"additionalProperties":{"type":"boolean"},"propertyNames":{"enum":["card_assigned","automation_notify"]},"type":"object","title":"Email"}},"type":"object","title":"NotificationPreferencesResponse","description":"Effective per-channel notification preferences (NOV-364, spec §22.3).\n\n``email`` maps EVERY v1 notification type to its EFFECTIVE boolean with\ndefaults resolved server-side (absence of a stored override => the type's\ndefault, ON in v1) — so the settings UI never re-derives the default logic.\nIn-app is intentionally omitted: it has no opt-out in v1 (always on)."},"NotificationResponse":{"properties":{"object":{"type":"string","title":"Object","default":"notification"},"id":{"type":"string","format":"uuid","title":"Id"},"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"body":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Body"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"card_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Card Id"},"comment_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Comment Id"},"actor_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Actor Id"},"read_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Read At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"read":{"type":"boolean","title":"Read","readOnly":true}},"additionalProperties":false,"type":"object","required":["id","type","title","created_at","read"],"title":"NotificationResponse"},"NotionDatabaseSummary":{"properties":{"id":{"type":"string","title":"Id"},"title":{"type":"string","title":"Title"}},"type":"object","required":["id","title"],"title":"NotionDatabaseSummary","description":"One pickable Notion database: its id + human title (spec §21.9)."},"NpsRollup":{"properties":{"score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score"},"promoters":{"type":"integer","title":"Promoters","default":0},"passives":{"type":"integer","title":"Passives","default":0},"detractors":{"type":"integer","title":"Detractors","default":0},"responses":{"type":"integer","title":"Responses","default":0},"average_rating":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Average Rating"}},"type":"object","title":"NpsRollup","description":"``(promoters − detractors) / total × 100`` over the range (§25.7).\n\nThe bands are the standard NPS definition — promoters 9-10, passives 7-8,\ndetractors 0-6 — and are deliberately NOT read from\n``feedback_nps_detractor_max``. That setting is the §25.8 *alerting*\nsensitivity; turning the pager down must not retroactively rewrite the\nscore. ``score`` is ``None`` with no responses, never ``0``: \"nobody\nanswered\" and \"answered, net zero\" are different facts."},"OrgGrantRow":{"properties":{"object":{"type":"string","title":"Object","default":"org_grant"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"grant_type":{"type":"string","title":"Grant Type"},"status":{"type":"string","title":"Status"},"reason":{"type":"string","title":"Reason"},"granted_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Granted By User Id"},"granted_at":{"type":"string","format":"date-time","title":"Granted At"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"},"revoked_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Revoked By User Id"},"free_seat_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Seat Count"},"percent_off":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Percent Off"},"stripe_object_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Object Id"},"idempotency_key":{"type":"string","title":"Idempotency Key"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata"}},"type":"object","required":["id","org_id","grant_type","status","reason","granted_at","idempotency_key"],"title":"OrgGrantRow","description":"One ``org_grants`` ledger row (response shape)."},"OrgVolumeRow":{"properties":{"org_id":{"type":"string","format":"uuid","title":"Org Id"},"org_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Name"},"org_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Slug"},"count":{"type":"integer","title":"Count","default":0}},"type":"object","required":["org_id"],"title":"OrgVolumeRow"},"OrganizationResponse":{"properties":{"object":{"type":"string","title":"Object","default":"organization"},"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"slug":{"type":"string","title":"Slug"},"primary_domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Domain"},"billing_plan":{"type":"string","title":"Billing Plan","default":"free"},"billing_status":{"type":"string","title":"Billing Status","default":"active"},"billing_seats":{"type":"integer","title":"Billing Seats","default":0},"default_board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Default Board Id"}},"type":"object","required":["id","name","slug"],"title":"OrganizationResponse"},"PageResponse":{"properties":{"object":{"type":"string","title":"Object","default":"page"},"id":{"type":"string","format":"uuid","title":"Id"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"title":{"type":"string","title":"Title"},"properties":{"additionalProperties":true,"type":"object","title":"Properties"},"position":{"type":"number","title":"Position"},"assignees":{"items":{"type":"string"},"type":"array","title":"Assignees"},"due_date":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Due Date"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"labels":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Labels"},"is_archived":{"type":"boolean","title":"Is Archived"},"agent_activity":{"anyOf":[{"$ref":"#/components/schemas/AgentActivity"},{"type":"null"}]},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"},"body_last_edited_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Body Last Edited Time"},"etag":{"type":"integer","title":"Etag"},"attachment_count":{"type":"integer","title":"Attachment Count","default":0},"unique_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unique Id"}},"additionalProperties":false,"type":"object","required":["id","board_id","title","properties","position","assignees","labels","is_archived","created_time","last_edited_time","etag"],"title":"PageResponse","description":"Notion-compat wrapper for a Card (NOV-32, NOV-78).\n\n``properties`` is a Notion-shape **superset**: the synthesized built-ins\n(``Name``, ``Status``, ``Assignees``, ``Due date``, ``Labels``) are built\nin the router via ``app.services.cards.build_notion_properties`` and\nmerged with user-set keys from ``card.properties`` JSONB (user wins on\ncollisions). The column lookup needs a DB session, so this can't be a\npure ``@computed_field`` on the schema — the router constructs the dict\nand passes it via ``model_copy``.\n\nNotion-trained clients read ``properties.Name.title[0].plain_text`` and\n``properties.Status.status.name``; the native top-level fields below\nstay populated for the existing Novum frontend (NOV-78 is read-side\nadditive, frontend migration is a separate ticket)."},"PaginatedResponse_AdminAuditRow_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/AdminAuditRow"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[AdminAuditRow]"},"PaginatedResponse_AdminBillingOrgRow_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/AdminBillingOrgRow"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[AdminBillingOrgRow]"},"PaginatedResponse_AdminFeedbackRow_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/AdminFeedbackRow"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[AdminFeedbackRow]"},"PaginatedResponse_AdminOrgRow_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/AdminOrgRow"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[AdminOrgRow]"},"PaginatedResponse_AdminUserRow_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/AdminUserRow"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[AdminUserRow]"},"PaginatedResponse_AgentPresence_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/AgentPresence"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[AgentPresence]"},"PaginatedResponse_AiRunUsageResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/AiRunUsageResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[AiRunUsageResponse]"},"PaginatedResponse_AutomationResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/AutomationResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[AutomationResponse]"},"PaginatedResponse_AutomationRunResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/AutomationRunResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[AutomationRunResponse]"},"PaginatedResponse_AutopilotRunProvenanceResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/AutopilotRunProvenanceResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[AutopilotRunProvenanceResponse]"},"PaginatedResponse_BoardColumnResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/BoardColumnResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[BoardColumnResponse]"},"PaginatedResponse_BoardLabelResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/BoardLabelResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[BoardLabelResponse]"},"PaginatedResponse_BoardResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/BoardResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[BoardResponse]"},"PaginatedResponse_BoardTemplateResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/BoardTemplateResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[BoardTemplateResponse]"},"PaginatedResponse_CardAuditEntry_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/CardAuditEntry"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[CardAuditEntry]"},"PaginatedResponse_CardResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/CardResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[CardResponse]"},"PaginatedResponse_CardTemplateResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/CardTemplateResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[CardTemplateResponse]"},"PaginatedResponse_DomainClaimResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/DomainClaimResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[DomainClaimResponse]"},"PaginatedResponse_ImportJobResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/ImportJobResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[ImportJobResponse]"},"PaginatedResponse_IntegrationResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/IntegrationResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[IntegrationResponse]"},"PaginatedResponse_InvitationResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/InvitationResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[InvitationResponse]"},"PaginatedResponse_LeaseResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/LeaseResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[LeaseResponse]"},"PaginatedResponse_MembershipResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/MembershipResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[MembershipResponse]"},"PaginatedResponse_OrgGrantRow_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/OrgGrantRow"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[OrgGrantRow]"},"PaginatedResponse_OrganizationResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/OrganizationResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[OrganizationResponse]"},"PaginatedResponse_PlatformAdminRow_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/PlatformAdminRow"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[PlatformAdminRow]"},"PaginatedResponse_PlaybookResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/PlaybookResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[PlaybookResponse]"},"PaginatedResponse_SearchHitResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/SearchHitResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[SearchHitResponse]"},"PaginatedResponse_ShareLinkResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/ShareLinkResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[ShareLinkResponse]"},"PaginatedResponse_UserSessionResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/UserSessionResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[UserSessionResponse]"},"PaginatedResponse_WebhookDeliveryResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/WebhookDeliveryResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[WebhookDeliveryResponse]"},"PaginatedResponse_WebhookResponse_":{"properties":{"object":{"type":"string","title":"Object","default":"list"},"results":{"items":{"$ref":"#/components/schemas/WebhookResponse"},"type":"array","title":"Results"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"page_size":{"type":"integer","title":"Page Size","default":25}},"type":"object","required":["results"],"title":"PaginatedResponse[WebhookResponse]"},"PasswordPolicy":{"properties":{"object":{"type":"string","title":"Object","default":"password_policy"},"min_length":{"type":"integer","title":"Min Length"},"require_letter_and_digit":{"type":"boolean","title":"Require Letter And Digit"}},"type":"object","required":["min_length","require_letter_and_digit"],"title":"PasswordPolicy","description":"The rules ``app.services.auth.validate_password_strength`` enforces.\n\nBuilt by :func:`app.services.auth.password_policy` from the same settings\nthe validator reads, so the published policy cannot describe a rule the API\ndoes not actually apply."},"PasswordResetConfirmRequest":{"properties":{"token":{"type":"string","title":"Token"},"new_password":{"type":"string","minLength":1,"title":"New Password"}},"type":"object","required":["token","new_password"],"title":"PasswordResetConfirmRequest"},"PasswordResetRequest":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"PasswordResetRequest"},"PauseAgentRequest":{"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","title":"PauseAgentRequest","description":"Body for POST /v1/orgs/{org_id}/agents/{agent_user_id}:pause.\n\n``reason`` is optional and free-form; the handler trims it to fit the\n``agent_budgets.paused_reason`` ``varchar(200)`` column. The body itself is\noptional (``:pause`` with no body is allowed)."},"PlatformAdminRow":{"properties":{"object":{"type":"string","title":"Object","default":"platform_admin"},"id":{"type":"string","format":"uuid","title":"Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"role":{"type":"string","title":"Role"},"granted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Granted At"},"granted_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Granted By User Id"}},"type":"object","required":["id","user_id","role"],"title":"PlatformAdminRow"},"PlaybookResponse":{"properties":{"object":{"type":"string","title":"Object","default":"playbook"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"name":{"type":"string","title":"Name"},"steps":{"items":{},"type":"array","title":"Steps"},"output_target":{"type":"string","title":"Output Target"},"on_success_move_to":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"On Success Move To"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"}},"type":"object","required":["id","org_id","name","steps","output_target","on_success_move_to","created_time","last_edited_time"],"title":"PlaybookResponse"},"PortalResponse":{"properties":{"portal_url":{"type":"string","title":"Portal Url"}},"type":"object","required":["portal_url"],"title":"PortalResponse","description":"Response for ``POST /v1/orgs/{org_id}/billing:portal`` (spec §18.6).\n\nThe owner is redirected to ``portal_url`` (a Stripe-hosted Customer Portal\nSession) to manage their subscription — cancel, update payment method, view\ninvoices. Requires an existing ``stripe_customer_id`` (``409 no_subscription``\nif absent)."},"PropertyItemResponse":{"properties":{"object":{"type":"string","title":"Object","default":"property_item"},"id":{"type":"string","title":"Id"},"type":{"type":"string","title":"Type"},"value":{"title":"Value"}},"additionalProperties":false,"type":"object","required":["id","type","value"],"title":"PropertyItemResponse","description":"Single property fetched from a card. Notion's `property_item` shape."},"PublicAgentActivityResponse":{"properties":{"object":{"type":"string","title":"Object","default":"public_agent_activity"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"summary":{"$ref":"#/components/schemas/AgentActivitySummary"},"entries":{"items":{"$ref":"#/components/schemas/AgentActivityEntry"},"type":"array","title":"Entries"},"has_more":{"type":"boolean","title":"Has More","default":false},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["board_id","summary","entries"],"title":"PublicAgentActivityResponse","description":"Client-shareable, read-only agent-activity report for ONE board (NOV-271).\n\nServed on the seatless share-link surface (``/v1/public/...``) so an agency\ncan show a CLIENT holding a viewer/commenter share-link token exactly what\nagents did on THEIR board — the \"run bots on a client board and show that\nclient what happened\" trust flow (spec §4.6 + §4.7). Deliberately narrower\nthan :class:`AgentActivityResponse`: it is ALWAYS board-scoped (``board_id``\nis the bound board, never org-wide) and all-agents (no ``agent_user_id`` — a\nclient sees the board's activity, not internal per-agent breakdowns). No\n``page_size`` — the feed is still cursor-paginated via ``next_cursor``."},"PublicCommentRequest":{"properties":{"body":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Body"}},"additionalProperties":false,"type":"object","required":["body"],"title":"PublicCommentRequest","description":"A comment posted through a ``commenter`` share link (NOV-199).\n\nOnly the block ``body`` is accepted — the card is fixed by the path and the\nauthor is the (anonymous) link, never a User. Emptiness is enforced in the\ncomment service."},"PublicConfigResponse":{"properties":{"object":{"type":"string","title":"Object","default":"public_config"},"password":{"$ref":"#/components/schemas/PasswordPolicy"}},"type":"object","required":["password"],"title":"PublicConfigResponse","description":"Envelope for the unauthenticated runtime-config read."},"PurgeBoardPropertyRequest":{"properties":{"name":{"type":"string","title":"Name"}},"additionalProperties":false,"type":"object","required":["name"],"title":"PurgeBoardPropertyRequest","description":"NOV-459 (§7.1): body of ``POST /v1/boards/{id}/properties:purge``.\n\nNames the ARCHIVED property definition to delete permanently. Separate from\nthe properties patch on purpose: ``{\"properties\": {\"ID\": null}}`` archives a\n``unique_id`` property (recoverable — re-adding the name reinstates the same\ndefinition, id, prefix and counter), and this is the one action that is not."},"RenewLeaseRequest":{"properties":{"lease_token":{"type":"string","maxLength":64,"minLength":1,"title":"Lease Token"},"lease_ttl_seconds":{"anyOf":[{"type":"integer","maximum":86400.0,"minimum":1.0},{"type":"null"}],"title":"Lease Ttl Seconds"}},"additionalProperties":false,"type":"object","required":["lease_token"],"title":"RenewLeaseRequest","description":"Body for ``POST /v1/leases/{lease_id}:renew`` (and ``:heartbeat``)."},"ResendVerificationRequest":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"ResendVerificationRequest"},"RevokeAgentTokensResponse":{"properties":{"object":{"type":"string","title":"Object","default":"agent_tokens_revoked"},"agent_user_id":{"type":"string","format":"uuid","title":"Agent User Id"},"revoked_count":{"type":"integer","title":"Revoked Count"}},"type":"object","required":["agent_user_id","revoked_count"],"title":"RevokeAgentTokensResponse","description":"Response for the hard, irreversible :revoke_tokens variant (spec §4.7).\n\n``revoked_count`` is how many ``Integration`` credentials were deleted for\nthe agent in this org. Unlike :pause, this sets no paused/disabled state — it\nonly wipes credentials."},"RevokeOrgGrantRequest":{"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","title":"RevokeOrgGrantRequest","description":"Optional revoke body — an operator note recorded in the audit trail."},"RouteVolumeRow":{"properties":{"route":{"type":"string","title":"Route"},"count":{"type":"integer","title":"Count","default":0}},"type":"object","required":["route"],"title":"RouteVolumeRow"},"SearchHitResponse":{"properties":{"object":{"type":"string","title":"Object","default":"card"},"id":{"type":"string","format":"uuid","title":"Id"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"column_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Column Id"},"title":{"type":"string","title":"Title"},"properties":{"additionalProperties":true,"type":"object","title":"Properties"},"position":{"type":"number","title":"Position"},"assignees":{"items":{"type":"string"},"type":"array","title":"Assignees"},"due_date":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Due Date"},"labels":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Labels"},"is_archived":{"type":"boolean","title":"Is Archived"},"agent_activity":{"anyOf":[{"$ref":"#/components/schemas/AgentActivity"},{"type":"null"}]},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"},"body_last_edited_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Body Last Edited Time"},"etag":{"type":"integer","title":"Etag"},"attachment_count":{"type":"integer","title":"Attachment Count","default":0},"unique_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unique Id"},"_search":{"$ref":"#/components/schemas/SearchResultMeta"}},"additionalProperties":false,"type":"object","required":["id","board_id","title","properties","position","assignees","labels","is_archived","created_time","last_edited_time","etag","_search"],"title":"SearchHitResponse","description":"One ``POST /v1/search`` result: a card PLUS its relevance block (NOV-457).\n\nA search hit is a full ``CardResponse`` with one extra key — it is NOT a\ndifferent object, so this subclasses the card rather than wrapping it. That\nkeeps the wire flat (the hit *is* the card) and means every card field stays\nin one place; adding a field to ``CardResponse`` reaches search for free.\n\n``_search`` cannot be a Python field name — pydantic reserves the leading\nunderscore for private attributes — so the field is ``search`` carrying an\nexplicit alias. FastAPI serializes response models with ``by_alias=True``,\nand ``populate_by_name`` (inherited from ``APIModel``) lets the service's\nhand-built ``{\"_search\": ...}`` dict validate, so the key crosses the wire\nunchanged in both directions."},"SearchRequest":{"properties":{"query":{"type":"string","maxLength":500,"minLength":1,"title":"Query"},"types":{"anyOf":[{"items":{"type":"string","const":"card"},"type":"array"},{"type":"null"}],"title":"Types"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"page_size":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":1.0},{"type":"null"}],"title":"Page Size"},"start_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Cursor"}},"additionalProperties":false,"type":"object","required":["query"],"title":"SearchRequest"},"SearchResultMeta":{"properties":{"score":{"type":"number","title":"Score"},"highlight":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Highlight"}},"additionalProperties":false,"type":"object","required":["score"],"title":"SearchResultMeta","description":"Search-only envelope attached to result objects under the `_search` key.\n\nKept off the canonical Card shape so result consumers can ignore it and\ncallers wanting ranking signal can pluck it out."},"SeatBreakdown":{"properties":{"humans":{"type":"integer","title":"Humans"},"agents":{"type":"integer","title":"Agents"},"billable_agents":{"type":"integer","title":"Billable Agents"},"guests":{"type":"integer","title":"Guests","default":0},"guest_allowance":{"type":"integer","title":"Guest Allowance","default":0},"free_guests":{"type":"integer","title":"Free Guests","default":0},"billable_guests":{"type":"integer","title":"Billable Guests","default":0}},"type":"object","required":["humans","agents","billable_agents"],"title":"SeatBreakdown","description":"Seat split for the People/Billing UI (spec §18.9 / §18.14, NOV-189/NOV-533).\n\nComputed server-side from ``billing.seat_breakdown`` so neither the \"first\nagent free\" rule (§18.1) nor the guest allowance (§18.14) is ever re-derived\nin the frontend — clients render this split **verbatim**.\n\n* ``humans`` — non-guest human members. Guests are NOT included (§18.14).\n* ``guests`` — ``role='guest'`` members (§4.4 external collaborators).\n* ``guest_allowance`` = ``max(humans, free_caps.max_human_seats)`` — the\n  free guest room, which floats with paid headcount.\n* ``free_guests`` / ``billable_guests`` — guests inside / beyond it. A\n  billable guest bills on the **human** seat price; there is no guest SKU.\n* ``billable_agents`` = ``max(0, agents - 1)``.\n\nThe top-level ``billable_seats`` on :class:`BillingResponse` equals\n``humans + billable_guests + billable_agents``. §18.14: \"the org sees the\ncount before it is charged for it\" — this is that surface."},"SetAgentActivityRequest":{"properties":{"agent_name":{"type":"string","maxLength":200,"minLength":1,"title":"Agent Name"},"doing":{"type":"string","maxLength":500,"minLength":1,"title":"Doing"}},"additionalProperties":false,"type":"object","required":["agent_name","doing"],"title":"SetAgentActivityRequest","description":"Body for POST /v1/cards/{card_id}/agent_activity."},"SetPasswordRequest":{"properties":{"new_password":{"type":"string","minLength":1,"title":"New Password"}},"type":"object","required":["new_password"],"title":"SetPasswordRequest","description":"OAuth-only users who want to enable email/password login alongside\ntheir existing identity provider. Idempotent — once they have a password,\nthey must use ``POST /v1/me/password`` to change it."},"ShareLinkCreatedResponse":{"properties":{"object":{"type":"string","title":"Object","default":"board_share_link"},"id":{"type":"string","format":"uuid","title":"Id"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"role":{"type":"string","title":"Role"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"token_last4":{"type":"string","title":"Token Last4"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"},"token":{"type":"string","title":"Token"},"url":{"type":"string","title":"Url"}},"additionalProperties":false,"type":"object","required":["id","board_id","role","token_last4","created_time","last_edited_time","token","url"],"title":"ShareLinkCreatedResponse","description":"Returned ONCE from create — carries the raw token + ready-to-share URL.\n\n``token`` and ``url`` are present only on this create response and are never\nretrievable again (only the argon2id hash is stored)."},"ShareLinkResponse":{"properties":{"object":{"type":"string","title":"Object","default":"board_share_link"},"id":{"type":"string","format":"uuid","title":"Id"},"board_id":{"type":"string","format":"uuid","title":"Board Id"},"role":{"type":"string","title":"Role"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"token_last4":{"type":"string","title":"Token Last4"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"}},"additionalProperties":false,"type":"object","required":["id","board_id","role","token_last4","created_time","last_edited_time"],"title":"ShareLinkResponse","description":"A share link's management-side view — never includes the raw token.\n\n``token_last4`` identifies the link in the UI; the full token is shown only\nonce, in :class:`ShareLinkCreatedResponse`."},"SignupRequest":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"type":"object","required":["email","password"],"title":"SignupRequest"},"SurveyDecisionResponse":{"properties":{"eligible":{"type":"boolean","title":"Eligible"},"last_shown_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Shown At"}},"additionalProperties":false,"type":"object","required":["eligible"],"title":"SurveyDecisionResponse","description":"Whether one triggered survey may be shown right now (NOV-447, §25.9).\n\n``last_shown_at`` rides along with the verdict so the client can show a\n\"you last answered this in May\" affordance, and so a frontend test can\nassert the cap round-tripped, without a second read of the preferences blob."},"SurveyEligibilityResponse":{"properties":{"object":{"type":"string","title":"Object","default":"survey_eligibility"},"nps":{"$ref":"#/components/schemas/SurveyDecisionResponse"},"upgrade_exit":{"$ref":"#/components/schemas/SurveyDecisionResponse"}},"additionalProperties":false,"type":"object","required":["nps","upgrade_exit"],"title":"SurveyEligibilityResponse","description":"``GET /v1/me/surveys`` (NOV-447, spec §25.9).\n\nThe server owns the whole NPS decision because the client cannot make it:\nthe SPA is never told how old its workspace is and there is no cards-moved\ncounter on the wire. Deliberately a *capability* answer (\"may this survey be\nshown\") rather than a data dump — the org's age and this person's move count\nare inputs to a product decision, not fields a browser needs.\n\n``upgrade_exit.eligible`` covers only the 30-day cap. The other half of that\ntrigger — abandoning the in-app upgrade flow after >= 5 s — is a behaviour\nonly the client can observe, so the client ANDs its own observation with\nthis flag."},"SurveyPreferencesResponse":{"properties":{"nps_last_shown_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Nps Last Shown At"},"upgrade_exit_last_shown_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Upgrade Exit Last Shown At"}},"type":"object","title":"SurveyPreferencesResponse","description":"When each triggered survey was last SHOWN to this user (NOV-447, §25.9).\n\nShown, not submitted: the 90-day / 30-day caps in §25.9 are caps on\ninterrupting someone, so a survey they dismissed without answering has to\ncount exactly as much as one they filled in. Absent (``None``) means \"never\nshown\" and the survey is eligible as far as the cap is concerned — the\nother NPS conditions (org age, cards moved) are evaluated by\n``GET /v1/me/surveys``, not here."},"UnreadCountResponse":{"properties":{"object":{"type":"string","title":"Object","default":"notification_count"},"unread":{"type":"integer","title":"Unread"}},"type":"object","required":["unread"],"title":"UnreadCountResponse","description":"Envelope for ``GET /v1/notifications/count`` (spec §22.2)."},"UpdateAutomationRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Name"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"trigger":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Trigger"},"conditions":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Conditions"},"actions":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Actions"},"run_as_agent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Run As Agent Id"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"}},"type":"object","title":"UpdateAutomationRequest","description":"Body for ``PATCH /v1/orgs/{org_id}/automations/{id}`` (§20.8).\n\nEvery field is optional — a client sends only what it changes. ``is_active``\nsupports the enable/disable toggle. Fields the client omits are left untouched\n(the router forwards only ``model_dump(exclude_unset=True)`` to the service, so\nan explicit ``null`` is distinguishable from an absent key)."},"UpdateBlockRequest":{"properties":{"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"archived":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Archived"}},"additionalProperties":true,"type":"object","title":"UpdateBlockRequest","description":"`PATCH /v1/blocks/{id}` body.\n\nThe shape mirrors Notion: a top-level key matching ``type`` carries the\nnew payload. ``archived`` toggles soft-delete. ``type`` is optional and\nonly used when changing block kind.\n\n``extra=\"allow\"`` is load-bearing — the type-key payload arrives as an\nextra — so a stray ``parent`` key cannot be caught here by\n``extra=\"forbid\"``. It is rejected in ``update_block_for_principal``\ninstead (NOV-498), which keeps the failure a 400 in the Notion-shape error\nenvelope rather than pydantic's 422, and catches MCP callers on the same\npath as HTTP ones."},"UpdateBoardAccessRequest":{"properties":{"role":{"type":"string","title":"Role"}},"additionalProperties":false,"type":"object","required":["role"],"title":"UpdateBoardAccessRequest"},"UpdateBoardRequest":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Description"},"icon":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Icon"},"cover":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Cover"},"status_groups":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Status Groups"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties"},"visibility":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Visibility"},"workspace_access":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace Access"},"permissions":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Permissions"},"property_validation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Validation"}},"additionalProperties":false,"type":"object","title":"UpdateBoardRequest"},"UpdateCardRequest":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties"},"assignees":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Assignees"},"due_date":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Due Date"},"labels":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Labels"},"remove_labels":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Remove Labels"},"is_archived":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Archived"}},"additionalProperties":false,"type":"object","title":"UpdateCardRequest"},"UpdateCardTemplateRequest":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties"},"body_blocks":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Body Blocks"},"assignees":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Assignees"},"labels":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Labels"},"recurrence_rule":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Recurrence Rule"},"next_materialization_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Next Materialization At"},"until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Until"},"count_remaining":{"anyOf":[{"type":"integer","maximum":10000.0,"minimum":0.0},{"type":"null"}],"title":"Count Remaining"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"}},"additionalProperties":false,"type":"object","title":"UpdateCardTemplateRequest"},"UpdateColumnRequest":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"position":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Position"},"status_group":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status Group"},"autopilot":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Autopilot"},"playbook_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Playbook Id"},"autopilot_label_gate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Autopilot Label Gate"}},"additionalProperties":false,"type":"object","title":"UpdateColumnRequest"},"UpdateCommentRequest":{"properties":{"body":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Body"}},"additionalProperties":false,"type":"object","required":["body"],"title":"UpdateCommentRequest"},"UpdateFeedbackRequest":{"properties":{"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"admin_notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Admin Notes"}},"additionalProperties":false,"type":"object","title":"UpdateFeedbackRequest","description":"``PATCH /v1/admin/feedback/{id}`` — status and/or admin notes.\n\nBoth fields are optional and the two are independent, but a body that sets\nNEITHER is a 400 from the router rather than a silent 200: an empty PATCH\nis a client bug, and answering it with the unchanged row would hide it.\n``admin_notes`` accepts the empty string as \"clear the notes\" — distinct\nfrom omitting the key, which leaves them alone."},"UpdateMembershipRequest":{"properties":{"role":{"type":"string","title":"Role"}},"type":"object","required":["role"],"title":"UpdateMembershipRequest"},"UpdateNotificationPreferencesRequest":{"properties":{"email":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"propertyNames":{"enum":["card_assigned","automation_notify"]},"type":"object"},{"type":"null"}],"title":"Email"}},"type":"object","title":"UpdateNotificationPreferencesRequest","description":"Partial per-type notification write (NOV-364).\n\n``email`` is a partial MERGE map: each key sets that type's email flag and\ntypes absent from the map are left untouched; an explicit ``None`` value\nCLEARS that type's stored override so it follows the default again (the\nsame tri-state as the ``board_card_view`` merge idiom). An unknown type is\nrejected by the ``NotificationType`` Literal (422), the same way an unknown\n``theme`` value is; ``StrictBool`` pins non-bool values (\"yes\", 1, …) to a\n422 as well — no lax coercion on a consent field. Omitting ``email`` (or\nthe whole ``notifications`` block) is a no-op."},"UpdateOrganizationRequest":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"primary_domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Domain"}},"type":"object","title":"UpdateOrganizationRequest"},"UpdatePlaybookRequest":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"steps":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Steps"},"output_target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output Target"},"on_success_move_to":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"On Success Move To"}},"type":"object","title":"UpdatePlaybookRequest","description":"Body for ``PATCH /v1/orgs/{org_id}/playbooks/{id}`` (§23.4).\n\nEvery field is optional — a client sends only what it changes. Fields the client\nomits are left untouched (the router forwards only ``model_dump(exclude_unset=\nTrue)``, so an explicit ``null`` clearing ``on_success_move_to`` is\ndistinguishable from an absent key)."},"UpdatePreferencesRequest":{"properties":{"theme":{"anyOf":[{"type":"string","enum":["dark","light","system"]},{"type":"null"}],"title":"Theme"},"default_card_view":{"anyOf":[{"type":"string","enum":["side_panel","center_peek","focused_overlay","full_page"]},{"type":"null"}],"title":"Default Card View"},"board_card_view":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"string","enum":["side_panel","center_peek","focused_overlay","full_page"]},{"type":"null"}]},"type":"object"},{"type":"null"}],"title":"Board Card View"},"notifications":{"anyOf":[{"$ref":"#/components/schemas/UpdateNotificationPreferencesRequest"},{"type":"null"}]},"dismissed_hints":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"propertyNames":{"const":"connect_agent"},"type":"object"},{"type":"null"}],"title":"Dismissed Hints"},"surveys":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"propertyNames":{"enum":["nps","upgrade_exit"]},"type":"object"},{"type":"null"}],"title":"Surveys"}},"type":"object","title":"UpdatePreferencesRequest","description":"PATCH /v1/me/preferences. Only the keys the caller wants to change.\n\nSending ``default_card_view: null`` explicitly clears it so the user\nfalls back to the client-side first-time default (NOV-81)."},"UpdateProfileRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name"},"avatar_url":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Avatar Url"}},"type":"object","title":"UpdateProfileRequest","description":"PATCH /v1/me/profile. Both fields are optional — caller sends only what\nthey want to change. ``None`` and \"omitted\" are different on the wire; we\ntreat \"omitted\" as no-op and an empty string as \"clear the field\"."},"UpdateWebhookRequest":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"event_types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Event Types"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"}},"type":"object","title":"UpdateWebhookRequest"},"UserPreferencesResponse":{"properties":{"object":{"type":"string","title":"Object","default":"user_preferences"},"theme":{"type":"string","enum":["dark","light","system"],"title":"Theme","default":"system"},"default_card_view":{"anyOf":[{"type":"string","enum":["side_panel","center_peek","focused_overlay","full_page"]},{"type":"null"}],"title":"Default Card View"},"board_card_view":{"additionalProperties":{"type":"string","enum":["side_panel","center_peek","focused_overlay","full_page"]},"type":"object","title":"Board Card View"},"notifications":{"$ref":"#/components/schemas/NotificationPreferencesResponse"},"dismissed_hints":{"additionalProperties":{"type":"boolean"},"propertyNames":{"const":"connect_agent"},"type":"object","title":"Dismissed Hints"},"surveys":{"$ref":"#/components/schemas/SurveyPreferencesResponse"}},"type":"object","title":"UserPreferencesResponse"},"UserProfileResponse":{"properties":{"object":{"type":"string","title":"Object","default":"user_profile"},"id":{"type":"string","format":"uuid","title":"Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"email_verified":{"type":"boolean","title":"Email Verified","default":false},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"avatar_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Avatar Url"},"signup_source":{"type":"string","title":"Signup Source"},"has_password":{"type":"boolean","title":"Has Password"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"last_signed_in_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Signed In At"}},"type":"object","required":["id","signup_source","has_password","created_at"],"title":"UserProfileResponse","description":"GET /v1/me/profile shape. Self-only — never leaks across users."},"UserResponse":{"properties":{"object":{"type":"string","title":"Object","default":"user"},"id":{"type":"string","format":"uuid","title":"Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"avatar_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Avatar Url"},"email_verified":{"type":"boolean","title":"Email Verified","default":false},"kind":{"type":"string","title":"Kind","default":"human"},"agent_runtime_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Runtime Url"},"is_platform_admin":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Platform Admin"},"platform_admin_role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Platform Admin Role"},"active_workspace":{"anyOf":[{"$ref":"#/components/schemas/ActiveWorkspaceResponse"},{"type":"null"}]}},"type":"object","required":["id"],"title":"UserResponse"},"UserSessionResponse":{"properties":{"object":{"type":"string","title":"Object","default":"user_session"},"id":{"type":"string","format":"uuid","title":"Id"},"user_agent_hint":{"type":"string","title":"User Agent Hint"},"user_agent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Agent"},"ip_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ip Address"},"last_active_at":{"type":"string","format":"date-time","title":"Last Active At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"is_current":{"type":"boolean","title":"Is Current","default":false}},"type":"object","required":["id","user_agent_hint","last_active_at","created_at","expires_at"],"title":"UserSessionResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifyEmailRequest":{"properties":{"token":{"type":"string","title":"Token"}},"type":"object","required":["token"],"title":"VerifyEmailRequest"},"WebhookDeliveryResponse":{"properties":{"object":{"type":"string","title":"Object","default":"webhook_delivery"},"id":{"type":"string","format":"uuid","title":"Id"},"webhook_id":{"type":"string","format":"uuid","title":"Webhook Id"},"event_id":{"type":"string","format":"uuid","title":"Event Id"},"event_type":{"type":"string","title":"Event Type"},"status":{"type":"string","title":"Status"},"attempts":{"type":"integer","title":"Attempts"},"last_response_status":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Last Response Status"},"last_response_body_excerpt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Response Body Excerpt"},"next_retry_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Next Retry At"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"}},"type":"object","required":["id","webhook_id","event_id","event_type","status","attempts","last_response_status","last_response_body_excerpt","next_retry_at","created_time","last_edited_time"],"title":"WebhookDeliveryResponse"},"WebhookResponse":{"properties":{"object":{"type":"string","title":"Object","default":"webhook"},"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"url":{"type":"string","title":"Url"},"event_types":{"items":{"type":"string"},"type":"array","title":"Event Types"},"board_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Board Id"},"is_active":{"type":"boolean","title":"Is Active"},"secret_last4":{"type":"string","title":"Secret Last4"},"created_time":{"type":"string","format":"date-time","title":"Created Time"},"last_edited_time":{"type":"string","format":"date-time","title":"Last Edited Time"}},"type":"object","required":["id","org_id","url","event_types","board_id","is_active","secret_last4","created_time","last_edited_time"],"title":"WebhookResponse"}},"securitySchemes":{"IntegrationToken":{"type":"http","scheme":"bearer","description":"Integration token. Mint one in the app under **Settings → Integrations** and paste the `nov_…` value here — it is sent as `Authorization: Bearer nov_…`, the same credential the API enforces. Browser session cookies are NOT used by try-it-out (the cookie flow additionally requires an `X-CSRF-Token` header this page cannot mint)."}}}}