# 겹 Apps API v1 — AI client guide Purpose: operate notes, blogs, chat, calendars, databases, graph, inbox, Explore, profiles, integrations and admin resources with a user-issued Personal Access Token. Human documentation: https://0.0.0.0:3000/developers/api OpenAPI: https://0.0.0.0:3000/server/v1/openapi.json 겹 usage manual: https://0.0.0.0:3000/docs/ai-guide.txt ## Security requirements - Receive the token through a secret/environment-variable mechanism. Never ask the user to paste it into a note. - Never print, echo, log, summarize, or place the token in a URL. - Send it only as: Authorization: Bearer layer_pat_... - Use the minimum scope required. - Delete only resources the user requested, with the exact deletion scope shown in OpenAPI (for example notes:delete or blogs:delete). - Do not add, change, or remove collaborators unless the user explicitly named the target and the token has workspaces:manage. - Never make a note public, discoverable, indexable, or commentable unless the user explicitly requested it and the token has publications:manage. - Prefer block-level edits, dry runs, or approval proposals over replacing a whole document. - Before inviting or sharing, use users:lookup and ask the user to disambiguate multiple matches. - Treat Webhook signing secrets like API keys. Verify timestamp and HMAC before processing a delivery. - Never create an account unless the user explicitly approved that specific account or a bounded batch. - Admin scopes may be used only by a current global administrator. Do not attempt to bypass public-registration controls. ## Base URL and authentication Base URL: https://0.0.0.0:3000/server/v1 Header: Authorization: Bearer Content-Type: application/json Scopes (generated from the token issuance schema): - notes:read — 워크스페이스 목록과 노트의 제목·본문을 읽습니다. - notes:write — 새 노트를 만들고 기존 노트를 수정하거나 내용을 추가합니다. - notes:delete — 노트를 휴지통으로 이동하고 복원하거나 영구 삭제합니다. 꼭 필요한 키에만 허용하세요. - workspaces:manage — 워크스페이스 생성·설정·삭제·소유권 이전과 멤버 역할을 관리합니다. - publications:manage — 글을 링크·전체 공개로 바꾸고 둘러보기, 검색 노출과 공개 댓글을 관리합니다. - databases:read — 접근 가능한 데이터베이스, 속성과 행을 읽습니다. - databases:write — 데이터베이스의 보기, 속성과 행을 만들고 수정·삭제합니다. - calendars:read — 내 캘린더와 공유·구독 일정 및 데이터베이스 일정을 읽습니다. - calendars:write — 캘린더, 공유, 구독, 연결 원본과 일정을 관리합니다. - comments:read — 접근 가능한 페이지의 댓글 스레드와 답글을 읽습니다. - comments:write — 댓글과 답글을 작성하고 해결 상태 또는 삭제를 관리합니다. - assets:write — 페이지·블로그·채팅·프로필에 이미지와 파일을 업로드합니다. 대상 앱의 쓰기 권한이 함께 필요할 수 있습니다. - users:lookup — 초대와 공유 전에 사용자명·표시 이름을 실시간 검색합니다. - chat:read — 친구 목록, 참여 중인 채팅방과 메시지를 읽습니다. - chat:write — 친구 요청, 채팅방 생성·변경·나가기, 메시지 전송과 읽음 처리를 수행합니다. - drafts:write — 노트를 바로 바꾸지 않고 검토 가능한 변경 미리보기를 만듭니다. - drafts:approve — 대기 중인 제안을 최신 버전 확인 후 실제 노트에 적용합니다. - automations:manage — 변경 피드, Webhook, 배치·백그라운드 작업과 데이터베이스 자동화 규칙을 관리합니다. - admin:users:read — 전체 회원 목록과 계정 상태를 조회합니다. - admin:users:create — 운영자 승인 계정을 생성합니다. 기본값은 키당 시간당 5회입니다. - admin:users:write — 회원의 프로필, 인증 여부와 활성 상태를 변경합니다. - admin:roles:manage — 글로벌 관리자 지정·해제를 허용하는 최고위험 권한입니다. - admin:audit:read — 보안 및 관리자 작업의 감사 기록을 조회합니다. - assets:read — 접근 가능한 페이지의 파일·이미지 목록을 검색합니다. - blogs:read — 블로그·글·초안·버전·통계·검토 상태를 읽습니다. - blogs:write — 블로그 설정과 글·블록·시리즈·편집 상태를 변경합니다. - blogs:delete — 소유한 블로그를 삭제하거나 글 일괄 삭제를 허용합니다. - blogs:publish — 글 공개·비공개·예약과 탐험 노출을 관리합니다. - explore:read — 공개 콘텐츠·추천·구독·저장 목록을 읽습니다. - explore:write — 팔로우·좋아요·북마크·숨김·추천 설정을 변경합니다. - notifications:read — 알림·읽음 수·보관함·알림 설정을 읽습니다. - notifications:write — 알림의 읽음·보관·삭제와 계정 알림 설정을 변경합니다. - profile:read — 내 프로필·온보딩·이미지 편집 설정을 읽습니다. - profile:write — 내 프로필·아바타·온보딩·이미지 편집 설정을 변경합니다. - integrations:read — 연결된 Google 캘린더와 동기화 충돌을 읽습니다. - integrations:write — 기존 Google 연결의 선택·동기화·연결 해제를 관리합니다. 최초 승인은 웹에서 진행합니다. - admin:system:read — 관리자 전용 시스템 상태·큐·로그·설정 조회입니다. - admin:system:manage — 관리자 전용 작업 재시도·삭제·정리입니다. - admin:settings:manage — 관리자 전용 서비스·인증·기능 설정 변경입니다. - admin:content:read — 관리자 전용 블로그·노트·탐험·검토 대상 조회입니다. - admin:content:manage — 관리자 전용 콘텐츠 검토·노출·삭제·도메인 요청 처리입니다. - admin:notifications:manage — 관리자 전용 공지 알림 생성·예약·반복·삭제입니다. - admin:users:delete — 관리자 전용 체험 계정·미승인 계정 정리입니다. Admin scopes are issued only to global administrators, expire within 30 days, and re-check the owner's current global-admin status on every request. By default, POST /admin/users is limited to 5 attempts per hour per PAT. Honor 429 and do not switch to public signup as a fallback. Public registration may be disabled and is independently rate-limited by IP. ## Recommended workflow 1. GET /workspaces and choose the target workspace. If the user explicitly requested a new workspace, POST /workspaces first; otherwise ask or use their default workspace by omitting workspace_id. 2. Generate one stable client_request_id for each intended note creation and reuse it only when retrying the exact same POST body. 3. GET /search?q= to search titles, bodies, IDs, and tags. Use GET /workspaces/{id}/tree when hierarchy matters. 4. GET /notes/{id} before editing. Keep the returned version. 5. For a local edit, GET /notes/{id}/blocks and update one stable blockId. Replace the whole body only when the user requested it. 6. Send expected_version on note body writes and expected_sequence on calendar event updates where the schema requires them. On 409, read again and merge. 7. For autonomous or high-impact work, POST a proposal or run POST /batch with dry_run=true before applying. 8. Before changing membership, use GET /users/search?q=... and confirm the exact user and viewer/editor/manager role. 9. Before publishing, confirm unlisted versus fully public and each Explore, search-indexing, and public-comment option. 10. Persist the cursor returned by GET /changes. Webhook consumers must be idempotent because delivery can be retried. 11. For account administration, show the exact account count and identities before creating them. Never expand the batch on your own. ## Endpoints Discover all operations: GET https://0.0.0.0:3000/server/v1/capabilities The following catalog is generated from registered routes. Fetch OpenAPI for exact request bodies, pagination parameters, response schemas and conditional scopes. Paths below include /v1; prepend the service origin and /server when using gyeop.com. GET /v1/admin/audit-logs — admin:audit:read DELETE /v1/admin/blog-curation/{publication_id} — admin:content:manage PUT /v1/admin/blog-curation/{publication_id} — admin:content:manage GET /v1/admin/blog-discovery/audit — admin:audit:read GET /v1/admin/blog-discovery/posts — admin:content:read PUT /v1/admin/blog-discovery/posts/{publication_id} — admin:content:manage GET /v1/admin/blog-discovery/topics — admin:content:read PUT /v1/admin/blog-discovery/topics/{topic_id} — admin:content:manage GET /v1/admin/blog-domain-requests — admin:content:read PATCH /v1/admin/blog-domain-requests/{blog_id} — admin:content:manage GET /v1/admin/demo-chat/messages — admin:content:read POST /v1/admin/demo-chat/messages/delete — admin:content:manage GET /v1/admin/moderation/overview — admin:content:read GET /v1/admin/moderation/pages — admin:content:read GET /v1/admin/moderation/pages/{page_id} — admin:content:read PATCH /v1/admin/moderation/pages/{page_id} — admin:content:manage PATCH /v1/admin/moderation/users/{user_id}/status — admin:users:write GET /v1/admin/settings/auth — admin:system:read PATCH /v1/admin/settings/auth — admin:settings:manage GET /v1/admin/system-logs — admin:system:read GET /v1/admin/system-queues — admin:system:read POST /v1/admin/system-queues/delete — admin:system:manage POST /v1/admin/system-queues/purge — admin:system:manage POST /v1/admin/system-queues/retry — admin:system:manage GET /v1/admin/system-status — admin:system:read GET /v1/admin/users — admin:users:read POST /v1/admin/users — admin:users:create DELETE /v1/admin/users/demo — admin:users:delete GET /v1/admin/users/{user_id} — admin:users:read PATCH /v1/admin/users/{user_id} — admin:users:write; conditional: admin:roles:manage PATCH /v1/admin/users/{user_id}/registration — admin:users:write DELETE /v1/admin/users/{user_id}/unapproved — admin:users:delete GET /v1/blogs/admin/category-settings — admin:content:read PATCH /v1/blogs/admin/category-settings — admin:content:manage GET /v1/blogs/admin/content/blogs — admin:content:read POST /v1/blogs/admin/content/blogs/bulk-actions — admin:content:manage POST /v1/blogs/admin/content/blogs/{blog_id}/actions — admin:content:manage GET /v1/blogs/admin/content/facets — admin:content:read GET /v1/blogs/admin/content/posts — admin:content:read POST /v1/blogs/admin/content/posts/bulk-actions — admin:content:manage POST /v1/blogs/admin/content/posts/{publication_id}/actions — admin:content:manage GET /v1/notifications/admin/broadcasts — admin:notifications:manage POST /v1/notifications/admin/broadcasts — admin:notifications:manage DELETE /v1/notifications/admin/broadcasts/{broadcast_id} — admin:notifications:manage POST /v1/notifications/admin/broadcasts/{broadcast_id}/repeat — admin:notifications:manage POST /v1/notes/{note_id}/assets — assets:write POST /v1/batch — automations:manage + notes:write GET /v1/changes — automations:manage POST /v1/jobs — automations:manage + notes:write DELETE /v1/jobs/{job_id} — automations:manage GET /v1/jobs/{job_id} — automations:manage POST /v1/mcp — tool-specific scopes GET /v1/webhooks — automations:manage POST /v1/webhooks — automations:manage DELETE /v1/webhooks/{webhook_id} — automations:manage PATCH /v1/webhooks/{webhook_id} — automations:manage GET /v1/webhooks/{webhook_id}/deliveries — automations:manage POST /v1/webhooks/{webhook_id}/test — automations:manage GET /v1/blogs — blogs:read POST /v1/blogs — blogs:write POST /v1/blogs/default-for-page/{page_id} — blogs:write + notes:read GET /v1/blogs/publication/by-page/{page_id} — blogs:read DELETE /v1/blogs/{blog_id} — blogs:delete PATCH /v1/blogs/{blog_id} — blogs:write; conditional: blogs:publish GET /v1/blogs/{blog_id}/analytics — blogs:read POST /v1/blogs/{blog_id}/appearance-preview — blogs:read GET /v1/blogs/{blog_id}/categories — blogs:read GET /v1/blogs/{blog_id}/discovery-analytics — blogs:read GET /v1/blogs/{blog_id}/discovery-settings — blogs:read PUT /v1/blogs/{blog_id}/discovery-settings — blogs:publish DELETE /v1/blogs/{blog_id}/domain-change-request — blogs:write GET /v1/blogs/{blog_id}/management — blogs:read GET /v1/blogs/{blog_id}/posts — blogs:read POST /v1/blogs/{blog_id}/posts/bulk — blogs:write + blogs:publish; conditional: blogs:delete POST /v1/blogs/{blog_id}/posts/new — blogs:write POST /v1/blogs/{blog_id}/posts/publish — blogs:publish + notes:read GET /v1/blogs/{blog_id}/posts/{publication_id} — blogs:read POST /v1/blogs/{blog_id}/posts/{publication_id}/assets — blogs:write + assets:write POST /v1/blogs/{blog_id}/posts/{publication_id}/block-operations — blogs:write GET /v1/blogs/{blog_id}/posts/{publication_id}/blocks — blogs:read PUT /v1/blogs/{blog_id}/posts/{publication_id}/comment-tasks/{thread_id} — blogs:write GET /v1/blogs/{blog_id}/posts/{publication_id}/discovery-settings — blogs:read PUT /v1/blogs/{blog_id}/posts/{publication_id}/discovery-settings — blogs:publish PATCH /v1/blogs/{blog_id}/posts/{publication_id}/draft — blogs:write POST /v1/blogs/{blog_id}/posts/{publication_id}/export — blogs:read + notes:write POST /v1/blogs/{blog_id}/posts/{publication_id}/place — blogs:write + notes:write POST /v1/blogs/{blog_id}/posts/{publication_id}/publish — blogs:publish GET /v1/blogs/{blog_id}/posts/{publication_id}/review — blogs:read PATCH /v1/blogs/{blog_id}/posts/{publication_id}/review — blogs:write GET /v1/blogs/{blog_id}/posts/{publication_id}/revisions — blogs:read POST /v1/blogs/{blog_id}/posts/{publication_id}/revisions/{revision_number}/restore — blogs:write DELETE /v1/blogs/{blog_id}/posts/{publication_id}/schedule — blogs:publish POST /v1/blogs/{blog_id}/posts/{publication_id}/schedule — blogs:publish GET /v1/blogs/{blog_id}/posts/{publication_id}/source — blogs:read PUT /v1/blogs/{blog_id}/posts/{publication_id}/source — blogs:write + notes:read POST /v1/blogs/{blog_id}/posts/{publication_id}/source/apply — blogs:write + notes:read POST /v1/blogs/{blog_id}/posts/{publication_id}/unpublish — blogs:publish GET /v1/blogs/{blog_id}/series — blogs:read POST /v1/blogs/{blog_id}/series — blogs:write DELETE /v1/blogs/{blog_id}/series/{series_id} — blogs:write PUT /v1/blogs/{blog_id}/series/{series_id} — blogs:write DELETE /v1/calendar-events/{event_id} — calendars:write GET /v1/calendar-events/{event_id} — calendars:read PATCH /v1/calendar-events/{event_id} — calendars:write GET /v1/calendars — calendars:read POST /v1/calendars — calendars:write GET /v1/calendars/lunar-dates — calendars:read GET /v1/calendars/public — calendars:read DELETE /v1/calendars/{calendar_id} — calendars:write PATCH /v1/calendars/{calendar_id} — calendars:write POST /v1/calendars/{calendar_id}/database-sources — calendars:write DELETE /v1/calendars/{calendar_id}/database-sources/{source_id} — calendars:write GET /v1/calendars/{calendar_id}/events — calendars:read POST /v1/calendars/{calendar_id}/events — calendars:write GET /v1/calendars/{calendar_id}/export.ics — calendars:read POST /v1/calendars/{calendar_id}/shares — calendars:write DELETE /v1/calendars/{calendar_id}/shares/{target_user_id} — calendars:write DELETE /v1/calendars/{calendar_id}/subscription — calendars:write POST /v1/calendars/{calendar_id}/subscription — calendars:write POST /v1/chat/assets — chat:write + assets:write POST /v1/chat/friend-requests — chat:write POST /v1/chat/friend-requests/{friendship_id}/accept — chat:write GET /v1/chat/friends — chat:read DELETE /v1/chat/friends/{friendship_id} — chat:write GET /v1/chat/images/received — chat:read GET /v1/chat/open-rooms — chat:read POST /v1/chat/open-rooms — chat:write POST /v1/chat/open-rooms/{room_id}/join — chat:write GET /v1/chat/rooms — chat:read POST /v1/chat/rooms/direct — chat:write POST /v1/chat/rooms/group — chat:write PATCH /v1/chat/rooms/{room_key} — chat:write DELETE /v1/chat/rooms/{room_key}/membership — chat:write GET /v1/chat/rooms/{room_key}/messages — chat:read POST /v1/chat/rooms/{room_key}/messages — chat:write POST /v1/chat/rooms/{room_key}/read — chat:write GET /v1/chat/users/search — chat:read GET /v1/workspaces/chat/unread — chat:read GET /v1/workspaces/{workspace_id}/chat/messages — chat:read POST /v1/workspaces/{workspace_id}/chat/messages — chat:write POST /v1/workspaces/{workspace_id}/chat/read — chat:write GET /v1/notes/{note_id}/comments — comments:read POST /v1/notes/{note_id}/comments — comments:write PATCH /v1/notes/{note_id}/comments/{thread_id} — comments:write POST /v1/notes/{note_id}/comments/{thread_id}/replies — comments:write DELETE /v1/notes/{note_id}/comments/{thread_id}/{comment_id} — comments:write GET /v1/public/blogs/posts/{publication_id}/comments — comments:read POST /v1/public/blogs/posts/{publication_id}/comments — comments:write POST /v1/public/blogs/posts/{publication_id}/comments/{thread_id}/replies — comments:write DELETE /v1/public/blogs/posts/{publication_id}/comments/{thread_id}/{comment_id} — comments:write PATCH /v1/public/blogs/posts/{publication_id}/comments/{thread_id}/{comment_id} — comments:write GET /v1/public/pages/{public_id}/comments — comments:read POST /v1/public/pages/{public_id}/comments — comments:write POST /v1/public/pages/{public_id}/comments/{thread_id}/replies — comments:write DELETE /v1/public/pages/{public_id}/comments/{thread_id}/{comment_id} — comments:write PATCH /v1/public/pages/{public_id}/comments/{thread_id}/{comment_id} — comments:write GET /v1/agenda/databases — databases:read GET /v1/agenda/databases/{database_id} — databases:read POST /v1/agenda/query — calendars:read + databases:read POST /v1/database-deletions/{deletion_id}/restore — databases:write + notes:write + automations:manage DELETE /v1/databases/{database_id} — databases:write GET /v1/databases/{database_id} — databases:read PATCH /v1/databases/{database_id} — databases:write GET /v1/databases/{database_id}/automation-runs — databases:read GET /v1/databases/{database_id}/automations — databases:read POST /v1/databases/{database_id}/automations — databases:write + automations:manage DELETE /v1/databases/{database_id}/automations/{rule_id} — databases:write + automations:manage PATCH /v1/databases/{database_id}/automations/{rule_id} — databases:write + automations:manage GET /v1/databases/{database_id}/content-search — databases:read POST /v1/databases/{database_id}/properties — databases:write DELETE /v1/databases/{database_id}/properties/{property_id} — databases:write PATCH /v1/databases/{database_id}/properties/{property_id} — databases:write POST /v1/databases/{database_id}/query — databases:read DELETE /v1/databases/{database_id}/recurrence — databases:write + automations:manage GET /v1/databases/{database_id}/recurrence — databases:read PATCH /v1/databases/{database_id}/recurrence — databases:write + notes:write + automations:manage + calendars:read PUT /v1/databases/{database_id}/recurrence — databases:write + notes:write + automations:manage + calendars:read POST /v1/databases/{database_id}/recurrence/ensure — databases:write + notes:write + automations:manage POST /v1/databases/{database_id}/recurrence/plan — databases:read POST /v1/databases/{database_id}/recurrence/preview — databases:read + calendars:read POST /v1/databases/{database_id}/recurrence/run — databases:write + notes:write + automations:manage + calendars:read POST /v1/databases/{database_id}/recurrences — databases:write + notes:write + automations:manage + calendars:read POST /v1/databases/{database_id}/recurrences/ensure — databases:write + notes:write + automations:manage DELETE /v1/databases/{database_id}/recurrences/{recurrence_id} — databases:write + automations:manage GET /v1/databases/{database_id}/recurrences/{recurrence_id} — databases:read PATCH /v1/databases/{database_id}/recurrences/{recurrence_id} — databases:write + notes:write + automations:manage + calendars:read PUT /v1/databases/{database_id}/recurrences/{recurrence_id} — databases:write + notes:write + automations:manage + calendars:read POST /v1/databases/{database_id}/recurrences/{recurrence_id}/run — databases:write + notes:write + automations:manage + calendars:read POST /v1/databases/{database_id}/rows — databases:write POST /v1/databases/{database_id}/rows/attach — databases:write + notes:write POST /v1/databases/{database_id}/rows/from-block — databases:write + notes:write DELETE /v1/databases/{database_id}/rows/{row_id} — databases:write PATCH /v1/databases/{database_id}/rows/{row_id} — databases:write POST /v1/databases/{database_id}/rows/{row_id}/detach — databases:write + notes:write POST /v1/databases/{database_id}/rows/{row_id}/move — databases:write + notes:write POST /v1/databases/{database_id}/rows/{row_id}/restore — databases:write + notes:write POST /v1/databases/{database_id}/trash — databases:write + notes:write + automations:manage POST /v1/notes/{note_id}/databases — databases:write GET /v1/recurrences — databases:read POST /v1/recurrences/ensure — databases:write + notes:write + automations:manage GET /v1/workspaces/{workspace_id}/databases — databases:read DELETE /v1/blogs/posts/{publication_id}/bookmark — explore:write PUT /v1/blogs/posts/{publication_id}/bookmark — explore:write DELETE /v1/blogs/posts/{publication_id}/like — explore:write PUT /v1/blogs/posts/{publication_id}/like — explore:write GET /v1/blogs/posts/{publication_id}/reader-state — explore:read PUT /v1/blogs/reader/discovery-hidden — explore:write DELETE /v1/blogs/reader/discovery-hidden/{kind}/{target_id} — explore:write DELETE /v1/blogs/reader/discovery-history — explore:write GET /v1/blogs/reader/discovery-preferences — explore:read PUT /v1/blogs/reader/discovery-preferences — explore:write GET /v1/blogs/reader/library — explore:read DELETE /v1/blogs/reader/saved/{publication_id} — explore:write DELETE /v1/blogs/{blog_id}/follow — explore:write PUT /v1/blogs/{blog_id}/follow — explore:write GET /v1/blogs/{blog_id}/reader-state — explore:read GET /v1/public/blogs/discovery — explore:read GET /v1/public/blogs/discovery/topics — explore:read POST /v1/public/blogs/events — explore:write GET /v1/public/blogs/posts/{publication_id}/passages/{block_id} — explore:read GET /v1/public/blogs/sitemap — explore:read GET /v1/public/blogs/stats — explore:read GET /v1/public/blogs/{blog_slug} — explore:read GET /v1/public/blogs/{blog_slug}/atom.xml — explore:read GET /v1/public/blogs/{blog_slug}/feed.json — explore:read GET /v1/public/blogs/{blog_slug}/rss.xml — explore:read GET /v1/public/blogs/{blog_slug}/{post_slug} — explore:read GET /v1/public/blogs/{blog_slug}/{post_slug}/view — explore:read GET /v1/public/pages — explore:read GET /v1/public/pages/explore — explore:read GET /v1/public/pages/sitemap — explore:read GET /v1/public/pages/{username}/{slug} — explore:read GET /v1/pages/{page_id}/relations — notes:read GET /v1/public-graph/pages/{public_id} — notes:read GET /v1/workspaces/{workspace_id}/graph — notes:read DELETE /v1/integrations/google-calendar — integrations:write GET /v1/integrations/google-calendar/calendars — integrations:read PATCH /v1/integrations/google-calendar/calendars/{selection_id} — integrations:write + calendars:write POST /v1/integrations/google-calendar/calendars/{selection_id}/sync — integrations:write + calendars:write GET /v1/integrations/google-calendar/conflicts — integrations:read DELETE /v1/integrations/google-calendar/connections/{connection_id} — integrations:write GET /v1/integrations/google-calendar/status — integrations:read GET /v1/capabilities — public documentation GET /v1/notes — notes:read POST /v1/notes — notes:write; conditional: publications:manage DELETE /v1/notes/{note_id} — notes:delete GET /v1/notes/{note_id} — notes:read PATCH /v1/notes/{note_id} — notes:write; conditional: publications:manage GET /v1/notes/{note_id}/blocks — notes:read POST /v1/notes/{note_id}/blocks — notes:write DELETE /v1/notes/{note_id}/blocks/{block_id} — notes:write PUT /v1/notes/{note_id}/blocks/{block_id} — notes:write POST /v1/notes/{note_id}/blocks/{block_id}/move — notes:write GET /v1/notes/{note_id}/collaboration — workspaces:manage PATCH /v1/notes/{note_id}/collaboration — workspaces:manage; conditional: publications:manage POST /v1/notes/{note_id}/collaboration/members — workspaces:manage DELETE /v1/notes/{note_id}/collaboration/members/{user_id} — workspaces:manage PATCH /v1/notes/{note_id}/collaboration/members/{user_id} — workspaces:manage DELETE /v1/notes/{note_id}/collaboration/membership — workspaces:manage GET /v1/notes/{note_id}/diff — notes:read GET /v1/notes/{note_id}/metadata — notes:read PUT /v1/notes/{note_id}/metadata — notes:write PATCH /v1/notes/{note_id}/move — notes:write POST /v1/notes/{note_id}/proposals — drafts:write GET /v1/notes/{note_id}/relations — notes:read GET /v1/notes/{note_id}/versions — notes:read GET /v1/notes/{note_id}/versions/{version_id} — notes:read POST /v1/notes/{note_id}/versions/{version_id}/restore — notes:write POST /v1/page-templates/from-page — notes:read + databases:read POST /v1/page-templates/materialize — notes:write + databases:write GET /v1/page-templates/sources — notes:read + databases:read GET /v1/pages/assets — assets:read POST /v1/pages/quick-capture — notes:write GET /v1/pages/resolve/{page_key} — notes:read GET /v1/pages/search — notes:read GET /v1/pages/shared — notes:read DELETE /v1/pages/trash — notes:delete GET /v1/pages/tree — notes:read GET /v1/pages/{page_id} — notes:read GET /v1/pages/{page_id}/appearance — notes:read PATCH /v1/pages/{page_id}/appearance — notes:write POST /v1/pages/{page_id}/block-operations — notes:write POST /v1/pages/{page_id}/block-transfers — notes:write GET /v1/pages/{page_id}/blocks — notes:read POST /v1/pages/{page_id}/blocks — notes:write GET /v1/proposals — drafts:write DELETE /v1/proposals/{proposal_id} — drafts:write POST /v1/proposals/{proposal_id}/apply — drafts:approve + notes:write GET /v1/search — notes:read GET /v1/templates — notes:read POST /v1/templates — notes:write DELETE /v1/templates/{template_id} — notes:delete PATCH /v1/templates/{template_id} — notes:write GET /v1/trash — notes:read DELETE /v1/trash/{note_id} — notes:delete POST /v1/trash/{note_id}/restore — notes:write GET /v1/notifications — notifications:read POST /v1/notifications/archive-all — notifications:write POST /v1/notifications/archive-read — notifications:write GET /v1/notifications/preferences — notifications:read PATCH /v1/notifications/preferences — notifications:write GET /v1/notifications/push/config — notifications:read POST /v1/notifications/push/test — notifications:write DELETE /v1/notifications/read — notifications:write POST /v1/notifications/read-all — notifications:write GET /v1/notifications/unread-count — notifications:read DELETE /v1/notifications/{notification_id} — notifications:write PATCH /v1/notifications/{notification_id}/archive — notifications:write PATCH /v1/notifications/{notification_id}/read — notifications:write PATCH /v1/notifications/{notification_id}/unarchive — notifications:write PATCH /v1/notifications/{notification_id}/unread — notifications:write GET /v1/onboarding — profile:read POST /v1/onboarding/complete — profile:write POST /v1/onboarding/skip — profile:write GET /v1/users/me — profile:read PATCH /v1/users/me — profile:write POST /v1/users/me/avatar — profile:write + assets:write GET /v1/users/me/image-editor-settings — profile:read PUT /v1/users/me/image-editor-settings — profile:write GET /v1/users/search — users:lookup GET /v1/notes/{note_id}/publication — publications:manage PATCH /v1/notes/{note_id}/publication — publications:manage PATCH /v1/pages/publications/bulk — publications:manage GET /v1/pages/publications/mine — publications:manage GET /v1/workspaces — notes:read POST /v1/workspaces — workspaces:manage POST /v1/workspaces/import — workspaces:manage + notes:write PUT /v1/workspaces/order — workspaces:manage GET /v1/workspaces/organization — notes:read PUT /v1/workspaces/organization — workspaces:manage DELETE /v1/workspaces/{workspace_id} — workspaces:manage PATCH /v1/workspaces/{workspace_id} — workspaces:manage POST /v1/workspaces/{workspace_id}/entry — workspaces:manage + notes:write GET /v1/workspaces/{workspace_id}/export — notes:read GET /v1/workspaces/{workspace_id}/members — workspaces:manage POST /v1/workspaces/{workspace_id}/members — workspaces:manage DELETE /v1/workspaces/{workspace_id}/members/{member_user_id} — workspaces:manage PATCH /v1/workspaces/{workspace_id}/members/{member_user_id} — workspaces:manage DELETE /v1/workspaces/{workspace_id}/membership — workspaces:manage POST /v1/workspaces/{workspace_id}/transfer-ownership — workspaces:manage GET /v1/workspaces/{workspace_id}/tree — notes:read ## App data and identifiers GET /notes/{note_id} returns the stable public id as id and the numeric page_id. Supplemental /pages routes and blog/database linkage bodies use numeric page_id; GET /pages/resolve/{page_key} resolves an existing public id, legacy slug or number. Do not confuse either identifier with a database row id or a blog publication id. Drawing, canvas, presentation and gallery data live in Tiptap JSON block attributes. Read the current block, preserve unknown fields and use expected_version when updating it. Do not round-trip these rich blocks through Markdown. Image files use the asset upload API; image editor preferences use /users/me/image-editor-settings. Existing Google connections support status, calendar selection and synchronization; initial OAuth approval remains an interactive web action. Push subscription creation, credentials, token issuance and impersonation remain behind the web-session boundary. ## Blog and inbox workflow 1. GET /blogs and choose a blog. To create one, choose an existing owned workspace from GET /workspaces (or create it first), then POST /blogs with workspace_id. POST /blogs/{blog_id}/posts/new, then GET the returned publication. 2. PATCH /blogs/{blog_id}/posts/{publication_id}/draft with expected_version. 3. Publishing or scheduling requires blogs:publish; deletion requires blogs:delete. A blog is_public change requires blogs:publish in addition to blogs:write. 4. GET /notifications?view=inbox&limit=30&offset=0, then use read/unread/archive endpoints for the chosen notification. Reading the list does not acknowledge it. 5. API chat reads broadcast the same read receipt events as the app, and database row writes run the same configured automations and assignment notifications. 6. The same server feature policies apply: partial block reads require block-storage rollout flags and a migrated page; database content search requires user eligibility. A PAT does not override these policies. Honor the returned 403/409 error code. ## Create and manage a workspace POST /workspaces { "name": "AI project", "icon": "✨" } The response contains the workspace id and its entry_page_public_id. Continue writing at that page or pass workspace_id to POST /notes. Workspace rename, ownership transfer, leave, member management, and deletion all require workspaces:manage and still enforce the user's owner/manager role. ## Create a note POST /notes { "title": "Weekly review", "client_request_id": "weekly-review-2026-07-30", "workspace_id": 1, "parent_id": null, "icon": "📝", "visibility": "private", "content_markdown": "# Summary\n\n- Progress\n- Next action" } workspace_id, parent_id, icon, visibility, client_request_id, content_markdown and content are optional. Do not send content_markdown and content together. client_request_id must be 8-80 characters using letters, numbers, dot, underscore, colon or hyphen. Identical retries are replayed for 24 hours; reusing it with a different body returns 409. ## Update or append PATCH /notes/{id} { "content_markdown": "## New section\n\nAdditional text", "content_mode": "append", "expected_version": 3 } content_mode is replace by default. append adds converted blocks after the existing document. expected_version is always required for PATCH. ## Precise block editing 1. GET /notes/{id}/blocks and select a block_id. 2. POST /notes/{id}/blocks inserts a block at start/end or before/after an anchor. 3. PUT replaces one block while preserving its stable blockId. 4. POST .../{block_id}/move moves it without regenerating the body. 5. DELETE removes exactly one block. Example insert: POST /notes/{id}/blocks { "expected_version": 3, "position": "after", "anchor_block_id": "existing-block-id", "block": { "type": "paragraph", "content": [{"type": "text", "text": "New paragraph"}] } } Never cache path:0-style fallback IDs for later use. They identify legacy blocks without blockId and can move after an edit. Stable UUID blockIds are returned for newly inserted blocks. ## Reviewable proposals and atomic batches POST /notes/{id}/proposals creates a preview without changing the note: { "base_version": 3, "update": { "content_markdown": "## Proposed section\n\nReview this first.", "content_mode": "append" } } Applying requires drafts:approve plus notes:write and the unchanged expected_version. POST /batch accepts up to 50 distinct notes. dry_run=true performs all access, version, Markdown, and block-operation validation without mutation. A non-dry run commits all note changes atomically. ## Metadata, databases, calendars, comments, and files - Tags and explicit note relations are replaced with PUT /notes/{id}/metadata and participate in note version conflicts. - Creating a database under a note requires expected_version and atomically adds its database block to the host document. - Database rows are real note pages. Modify property values through the row API and bodies through the note API. - Calendar fields follow common Google/Samsung/iCalendar concepts: UID, time zone, all-day exclusive end date, status, visibility, availability, recurrence, organizer, attendees, reminders, attachments, conference, external provider IDs, etag, and sequence. - Use expected_sequence when updating a native calendar event. Database-backed calendar events expose sequence 0 and accept date/title edits supported by their source. - Create comments against a stable block_id. Do not invent a block ID; read the block list first. - Asset upload is multipart/form-data with field name file. Use the returned URL in a later note edit. ## Change feed and signed Webhooks GET /changes?cursor=0 returns ordered events and next_cursor. Store next_cursor after successful processing. Webhook URLs must resolve to public Internet IPs, use HTTPS port 443, and contain no credentials or fragment. The signing_secret is shown only in the POST /webhooks response. Verify: HMAC-SHA256(signing_secret, X-Layer-Timestamp + "." + raw_request_body) Compare with the hex value after "sha256=" in X-Layer-Signature-256 using a timing-safe comparison. Use X-Layer-Event-Id as an idempotency key. 겹 retries delivery and automatically disables a repeatedly failing Webhook. ## MCP Streamable HTTP endpoint: https://0.0.0.0:3000/server/v1/mcp Authorization remains Bearer layer_pat_... Supported protocol versions: 2026-07-28 and 2025-11-25. Call tools/list first. 겹 exposes only tools permitted by the token's scopes. Supported methods include initialize (legacy compatibility), server/discover, tools/list, and tools/call. MCP tools apply the same 겹 permission checks, version conflicts, and rate limits as REST. ## Operator-only account administration These REST endpoints are intentionally not exposed as general MCP tools. They require a PAT owned by a current global administrator and the exact admin scope. Create one explicitly approved account: POST /admin/users { "email": "approved-user@example.com", "username": "approved-user", "password": "A-strong-initial-password!42", "display_name": "Approved User", "is_email_verified": false } The created account is a normal active user, never a global administrator. Setting is_global_admin is not accepted by account creation. To change a role, PATCH /admin/users/{user_id} with {"is_global_admin": true} and a token that has both admin:users:write and admin:roles:manage. Role or active-status changes revoke the target user's existing sessions and PATs. Successful creation is recorded in the audit log, while failed creation attempts still count toward the rate limit. ## Manage workspace collaborators POST /workspaces/{workspace_id}/members { "login": "sUser1", "role": "editor" } login accepts an exact username or email. role is viewer, editor, or manager. Use the returned user_id for PATCH or DELETE. Existing 겹 permissions still apply: only an owner or permitted manager can manage members, and managers cannot grant or alter roles above their authority. PATCH /workspaces/{workspace_id}/members/{user_id} { "role": "viewer" } ## Publish or change visibility PATCH /notes/{id}/publication { "visibility": "public", "expected_version": 3, "explore_enabled": true, "seo_index_enabled": true, "public_comments_enabled": true } visibility is private, unlisted, or public. Changing it requires expected_version. Explore, SEO indexing, public comments, and manual SEO metadata can be enabled only when visibility is public. Changing visibility through POST /notes or PATCH /notes/{id} requires both notes:write and publications:manage. Only the page owner can change publication settings. ## Markdown subset Supported: paragraphs, headings H1-H4, bold, italic, strike, inline code, http/https/mailto links, blockquotes, bullet lists, ordered lists, task lists, horizontal rules and fenced code blocks. The GET response includes both content_markdown and full Tiptap content JSON. ## Errors and limits - 401: invalid, expired or revoked token. - 403 insufficient_scope: token lacks the required scope. - 404: resource is missing or inaccessible. - 409: version conflict; read latest state and merge. - 422: invalid request body. - 429: rate limit; honor Retry-After. - Default rate limit: 120 requests per 60 seconds per token. - Admin PAT maximum expiry: 30 days. - Default admin account-creation limit: 5 attempts per hour per PAT. - Maximum note body: 1MB. - Maximum list page: 100 items; follow next_offset. - Change feed page: maximum 500 events; events are retained for 30 days. - Batch: maximum 50 notes and 100 block operations per note. - Webhooks retry three times per event and are disabled after repeated delivery failures. ## Never do - Never publish a note unless the user explicitly requested public or unlisted visibility. - Never interpret "share" as "public": ask whether the user means adding a collaborator, an unlisted link, or full public publishing. - Never grant manager access when viewer or editor is sufficient. - Never turn a 409 into a blind retry with a stale version. - Never use DELETE as a substitute for clearing or replacing content. - Never process an unsigned or stale Webhook body. - Never approve your own high-impact proposal unless the user explicitly delegated approval. - Never create speculative, placeholder, test, or duplicate accounts. - Never grant global-admin status unless the user explicitly named the target and confirmed the elevation. - Never use public signup to evade an admin-scope denial or account-creation rate limit. - Never expose the token in your final answer.