핀노트 API · CLI

1. 개발자 REST API v1

토큰은 관리 화면 API 토큰 메뉴에서 만든다. 원문은 만들 때 한 번만 보인다.

export PN=https://pinnote.itemview.co.kr
export PN_TOKEN=pn_여기에_토큰

사이트 목록

curl -s -H "Authorization: Bearer $PN_TOKEN" $PN/api/v1/sites

의견 목록

curl -s -H "Authorization: Bearer $PN_TOKEN" "$PN/api/v1/items?site=pk_a8d81b33751c7fc8e2120547&status=open&per_page=20"
파라미터값
site사이트 id 또는 사이트 키
statusopen(NEW·TRIAGED·IN_PROGRESS·NEEDS_INFO·REOPENED), resolved, active(open+resolved), closed, all, 또는 NEW,TRIAGED
kindBUG(오류) DESIGN(디자인) COPY(문구) IDEA(아이디어) UX(불편), 쉼표로 여러 개
anchor_statusATTACHED RELOCATED MISSING ARCHIVED
page_key화면 키, 예: /t/:token (URL 인코딩)
assignee멤버 id 또는 none
label, q라벨 / 본문·요소 이름·번호 검색
sortnew(기본) old votes updated page
page, per_page페이지 나누기(최대 200)

응답의 meta: {total, page, per_page, pages}

의견 상세 (스냅샷·문맥·댓글·히스토리)

curl -s -H "Authorization: Bearer $PN_TOKEN" $PN/api/v1/items/12

주요 필드

댓글 달기

curl -s -X POST -H "Authorization: Bearer $PN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"body":"재현했습니다. 오늘 고칠게요","author":"claude"}' $PN/api/v1/items/12/comments

상태 바꾸기

# 고치는 중
curl -s -X POST -H "Authorization: Bearer $PN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"status":"IN_PROGRESS","author":"claude"}' $PN/api/v1/items/12/status

# 해결: note(무엇을 어떻게 고쳤는지)가 없으면 422 RESOLUTION_REQUIRED
curl -s -X POST -H "Authorization: Bearer $PN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"status":"RESOLVED","note":"주문 버튼 onClick 누락을 고치고 로딩 표시를 넣었습니다","version":"1.4.2","ref":"a1b2c3d"}' \
  $PN/api/v1/items/12/status

# 안 고침(사유 필수) / 중복(원본 번호 필수) / 다시 열기
curl -s -X POST -H "Authorization: Bearer $PN_TOKEN" -H 'Content-Type: application/json' -d '{"status":"WONT_FIX","note":"정책상 유지"}' $PN/api/v1/items/13/status
curl -s -X POST -H "Authorization: Bearer $PN_TOKEN" -H 'Content-Type: application/json' -d '{"status":"DUPLICATE","duplicate_of":12}' $PN/api/v1/items/14/status
curl -s -X POST -H "Authorization: Bearer $PN_TOKEN" -H 'Content-Type: application/json' -d '{"status":"REOPENED","note":"아이폰에서는 그대로"}' $PN/api/v1/items/12/status

허용되는 이동

지금바꿀 수 있는 상태
NEWTRIAGED, IN_PROGRESS, NEEDS_INFO, RESOLVED, WONT_FIX, DUPLICATE
TRIAGED / IN_PROGRESS / NEEDS_INFO / REOPENED(서로) + RESOLVED, WONT_FIX, DUPLICATE
RESOLVEDVERIFIED, REOPENED
VERIFIED / WONT_FIX / DUPLICATEREOPENED

오류 코드

중요도·종류·담당자·라벨

curl -s -X PATCH -H "Authorization: Bearer $PN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"priority":"HIGH","kind":"BUG","assignee":"홍길동","labels":["결제","모바일"]}' $PN/api/v1/items/12

다시 연결

# 새 선택자를 직접 지정. 다음 방문 때 위젯이 확인한다.
curl -s -X POST -H "Authorization: Bearer $PN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"ui":"order.submit","note":"버튼을 data-ui로 교체"}' $PN/api/v1/items/12/relink
# 본문을 비우면 브라우저 재지정 링크(24시간)를 준다. 열고 새 요소를 누르면 연결된다.
curl -s -X POST -H "Authorization: Bearer $PN_TOKEN" -H 'Content-Type: application/json' -d '{}' $PN/api/v1/items/12/relink

사라진 요소

curl -s -H "Authorization: Bearer $PN_TOKEN" "$PN/api/v1/missing?site=1"
curl -s -H "Authorization: Bearer $PN_TOKEN" $PN/api/v1/anchors/7          # 찾는 방법·스냅샷·요소 히스토리·relink_url
# [수정으로 해결됨]: 열린 의견을 모두 RESOLVED로(note 필수), 요소는 보관
curl -s -X POST -H "Authorization: Bearer $PN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"note":"쿠폰 배너를 없애고 주문 화면으로 옮겼습니다"}' $PN/api/v1/anchors/7/fixed
# [보관]
curl -s -X POST -H "Authorization: Bearer $PN_TOKEN" -H 'Content-Type: application/json' -d '{"note":"실험 화면 종료"}' $PN/api/v1/anchors/7/archive

