Разработчики
Вебхуки и Zapier
Вебхуки отправляют HTTP-запрос на ваш сервер, как только в рабочем пространстве что-то происходит, например приложение приостанавливается или кто-то кликает по умной ссылке. С их помощью можно обновлять собственные системы, публиковать сообщения в Slack или подключить mapps.one к Zapier, Make или n8n без собственного сервера. Вебхуки доступны на плане Studio, до 10 эндпоинтов на рабочее пространство.
Добавление эндпоинта
- В панели управления откройте Разработчики → Вебхуки и нажмите Добавить эндпоинт. Это могут делать владельцы и администраторы рабочего пространства.
- Введите публичный URL с
https, выберите события для отправки (или все события) и добавьте описание. - Скопируйте секрет подписи и сохраните его вместе с другими секретами вашего сервера.
- Нажмите Отправить тестовое событие, чтобы проверить, что эндпоинт отвечает.
На странице эндпоинта показываются недавние доставки со статусом ответа, первыми 2000 символами тела ответа и длительностью каждой попытки. Эндпоинты также можно создавать и удалять через API.
События
| Тип | Когда отправляется |
|---|---|
app.created | В рабочее пространство добавлено приложение. |
app.updated | Изменились данные приложения, ссылки или настройки страницы. |
app.deleted | Приложение удалено. |
app.status_changed | Приложение стало активным, было приостановлено или заблокировано. |
app.metadata_fetched | Для приложения импортированы метаданные из магазина. |
legal.published | Опубликована политика конфиденциальности или условия использования. |
domain.verified | Собственный домен подтверждён. |
link.clicked | Каждый клик по умной ссылке. Для популярного приложения это может быть очень много запросов. |
analytics.daily_summary | Итоги кликов за предыдущий день по каждому приложению, отправляются раз в день. |
Формат запроса
Каждое событие отправляется как запрос POST с телом в формате JSON.
| Заголовок | Значение |
|---|---|
Content-Type | application/json |
User-Agent | mapps.one-Webhooks/1.0 |
X-Mapps-Event | Тип события, например link.clicked |
X-Mapps-Delivery | ID события. Он не меняется при повторных попытках. |
X-Mapps-Timestamp | Время этой попытки доставки в формате Unix |
X-Mapps-Signature | t={timestamp},v1={signature} |
Тело запроса — это конверт одинаковой структуры для всех событий:
{
"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"
}
}
Содержимое data зависит от события. События, связанные с приложением, содержат объект app с полями id, slug и name.
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 указывается в UTC. device_type принимает значения mobile, tablet или desktop. destination — это ключ магазина, web или landing. Неизвестные поля имеют значение null. Посещения ботов никогда не вызывают это событие.
app.metadata_fetched
"data": {
"app": { "id": "01j8b2k6r3xq9v7m4n5p0s1t2w", "slug": "habitly", "name": "Habitly" },
"source": "app_store"
}
Проверка подписей
Проверяйте подпись каждого запроса, чтобы убедиться, что он пришёл от mapps.one и не был изменён по пути:
- Прочитайте
tиv1из заголовкаX-Mapps-Signature. - Вычислите HMAC-SHA256 от
{t}.{raw request body}с секретом подписи вашего эндпоинта в виде шестнадцатеричной строки в нижнем регистре. - Сравните результат с
v1с помощью сравнения за постоянное время. - Отклоните запрос, если
tотличается от часов вашего сервера больше чем на пять минут, чтобы блокировать повторно отправленные запросы.
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);
В Laravel прочитайте тело с помощью $request->getContent(), а заголовок — с помощью $request->header('X-Mapps-Signature') и исключите маршрут из 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);
Ответы и повторные попытки
- Отвечайте любым статусом 2xx в течение 10 секунд. Долгую работу выполняйте в фоновой задаче после ответа.
- Перенаправления не выполняются, поэтому указывайте конечный URL.
- URL должен быть публичным и использовать
https. Частные и локальные сетевые адреса отклоняются. - Если ваш эндпоинт не отвечает вовремя или возвращает что-либо кроме 2xx, мы повторяем попытку ещё до пяти раз: примерно через 1 минуту, 5 минут, 30 минут, 2 часа и 6 часов. У каждой попытки новая метка времени и новая подпись.
- Одно и то же событие может прийти несколько раз, а события могут приходить не по порядку. Используйте
X-Mapps-Delivery, то естьidсобытия, чтобы отбрасывать дубликаты, иcreated_at, чтобы упорядочивать события. - После 20 неудачных попыток подряд эндпоинт отключается, и на него больше ничего не отправляется. Устраните проблему, а затем снова включите эндпоинт в панели управления.
Zapier, Make и n8n
Вы можете подключить mapps.one к тысячам приложений без собственного сервера.
Zapier
- Создайте Zap с триггером Webhooks by Zapier и выберите Catch Hook.
- Скопируйте URL вебхука, который выдаст Zapier.
- В mapps.one добавьте эндпоинт с этим URL и выберите нужные события, например
app.status_changedилиanalytics.daily_summary. - Нажмите Отправить тестовое событие в mapps.one, а затем Test trigger в Zapier. Теперь поля из содержимого события, например
data.app.name, можно использовать в следующих шагах.
Примеры: отправлять сообщение в Slack, когда приложение приостановлено, добавлять клики за каждый день в таблицу Google Sheets или писать клиенту, когда его домен подтверждён.
Make и n8n
В Make используйте триггер Webhooks → Custom webhook. В n8n используйте узел Webhook с методом POST. Затем добавьте URL как эндпоинт в mapps.one, как описано выше.
Создание интеграции
Если вы создаёте интеграцию mapps.one для других пользователей, подписывайтесь через API, когда пользователь подключается (POST /api/v1/webhooks), отписывайтесь, когда он отключается (DELETE /api/v1/webhooks/{id}), используйте GET /api/v1/events для выбора событий и GET /api/v1/workspace для проверки подключения. Подробнее — в справочнике API.