# 1page.run API — 에이전트 가이드 HTML 또는 Markdown을 게시하면 즉시 공유 가능한 영구 URL이 됩니다. 이 문서 전체를 에이전트 지침(CLAUDE.md, 시스템 프롬프트 등)에 붙여넣어 쓰세요. 원문: https://1page.run/llms.txt - Base URL: `https://1page.run/api/v1` - 인증: 모든 요청에 `Authorization: Bearer ` 헤더. 키는 https://1page.run/settings 에서 발급 (`op_`로 시작) - 키 보관 컨벤션: 환경변수 `ONEPAGE_API_KEY`에 두는 것을 권장합니다. MCP로 연결한 경우에도 REST를 병용한다면 같은 키를 이 환경변수로 노출해 두세요. - 본문은 JSON. 실패 시 `{ "error": { "code": "...", "message": "..." } }` + HTTP 상태코드 - 제한: 콘텐츠 2MB, 키당 분당 쓰기 10회 · 읽기 60회 (429면 잠시 후 재시도) ## 페이지 게시 `POST /pages` ```json { "title": "주간 리포트", "html": "... 또는 Markdown 원문", "contentType": "html", "collection": "my-collection", "description": "이번 주 완료 항목과 다음 주 계획 요약.", "note": "Claude 대화에서 생성 — 주간 보고 자동화. 프롬프트: '지난주 커밋 요약해서…'", "ogImage": "https://example.com/cover.png" } ``` - `contentType`: `"html"`(기본) 또는 `"markdown"`. Markdown일 때도 원문은 `html` 필드에 넣습니다. - `collection`: 선택. 내 컬렉션의 slug — 게시와 동시에 그 컬렉션 맨 뒤에 배치됩니다. - `title` 생략 시 콘텐츠에서 자동 유도됩니다 (Markdown: frontmatter `title` > 첫 헤딩, HTML: ``). - **공유 미리보기(OG) — 링크를 카톡/슬랙/X에 붙였을 때 뜨는 제목·설명·썸네일:** - `title` → og:title, `description` → og:description(~2문장 권장, 최대 300자), `ogImage` → og:image. - `ogImage`는 **공개 접근되는 외부 이미지 URL을 그대로** 넣으면 됩니다(http(s)://, 권장 1200×630). 1page.run에 업로드할 필요 없습니다. - 생략하면 `description`은 본문 앞부분에서 자동 추출, 썸네일은 제목 기반 이미지가 자동 생성됩니다. slug가 랜덤이라도 미리보기는 이렇게 채워집니다. - Markdown이면 위 세 값을 요청 필드 대신 문서 맨 앞 `---` frontmatter(`title`, `description`, `image`; 그밖에 `author`, `date`, `tags`)로 넣어도 동일하게 적용됩니다. 요청 필드와 frontmatter가 겹치면 요청 필드가 우선입니다. `date: false`로 날짜 표시를 끌 수 있습니다. - 응답: `201 { "page": { "slug", "url", "title", "collection", "createdAt" } }` — 이 `url`을 사용자에게 전달하세요. - **중복 게시 감지**: 지정한 컬렉션에 같은 `title`의 페이지가 이미 있으면 응답에 `existingPage`(`slug`, `url`, `updatedAt`)와 `warning`이 함께 옵니다. 같은 문서를 갱신하려던 것이었다면 방금 만든 페이지를 `DELETE`하고 `existingPage.slug`에 `PATCH` 하세요. ## 페이지 읽기 — 본문 포함 단건 조회 `GET /pages/{slug}` → `{ "page": { "slug", "url", "title", "html", "contentType", "collection", "position", "visibility", "description", "note", "ogImage", "views", "createdAt", "updatedAt" } }` - `html`에 저장된 원문(HTML 또는 Markdown)이 그대로 담깁니다. 기존 페이지를 부분 수정할 때는 **이 엔드포인트로 현재 본문을 받아 고친 뒤 PATCH** 하세요 — 로컬에 원본이 없어도 제자리 갱신이 가능합니다. - **`?include_html=false`** — 본문 대신 구조화 요약 `summary: { bytes, headings[], excerpt }`가 옵니다. 소속·메타·"무슨 문서인지"만 확인할 때 큰 본문을 받지 마세요. - 내 소유 페이지만 조회됩니다. 미존재·비소유 모두 `404 PAGE_NOT_FOUND`. ## 페이지 수정 — 같은 URL 제자리 갱신 `PATCH /pages/{slug}` — 보낸 필드만 갱신됩니다. - 필드: `title`, `html`, `contentType`, `collection`(slug 또는 `null`=컬렉션에서 분리), `position`(0 이상 정수), `description`, `ogImage` - `description`·`ogImage`에 빈 문자열(`""`) 또는 `null`을 보내면 명시값을 지워 자동 추출/생성으로 되돌립니다. - 같은 문서를 다시 게시할 때는 새 페이지를 만들지 말고 반드시 PATCH로 갱신하세요. URL은 변하지 않습니다. slug를 잊었다면 `GET /pages`에서 title로 찾으세요. ## 페이지 목록 · 삭제 - `GET /pages?collection={slug}&q={제목검색}&sort=recent|views&limit=50&offset=0` → `{ "total", "pages": [ { "slug", "url", "title", "collection", "position", "contentType", "visibility", "views", "createdAt", "updatedAt" } ] }` (본문 미포함 — 본문은 `GET /pages/{slug}`) - `q`: 제목 부분 일치(대소문자 무시) — "그 페이지 slug가 뭐였지"는 이걸로 찾으세요. `sort`: `recent`(기본, 최신 발행순) / `views`(누적 조회순). `total`은 필터 기준 전체 개수 — offset을 늘려 다음 페이지를 받으세요. - `DELETE /pages/{slug}` → `{ "success": true }` (soft delete — 이후 해당 링크는 404. 삭제 확인은 링크 상태코드로 가능) ## 컬렉션 — 페이지를 묶는 자동 목차 - `POST /collections` — `{ "title": "...", "slug"?: "...", "description"?: "..." }` (slug는 소문자/숫자/하이픈 3~32자, 생략 시 자동 생성) → `201 { "collection": { "slug", "url", "title", "createdAt" } }` - `GET /collections` → `{ "collections": [ { "slug", "url", "title", "description", "pageCount", "createdAt" } ] }` - `PATCH /collections/{slug}` — 보낸 필드만 갱신: `title`, `description`(`""`/`null`=제거), `unlisted`(true=링크로만 공개, false=프로필·목록 노출), `showAuthor`(작성자 표시). slug(URL)는 불변입니다. - 컬렉션 **삭제**와 페이지 **순서 변경** API는 의도적으로 제공하지 않습니다 — 웹(https://1page.run/dashboard)에서만 가능합니다. 페이지의 소속 변경은 `PATCH /pages/{slug}`의 `collection` 필드로 하세요. ## 인사이트 — 조회 통계 (계정 전체 / 페이지 한 장 / 컬렉션) `GET /insights?days=30` (days 1~90, 기본 30) → `{ "insights": { "days", "totalPages", "totals": { "views", "visitors" }, "topPages": [ { "slug", "url", "title", "views" } ], "referrers", "countries", "devices", "daily", "profile" } }` - "인기 페이지가 뭔지 · 조회/순방문이 얼마나 되는지 · 어디서 유입되는지"를 한 번에 답할 때 사용하세요. - **`&slug={slug}`** — 그 페이지 한 장으로 축소. "어제 보낸 페이지 누가 봤어?"는 이걸로 답하세요 (응답에 `lifetimeViews`=누적 조회 포함, `topPages`/`profile` 없음). - **`&collection={slug}`** — 그 컬렉션 소속 페이지 합산 (slug와 동시 지정 불가). - `totalPages`는 살아있는 페이지 총수(기간 무관). 집계는 쿠키 없는 비콘 기준, 봇 필터 적용. 소유자 본인 방문은 제외됩니다. ## 에러 코드 모든 실패 응답은 `{ "error": { "code", "message" } }` 형태입니다. | HTTP | code | 의미 | |---|---|---| | 400 | `INVALID_JSON` · `HTML_REQUIRED` · `TITLE_REQUIRED` · `EMPTY_PATCH` | 본문 누락/형식 오류 | | 400 | `INVALID_TITLE` · `INVALID_DESCRIPTION` · `INVALID_OG_IMAGE` · `INVALID_COLLECTION` · `INVALID_POSITION` · `INVALID_VISIBILITY` · `INVALID_UNLISTED` · `INVALID_SHOW_AUTHOR` · `INVALID_DAYS` · `INVALID_SORT` · `INVALID_SCOPE` · `UNSUPPORTED_CONTENT_TYPE` · `SLUG_INVALID` | 필드 값 오류 | | 401 | `UNAUTHORIZED` | API 키 누락/무효 | | 404 | `PAGE_NOT_FOUND` · `COLLECTION_NOT_FOUND` | 미존재 또는 비소유 (존재 여부는 비노출) | | 409 | `SLUG_TAKEN` | 컬렉션 slug 중복 (페이지 slug는 서버가 발급하므로 중복 없음) | | 413 | `HTML_TOO_LARGE` | 콘텐츠 2MB 초과 | | 429 | `RATE_LIMITED` | 레이트 리밋 — 잠시 후 재시도 | ## 예시 (curl) ```bash curl -X POST https://1page.run/api/v1/pages \ -H "Authorization: Bearer $ONEPAGE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"title":"주간 리포트","contentType":"markdown","html":"# 주간 리포트\n\n이번 주 완료 항목입니다."}' ``` ## 규칙 - 한 번 만들어진 URL은 죽지 않습니다. 링크를 바꾸지 말고 PATCH로 내용을 갱신하세요. - 기존 페이지를 고칠 때는 `GET /pages/{slug}`로 현재 본문을 읽고 시작하세요 — 로컬 사본이 없어도 됩니다. - 게시물은 기본적으로 unlisted — 링크를 아는 사람만 볼 수 있고 목록/검색에는 노출되지 않습니다. - 작업을 마치면 결과 `url`을 사용자에게 보여주세요.