> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metrito.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Zapflow integration

# Integração ZapFlow × Metrito

> **ZapFlow é o primeiro parceiro nativo do Metrito.** Esta integração é exclusiva e direta — a ZapFlow tem acesso privilegiado à nossa API de rastreamento, podendo conectar workspaces de seus usuários via OAuth, disparar eventos de rastreamento, criar registros de vendas e decodificar UTMs embutidas em mensagens do WhatsApp.

***

## Visão Geral

A integração entre ZapFlow e Metrito é composta por quatro pilares:

| Pilar                          | O que faz                                                                                              |
| ------------------------------ | ------------------------------------------------------------------------------------------------------ |
| **OAuth**                      | Usuário conecta seu workspace Metrito diretamente de dentro do ZapFlow, sem copiar/colar chaves        |
| **Decodificação de mensagens** | Extrai UTMs e parâmetros de rastreamento embutidos de forma invisível em mensagens do WhatsApp         |
| **Nó de automação Metrito**    | No módulo de automações do ZapFlow, o usuário dispara eventos ou cria gatilhos configurados no Metrito |
| **Webhook de Pedido**          | Registra vendas diretamente no Metrito, impactando métricas de dashboard, campanhas e notificações     |

***

## 1. Conexão via OAuth

### Por que OAuth e não API Key manual?

Pedir ao usuário que copie e cole uma API Key é uma barreira. Com OAuth, o fluxo é:

1. Usuário clica em **"Conectar Metrito"** dentro do ZapFlow
2. É redirecionado para a tela de autorização do Metrito (já estará logado na maioria dos casos)
3. Seleciona a workspace e clica em **Autorizar**
4. Retorna ao ZapFlow com a API Key já gerada e armazenada automaticamente

> **Importante:** o usuário precisa estar logado no Metrito para que a tela de consentimento seja exibida. Se não estiver, será redirecionado para o login e depois voltará automaticamente para a tela de autorização — o fluxo retoma sem intervenção.

### Credenciais ZapFlow

As credenciais abaixo foram fornecidas pela equipe do Metrito exclusivamente para a ZapFlow:

```
client_id:     metrito_app_zapflow
redirect_uri:  https://zapflow.io/metrito/callback   (ou o URI configurado internamente)
```

O `client_secret` deve ser armazenado de forma segura no backend da ZapFlow. Nunca exponha-o no frontend.

### Construindo a URL de autorização

```js theme={null}
const METRITO_AUTHORIZE_URL = "https://app.metrito.com/authorize";

function buildAuthorizationUrl(state) {
  const params = new URLSearchParams({
    client_id: "metrito_app_zapflow",
    redirect_uri: "https://zapflow.io/metrito/callback",
    state, // valor aleatório gerado por vocês para proteção CSRF
  });
  return `${METRITO_AUTHORIZE_URL}?${params.toString()}`;
}

// Exemplo de uso
const state = crypto.randomUUID();
// Armazene 'state' na sessão do usuário para validar no callback

const url = buildAuthorizationUrl(state);
// Redirecione o usuário para 'url'
```

### Callback: trocando o código pela API Key

No endpoint `https://zapflow.io/metrito/callback` (backend):

```js theme={null}
// POST /v3/oauth/token
async function exchangeCodeForApiKey({ code, redirectUri, keyName }) {
  const response = await fetch("https://api.metrito.com/v3/oauth/token", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      grant_type: "authorization_code",
      client_id: "metrito_app_zapflow",
      client_secret: process.env.METRITO_CLIENT_SECRET, // nunca expor no frontend
      code,
      redirect_uri: redirectUri,
      key_name: keyName ?? "ZapFlow", // nome que aparecerá na workspace do usuário
    }),
  });

  if (!response.ok) {
    const err = await response.json();
    throw new Error(err.message ?? "Falha ao trocar código Metrito");
  }

  const data = await response.json();
  // data.access_token → API Key no formato "mtk_live_..."
  // data.workspace_id → ID da workspace autorizada
  // Armazene access_token e workspace_id vinculados ao usuário ZapFlow

  return data;
}
```

Resposta de sucesso:

```json theme={null}
{
  "access_token": "mtk_live_AbCdEfGhIjKlMnOpQrStUvWxYz",
  "token_type": "bearer",
  "scope": "tracking:read tracking:write data:read data:write",
  "workspace_id": "60f1b2c3d4e5f6a7b8c9d0e1",
  "key_name": "ZapFlow",
  "expires_at": null
}
```

