씰로
SEALO API 문서
PHASE 0 · UNSTABLE
v0.2 · 2026-09-02
SEALO의 서버 API는 AI 초안을 사용자 본인의 말투로 다시 쓰기 위한 말투 추출·다시 쓰기·프로필 저장·계측 4종으로 구성됩니다. 아래는 Phase 0 단계의 API 레퍼런스입니다 — 정식 v1은 아니며 사전 통지 없이 바뀔 수 있습니다.
인증은 아직 없고, IP당 일일 호출 수 제한만 있습니다. 이 문서의 엔드포인트는 SEALO 웹앱(
/voice)이
같은 출처에서 호출하도록 만들어졌습니다.
/api/style-extract·
/api/rewrite는 호출마다 모델 API 비용이 발생하며, IP당 하루 호출 수를
넘으면
429를 반환합니다(정확한 한도는 비공개 — 어뷰징 방지). 대량·자동화 연동을 계획 중이라면 먼저
ilgam.jtbd@gmail.com로 문의해 주세요 — 사전 협의 없는 대량 호출은 예고 없이 차단될 수 있습니다.
Base URL
https://sealo-site.vercel.app # sealo.kr DNS 연결 전 임시 도메인 — 연결 후 https://sealo.kr로 교체됩니다
모든 요청·응답 본문은 application/json이며, 요청은 전부 POST만 허용합니다. 그 외 메서드는 405를 반환합니다.
POST/api/style-extract
사용자가 직접 쓴 한국어 글에서 말투(관찰·말투 항목 후보·안 쓰는 표현)를 추출합니다. 모든 관찰·항목에는 입력 원문에서 그대로 복사한 근거 인용이 붙고, 근거가 원문에 실재하지 않으면 서버가 해당 항목을 드롭합니다(생성 금지 게이트) — 응답의 dropped가 그 개수입니다.
내부적으로 복수의 추출 엔진을 정해진 순서로 시도하고, 앞선 엔진이 실패(미설정·오류·응답 파싱 실패)하면 다음으로 넘어갑니다. 생성 금지 게이트는 어느 엔진이 응답했든 동일하게 적용되므로 응답 형식과 생성 금지 게이트는 엔진에 무관하게 동일합니다 — 어느 엔진이 실제로 응답했는지는 클라이언트에 노출하지 않습니다.
요청 본문
| 필드 | 타입 | 필수 | 설명 |
| text | string | 필수 | 분석할 원문. 80자 이상 20,000자 이하. 원문은 저장되지 않습니다. |
요청 예시
curl -sS -X POST https://sealo-site.vercel.app/api/style-extract \
-H "Content-Type: application/json" \
-d '{"text":"여기에 80자 이상의 직접 쓴 글을 넣습니다..."}'
응답 (200)
| 필드 | 타입 | 설명 |
| observations | Array<{title, evidence}> | 말투 관찰 3~6개. evidence는 원문 그대로의 인용 |
| rules | Array<{rule, why, evidence}> | 실행 가능한 말투 항목 후보 2~5개. rule은 15자 이내 한 줄 |
| avoids | Array<{phrase, why}> | 이 글이 일관되게 피하는 표현 0~5개. 확실하지 않으면 빈 배열 |
| dropped | number | 근거가 원문에 없어 드롭된 항목 수(생성 금지 게이트 작동 확인용) |
응답 예시
{
"observations": [
{ "title": "한 문장에 한 가지 사실만 담아 짧게 끊어 씀",
"evidence": "그래서 매번 처음부터 다시 씁니다." }
],
"rules": [
{ "rule": "문장은 짧게 끊는다",
"why": "글 전체가 단문 위주로 구성되어 있고, 본인이 그 습관을 명시적으로 드러낸다",
"evidence": "문장도 짧게 끊어 쓰는 편인데 AI는 자꾸 길게 늘여 씁니다." }
],
"avoids": [],
"dropped": 0
}
에러
| 상태 | 사유 |
| 400 | text가 80자 미만이거나 20,000자 초과 |
| 429 | IP당 일일 호출 수 초과, 또는 상위 API 한도 초과 — 잠시 후·다음 날 재시도 |
| 502 | 추출 실패(모델 거부·응답 파싱 실패 등) — 입력을 바꾸지 않고 재시도 가능 |
| 503 | 추출 엔진 미연결(서버 설정 문제) — 클라이언트에서 해결 불가 |
다시 쓰기
POST/api/rewrite
AI 초안을 사용자의 말투 항목으로 문장 단위로 다시 씁니다. 의미·주장·수치는 바꾸지 않고 말투만 바꿉니다. 바뀐 문장에 원문에 없던 숫자가 생기면 서버가 그 문장을 원문으로 되돌립니다(생성 금지 게이트, reverted_count). 조직 모드(mode:"org")에서는 회사 문서가 아직 0건이므로 수치·비교·전망 문장을 blank:true로 표시합니다 — 근거 없으면 비웁니다. 초안·결과는 저장되지 않습니다.
요청 본문
| 필드 | 타입 | 필수 | 설명 |
| draft | string | 필수 | AI 초안. 20자 이상 10,000자 이하 |
| rules | Array<{id, rule, evidence?}> | 필수 | 1~10개. /api/style-extract의 rules에 번호(id)를 붙여 보냅니다 |
| mode | "personal"|"org" | 선택 | 기본 personal. org는 수치·비교·전망 문장을 빈칸 판정 |
요청 예시
curl -sS -X POST https://sealo-site.vercel.app/api/rewrite \
-H "Content-Type: application/json" \
-d '{"draft":"저희 팀은 남다른 방식으로 문제를 풉니다. 시장은 앞으로도 계속 성장할 전망입니다.",
"rules":[{"id":1,"rule":"결론을 첫 문장에 둔다"},{"id":2,"rule":"숫자엔 단위를 붙인다"}],
"mode":"personal"}'
응답 (200)
| 필드 | 타입 | 설명 |
| sentences | Array<{original, rewritten, rule_ids, claim, blank, reason?, reverted?}> | 초안 문장 순서대로. rule_ids는 적용한 항목 번호. claim은 수치·비교·전망 신호. blank는 조직 모드에서 근거 없음 |
| changed_count | number | 말투가 바뀐 문장 수 |
| reverted_count | number | 새 숫자가 생겨 원문으로 되돌린 문장 수(생성 금지 게이트) |
| org_docs | number | 조직 문서 수 — 현재 항상 0 |
| truncated | boolean | 모델 출력이 max_tokens에서 잘렸을 때 true. 완결된 문장까지만 반환됩니다(화면 v2 P1 §1) |
에러
| 상태 | 사유 |
| 400 | draft 길이 위반 또는 유효한 rules 0개 |
| 429 | IP당 일일 호출 수 초과, 또는 상위 API 한도 초과 |
| 502 | 다시 쓰기 실패(모델 거부·응답 파싱 실패, 또는 잘림 후 건질 문장이 0개) — 초안을 바꾸지 않고 재시도 가능 |
| 503 | 다시 쓰기 엔진 미연결(서버 설정 문제) |
리포트 재배열
POST/api/report
이미 /api/rewrite로 다시 쓴 문장 목록을 5단 리포트 구조(한 줄 결론·핵심 3·본문 소제목·숫자·다음 할 일)로 재배열합니다. 새 내용을 만들지 않습니다 — 입력 문장을 고르고 순서만 바꿉니다. 각 항목은 입력 문장 중 하나를 그대로 인용한 evidence가 있어야 채택되고, 없으면 서버가 드롭합니다(생성 금지 게이트).
요청 본문
| 필드 | 타입 | 필수 | 설명 |
| sentences | string[] | 필수 | 이미 다시 쓴 최종 문장 목록. 합쳐서 10,000자 이하 |
응답 (200)
| 필드 | 타입 | 설명 |
| conclusion | string | 한 줄 결론. 원문에 결론 문장이 없으면 빈 문자열 |
| key_points | Array<{text, evidence}> | 핵심 최대 3개 |
| sections | Array<{heading, body}> | 소제목 단위 본문 재배열. 최대 6개 |
| numbers | Array<{value, unit, context, evidence}> | 입력에 나온 수치만 |
| next_actions | Array<{text, evidence}> | 입력이 행동을 제안한 경우만. 최대 4개 |
에러
| 상태 | 사유 |
| 400 | sentences 0개 또는 10,000자 초과 |
| 429 | IP당 일일 호출 수 초과, 또는 상위 API 한도 초과 |
| 502 | 재배열 실패(모델 거부·응답 파싱 실패) |
| 503 | 리포트 엔진 미연결(서버 설정 문제) |
프로필 저장 내부용
POST/api/profileWEBAPP INTERNAL
사용자가 확정한 말투 항목을 프로필로 저장합니다. 원문은 저장하지 않습니다 — materials에는 재료 출처와 글자 수만 남습니다(확정 9). 소유권 인증이 없는 익명 세션 모델이라 외부 통합용이 아니라 SEALO 웹앱 전용으로 설계됐습니다. 현재 미리보기 화면(/voice)은 이 API를 호출하지 않습니다 — 저장은 대기목록 이후 실서비스에서만.
요청 본문
| 필드 | 타입 | 필수 | 설명 |
| rules | Array<{rule, why?, evidence?}> | 필수 | 1~20개. rule이 빈 문자열인 항목은 제외됩니다 |
| asset_source | "paste"|"blog"|"kakao" | 선택 | 재료 출처(확정 10 · P1 재료 3종). 기본값 paste |
| char_count | number | 선택 | 재료 글자 수(원문 대신 저장되는 메타) |
| anon | string | 선택 | 익명 세션 ID(최대 64자) — 클라이언트가 로컬에서 생성해 재사용 |
응답 (200)
{ "profile_id": "uuid", "rules": 4 }
에러
| 상태 | 사유 |
| 400 | 유효한 rule이 1개 미만이거나 20개 초과 |
| 502 | 저장 실패 — 확정 내용은 클라이언트(브라우저)에 남아 있으므로 재시도 가능 |
| 503 | 저장소 미연결(서버 설정 문제) |
계측 수집 내부용
POST/api/trackWEBAPP INTERNAL
화이트리스트에 있는 이벤트만 기록합니다(확정 7 — 계측은 서버 기록이 정본). 전송 실패가 사용자 경험을 막지 않도록 설계돼 있어, 저장소 미연결 시에도 202로 무해 응답합니다. 화면에서는 data-ev 속성 한 개와 위임 리스너 한 개로 발화합니다. published_as_is는 edit_ratio 0(원래대로·직접 쓰기 0건) 상태에서 복사·내보내기 행동이 있을 때만 셉니다 — 되돌리거나 직접 채운 문장이 있으면 복사해도 세지 않습니다.
허용 이벤트
profile_created · taste_rule_edited · draft_submitted · transform_done · published_as_is · revision_loop
미리보기 화면의 profile_created는 stored:false 속성으로 옵니다 — 내 말투가 만들어진 시점이지 저장이 아닙니다. 서버 저장은 실서비스에서만.
요청 본문
| 필드 | 타입 | 필수 | 설명 |
| ev | string | 필수 | 위 허용 이벤트 중 하나. 목록 밖 값은 400 |
| anon | string | 선택 | 익명 세션 ID(최대 64자) |
| props | object | 선택 | 이벤트 부가 속성(자유 형식 JSON) |
응답
| 상태 | 본문 | 의미 |
| 200 | {"stored":true} | 저장 성공 |
| 202 | {"stored":false} | 저장소 미연결 — 무해 응답(클라이언트 재시도 불필요) |
| 400 | {"error":"..."} | 허용되지 않은 이벤트 |
| 502 | {"stored":false} | 저장 실패 |
공통 사항
모든 엔드포인트는 POST 외 메서드에 405를 반환합니다. 에러 응답 본문은 {"error": "사람이 읽는 한국어 메시지"} 형식이며, 내부 원인(모델 응답 원문·DB 에러 상세)은 클라이언트에 노출하지 않고 서버 로그에만 남습니다 — 신고 시 요청 시각과 상태 코드를 함께 알려주세요.