Afterlog cho nhà phát triển
Đưa hành trình Afterlog vào ứng dụng và dịch vụ của bạn.

Widget nhúng
Đặt thanh trượt Before↔Current hoặc thẻ hành trình lên bất kỳ trang nào. Chỉ hành trình công khai — không cần API key.
Xem trực tiếp
Thẻ script
Thêm script SDK và một div giữ chỗ; widget tự gắn và tự điều chỉnh chiều cao.
<script async src="https://afterlog.me/sdk/afterlog.js"></script>
<div data-afterlog-journey="JOURNEY_ID" data-afterlog-theme="light"></div>iframe trực tiếp
Nhúng không cần JavaScript. Dùng theme=light|dark và 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
Dán URL hành trình vào Slack, WordPress và các công cụ hỗ trợ oEmbed.
GET https://afterlog.me/api/oembed?url=https://afterlog.me/journey/JOURNEY_ID&format=jsonPartner API
API REST chỉ đọc dành cho đối tác đã duyệt. Đưa hành trình công khai, xu hướng, tìm kiếm và hồ sơ vào sản phẩm của bạn.
Xác thực
Gửi khóa của bạn trong header x-api-key. Cấp khóa từ bảng điều khiển nhà phát triển bên dưới.
curl https://api.afterlog.me/v1/partner/trending \
-H "x-api-key: ak_live_..."Truy cập sớm
API Đối tác hiện chỉ dành cho người được mời. Đăng ký ứng dụng, rồi chúng tôi duyệt trước khi khóa của bạn hoạt động.
403— Ứng dụng chưa được duyệt, hoặc khóa đã bị thu hồi.401— Thiếu hoặc x-api-key không hợp lệ.429— Vượt giới hạn tần suất — chờ theo header Retry-After rồi thử lại.
Điểm cuối
Mọi đường dẫn đều tương đối so với https://api.afterlog.me/v1 và chỉ đọc. Xu hướng và tìm kiếm phân trang bằng cursor và 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|pinnedCấu trúc phản hồi
Hành trình được trả về dưới dạng chế độ xem công khai — ảnh bìa, thẻ, thống kê và chủ sở hữu. Không có trường riêng của người xem hay trường riêng tư.
{
"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"
}Sẵn sàng xây dựng? Đăng ký ứng dụng và cấp khóa đầu tiên của bạn.
Mở bảng điều khiển nhà phát triểnOAuth cho dữ liệu người dùng
Cho phép người dùng kết nối tài khoản Afterlog để ứng dụng của bạn đọc hành trình của họ — kể cả riêng tư — thay mặt họ. Authorization Code + PKCE (S256).
Luồng
- 1. Đưa người dùng đến URL ủy quyền kèm PKCE challenge và các scope yêu cầu.
- 2. Người dùng xem xét và chấp thuận trên Afterlog; chúng tôi chuyển hướng về redirect_uri kèm code dùng một lần và state của bạn.
- 3. Đổi code lấy token tại token endpoint, gửi kèm code_verifier ban đầu của bạn.
- 4. Gọi Partner API với Authorization: Bearer <access_token>. Token truy cập kéo dài 1 giờ; dùng refresh để xoay vòng.
Scope
journeys.read | Đọc hành trình và nhật ký của người dùng đã kết nối, kể cả riêng tư. |
profile.read | Đọc hồ sơ công khai của người dùng đã kết nối. |
URL ủy quyền
Chuyển hướng trình duyệt đến đây. redirect_uri phải khớp chính xác với một giá trị đã đăng ký trên ứng dụng, và bắt buộc PKCE với 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Đổi token
Đổi code lấy token access + refresh. Client confidential còn gửi 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>"
}'Dùng token
Gửi access token dưới dạng header Bearer khi đọc Partner API. Với journeys.read, hành trình riêng tư của người dùng đã kết nối cũng được bao gồm.
curl https://api.afterlog.me/v1/partner/journeys/JOURNEY_ID \
-H "Authorization: Bearer <access_token>"Webhook
Nhận thông báo khi người dùng đã kết nối thêm nhật ký hoặc công khai hành trình. Payload là tín hiệu mỏng — lấy chi tiết từ Partner API.
Quản lý điểm cuối
Đăng ký, liệt kê và xóa điểm cuối theo ứng dụng trong bảng điều khiển nhà phát triển. Secret ký được hiển thị một lần khi tạo. URL phải là https và không được trỏ tới host riêng.
Sự kiện
journey.update.created | Người dùng đã kết nối thêm một nhật ký (Update) vào hành trình. |
journey.published | Người dùng đã kết nối công khai một hành trình. |
Payload
Mỗi lần gửi có id duy nhất (dùng cho idempotency), một event, dấu thời gian và một đối tượng data mỏng.
{
"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ác minh chữ ký
Mỗi yêu cầu có X-Afterlog-Signature: t=<unix>,v1=<hex>, trong đó v1 = HMAC-SHA256 của "<t>.<body thô>". Tính lại trên body thô và so sánh theo thời gian hằng số.
// 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)을 막는다.Thử lại và tự tắt
2xx là thành công. Thất bại và hết thời gian (10s) được thử lại tối đa 3 lần. Sau 10 lần thất bại tích lũy, điểm cuối tự động bị tắt; tạo lại để bật lại.