A partir daqui, `access_token` é a API Key do usuário no Metrito. Use-a como `Bearer` token em todas as chamadas subsequentes.

***

## 2. Decodificação de Mensagens WhatsApp

### Como funciona o rastreamento invisível do Metrito

O Metrito embute um identificador invisível nas mensagens do WhatsApp usando caracteres Unicode de largura zero:

| Caractere | Unicode  | Nome                        |
| --------- | -------- | --------------------------- |
| `⁠`       | `U+2060` | Word Joiner (separador)     |
| `⁤`       | `U+2064` | Invisible Plus (bit 1)      |
| `⁣`       | `U+2063` | Invisible Separator (bit 0) |

Esses caracteres são completamente invisíveis para o usuário final, mas quando o ZapFlow recebe uma mensagem do WhatsApp, pode detectá-los e enviar ao Metrito para obter os UTMs e parâmetros da sessão original do lead.

### Snippet: detectar e decodificar em uma mensagem

```js theme={null}
// Caracteres invisíveis usados pelo Metrito
const METRITO_CHARS = {
  SEP: "\u2060", // Word Joiner — separador de bytes
  ONE: "\u2064", // Invisible Plus — bit 1
  NIL: "\u2063", // Invisible Separator — bit 0
};

/**
 * Verifica se uma mensagem contém caracteres invisíveis do Metrito.
 * Use isso antes de chamar o endpoint de decodificação para evitar
 * chamadas desnecessárias à API.
 */
function hasMetritoTracking(text) {
  return (
    typeof text === "string" && text.includes(METRITO_CHARS.SEP) && (text.includes(METRITO_CHARS.ONE) || text.includes(METRITO_CHARS.NIL))
  );
}

/**
 * Decodifica um lote de mensagens do WhatsApp via API do Metrito.
 * Retorna os UTMs e parâmetros de rastreamento de cada mensagem que os contiver.
 *
 * @param {string} apiKey        - API Key do usuário (obtida via OAuth)
 * @param {Array<{text: string}>} messages - Mensagens a decodificar
 */
async function decodeMetritoMessages(apiKey, messages) {
  const response = await fetch("https://api.metrito.com/v3/tracking/messages/decode", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ messages }),
  });

  if (!response.ok) {
    throw new Error(`Metrito decode failed: ${response.status}`);
  }

  return response.json();
  // Retorno: { messages: [{ text, decoded_text, params, tracking_link_id, ... }] }
}

/**
 * Enriquece uma nova conversa com UTMs do Metrito.
 * Use no evento "nova mensagem recebida" do ZapFlow.
 *
 * @param {string} apiKey         - API Key do usuário
 * @param {string} messageText    - Texto da primeira mensagem do lead
 * @returns {object|null}         - Parâmetros UTM ou null se não rastreado
 */
async function enrichLeadFromMessage(apiKey, messageText) {
  // Pulo rápido: evita chamada à API se não há rastreamento
  if (!hasMetritoTracking(messageText)) {
    return null;
  }

  try {
    const result = await decodeMetritoMessages(apiKey, [{ text: messageText }]);
    const decoded = result.messages?.[0];

    if (!decoded?.params) return null;

    // decoded.params contém os UTMs da sessão original do lead
    // decoded.decoded_text é o texto sem os caracteres invisíveis
    return {
      utms: decoded.params, // { utm_source, utm_medium, utm_campaign, ... }
      cleanText: decoded.decoded_text,
      trackingLinkId: decoded.tracking_link_id,
    };
  } catch (err) {
    console.error("[Metrito] Erro ao decodificar mensagem:", err.message);
    return null;
  }
}
```

### Exemplo de uso no handler de mensagens do ZapFlow

```js theme={null}
// Handler chamado quando uma nova mensagem chega no WhatsApp
async function onNewWhatsAppMessage({ contact, message, userApiKey }) {
  // 1. Tenta extrair UTMs do Metrito
  const tracking = await enrichLeadFromMessage(userApiKey, message.text);

  if (tracking) {
    // 2. Enriquece o contato no CRM do ZapFlow com os dados de origem
    await updateContactTracking(contact.id, {
      utm_source: tracking.utms.utm_source,
      utm_medium: tracking.utms.utm_medium,
      utm_campaign: tracking.utms.utm_campaign,
      utm_content: tracking.utms.utm_content,
      utm_term: tracking.utms.utm_term,
      metrito_tracking_link_id: tracking.trackingLinkId,
    });

    console.log(`[Metrito] Lead ${contact.id} enriquecido:`, tracking.utms);
  }
}
```

