Pular para o conteúdo

Desenvolvedores

Webhooks e Zapier

Os webhooks enviam uma solicitação HTTP ao seu servidor no momento em que algo acontece no seu espaço de trabalho, como quando um app é pausado ou um link inteligente é clicado. Use-os para atualizar seus próprios sistemas, publicar no Slack ou conectar o mapps.one ao Zapier, ao Make ou ao n8n sem escrever um servidor. Os webhooks estão disponíveis no plano Studio, com até 10 endpoints por espaço de trabalho.

Adicione um endpoint

  1. No painel, abra Desenvolvedores → Webhooks e escolha Adicionar endpoint. Proprietários e admins do espaço de trabalho podem fazer isso.
  2. Digite uma URL https pública, escolha os eventos que serão enviados (ou todos os eventos) e adicione uma descrição.
  3. Copie o segredo de assinatura e guarde-o junto com os outros segredos do seu servidor.
  4. Escolha Enviar evento de teste para verificar se o seu endpoint responde.

A página do endpoint mostra as entregas recentes com o status da resposta, os primeiros 2.000 caracteres do corpo da resposta e quanto tempo cada tentativa levou. Você também pode criar e excluir endpoints com a API.

Eventos

TipoEnviado quando
app.createdUm app foi adicionado ao espaço de trabalho.
app.updatedOs detalhes, os links ou as configurações de página de um app foram alterados.
app.deletedUm app foi excluído.
app.status_changedUm app ficou ativo, foi pausado ou foi suspenso.
app.metadata_fetchedOs metadados da loja foram importados para um app.
legal.publishedUma política de privacidade ou um documento de termos foi publicado.
domain.verifiedUm domínio personalizado foi verificado.
link.clickedCada clique no link inteligente. Isso pode gerar muitas solicitações para um app popular.
analytics.daily_summaryOs totais de cliques do dia anterior para cada app, enviados uma vez por dia.

Formato da solicitação

Cada evento é enviado como uma solicitação POST com um corpo JSON.

CabeçalhoValor
Content-Typeapplication/json
User-Agentmapps.one-Webhooks/1.0
X-Mapps-EventO tipo do evento, como link.clicked
X-Mapps-DeliveryO ID do evento. Ele continua o mesmo em todas as novas tentativas.
X-Mapps-TimestampHorário Unix desta tentativa de entrega
X-Mapps-Signaturet={timestamp},v1={signature}

O corpo é um envelope com o mesmo formato para todos os eventos:

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

O conteúdo de data depende do evento. Eventos sobre um app incluem um objeto app com o id, o slug e o name dele.

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 está em UTC. device_type é mobile, tablet ou desktop. destination é uma chave de loja, web ou landing. Campos desconhecidos são null. Visitas de bots nunca disparam este evento.

app.metadata_fetched

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

Verifique as assinaturas

Verifique a assinatura de cada solicitação, para ter certeza de que ela veio do mapps.one e não foi alterada no caminho:

  1. Leia t e v1 do cabeçalho X-Mapps-Signature.
  2. Calcule um HMAC-SHA256 de {t}.{raw request body} usando o segredo de assinatura do seu endpoint, em hexadecimal minúsculo.
  3. Compare o resultado com v1 usando uma comparação em tempo constante.
  4. Rejeite a solicitação se t estiver a mais de cinco minutos do relógio do seu servidor, para bloquear solicitações reenviadas por terceiros.
Use o corpo bruto. Calcule a assinatura sobre exatamente os bytes que você recebeu, antes de qualquer parsing do JSON. Recodificar o JSON pode alterar barras ou caracteres Unicode e invalidar a assinatura.

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

No Laravel, leia o corpo com $request->getContent() e o cabeçalho com $request->header('X-Mapps-Signature'), e exclua a rota da proteção 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);

Respostas e novas tentativas

  • Responda com qualquer status 2xx em até 10 segundos. Faça o trabalho demorado em um job em segundo plano depois de responder.
  • Redirecionamentos não são seguidos, então use a URL final.
  • A URL deve ser https pública. Endereços de redes privadas e locais são recusados.
  • Se o seu endpoint exceder o tempo limite ou retornar qualquer coisa diferente de 2xx, tentamos novamente até mais cinco vezes: depois de cerca de 1 minuto, 5 minutos, 30 minutos, 2 horas e 6 horas. Cada tentativa tem um novo timestamp e uma nova assinatura.
  • O mesmo evento pode chegar mais de uma vez, e os eventos podem chegar fora de ordem. Use X-Mapps-Delivery, o id do evento, para ignorar duplicatas, e created_at para ordená-los.
  • Depois de 20 tentativas seguidas com falha, o endpoint é desativado e nada mais é enviado para ele. Corrija o problema e depois reative-o no painel.

Zapier, Make e n8n

Você pode conectar o mapps.one a milhares de apps sem manter um servidor.

Zapier

  1. Crie um Zap com Webhooks by Zapier como gatilho e escolha Catch Hook.
  2. Copie a URL de webhook que o Zapier fornecer.
  3. No mapps.one, adicione um endpoint com essa URL e escolha os eventos que você quer, por exemplo app.status_changed ou analytics.daily_summary.
  4. Escolha Enviar evento de teste no mapps.one e depois Test trigger no Zapier. Os campos do payload, como data.app.name, agora podem ser usados nas próximas etapas.

Exemplos: publicar uma mensagem no Slack quando um app for pausado, adicionar os cliques de cada dia a uma planilha do Google Sheets ou enviar um e-mail para um cliente quando o domínio dele for verificado.

Make e n8n

No Make, use o gatilho Webhooks → Custom webhook. No n8n, use o nó Webhook com o método POST. Depois, adicione a URL como endpoint no mapps.one, como descrito acima.

Como criar uma integração

Se você está criando uma integração do mapps.one para outras pessoas, faça a inscrição com a API quando um usuário se conectar (POST /api/v1/webhooks), cancele a inscrição quando ele se desconectar (DELETE /api/v1/webhooks/{id}), use GET /api/v1/events para o seletor de eventos e use GET /api/v1/workspace para testar a conexão. Veja a referência da API.