Saltar al contenido

Desarrolladores

Webhooks y Zapier

Los webhooks envían una solicitud HTTP a tu servidor en el momento en que ocurre algo en tu espacio de trabajo, como cuando se pausa una app o alguien hace clic en un enlace inteligente. Úsalos para actualizar tus propios sistemas, publicar en Slack o conectar mapps.one con Zapier, Make o n8n sin escribir un servidor. Los webhooks están disponibles en el plan Studio, con hasta 10 endpoints por espacio de trabajo.

Añadir un endpoint

  1. En el panel, abre Desarrolladores → Webhooks y elige Añadir endpoint. Pueden hacerlo los propietarios y administradores del espacio de trabajo.
  2. Introduce una URL https pública, elige los eventos que quieres enviar (o todos los eventos) y añade una descripción.
  3. Copia el secreto de firma y guárdalo junto con los demás secretos de tu servidor.
  4. Elige Enviar evento de prueba para comprobar que tu endpoint responde.

La página del endpoint muestra las entregas recientes con el estado de la respuesta, los primeros 2000 caracteres del cuerpo de la respuesta y cuánto tardó cada intento. También puedes crear y eliminar endpoints con la API.

Eventos

TipoSe envía cuando
app.createdSe añadió una app al espacio de trabajo.
app.updatedCambiaron los detalles, enlaces o ajustes de página de una app.
app.deletedSe eliminó una app.
app.status_changedUna app se activó, se pausó o se suspendió.
app.metadata_fetchedSe importaron los metadatos de tienda de una app.
legal.publishedSe publicó una política de privacidad o un documento de términos.
domain.verifiedSe verificó un dominio personalizado.
link.clickedCada clic en un enlace inteligente. Puede suponer muchas solicitudes en una app popular.
analytics.daily_summaryLos totales de clics del día anterior de cada app, enviados una vez al día.

Formato de la solicitud

Cada evento se envía como una solicitud POST con un cuerpo JSON.

EncabezadoValor
Content-Typeapplication/json
User-Agentmapps.one-Webhooks/1.0
X-Mapps-EventEl tipo de evento, como link.clicked
X-Mapps-DeliveryEl ID del evento. Se mantiene igual en cada reintento.
X-Mapps-TimestampHora Unix de este intento de entrega
X-Mapps-Signaturet={timestamp},v1={signature}

El cuerpo es un sobre con la misma estructura para todos los 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"
  }
}

El contenido de data depende del evento. Los eventos sobre una app incluyen un objeto app con su id, slug y 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 está en UTC. device_type es mobile, tablet o desktop. destination es una clave de tienda, web o landing. Los campos desconocidos son null. Las visitas de bots nunca activan este evento.

app.metadata_fetched

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

Verificar las firmas

Comprueba la firma de cada solicitud para saber que procede de mapps.one y que no se modificó por el camino:

  1. Lee t y v1 del encabezado X-Mapps-Signature.
  2. Calcula un HMAC-SHA256 de {t}.{raw request body} con el secreto de firma de tu endpoint, en hexadecimal y en minúsculas.
  3. Compáralo con v1 mediante una comparación de tiempo constante.
  4. Rechaza la solicitud si t se aleja más de cinco minutos del reloj de tu servidor, para bloquear solicitudes reutilizadas.
Usa el cuerpo sin procesar. Calcula la firma sobre los bytes exactos que recibiste, antes de analizar el JSON. Volver a codificar el JSON puede cambiar las barras o los caracteres Unicode y romper la firma.

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

En Laravel, lee el cuerpo con $request->getContent() y el encabezado con $request->header('X-Mapps-Signature'), y excluye la ruta de la protección 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);

Respuestas y reintentos

  • Responde con cualquier estado 2xx en un plazo de 10 segundos. Haz el trabajo lento en una tarea en segundo plano después de responder.
  • Las redirecciones no se siguen, así que usa la URL final.
  • La URL debe ser https pública. Las direcciones de redes privadas y locales se rechazan.
  • Si tu endpoint agota el tiempo de espera o devuelve cualquier estado distinto de 2xx, reintentamos hasta cinco veces más: después de aproximadamente 1 minuto, 5 minutos, 30 minutos, 2 horas y 6 horas. Cada intento lleva una nueva marca de tiempo y una nueva firma.
  • El mismo evento puede llegar más de una vez, y los eventos pueden llegar desordenados. Usa X-Mapps-Delivery, el id del evento, para ignorar los duplicados, y created_at para ordenarlos.
  • Tras 20 intentos fallidos seguidos, el endpoint se desactiva y no se le envía nada más. Soluciona el problema y luego vuelve a activarlo en el panel.

Zapier, Make y n8n

Puedes conectar mapps.one con miles de apps sin ejecutar un servidor.

Zapier

  1. Crea un Zap con Webhooks by Zapier como disparador y elige Catch Hook.
  2. Copia la URL de webhook que te da Zapier.
  3. En mapps.one, añade un endpoint con esa URL y elige los eventos que quieras, por ejemplo app.status_changed o analytics.daily_summary.
  4. Elige Enviar evento de prueba en mapps.one y luego Test trigger en Zapier. Los campos del payload, como data.app.name, ya se pueden usar en los pasos siguientes.

Ejemplos: publica un mensaje en Slack cuando se pause una app, añade los clics de cada día a una hoja de cálculo de Google Sheets o envía un correo electrónico a un cliente cuando se verifique su dominio.

Make y n8n

En Make, usa el disparador Webhooks → Custom webhook. En n8n, usa el nodo Webhook con el método POST. Luego añade la URL como endpoint en mapps.one, como se explicó arriba.

Crear una integración

Si estás creando una integración de mapps.one para otras personas, suscríbete con la API cuando un usuario se conecte (POST /api/v1/webhooks), cancela la suscripción cuando se desconecte (DELETE /api/v1/webhooks/{id}), usa GET /api/v1/events para el selector de eventos y GET /api/v1/workspace para probar la conexión. Consulta la referencia de la API.