Nhà phát triển
Webhook và Zapier
Webhook gửi một yêu cầu HTTP đến máy chủ của bạn ngay khi có sự việc xảy ra trong không gian làm việc, chẳng hạn một ứng dụng bị tạm dừng hoặc một liên kết thông minh được nhấp. Hãy dùng webhook để cập nhật hệ thống của riêng bạn, đăng lên Slack, hoặc kết nối mapps.one với Zapier, Make hoặc n8n mà không cần viết máy chủ. Webhook có trong gói Studio, với tối đa 10 endpoint cho mỗi không gian làm việc.
Thêm endpoint
- Trong bảng điều khiển, mở Nhà phát triển → Webhook và chọn Thêm endpoint. Chủ sở hữu và quản trị viên không gian làm việc có thể thực hiện thao tác này.
- Nhập một URL
httpscông khai, chọn các sự kiện cần gửi (hoặc tất cả sự kiện) và thêm mô tả. - Sao chép khóa bí mật ký và lưu cùng các khóa bí mật khác của máy chủ.
- Chọn Gửi sự kiện thử để kiểm tra xem endpoint của bạn có phản hồi hay không.
Trang endpoint hiển thị các lần gửi gần đây kèm trạng thái phản hồi, 2.000 ký tự đầu tiên của body phản hồi và thời gian của mỗi lần thử. Bạn cũng có thể tạo và xóa endpoint bằng API.
Sự kiện
| Loại | Được gửi khi |
|---|---|
app.created | Một ứng dụng đã được thêm vào không gian làm việc. |
app.updated | Thông tin, liên kết hoặc cài đặt trang của ứng dụng đã thay đổi. |
app.deleted | Một ứng dụng đã bị xóa. |
app.status_changed | Một ứng dụng đã hoạt động, bị tạm dừng hoặc bị đình chỉ. |
app.metadata_fetched | Siêu dữ liệu cửa hàng đã được nhập cho một ứng dụng. |
legal.published | Một chính sách quyền riêng tư hoặc điều khoản dịch vụ đã được xuất bản. |
domain.verified | Một tên miền tùy chỉnh đã được xác minh. |
link.clicked | Mọi lượt nhấp vào liên kết thông minh. Với ứng dụng phổ biến, số lượng yêu cầu có thể rất lớn. |
analytics.daily_summary | Tổng số lượt nhấp của ngày hôm trước cho từng ứng dụng, được gửi mỗi ngày một lần. |
Định dạng yêu cầu
Mọi sự kiện được gửi dưới dạng yêu cầu POST với body JSON.
| Header | Giá trị |
|---|---|
Content-Type | application/json |
User-Agent | mapps.one-Webhooks/1.0 |
X-Mapps-Event | Loại sự kiện, chẳng hạn link.clicked |
X-Mapps-Delivery | ID sự kiện. Giá trị này giữ nguyên qua mọi lần thử lại. |
X-Mapps-Timestamp | Thời gian Unix của lần gửi này |
X-Mapps-Signature | t={timestamp},v1={signature} |
Body là một envelope có cùng cấu trúc cho mọi sự kiện:
{
"id": "evt_01j8c3m9t5v2x7z4b6d8f0h2k4",
"type": "app.status_changed",
"created_at": "2026-09-14T09:41:07+00:00",
"workspace": {
"id": "01j8a0f4c7d2e9h6k3m5n8q1r4",
"name": "Habitly Labs"
},
"data": {
"app": {
"id": "01j8b2k6r3xq9v7m4n5p0s1t2w",
"slug": "habitly",
"name": "Habitly"
},
"status": "paused"
}
}
Nội dung của data tùy thuộc vào sự kiện. Các sự kiện liên quan đến ứng dụng bao gồm đối tượng app với id, slug và name của ứng dụng.
link.clicked
"data": {
"app": { "id": "01j8b2k6r3xq9v7m4n5p0s1t2w", "slug": "habitly", "name": "Habitly" },
"click": {
"occurred_at": "2026-09-14 09:41:07",
"os": "iOS",
"device_type": "mobile",
"country": "TR",
"source": "instagram",
"destination": "app_store",
"utm_source": "instagram",
"utm_medium": "social",
"utm_campaign": "launch"
}
}
occurred_at theo giờ UTC. device_type là mobile, tablet hoặc desktop. destination là một khóa cửa hàng, web hoặc landing. Các trường không xác định có giá trị null. Lượt truy cập của bot không bao giờ kích hoạt sự kiện này.
app.metadata_fetched
"data": {
"app": { "id": "01j8b2k6r3xq9v7m4n5p0s1t2w", "slug": "habitly", "name": "Habitly" },
"source": "app_store"
}
Xác minh chữ ký
Hãy kiểm tra chữ ký trên mọi yêu cầu, để bạn biết yêu cầu đến từ mapps.one và không bị thay đổi trên đường truyền:
- Đọc
tvàv1từ headerX-Mapps-Signature. - Tính HMAC-SHA256 của
{t}.{raw request body}bằng khóa bí mật ký của endpoint, dưới dạng chuỗi hex chữ thường. - So sánh kết quả với
v1bằng phép so sánh thời gian hằng (constant-time). - Từ chối yêu cầu nếu
tlệch quá năm phút so với đồng hồ của máy chủ, để chặn các yêu cầu bị phát lại.
PHP
<?php
$secret = getenv('MAPPS_WEBHOOK_SECRET');
$body = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_MAPPS_SIGNATURE'] ?? ''), $parts);
$timestamp = (int) ($parts['t'] ?? 0);
$expected = hash_hmac('sha256', $timestamp.'.'.$body, $secret);
if (! hash_equals($expected, (string) ($parts['v1'] ?? '')) || abs(time() - $timestamp) > 300) {
http_response_code(400);
exit;
}
$event = json_decode($body, true);
if ($event['type'] === 'link.clicked') {
// Store $event['data']['click'] ...
}
http_response_code(200);
Trong Laravel, đọc body bằng $request->getContent() và header bằng $request->header('X-Mapps-Signature'), đồng thời loại trừ route khỏi cơ chế bảo vệ CSRF.
Node.js (Express)
import crypto from 'node:crypto';
import express from 'express';
const app = express();
const secret = process.env.MAPPS_WEBHOOK_SECRET;
app.post('/webhooks/mapps', express.raw({ type: 'application/json' }), (req, res) => {
const header = req.get('X-Mapps-Signature') ?? '';
const parts = Object.fromEntries(header.split(',').map((pair) => pair.split('=')));
const timestamp = Number(parts.t);
const body = req.body.toString('utf8');
const expected = crypto.createHmac('sha256', secret).update(`${timestamp}.${body}`).digest();
const received = Buffer.from(parts.v1 ?? '', 'hex');
const valid = received.length === expected.length && crypto.timingSafeEqual(received, expected);
if (!valid || Math.abs(Date.now() / 1000 - timestamp) > 300) {
return res.sendStatus(400);
}
const event = JSON.parse(body);
if (event.type === 'link.clicked') {
// Store event.data.click ...
}
res.sendStatus(200);
});
app.listen(3000);
Phản hồi và thử lại
- Phản hồi bằng bất kỳ mã trạng thái 2xx nào trong vòng 10 giây. Hãy xử lý các tác vụ chậm trong một background job sau khi đã phản hồi.
- Chúng tôi không đi theo chuyển hướng, vì vậy hãy dùng URL cuối cùng.
- URL phải là
httpscông khai. Địa chỉ mạng riêng và mạng cục bộ sẽ bị từ chối. - Nếu endpoint của bạn hết thời gian chờ hoặc trả về bất kỳ mã nào ngoài 2xx, chúng tôi sẽ thử lại tối đa năm lần nữa: sau khoảng 1 phút, 5 phút, 30 phút, 2 giờ và 6 giờ. Mỗi lần thử có dấu thời gian và chữ ký mới.
- Cùng một sự kiện có thể đến nhiều lần, và các sự kiện có thể đến không theo thứ tự. Hãy dùng
X-Mapps-Delivery, tứcidcủa sự kiện, để bỏ qua bản trùng lặp, vàcreated_atđể sắp xếp chúng. - Sau 20 lần thất bại liên tiếp, endpoint sẽ bị tắt và không có gì được gửi đến endpoint đó nữa. Hãy khắc phục sự cố, sau đó bật lại endpoint trong bảng điều khiển.
Zapier, Make và n8n
Bạn có thể kết nối mapps.one với hàng nghìn ứng dụng mà không cần vận hành máy chủ.
Zapier
- Tạo một Zap với Webhooks by Zapier làm trigger và chọn Catch Hook.
- Sao chép URL webhook mà Zapier cung cấp cho bạn.
- Trong mapps.one, thêm một endpoint với URL đó và chọn các sự kiện bạn muốn, ví dụ
app.status_changedhoặcanalytics.daily_summary. - Chọn Gửi sự kiện thử trong mapps.one, sau đó chọn Test trigger trong Zapier. Giờ đây các trường từ payload, chẳng hạn
data.app.name, có thể được dùng trong các bước tiếp theo.
Ví dụ: đăng tin nhắn Slack khi một ứng dụng bị tạm dừng, thêm số lượt nhấp mỗi ngày vào Google Sheet, hoặc gửi email cho khách hàng khi tên miền của họ được xác minh.
Make và n8n
Trong Make, dùng trigger Webhooks → Custom webhook. Trong n8n, dùng node Webhook với phương thức POST. Sau đó thêm URL làm endpoint trong mapps.one như ở trên.
Xây dựng tích hợp
Nếu bạn đang xây dựng một tích hợp mapps.one cho người khác, hãy đăng ký qua API khi người dùng kết nối (POST /api/v1/webhooks), hủy đăng ký khi họ ngắt kết nối (DELETE /api/v1/webhooks/{id}), dùng GET /api/v1/events cho bộ chọn sự kiện, và dùng GET /api/v1/workspace để kiểm tra kết nối. Xem tài liệu tham khảo API.