Dla programistów
Webhooki i Zapier
Webhooki wysyłają żądanie HTTP do twojego serwera w chwili, gdy w twojej przestrzeni roboczej coś się dzieje, np. gdy aplikacja zostaje wstrzymana lub ktoś klika inteligentny link. Używaj ich do aktualizowania własnych systemów, publikowania na Slacku lub łączenia mapps.one z Zapier, Make czy n8n bez pisania serwera. Webhooki są dostępne w planie Studio, maksymalnie 10 endpointów na przestrzeń roboczą.
Dodawanie endpointu
- W panelu otwórz Dla programistów → Webhooki i wybierz Dodaj endpoint. Mogą to zrobić właściciele i administratorzy przestrzeni roboczej.
- Wpisz publiczny adres URL
https, wybierz zdarzenia do wysyłania (lub wszystkie zdarzenia) i dodaj opis. - Skopiuj sekret podpisu i przechowuj go razem z innymi sekretami serwera.
- Wybierz Wyślij zdarzenie testowe, aby sprawdzić, czy endpoint odpowiada.
Strona endpointu pokazuje ostatnie dostarczenia ze statusem odpowiedzi, pierwszymi 2000 znaków treści odpowiedzi i czasem trwania każdej próby. Endpointy możesz też tworzyć i usuwać za pomocą API.
Zdarzenia
| Typ | Wysyłane, gdy |
|---|---|
app.created | Dodano aplikację do przestrzeni roboczej. |
app.updated | Zmieniono szczegóły aplikacji, linki lub ustawienia strony. |
app.deleted | Usunięto aplikację. |
app.status_changed | Aplikacja została włączona, wstrzymana lub zawieszona. |
app.metadata_fetched | Zaimportowano metadane ze sklepu dla aplikacji. |
legal.published | Opublikowano politykę prywatności lub regulamin. |
domain.verified | Zweryfikowano własną domenę. |
link.clicked | Każde kliknięcie inteligentnego linku. W przypadku popularnej aplikacji może to oznaczać bardzo wiele żądań. |
analytics.daily_summary | Sumy kliknięć z poprzedniego dnia dla każdej aplikacji, wysyłane raz dziennie. |
Format żądania
Każde zdarzenie jest wysyłane jako żądanie POST z treścią w formacie JSON.
| Nagłówek | Wartość |
|---|---|
Content-Type | application/json |
User-Agent | mapps.one-Webhooks/1.0 |
X-Mapps-Event | Typ zdarzenia, np. link.clicked |
X-Mapps-Delivery | Identyfikator zdarzenia. Pozostaje taki sam przy każdym ponowieniu. |
X-Mapps-Timestamp | Czas uniksowy tej próby dostarczenia |
X-Mapps-Signature | t={timestamp},v1={signature} |
Treść ma postać koperty o tej samej strukturze dla każdego zdarzenia:
{
"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"
}
}
Zawartość data zależy od zdarzenia. Zdarzenia dotyczące aplikacji zawierają obiekt app z jej id, slug i 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 jest podawane w UTC. device_type ma wartość mobile, tablet lub desktop. destination to klucz sklepu, web lub landing. Nieznane pola mają wartość null. Wizyty botów nigdy nie wywołują tego zdarzenia.
app.metadata_fetched
"data": {
"app": { "id": "01j8b2k6r3xq9v7m4n5p0s1t2w", "slug": "habitly", "name": "Habitly" },
"source": "app_store"
}
Weryfikacja podpisów
Sprawdzaj podpis każdego żądania, aby mieć pewność, że pochodzi z mapps.one i nie zostało zmienione po drodze:
- Odczytaj
tiv1z nagłówkaX-Mapps-Signature. - Oblicz HMAC-SHA256 z
{t}.{raw request body}przy użyciu sekretu podpisu endpointu, w zapisie szesnastkowym małymi literami. - Porównaj wynik z
v1, używając porównania w stałym czasie. - Odrzuć żądanie, jeśli
tróżni się od zegara twojego serwera o więcej niż pięć minut, aby blokować powtórzone żądania.
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);
W Laravelu odczytaj treść za pomocą $request->getContent(), a nagłówek za pomocą $request->header('X-Mapps-Signature') i wyłącz trasę z ochrony 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);
Odpowiedzi i ponowienia
- Odpowiedz dowolnym statusem 2xx w ciągu 10 sekund. Czasochłonne operacje wykonuj w zadaniu w tle po wysłaniu odpowiedzi.
- Przekierowania nie są obsługiwane, więc używaj docelowego adresu URL.
- Adres URL musi być publicznym adresem
https. Adresy w sieciach prywatnych i lokalnych są odrzucane. - Jeśli endpoint przekroczy limit czasu lub zwróci coś innego niż 2xx, ponawiamy próbę jeszcze maksymalnie pięć razy: po około 1 minucie, 5 minutach, 30 minutach, 2 godzinach i 6 godzinach. Każda próba ma nowy znacznik czasu i nowy podpis.
- To samo zdarzenie może dotrzeć więcej niż raz, a zdarzenia mogą przychodzić w innej kolejności. Używaj
X-Mapps-Delivery, czyliidzdarzenia, aby pomijać duplikaty, orazcreated_at, aby je uporządkować. - Po 20 nieudanych próbach z rzędu endpoint zostaje wyłączony i nic więcej nie jest do niego wysyłane. Rozwiąż problem, a następnie włącz endpoint ponownie w panelu.
Zapier, Make i n8n
Możesz połączyć mapps.one z tysiącami aplikacji bez uruchamiania własnego serwera.
Zapier
- Utwórz Zap z Webhooks by Zapier jako wyzwalaczem i wybierz Catch Hook.
- Skopiuj adres URL webhooka podany przez Zapier.
- W mapps.one dodaj endpoint z tym adresem URL i wybierz potrzebne zdarzenia, np.
app.status_changedlubanalytics.daily_summary. - Wybierz Wyślij zdarzenie testowe w mapps.one, a następnie Test trigger w Zapier. Pól z ładunku, takich jak
data.app.name, możesz teraz używać w kolejnych krokach.
Przykłady: wiadomość na Slacku, gdy aplikacja zostanie wstrzymana, dopisywanie dziennych kliknięć do arkusza Google Sheets lub e-mail do klienta, gdy jego domena zostanie zweryfikowana.
Make i n8n
W Make użyj wyzwalacza Webhooks → Custom webhook. W n8n użyj węzła Webhook z metodą POST. Następnie dodaj adres URL jako endpoint w mapps.one, tak jak opisano powyżej.
Tworzenie integracji
Jeśli tworzysz integrację z mapps.one dla innych, subskrybuj zdarzenia przez API, gdy użytkownik łączy konto (POST /api/v1/webhooks), anuluj subskrypcję, gdy je rozłącza (DELETE /api/v1/webhooks/{id}), używaj GET /api/v1/events do wyboru zdarzeń, a GET /api/v1/workspace do testowania połączenia. Zobacz dokumentację API.