Chuyển đến nội dung

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

  1. 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.
  2. Nhập một URL https cô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ả.
  3. 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ủ.
  4. 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.createdMột ứng dụng đã được thêm vào không gian làm việc.
app.updatedThông tin, liên kết hoặc cài đặt trang của ứng dụng đã thay đổi.
app.deletedMột ứng dụng đã bị xóa.
app.status_changedMột ứng dụng đã hoạt động, bị tạm dừng hoặc bị đình chỉ.
app.metadata_fetchedSiêu dữ liệu cửa hàng đã được nhập cho một ứng dụng.
legal.publishedMộ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.verifiedMột tên miền tùy chỉnh đã được xác minh.
link.clickedMọ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_summaryTổ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.

HeaderGiá trị
Content-Typeapplication/json
User-Agentmapps.one-Webhooks/1.0
X-Mapps-EventLoại sự kiện, chẳng hạn link.clicked
X-Mapps-DeliveryID sự kiện. Giá trị này giữ nguyên qua mọi lần thử lại.
X-Mapps-TimestampThời gian Unix của lần gửi này
X-Mapps-Signaturet={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:

  1. Đọc t và v1 từ header X-Mapps-Signature.
  2. 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.
  3. So sánh kết quả với v1 bằng phép so sánh thời gian hằng (constant-time).
  4. Từ chối yêu cầu nếu t lệ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.
Dùng body thô. Hãy tính chữ ký trên đúng các byte bạn nhận được, trước khi phân tích JSON. Mã hóa lại JSON có thể thay đổi dấu gạch chéo hoặc ký tự Unicode và làm hỏng chữ ký.

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à https cô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ức id củ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

  1. Tạo một Zap với Webhooks by Zapier làm trigger và chọn Catch Hook.
  2. Sao chép URL webhook mà Zapier cung cấp cho bạn.
  3. 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_changed hoặc analytics.daily_summary.
  4. 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.