AFTERLOG

Afterlog สำหรับนักพัฒนา

นำเส้นทาง Afterlog ไปไว้ในแอปและบริการของคุณ

วิดเจ็ตฝัง

วางสไลเดอร์ Before↔Current หรือการ์ดเส้นทางลงบนเว็บใดก็ได้ เฉพาะเส้นทางสาธารณะ — ไม่ต้องใช้ API key

ตัวอย่างสด

แท็กสคริปต์

เพิ่มสคริปต์ 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

วาง URL เส้นทางใน Slack, WordPress และเครื่องมือที่รองรับ oEmbed

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

Partner API

REST API แบบอ่านอย่างเดียวสำหรับพาร์ทเนอร์ที่ได้รับอนุมัติ ดึงเส้นทางสาธารณะ ยอดนิยม การค้นหา และโปรไฟล์เข้าสู่ผลิตภัณฑ์ของคุณ

การยืนยันตัวตน

ส่งคีย์ของคุณในเฮดเดอร์ x-api-key ออกคีย์จากคอนโซลนักพัฒนาด้านล่าง

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

การเข้าถึงช่วงแรก

ขณะนี้ Partner API เปิดเฉพาะผู้ได้รับเชิญ ลงทะเบียนแอป แล้วเราจะตรวจสอบก่อนเปิดใช้งานคีย์ของคุณ

  • 403แอปยังไม่ได้รับอนุมัติ หรือคีย์ถูกเพิกถอน
  • 401ไม่มีหรือ x-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. ส่งผู้ใช้ไปยัง authorization URL พร้อม PKCE challenge และสโคปที่ขอ
  2. 2. ผู้ใช้ตรวจสอบและอนุมัติบน Afterlog จากนั้นเราจะพากลับไปที่ redirect_uri พร้อม code ครั้งเดียวและ state ของคุณ
  3. 3. แลก code เป็นโทเคนที่ token endpoint โดยส่ง code_verifier เดิมของคุณ
  4. 4. เรียก Partner API ด้วย Authorization: Bearer <access_token> โทเคนอยู่ได้ 1 ชั่วโมง ใช้ refresh เพื่อหมุนเวียน

สโคป

journeys.readอ่านเส้นทางและบันทึกของผู้ใช้ที่เชื่อมต่อ รวมถึงแบบส่วนตัว
profile.readอ่านโปรไฟล์สาธารณะของผู้ใช้ที่เชื่อมต่อ

Authorization URL

พาเบราว์เซอร์มาที่นี่ redirect_uri ต้องตรงกับที่ลงทะเบียนไว้ในแอปทุกตัวอักษร และต้องใช้ PKCE method=S256

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>"
  }'

การใช้โทเคน

ส่ง access token เป็นเฮดเดอร์ Bearer เมื่ออ่าน Partner API หากมี journeys.read จะรวมเส้นทางส่วนตัวของผู้ใช้ที่เชื่อมต่อด้วย

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

เว็บฮุก

รับแจ้งเตือนเมื่อผู้ใช้ที่เชื่อมต่อเพิ่มบันทึกหรือเผยแพร่เส้นทาง เพย์โหลดเป็นสัญญาณบาง ๆ — ดูรายละเอียดจาก Partner API

จัดการเอนด์พอยต์

ลงทะเบียน แสดง และลบเอนด์พอยต์ต่อแอปในคอนโซลนักพัฒนา secret สำหรับลงลายเซ็นจะแสดงครั้งเดียวตอนสร้าง URL ต้องเป็น https และห้ามชี้ไปโฮสต์ส่วนตัว

เหตุการณ์

journey.update.createdผู้ใช้ที่เชื่อมต่อเพิ่มบันทึก (Update) ในเส้นทาง
journey.publishedผู้ใช้ที่เชื่อมต่อเผยแพร่เส้นทาง

เพย์โหลด

ทุกการส่งมี id เฉพาะ (ใช้ทำ idempotency) เหตุการณ์ เวลา และอ็อบเจ็กต์ 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 = HMAC-SHA256 ของ "<t>.<บอดีดิบ>" คำนวณใหม่จากบอดีดิบและเปรียบเทียบแบบเวลาคงที่

// 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