### Resposta da API de decodificação

```json theme={null}
{
  "messages": [
    {
      "text": "Olá, vi o anúncio!⁠⁤⁣⁤⁣⁤⁣⁤",
      "decoded_text": "Olá, vi o anúncio!",
      "decoded_id": 1234567890,
      "params": {
        "utm_source": "instagram",
        "utm_medium": "cpc",
        "utm_campaign": "120215678901234567"
      },
      "tracking_link_id": "64a1b2c3d4e5f6a7b8c9d0e4",
      "selected_target": null
    }
  ]
}
```

Se a mensagem não contiver rastreamento, `params` e `tracking_link_id` serão `null`.

***

## 3. Nó de Automação Metrito

O ZapFlow possui um módulo de automações. O objetivo é ter um **nó exclusivo "Metrito"** que o usuário pode adicionar em qualquer fluxo para interagir com a plataforma.

### O que o nó deve fazer

```
┌─────────────────────────────────────────────────┐
│              Nó: Metrito                         │
│                                                  │
│  Ação:  [ Disparar Evento ▼ ]                    │
│                                                  │
│  Gatilho: [ Compra Aprovada ▼ ]  [+ Criar novo]  │
│                                                  │
│  Dados do evento:                                │
│    Email:  {{ contato.email }}                   │
│    Valor:  {{ pedido.valor }}                    │
│    Moeda:  BRL                                   │
└─────────────────────────────────────────────────┘
```

O usuário:

1. Seleciona qual ação executar (por enquanto: **Disparar Evento**)
2. Escolhe um gatilho existente do tipo `api` — listado diretamente da API do Metrito
3. Pode criar um novo gatilho caso não exista o que precisa

***

### 3.1 Buscando o Container do usuário

Antes de listar gatilhos, é necessário obter o container do Metrito associado à workspace do usuário. Use o `workspace_id` retornado no OAuth.

```js theme={null}
/**
 * Busca os containers disponíveis para um usuário.
 * Retorna o container_id para usar nas próximas chamadas.
 */
async function getContainers(apiKey) {
  // A API Key já está vinculada ao workspace — o container é resolvido internamente.
  // Use GET /v3/tracking/containers/{container_id} se souber o ID ou MTC.
  // Para obter o container_id, você pode armazenar após o primeiro uso ou
  // pedir ao usuário que informe seu Metrito Tracking Code (ex: MTC-AB12).

  const response = await fetch(`https://api.metrito.com/v3/tracking/containers/${containerId}`, {
    headers: { Authorization: `Bearer ${apiKey}` },
  });

  if (!response.ok) throw new Error("Container não encontrado");
  return response.json();
}
```

**Identificadores aceitos pelo endpoint `GET /v3/tracking/containers/{container_id}`:**

| Formato                    | Exemplo                    | Como obter                                              |
| -------------------------- | -------------------------- | ------------------------------------------------------- |
| ObjectId                   | `64a1b2c3d4e5f6a7b8c9d0e1` | URL da plataforma após `/containers/`                   |
| Domínio (v2)               | `minhaloja.com.br`         | Domínio real configurado no container                   |
| Metrito Tracking Code (v3) | `MTC-AB12`                 | Visível na sidebar da plataforma, na página de Tracking |

> **Recomendação:** no onboarding do nó Metrito, peça ao usuário seu **Metrito Tracking Code** (MTC). É curto, fácil de copiar e identifica o container v3 sem ambiguidade.

***

### 3.2 Listando Gatilhos disponíveis (tipo `api`)

```js theme={null}
/**
 * Lista os gatilhos do tipo "api" de um container.
 * Use para popular o dropdown de seleção de gatilhos no nó Metrito.
 */
