AFTERLOG

Afterlog 개발자

Afterlog 여정을 여러분의 앱과 서비스에 연결하세요.

임베드 위젯

Before↔Current 슬라이더나 여정 카드를 어떤 사이트에나 붙이세요. 공개 여정 전용 — API 키 불필요.

라이브 프리뷰

스크립트 태그

SDK 스크립트와 placeholder div 를 넣으면 위젯이 자동으로 마운트·리사이즈됩니다.

<script async src="https://afterlog.me/sdk/afterlog.js"></script>
<div data-afterlog-journey="JOURNEY_ID" data-afterlog-theme="light"></div>

iframe 직접 삽입

JavaScript 없이 임베드. theme=light|dark, variant=slider|card.

<iframe
  src="https://afterlog.me/embed/journey/JOURNEY_ID?theme=light&variant=slider"
  width="480" height="520" style="border:0;max-width:100%"
  scrolling="no" loading="lazy" title="Afterlog journey"></iframe>

oEmbed

Slack·WordPress 등 oEmbed 지원 도구에 여정 URL 을 붙여넣으세요.

GET https://afterlog.me/api/oembed?url=https://afterlog.me/journey/JOURNEY_ID&format=json

파트너 API

승인된 파트너를 위한 읽기 전용 REST API. 공개 여정·트렌딩·검색·프로필을 서비스에 가져오세요.

인증

x-api-key 헤더에 키를 담아 보냅니다. 키는 아래 개발자 콘솔에서 발급합니다.

curl https://api.afterlog.me/v1/partner/trending \
  -H "x-api-key: ak_live_..."

초기 액세스

파트너 API는 현재 초대제입니다. 앱을 등록하면 검토 후 키가 활성화됩니다.

  • 403앱이 아직 승인되지 않았거나 키가 회수되었습니다.
  • 401x-api-key가 없거나 유효하지 않습니다.
  • 429요청 한도 초과 — Retry-After 헤더만큼 기다린 뒤 재시도하세요.

엔드포인트

모든 경로는 https://api.afterlog.me/v1 기준 상대 경로이며 읽기 전용입니다. 트렌딩과 검색은 cursor·nextCursor로 페이지네이션합니다.

GET /partner/trending?category=&sort=trending|helpful&cursor=&limit=
GET /partner/search?q=&cursor=&limit=
GET /partner/journeys/:id
GET /partner/profiles/:username
GET /partner/profiles/:username/journeys?sort=recent|pinned

응답 형태

여정은 공개 뷰로 반환됩니다 — 커버·태그·통계·작성자. 뷰어 전용/비공개 필드는 없습니다.

{
  "items": [
    {
      "id": "cmr576hhy000n5s6a1b2c3d4",
      "userId": "cmr4qx8p0000ab12cd34",
      "title": "코 성형 회복 여정",
      "category": "BEAUTY",
      "categoryCustom": null,
      "startDate": "2026-01-15",
      "privacy": "PUBLIC",
      "status": "PUBLISHED",
      "description": "붓기와 회복 과정을 매주 기록합니다.",
      "tags": ["recovery", "beauty"],
      "coverMediaId": "cmr58a4k0001...",
      "coverUrl": "https://disk.afterlog.me/media/.../320.webp",
      "captureSlots": [{ "key": "front", "label": "Front" }, { "key": "side", "label": "Side" }],
      "heroSlot": "front",
      "createdAt": "2026-01-15T09:12:00.000Z",
      "updatedAt": "2026-07-14T02:31:00.000Z",
      "stats": {
        "daysCount": 180, "updatesCount": 12, "viewsCount": 3400,
        "savesCount": 210, "followersCount": 95, "helpfulCount": 88,
        "completedReadsCount": 40, "forksCount": 3, "helpfulnessScore": 0.82
      },
      "owner": {
        "userId": "cmr4qx8p0000ab12cd34", "username": "riah_kim",
        "displayName": "Riah", "avatarMediaId": null,
        "avatarUrl": "https://disk.afterlog.me/media/.../320.webp"
      },
      "trendingScore": 128.4
    }
  ],
  "nextCursor": "eyJjIjoiMjAyNi0wNy0xNCJ9"
}

만들 준비가 되셨나요? 앱을 등록하고 첫 키를 발급하세요.

개발자 콘솔 열기

사용자 데이터용 OAuth

