AI가 쓴 글, 내 PC가 발행합니다
ChatGPT·Claude 같은 내 AI가 만든 글과 사진을 API로 보내면, 켜져 있는 내 PC의 원스카우트가 가져가 네이버 블로그에 예약글로 올립니다. 글은 우리가 쓰지 않습니다 — 내 AI가 쓰고, 우리는 발행 길만 제공합니다. 네이버 접속은 항상 내 PC에서만 일어납니다.
시작하기
- 원스카우트 블로그 이용권을 구독합니다. API 키 발급은 이용권이 있는 계정만 할 수 있습니다.
- 웹에서 로그인한 뒤 API 키 발급(현재 위치: 도구 > 인스타 댓글 DM > 설정 탭)에서 권한
blog-post:write(+ 조회용blog-post:read)를 선택해 키를 만듭니다. 키(osk_…)는 만들 때 한 번만 보입니다. - PC에 원스카우트를 설치하고 같은 계정으로 로그인, 네이버 계정을 연결해 둡니다.
인증과 권한
모든 요청에 Authorization: Bearer osk_… 헤더를 붙입니다. 계정당 분당 60회까지 요청할 수 있고, 넘으면 429와 Retry-After 헤더가 옵니다.
| 권한 | 할 수 있는 일 |
|---|---|
blog-post:write | 글 접수(POST), 업로드 완료 알림, 대기 중인 글 취소(DELETE) |
blog-post:read | 대기열·상태 조회(GET) |
키가 없거나 틀리면 401, 권한이 모자라면 403 insufficient_scope, 이용권이 만료되면 403 paid_required입니다.
발행폴더 포맷 v1
글은 평문 텍스트 파일 한 개와 사진 파일들로 보냅니다. 앱의 “문서 폴더 발행”과 같은 규칙·같은 검사기를 쓰므로, 서버가 접수 시점에 먼저 검사해 문제가 있으면 바로 422와 이유 목록(report.items)을 돌려줍니다.
- 헤더 4줄:
제목:메뉴:대표이미지:사진:, 그 아래========== 본문 ==========줄. - 본문 안 사진 자리는 한 줄에
[사진 01],[사진 02]… 처럼 단독으로 씁니다. 번호는 01부터 연속, 한 번씩만. - 사진 파일명은 반드시
NN_접두(예:사진/01_atm.jpg)로 시작합니다.3월 여행.jpg처럼 번호가 아닌 이름은 사진 번호로 읽지 않습니다. (번호 바로 뒤에 한글이 붙는 이름은01내부.jpg처럼 0을 채운 두 자리일 때만 번호로 인식합니다.) - 맨 끝에
#태그를 한 줄로(최대 30개). 소제목은1. 제목한 줄. - 지원하지 않는 서식(표·HTML·글자색 등)은 단순 문단으로 바뀌고, 바뀐 내용은
report에 표시됩니다.
예시 문서
제목: 말레이시아 은행 계좌 없이 사는 법 메뉴: 정착·생활 대표이미지: 대표이미지/대표_은행계좌.jpg 사진: 본문 [사진 NN] 번호대로 2장 ========== 본문 ========== 말레이시아에 온 지 석 달이 넘었는데 아직 은행 계좌가 없다. [사진 01] 1. 현금은 ATM에서 뽑았다 메이뱅크 ATM에서 트래블 카드로 인출했다. [사진 02] #말레이시아 #은행계좌 #해외생활
AI에게 붙여넣는 지시문 (프롬프트 스니펫)
글을 쓰게 하기 전에 아래 지시문을 AI에게 그대로 붙여넣으세요. 형식이 어긋나는 일이 크게 줄어듭니다.
아래 규칙을 지켜서 블로그 글을 "발행폴더 포맷 v1" 평문(.txt)으로 써줘.
[파일 구성]
- 문서 1개: 글.txt (UTF-8)
- 사진: 사진/01_설명.jpg, 사진/02_설명.jpg … (파일명은 반드시 두 자리 번호 + 밑줄로 시작: NN_)
- 대표 이미지(선택): 대표이미지/대표_설명.jpg
[글.txt 형식]
제목: (글 제목 한 줄)
메뉴: (네이버 블로그 카테고리 이름, 없으면 빈칸)
대표이미지: 대표이미지/대표_설명.jpg
사진: 본문 [사진 NN] 번호대로 N장
========== 본문 ==========
(본문 첫 문단)
[사진 01]
(이어지는 본문. 사진을 넣을 자리마다 [사진 02], [사진 03] … 을 한 줄에 단독으로 쓴다)
1. 소제목은 이렇게 "번호. 제목" 한 줄로 쓴다
(마지막 줄) #태그1 #태그2 #태그3
[규칙]
- 사진 번호는 01부터 연속으로, 본문에서 한 번씩만 쓴다. 파일명 번호와 [사진 NN]이 같은 사진을 가리킨다.
- 사진 파일명은 "01_", "02_" 처럼 번호+밑줄로 시작한다. ("3월 여행.jpg" 같은 이름은 번호로 인식되지 않는다)
- (API 로 보낼 때) 발행 시각을 지정하려면 타임존 오프셋을 반드시 붙인다. 예: 2026-11-05T09:00:00+09:00 (오프셋 없는 시각은 거절된다)
- 태그는 맨 끝에 # 로 붙여 쓰고 30개 이하로 한다.
- 구분선은 ──────── 한 줄만 쓴다. 표·HTML·마크다운 이미지 문법은 쓰지 않는다.
- 출처 링크는 "출처: 사이트명 주소" 형태의 한 줄로 쓴다.
엔드포인트
기준 주소는 https://www.one-scout.com입니다. 이미지는 서버리스 본문 한도 때문에 요청 본문에 넣지 않고, 접수 응답에 돌려주는 업로드 주소로 직접 올립니다(주소는 2시간 유효).
| 메서드 | 경로 | 설명 |
|---|---|---|
| POST | /api/tools/blog-post/drafts | 글 접수. JSON 본문: document(fileName·text) + images[](name·size) 또는 zip(size), 선택 publishMode(reserve 기본 / immediate)·scheduledAt(ISO 8601, 타임존 오프셋 필수 — 예 2026-11-05T09:00:00+09:00 또는 …Z; 지금부터 30분~30일, 10분 단위로 올림). 헤더 Idempotency-Key 권장. |
| POST | /api/tools/blog-post/drafts/{id}/complete | 업로드를 마쳤다고 알림. 서버가 파일 존재·크기를 확인하고 대기열(queued)에 올립니다. 이미 올라갔으면 같은 응답(멱등). |
| GET | /api/tools/blog-post/drafts/{id} | 상태·postUrl·오류 조회. |
| GET | /api/tools/blog-post/drafts?status=queued,scheduled&limit=20 | 내 글 목록(최신순, 최대 50). |
| DELETE | /api/tools/blog-post/drafts/{id} | 앱이 가져가기 전(uploading·queued)에만 취소. 이미 가져갔다면 409 — 네이버 예약글에서 직접 삭제하세요. |
앱이 쓰는 /inbox/claim, /inbox/{id}/status는 앱 로그인 세션 전용이라 API 키로는 호출할 수 없습니다.
curl 예시
글 + 사진 보내기
# 0) 환경 변수
export OSK="osk_여기에_키"
export API="https://www.one-scout.com"
# 1) 글 접수 — 문서 텍스트 + 이미지 목록(이름·바이트 크기)을 보낸다
curl -sS -X POST "$API/api/tools/blog-post/drafts" \
-H "Authorization: Bearer $OSK" \
-H "Idempotency-Key: my-post-2026-11-05-001" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile text 글.txt '{
document: { fileName: "글.txt", text: $text },
images: [
{ name: "사진/01_atm.jpg", size: '"$(stat -f%z 사진/01_atm.jpg)"' },
{ name: "사진/02_cash.jpg", size: '"$(stat -f%z 사진/02_cash.jpg)"' }
]
}')" | tee res.json
# 2) 응답의 uploads[] 주소로 이미지를 올린다 (이름 순서대로). Content-Type 은 반드시 image/* 로,
# 한 번 올린 파일은 덮어쓸 수 없다(잘못 올렸다면 글을 취소하고 새로 접수)
curl -sS -X PUT -H "Content-Type: image/jpeg" \
--data-binary @사진/01_atm.jpg "$(jq -r '.uploads[0].uploadUrl' res.json)"
curl -sS -X PUT -H "Content-Type: image/jpeg" \
--data-binary @사진/02_cash.jpg "$(jq -r '.uploads[1].uploadUrl' res.json)"
# 3) 업로드 끝 알림 — 서버가 파일을 확인하고 대기열(queued)에 올린다
ID="$(jq -r '.draft.jobId' res.json)"
curl -sS -X POST "$API/api/tools/blog-post/drafts/$ID/complete" -H "Authorization: Bearer $OSK"
# 4) 상태 확인 (내 PC 앱이 가져가 예약하면 scheduled, 시각이 지나면 published)
curl -sS "$API/api/tools/blog-post/drafts/$ID" -H "Authorization: Bearer $OSK"폴더를 zip 으로 보내기
윈도우 탐색기로 만든 zip(한글 파일명)도 열 수 있습니다.
# 폴더를 zip 으로 묶어 보내는 방법 (글.txt + 사진/ 폴더)
SIZE="$(stat -f%z 발행폴더.zip)"
curl -sS -X POST "$API/api/tools/blog-post/drafts" \
-H "Authorization: Bearer $OSK" -H "Content-Type: application/json" \
-d "{\"zip\": {\"size\": $SIZE}}" | tee res.json
curl -sS -X PUT -H "Content-Type: application/zip" \
--data-binary @발행폴더.zip "$(jq -r '.uploads[0].uploadUrl' res.json)"
curl -sS -X POST "$API/api/tools/blog-post/drafts/$(jq -r '.draft.jobId' res.json)/complete" \
-H "Authorization: Bearer $OSK"접수 응답 예시
{
"draft": {
"schema": "hankkeut.blogPostInboxDraft/v1",
"toolId": "blog-post",
"jobId": "3f6c…",
"status": "uploading",
"createdAt": "2026-11-05T01:00:00.000Z",
"updatedAt": "2026-11-05T01:00:00.000Z",
"payload": {
"draftId": "3f6c…",
"title": "말레이시아 은행 계좌 없이 사는 법",
"inputKind": "files",
"publishMode": "reserve",
"scheduledAt": null,
"resolvedScheduledAt": null,
"postUrl": null,
"fileCount": 2,
"report": { "ok": true, "counts": { "…": 0 }, "items": [] }
},
"error": null
},
"uploads": [
{ "name": "사진/01_atm.jpg", "size": 482113, "method": "PUT",
"uploadUrl": "https://…/upload/sign/blog-post-inbox/…?token=…",
"headers": { "Content-Type": "image/jpeg" } }
],
"completeUrl": "/api/tools/blog-post/drafts/3f6c…/complete"
}같은 Idempotency-Key로 같은 내용을 다시 보내면 새 글을 만들지 않고 기존 글을 돌려줍니다(replayed: true). scheduledAt이 그 사이 30분 이내로 가까워져도 같은 요청이면 재생으로 응답합니다. 같은 키로 다른 내용을 보내면 422 idempotency_key_reuse이고, 이미 실패·취소·만료된 글의 키를 다시 쓰면409 idempotency_key_closed이니 새 키로 보내세요.
상태
uploading → queued → picked → scheduled → published
└──────────────→ failed
queued/uploading → cancelled · queued/uploading 장기 대기 → expired| 상태 | 의미 |
|---|---|
uploading | 접수됨, 이미지 업로드 대기(2시간 안에 complete 필요) |
queued | 앱이 가져가길 기다리는 중(7일 넘으면 expired) |
picked | 내 PC 앱이 가져가 처리 중 |
scheduled | 네이버에 예약글로 등록됨(resolvedScheduledAt에 실제 예약 시각) |
published | 예약 시각이 지나 발행됨. 주소를 알면 postUrl 포함 |
failed | error.code·error.message에 이유(예: DOCUMENT_INVALID, QUOTA, RETRY_EXHAUSTED) |
cancelled / expired | 취소됨 / 기간 안에 앱이 가져가지 못함(PC 꺼짐 등) |
발행 한도는 기존 앱 규칙 그대로 적용됩니다(이용권 기준 하루 발행 수 등). 한도에 걸리면 앱이 최대 48시간 동안 다시 시도한 뒤failed로 알립니다.
한도
| 항목 | 값 |
|---|---|
| 이미지 수 | 글당 최대 30장 |
| 이미지 크기 | 한 장 15MB 이하 (jpg·jpeg·png·webp·gif·heic·heif) |
| 전체 크기 | 글 하나(문서+이미지 또는 zip) 40MB 이하 |
| 문서 텍스트 | 300KB 이하, 접수 요청 본문 1MB 이하 |
| 대기 중인 글 | 계정당 동시에 10건(uploading·queued·picked). 넘으면 429 inbox_full |
| 요청 횟수 | 계정당 분당 60회 |
| 보관 기간 | 대기 7일. 앱이 가져간 뒤에는 서버의 파일을 지웁니다. |
자주 나는 오류
| 응답 | 원인과 해결 |
|---|---|
422 invalid_document | 포맷 v1 검사 실패. 응답의 report.items(예: 제목 없음, 본문 비어 있음, 사진 번호 불일치)를 AI에게 그대로 전달해 고쳐 다시 보내세요. |
422 invalid_upload | complete 때 업로드한 파일의 확장자·Content-Type(image/*, zip은 application/zip)·파일 내용이 선언과 다릅니다. 올린 파일은 덮어쓸 수 없어 이 글은 종료되므로 새로 접수하세요. |
409 upload_incomplete | complete 전에 이미지가 모두 올라오지 않았거나 선언한 size와 실제 크기가 다릅니다. missing·wrongSize를 확인하세요. 올린 파일은 덮어쓸 수 없으므로 크기가 다른 파일이 있으면 DELETE로 글을 취소한 뒤 새 Idempotency-Key로 다시 접수하세요(누락만 있으면 해당 파일을 올리고 complete를 다시 호출). |
413 too_large / too_many_images | 위 한도를 넘었습니다. 이미지를 줄이거나 압축하세요. |
429 inbox_full | 대기 중인 글이 많습니다. 앱이 가져갈 때까지 기다리거나 DELETE로 취소하세요. |
409 not_cancellable | 앱이 이미 가져간 글입니다. 네이버 예약글에서 직접 삭제하세요. |