AFTERLOG

開発者向け Afterlog

Afterlog の journey をあなたのアプリやサービスに。

埋め込みウィジェット

Before↔Current スライダーや journey カードをどんなサイトにも設置。公開 journey 専用 — API キー不要。

ライブプレビュー

スクリプトタグ

SDK スクリプトとプレースホルダー 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 対応ツールに journey 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

ブラウザをここへ送ります。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>"

Webhook

連携ユーザーがログを追加、またはジャーニーを公開したときに通知を受けます。ペイロードは薄い信号で、詳細はパートナーAPIで取得します。

エンドポイント管理

開発者コンソールでアプリごとにエンドポイントを登録・一覧・削除します。署名secretは作成時に1回だけ表示されます。URLはhttpsで、プライベートホストを指してはいけません。

イベント

journey.update.created連携ユーザーがジャーニーにログ(Update)を追加しました。
journey.published連携ユーザーがジャーニーを公開しました。

ペイロード

すべての配信に一意のid(冪等キー)、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