async function listApiTriggers(apiKey, containerId) {
  const url = new URL(`https://api.metrito.com/v3/tracking/containers/${containerId}/triggers`);
  url.searchParams.set("trigger_type", "api");
  url.searchParams.set("limit", "100");

  const response = await fetch(url.toString(), {
    headers: { Authorization: `Bearer ${apiKey}` },
  });

  if (!response.ok) throw new Error("Falha ao listar gatilhos Metrito");

  const { data } = await response.json();
  // data → array de gatilhos com: id, name, config.facebook.name
  return data;
}
```

Resposta:

```json theme={null}
{
  "data": [
    {
      "id": "64a1b2c3d4e5f6a7b8c9d0e2",
      "name": "Compra Aprovada",
      "config": {
        "trigger": { "type": "api" },
        "facebook": { "name": "Purchase", "track_custom": false }
      }
    },
    {
      "id": "64a1b2c3d4e5f6a7b8c9d0e3",
      "name": "Lead Cadastrado",
      "config": {
        "trigger": { "type": "api" },
        "facebook": { "name": "Lead", "track_custom": false }
      }
    }
  ],
  "pagination": { "page": 1, "limit": 100, "total": 2 }
}
```

***

### 3.3 Criando um novo Gatilho via API

Se o usuário quiser criar um novo gatilho diretamente pelo ZapFlow:

```js theme={null}
/**
 * Cria um gatilho do tipo "api" no container do usuário.
 *
 * @param {string} apiKey
 * @param {string} containerId
 * @param {object} trigger     - { name, facebookEventName }
 */
async function createApiTrigger(apiKey, containerId, { name, facebookEventName }) {
  const response = await fetch(`https://api.metrito.com/v3/tracking/containers/${containerId}/triggers`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
      // Opcional: evita duplicatas em caso de retry
      "Idempotency-Key": `zapflow-trigger-${containerId}-${name}`,
    },
    body: JSON.stringify({
      name,
      config: {
        trigger: { type: "api" },
        ...(facebookEventName && {
          facebook: { name: facebookEventName, track_custom: false },
        }),
      },
    }),
  });

  if (!response.ok) {
    const err = await response.json();
    throw new Error(err.message ?? "Falha ao criar gatilho Metrito");
  }

  return response.json();
  // Retorna o gatilho criado com seu id
}

// Exemplo:
await createApiTrigger(apiKey, "MTC-AB12", {
  name: "Proposta Enviada",
  facebookEventName: "Lead", // mapeamento para Meta — opcional
});
```

> Apenas gatilhos do tipo `api` podem ser criados via API pública. Gatilhos de pageview, clique, scroll etc. são criados pela interface da plataforma.

***

### 3.4 Disparando um Evento de Rastreamento

Com o gatilho selecionado (ou recém-criado), dispare o evento quando a automação executar o nó:

```js theme={null}
/**
 * Dispara um evento de rastreamento no Metrito.
 * Use no nó de automação quando o usuário configurar "Disparar Evento".
 *
 * @param {string} apiKey
 * @param {object} options
 * @param {string} options.triggerName   - Nome do gatilho (config.name)
 * @param {string} [options.fbEventName] - Nome do evento Meta (se configurado)
 * @param {object} [options.lead]        - Dados do lead: email, phone, name
 * @param {object} [options.data]        - Valor monetário: { value, currency }
 * @param {object} [options.utm]         - UTMs previamente extraídas da mensagem
 */
async function fireTrackingEvent(apiKey, { triggerName, fbEventName, lead, data, utm }) {
  const payload = {
    config: {
      name: triggerName,
      ...(fbEventName && { facebook: { name: fbEventName } }),
    },
    ...(lead && { lead }),
    ...(data && { data }),
    ...(utm && { utm }),
  };

  const response = await fetch("https://api.metrito.com/v3/tracking/events", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
      "Idempotency-Key": `zapflow-event-${Date.now()}-${Math.random()}`,
    },
    body: JSON.stringify(payload),
  });

  if (!response.ok) {
    const err = await response.json();
    throw new Error(err.message ?? "Falha ao disparar evento Metrito");
  }

  return response.json();
}