missing 응답의 normal_after_fix: true는 열린 의견이 없다는 뜻이다(해결 뒤 사라진 정상 경우).

내보내기 (AI에게 넘기기 좋은 형태)

# 마크다운: 사이트 → 화면 → 요소(선택자들·텍스트) → 의견. status 기본값은 active(열림+해결됨)
curl -s -H "Authorization: Bearer $PN_TOKEN" "$PN/api/v1/export?site=1&status=open" > pinnote.md
# JSON: 같은 구조
curl -s -H "Authorization: Bearer $PN_TOKEN" "$PN/api/v1/export?site=1&status=open&format=json"

마크다운 모양

## 사이트: 뉴팅 데모 (demo) — imgx.kr
### 화면 `/t/:token` — 테이블 화면 (3건)
예시 주소: https://imgx.kr/t/abc123
#### 요소: "주문하기" 버튼 `[data-ui="order.submit"]`
- 선택자: `[data-ui="order.submit"]` · `main > form > button.primary`
- DOM 경로: `html > body > main:nth-of-type(1) > form:nth-of-type(1) > button:nth-of-type(2)`
- 태그/역할: button / button · 접근성 이름: "주문하기"
- 텍스트: "주문하기"
- 근처 기준: h2 "장바구니"
- 요소 상태: ATTACHED (그대로 찾음) · 마지막으로 찾음 2026-09-16 14:00:00

- **#12** [오류 · HIGH] 상태 NEW · 공감 3 · 작성 홍길동 · 2026-09-16 13:20:00 · 버전 1.4.1 · 화면 390x844@3
  > 눌러도 반응이 없어요
  - 댓글(API:agent (claude)): 재현했습니다

통계

curl -s -H "Authorization: Bearer $PN_TOKEN" "$PN/api/v1/stats?site=1"

2. CLI (서버에서)

cd /home/webs/pinnote
php bin/pinnote.php sites
php bin/pinnote.php list --site=pk_a8d81b33751c7fc8e2120547 --status=open            # --kind=BUG --page=/t/:token --anchor=MISSING --q=검색 --limit=50
php bin/pinnote.php show 12                    # 사람이 읽는 형태 (--json 은 REST 상세와 같은 JSON)
php bin/pinnote.php comment 12 "재현했습니다" --as=claude
php bin/pinnote.php resolve 12 "주문 버튼 onClick 누락을 고쳤습니다" --version=1.4.2 --ref=a1b2c3d --as=claude
php bin/pinnote.php status 13 WONT_FIX "정책상 유지"
php bin/pinnote.php status 14 DUPLICATE --dup=12
php bin/pinnote.php missing --site=1
php bin/pinnote.php export --site=1 --status=open > pinnote.md       # --format=json

AI 에이전트 작업 순서 예

  1. php bin/pinnote.php export --site=1 --status=open > /tmp/pinnote.md를 읽는다.
  2. 요소마다 선택자(data-ui 우선)와 텍스트로 코드를 찾아 고친다.
  3. 고친 건마다 resolve 번호 "무엇을 어떻게 고쳤는지" --version=...을 실행한다.
  4. 요소가 사라졌거나 이름이 바뀌었다면 missing으로 확인하고, POST /api/v1/items/{id}/relink {"ui":"새이름"}이나 anchors/{id}/fixed로 정리한다.

3. 위젯 API (참고, 위젯 전용)

동작본문설명
POST /api/w/initurl, title, rk, visit, focus?, relink?화면 키, 설정, 이 화면의 앵커(찾는 방법·check)와 의견(작성·처리 시각은 넣지 않음), 포커스·재지정 정보
POST /api/w/itemurl, title, rk, name, kind, body, uid, anchor_id?, page_level?, loc, snap, ctx의견 저장(201). 같은 uid면 기존 의견을 돌려줌(200, duplicate:true). 응답의 shot_token으로 캡처 업로드
POST /api/w/shottoken, data(data:image/jpeg;base64)요소 캡처(300KB 이하)
POST /api/w/reporturl, visit, results[{id, found: primary/fallback/none, method, score, loc}]앵커 확인 결과 묶음
POST /api/w/voterk, item_id, on공감 토글
POST /api/w/comment / threadrk, name, item_id, body / item_id댓글 달기 / 스레드
POST /api/w/relinktoken, url, loc, snap재지정 모드 연결(서명 토큰 필요)

시간당 제한(IP 해시 기준)

크기 제한