Zum Inhalt springen

Entwickler

Webhooks und Zapier

Webhooks senden eine HTTP-Anfrage an deinen Server, sobald in deinem Workspace etwas passiert, etwa wenn eine App pausiert oder ein Smart Link angeklickt wird. Nutze sie, um deine eigenen Systeme zu aktualisieren, in Slack zu posten oder mapps.one ohne eigenen Server mit Zapier, Make oder n8n zu verbinden. Webhooks sind im Studio-Plan verfügbar, mit bis zu 10 Endpunkten pro Workspace.

Endpunkt hinzufügen

  1. Öffne im Dashboard Entwickler → Webhooks und wähle Endpunkt hinzufügen. Workspace-Owner und Admins können das tun.
  2. Gib eine öffentliche https-URL ein, wähle die zu sendenden Ereignisse (oder alle Ereignisse) und füge eine Beschreibung hinzu.
  3. Kopiere das Signing Secret und bewahre es zusammen mit den anderen Secrets deines Servers auf.
  4. Wähle Testereignis senden, um zu prüfen, ob dein Endpunkt antwortet.

Die Seite des Endpunkts zeigt die letzten Zustellungen mit dem Antwortstatus, den ersten 2.000 Zeichen des Antwort-Bodys und der Dauer jedes Versuchs. Du kannst Endpunkte auch über die API erstellen und löschen.

Ereignisse

TypGesendet, wenn
app.createdEine App wurde zum Workspace hinzugefügt.
app.updatedApp-Details, Links oder Seiteneinstellungen wurden geändert.
app.deletedEine App wurde gelöscht.
app.status_changedEine App ist live gegangen, wurde pausiert oder gesperrt.
app.metadata_fetchedStore-Metadaten wurden für eine App importiert.
legal.publishedEine Datenschutzerklärung oder Nutzungsbedingungen wurden veröffentlicht.
domain.verifiedEine eigene Domain wurde verifiziert.
link.clickedJeder Smart-Link-Klick. Bei einer beliebten App können das sehr viele Anfragen sein.
analytics.daily_summaryDie Klicksummen des Vortags für jede App, einmal täglich gesendet.

Anfrageformat

Jedes Ereignis wird als POST-Anfrage mit JSON-Body gesendet.

HeaderWert
Content-Typeapplication/json
User-Agentmapps.one-Webhooks/1.0
X-Mapps-EventDer Ereignistyp, etwa link.clicked
X-Mapps-DeliveryDie Ereignis-ID. Sie bleibt bei jedem erneuten Versuch gleich.
X-Mapps-TimestampUnix-Zeit dieses Zustellversuchs
X-Mapps-Signaturet={timestamp},v1={signature}

Der Body ist ein Umschlag mit derselben Struktur für jedes Ereignis:

{
  "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"
  }
}

Der Inhalt von data hängt vom Ereignis ab. Ereignisse zu einer App enthalten ein app-Objekt mit id, slug und 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 ist in UTC. device_type ist mobile, tablet oder desktop. destination ist ein Store-Schlüssel, web oder landing. Unbekannte Felder sind null. Besuche von Bots lösen dieses Ereignis nie aus.

app.metadata_fetched

"data": {
  "app": { "id": "01j8b2k6r3xq9v7m4n5p0s1t2w", "slug": "habitly", "name": "Habitly" },
  "source": "app_store"
}

Signaturen verifizieren

Prüfe die Signatur jeder Anfrage. So weißt du, dass sie von mapps.one stammt und unterwegs nicht verändert wurde:

  1. Lies t und v1 aus dem Header X-Mapps-Signature.
  2. Berechne mit dem Signing Secret deines Endpunkts einen HMAC-SHA256 von {t}.{raw request body}, als Hex in Kleinbuchstaben.
  3. Vergleiche ihn mit v1, und zwar mit einem Vergleich in konstanter Zeit.
  4. Lehne die Anfrage ab, wenn t mehr als fünf Minuten von der Uhr deines Servers abweicht, um wiederholt eingespielte Anfragen abzuwehren.
Verwende den unveränderten Body. Signiere genau die Bytes, die du empfangen hast, vor jedem JSON-Parsing. Neu kodiertes JSON kann Schrägstriche oder Unicode-Zeichen verändern und die Signatur ungültig machen.

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);

Lies in Laravel den Body mit $request->getContent() und den Header mit $request->header('X-Mapps-Signature') aus und nimm die Route vom CSRF-Schutz aus.

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);

Antworten und erneute Versuche

  • Antworte innerhalb von 10 Sekunden mit einem beliebigen 2xx-Status. Erledige langsame Arbeit nach der Antwort in einem Hintergrundjob.
  • Weiterleitungen werden nicht verfolgt. Verwende also die endgültige URL.
  • Die URL muss eine öffentliche https-URL sein. Private und lokale Netzwerkadressen werden abgelehnt.
  • Wenn dein Endpunkt nicht rechtzeitig antwortet oder etwas anderes als 2xx zurückgibt, versuchen wir es bis zu fünf weitere Male: nach etwa 1 Minute, 5 Minuten, 30 Minuten, 2 Stunden und 6 Stunden. Jeder Versuch hat einen neuen Zeitstempel und eine neue Signatur.
  • Dasselbe Ereignis kann mehr als einmal ankommen, und Ereignisse können in anderer Reihenfolge eintreffen. Verwende X-Mapps-Delivery, die id des Ereignisses, um Duplikate zu ignorieren, und created_at, um sie zu sortieren.
  • Nach 20 fehlgeschlagenen Versuchen in Folge wird der Endpunkt deaktiviert, und es wird nichts mehr an ihn gesendet. Behebe das Problem und aktiviere ihn dann im Dashboard wieder.

Zapier, Make und n8n

Du kannst mapps.one mit Tausenden Apps verbinden, ohne einen Server zu betreiben.

Zapier

  1. Erstelle einen Zap mit Webhooks by Zapier als Trigger und wähle Catch Hook.
  2. Kopiere die Webhook-URL, die Zapier dir gibt.
  3. Füge in mapps.one einen Endpunkt mit dieser URL hinzu und wähle die gewünschten Ereignisse, zum Beispiel app.status_changed oder analytics.daily_summary.
  4. Wähle in mapps.one Testereignis senden und dann in Zapier Test trigger. Die Felder aus dem Payload, etwa data.app.name, kannst du jetzt in den nächsten Schritten verwenden.

Beispiele: eine Slack-Nachricht posten, wenn eine App pausiert wird, die Klicks jedes Tages in ein Google Sheet eintragen oder einem Kunden eine E-Mail schicken, wenn seine Domain verifiziert wurde.

Make und n8n

Verwende in Make den Trigger Webhooks → Custom webhook. Verwende in n8n den Node Webhook mit der Methode POST. Füge die URL dann wie oben beschrieben als Endpunkt in mapps.one hinzu.

Eine Integration entwickeln

Wenn du eine mapps.one-Integration für andere entwickelst, abonniere über die API, sobald ein Nutzer sich verbindet (POST /api/v1/webhooks), beende das Abo, wenn er die Verbindung trennt (DELETE /api/v1/webhooks/{id}), verwende GET /api/v1/events für die Ereignisauswahl und GET /api/v1/workspace, um die Verbindung zu testen. Siehe die API-Referenz.