사용자가 Afterlog 계정을 연결하면, 앱이 그 사용자를 대신해 여정(비공개 포함)을 읽을 수 있습니다. Authorization Code + PKCE(S256).

플로우

  1. 1. PKCE 챌린지와 요청 스코프를 담아 사용자를 인가 URL로 보냅니다.
  2. 2. 사용자가 Afterlog에서 검토·승인하면, 일회용 code와 state를 실어 redirect_uri로 돌려보냅니다.
  3. 3. 토큰 엔드포인트에서 원래의 code_verifier와 함께 code를 토큰으로 교환합니다.
  4. 4. Authorization: Bearer <access_token> 헤더로 파트너 API를 호출합니다. 액세스 토큰은 1시간, refresh로 회전합니다.

스코프

journeys.read연결한 사용자의 여정과 기록을 읽습니다(비공개 포함).
profile.read연결한 사용자의 공개 프로필을 읽습니다.

인가 URL

브라우저를 이 URL로 보냅니다. redirect_uri는 앱에 등록된 값과 정확히 일치해야 하며, method=S256 PKCE가 필수입니다.

https://afterlog.me/oauth/authorize?response_type=code
  &client_id=YOUR_APP_ID
  &redirect_uri=https://your.app/callback
  &scope=journeys.read%20profile.read
  &state=RANDOM_CSRF
  &code_challenge=BASE64URL_SHA256_OF_VERIFIER
  &code_challenge_method=S256

토큰 교환

code를 access + refresh 토큰으로 교환합니다. confidential 클라이언트는 client_secret도 보냅니다.

curl -X POST https://api.afterlog.me/v1/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "client_id": "YOUR_APP_ID",
    "code": "<code from redirect>",
    "redirect_uri": "https://your.app/callback",
    "code_verifier": "<original PKCE verifier>"
  }'

토큰 사용

파트너 API read에 액세스 토큰을 Bearer 헤더로 보냅니다. journeys.read면 연결 사용자의 비공개 여정까지 포함됩니다.

curl https://api.afterlog.me/v1/partner/journeys/JOURNEY_ID \
  -H "Authorization: Bearer <access_token>"

웹훅

연결한 사용자가 기록을 추가하거나 여정을 공개하면 알림을 받습니다. 페이로드는 얇은 신호이며, 상세는 파트너 API로 조회합니다.

엔드포인트 관리

개발자 콘솔에서 앱별로 엔드포인트를 등록·조회·삭제합니다. 서명 secret은 생성 시 1회만 노출됩니다. URL은 https이며 사설 호스트를 가리키면 안 됩니다.

이벤트

journey.update.created연결한 사용자가 여정에 기록(Update)을 추가했습니다.
journey.published연결한 사용자가 여정을 공개했습니다.

페이로드

모든 배달에는 고유 id(idempotency 키), event, 타임스탬프, 그리고 얇은 data 객체가 담깁니다.

{
  "id": "whd_5f3a1c...",                     // 배달 고유 id (수신측 idempotency 키)
  "event": "journey.update.created",
  "createdAt": "2026-07-19T09:00:00.000Z",
  "data": {
    "journeyId": "jr_...", "updateId": "up_...",
    "username": "riah", "title": "코 성형 회복 여정"
  }
}

서명 검증

각 요청에 X-Afterlog-Signature: t=<unix>,v1=<hex> 헤더가 붙고, v1 = "<t>.<원문 바디>"의 HMAC-SHA256입니다. 받은 원문으로 재계산해 상수시간 비교하세요.

// header: X-Afterlog-Signature: t=<unix>,v1=<hex>
const [t, v1] = header.split(',').map((s) => s.split('=')[1]);
const expected = crypto
  .createHmac('sha256', secret)                // secret = whsec_...
  .update(`${t}.${rawBody}`)                   // 받은 원문 바디 그대로 사용
  .digest('hex');
const ok = crypto.timingSafeEqual(
  Buffer.from(expected), Buffer.from(v1),
);
// t 가 최근(±5분)인지도 확인해 재전송(replay)을 막는다.

재시도·자동 비활성

2xx는 성공입니다. 실패·타임아웃(10초)은 최대 3회 재시도합니다. 누적 실패 10회면 엔드포인트가 자동 비활성되며, 다시 만들어 재활성합니다.

Afterlog 개발자 | Afterlog