// Exemplo completo no nó Metrito de uma automação:
await fireTrackingEvent(userApiKey, {
  triggerName: "Proposta Enviada",
  fbEventName: "Lead",
  lead: {
    email: contact.email,
    phone: contact.phone,
    name: contact.name,
  },
  utm: enrichedContact.utms, // UTMs extraídas da primeira mensagem do lead
});
```

### Diferença entre `config.name` e `config.facebook.name`

| Campo                  | Onde aparece                             | Exemplo                              |
| ---------------------- | ---------------------------------------- | ------------------------------------ |
| `config.name`          | Relatórios e dashboards do Metrito       | `"Proposta Enviada"`                 |
| `config.facebook.name` | Meta Conversion API (Facebook/Instagram) | `"Lead"`, `"Purchase"`, `"PageView"` |

Se `config.facebook` for omitido, o evento é registrado no Metrito mas **não** é enviado para a Meta. Isso é válido para eventos internos que não precisam de atribuição.

***

## 4. Webhook de Pedido (Registro de Venda)

### Diferença em relação ao evento de rastreamento

|                                    | Evento de Rastreamento                    | Webhook de Pedido                      |
| ---------------------------------- | ----------------------------------------- | -------------------------------------- |
| **Endpoint**                       | `POST /v3/tracking/events`                | `POST /v2/tracking/generic?k={chave}`  |
| **Autenticação**                   | API Key Bearer                            | Parâmetro `k` na query string          |
| **O que cria**                     | Evento de rastreamento (funil, Meta CAPI) | **Registro de venda** no Metrito       |
| **Impacto no dashboard**           | Métricas de funil e conversão             | ✅ **Receita, ROAS, custo por venda**   |
| **Impacto na página de campanhas** | Atribuição de eventos                     | ✅ **Atribuição de receita à campanha** |
| **Notificações push**              | Não                                       | ✅ **Dispara notificação de venda**     |
| **Upsert por ID**                  | Não                                       | ✅ **Idempotente por `transaction.id`** |
| **Associação a lead**              | Via `lead.email` / `lead.phone`           | Via `utm.mlid`, e-mail ou telefone     |

> **Resumo:** use o Webhook de Pedido quando quiser registrar que uma **venda aconteceu**. Use o evento de rastreamento para sinais de funil (lead, proposta, clique). Os dois podem coexistir numa mesma automação.

### Onde encontrar a chave `k`

O parâmetro `k` não é a API Key OAuth. Ele é específico de uma **conexão "Personalizado"** criada pelo usuário na plataforma Metrito:

1. Na plataforma, acesse **Conexões → Adicionar Conexão → Personalizado**
2. Após criar, a URL completa do webhook (incluindo `?k=...`) é exibida
3. Copie e use como destino para os webhooks de pedido

> O ZapFlow pode armazenar essa chave `k` separadamente da API Key OAuth. São credenciais independentes.

### Disparando um Webhook de Pedido

```js theme={null}
/**
 * Registra uma venda no Metrito via Webhook de Pedido.
 * Impacta dashboard, campanhas e dispara notificação push.
 *
 * Valores monetários devem ser enviados em CENTAVOS (inteiros).
 * Ex: R$ 197,00 = 19700
 *
 * @param {string} webhookKey   - Valor do parâmetro `k` (da conexão Personalizado)
 * @param {object} sale         - Dados da venda
 * @param {object} [utms]       - UTMs do lead (extraídas da mensagem, se disponíveis)
 */
async function registerSale(webhookKey, sale, utms = null) {
  const url = `https://api.metrito.com/v2/tracking/generic?k=${webhookKey}`;

  const payload = {
    transaction: {
      id: sale.id, // ID único do pedido no ZapFlow
      status: sale.status, // "approved" | "pending" | "refunded" etc.
      currency: sale.currency ?? "BRL",
      value: Math.round(sale.totalCents), // total em centavos
      commission_currency: "BRL",
      commission_value: Math.round(sale.commissionCents ?? sale.totalCents),
      created_at: sale.createdAt,
      updated_at: sale.updatedAt ?? new Date().toISOString(),
      customer: {
        name: sale.customerName,
        email: sale.customerEmail,
        phone: sale.customerPhone,
      },
      products: sale.items?.map((item) => ({
        id: item.id,
        product_name: item.name,
        quantity: item.quantity,
        value: Math.round(item.priceCents),
      })),
      payment: {
        method: sale.paymentMethod ?? "unknown",
        installments: sale.installments ?? 1,
      },
    },
    ...(utms && {
      utm: {
        source: utms.utm_source,
        medium: utms.utm_medium,
        campaign: utms.utm_campaign,
        mlid: utms.mlid, // Metrito Lead ID — maximiza atribuição
      },
    }),
  };

  const response = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  });

  if (!response.ok) {
    const err = await response.json();
    throw new Error(err.message ?? "Falha ao registrar venda no Metrito");
  }

  return response.json(); // { success: true }
}

