Przejdź do treści

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

  1. W panelu otwórz Dla programistów → Webhooki i wybierz Dodaj endpoint. Mogą to zrobić właściciele i administratorzy przestrzeni roboczej.
  2. Wpisz publiczny adres URL https, wybierz zdarzenia do wysyłania (lub wszystkie zdarzenia) i dodaj opis.
  3. Skopiuj sekret podpisu i przechowuj go razem z innymi sekretami serwera.
  4. 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

TypWysyłane, gdy
app.createdDodano aplikację do przestrzeni roboczej.
app.updatedZmieniono szczegóły aplikacji, linki lub ustawienia strony.
app.deletedUsunięto aplikację.
app.status_changedAplikacja została włączona, wstrzymana lub zawieszona.
app.metadata_fetchedZaimportowano metadane ze sklepu dla aplikacji.
legal.publishedOpublikowano politykę prywatności lub regulamin.
domain.verifiedZweryfikowano własną domenę.
link.clickedKażde kliknięcie inteligentnego linku. W przypadku popularnej aplikacji może to oznaczać bardzo wiele żądań.
analytics.daily_summarySumy 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łówekWartość
Content-Typeapplication/json
User-Agentmapps.one-Webhooks/1.0
X-Mapps-EventTyp zdarzenia, np. link.clicked
X-Mapps-DeliveryIdentyfikator zdarzenia. Pozostaje taki sam przy każdym ponowieniu.
X-Mapps-TimestampCzas uniksowy tej próby dostarczenia
X-Mapps-Signaturet={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:

  1. Odczytaj t i v1 z nagłówka X-Mapps-Signature.
  2. Oblicz HMAC-SHA256 z {t}.{raw request body} przy użyciu sekretu podpisu endpointu, w zapisie szesnastkowym małymi literami.
  3. Porównaj wynik z v1, używając porównania w stałym czasie.
  4. Odrzuć żądanie, jeśli t różni się od zegara twojego serwera o więcej niż pięć minut, aby blokować powtórzone żądania.
Używaj surowej treści. Podpisuj dokładnie te bajty, które otrzymujesz, przed jakimkolwiek parsowaniem JSON. Ponowne zakodowanie JSON może zmienić ukośniki lub znaki Unicode i unieważnić podpis.

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, czyli id zdarzenia, aby pomijać duplikaty, oraz created_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

  1. Utwórz Zap z Webhooks by Zapier jako wyzwalaczem i wybierz Catch Hook.
  2. Skopiuj adres URL webhooka podany przez Zapier.
  3. W mapps.one dodaj endpoint z tym adresem URL i wybierz potrzebne zdarzenia, np. app.status_changed lub analytics.daily_summary.
  4. 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.