// Exemplo: venda aprovada com UTMs extraídas da primeira mensagem do lead
await registerSale(
  process.env.METRITO_WEBHOOK_KEY,
  {
    id: "zapflow-order-98765",
    status: "approved",
    totalCents: 29700, // R$ 297,00
    commissionCents: 29700,
    currency: "BRL",
    createdAt: new Date().toISOString(),
    customerName: "Maria Oliveira",
    customerEmail: "maria@email.com",
    customerPhone: "+5511988887777",
    items: [{ id: "prod-1", name: "Consultoria", quantity: 1, priceCents: 29700 }],
    paymentMethod: "pix",
    installments: 1,
  },
  enrichedContact.utms, // UTMs capturadas na primeira mensagem do lead
);
```

### Status de transação e seus efeitos

| Status       | Dispara evento Meta? | Aparece como receita no dashboard? |
| ------------ | -------------------- | ---------------------------------- |
| `pending`    | Não                  | Não                                |
| `approved`   | ✅ Sim (`Purchase`)   | ✅ Sim                              |
| `authorized` | Não                  | Não                                |
| `refunded`   | Não                  | Não (receita revertida)            |
| `failed`     | Não                  | Não                                |
| `chargeback` | Não                  | Não                                |

> O Metrito faz **upsert** automático pelo campo `transaction.id`. Se a mesma venda for enviada novamente com status atualizado (ex: `pending` → `approved`), o registro é atualizado e os impactos de receita são calculados corretamente.

***

## 5. Fluxo Completo: Da Mensagem à Venda

Este é o fluxo ideal de uma automação ZapFlow que usa todos os recursos Metrito:

```
1. Lead envia mensagem no WhatsApp
       │
       ▼
2. [Metrito] decodeMessages(message.text)
       │
       └── params encontrados?
           ├── Sim → salvar UTMs no perfil do lead
           └── Não → continuar sem UTMs
       │
       ▼
3. Fluxo de qualificação do ZapFlow
   (perguntas, atendimento, proposta...)
       │
       ▼
4. Lead aceita a proposta
       │
       ▼
5. [Nó Metrito] Disparar Evento
       ├── triggerName: "Proposta Aceita"
       ├── fbEventName: "Lead"
       ├── lead: { email, phone, name }
       └── utm: <UTMs salvas no passo 2>
       │
       ▼
6. Pagamento confirmado
       │
       ▼
7. [Nó Metrito] Webhook de Pedido
       ├── status: "approved"
       ├── value: valorEmCentavos
       ├── customer: { name, email, phone }
       └── utm: <UTMs salvas no passo 2>
       │
       ▼
8. No Metrito:
   ✅ Receita atribuída à campanha de origem
   ✅ ROAS atualizado no dashboard
   ✅ Notificação push "Nova venda!"
   ✅ Evento Purchase enviado à Meta Conversion API
```

***

## 6. Resumo de Endpoints

| Ação                     | Método | Endpoint                                                 | Auth                          |
| ------------------------ | ------ | -------------------------------------------------------- | ----------------------------- |
| Obter container          | `GET`  | `/v3/tracking/containers/{id}`                           | API Key                       |
| Listar gatilhos tipo api | `GET`  | `/v3/tracking/containers/{id}/triggers?trigger_type=api` | API Key                       |
| Criar gatilho tipo api   | `POST` | `/v3/tracking/containers/{id}/triggers`                  | API Key                       |
| Disparar evento          | `POST` | `/v3/tracking/events`                                    | API Key                       |
| Decodificar mensagens    | `POST` | `/v3/tracking/messages/decode`                           | API Key                       |
| Registrar venda          | `POST` | `/v2/tracking/generic?k={chave}`                         | Query param `k`               |
| Obter API Key (OAuth)    | `POST` | `/v3/oauth/token`                                        | `client_id` + `client_secret` |

**URL base:** `https://api.metrito.com`

***

## 7. Boas Práticas

* **Guarde a API Key por workspace:** cada usuário ZapFlow que conectar o Metrito terá uma API Key diferente, vinculada à workspace que escolheu. Armazene-a associada ao ID de usuário ZapFlow.
* **Use Idempotency-Key em POSTs:** previne duplicatas em caso de retry automático. Use um UUID gerado por evento ou uma combinação de IDs únicos.
* **Decodifique apenas se houver caracteres invisíveis:** use `hasMetritoTracking()` antes de chamar a API para evitar requisições desnecessárias.
* **Passe as UTMs em todos os eventos:** quanto mais contexto de atribuição o Metrito receber, mais precisa será a atribuição de receita às campanhas do usuário.
* **Use `mlid` quando disponível:** o Metrito Lead ID (`mlid`) nos UTMs tem prioridade máxima na atribuição. Se estiver nos `params` da decodificação, sempre inclua-o no webhook de pedido.

***

## Suporte

Para dúvidas técnicas sobre esta integração, entre em contato diretamente com a equipe de engenharia do Metrito:

**Email:** [contato@metrito.com](mailto:contato@metrito.com)
**Documentação pública:** [https://docs.metrito.com](https://docs.metrito.com)
