---
title: "Receitas"
slug: recipes
group: "Exemplos"
source: https://linkzap.orion.moe/developers/recipes
openapi: https://linkzap.orion.moe/openapi.json
---

# Receitas

Quatro integrações inteiras, do jeito que a gente faria. Copie e troque os ids.

## 1. O lead do site vira conversa

O visitante preenche o formulário e, em vez de entrar numa planilha para alguém ligar depois, já recebe a primeira mensagem — no minuto em que o interesse existe.

Trecho — No backend do seu site, depois de validar o formulário:

```js
const r = await fetch("https://linkzap.orion.moe/api/webhooks/channel/" + process.env.LINKZAP_CHANNEL_ID, {
  method: "POST",
  headers: {
    "x-api-key": process.env.LINKZAP_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phone: form.telefone,
    name: form.nome,
    email: form.email,
    message: `Oi, ${form.nome.split(" ")[0]}! Recebemos o seu contato sobre ${form.assunto}. Já te respondo por aqui.`,
    tags: ["lead-site"],
    fields: { origem: form.utm_source ?? "direto", assunto: form.assunto },
    optIn: true,   // a pessoa marcou a caixa de consentimento no formulário
  }),
});

if (!r.ok) {
  // 409 = o número não está pronto. O CONTATO foi salvo mesmo assim:
  // registre para a equipe retomar, não perca o lead.
  console.error("linkzap:", r.status, await r.text());
}
```

> [!NOTE]
> **Uma variação que costuma render mais**
>
> Troque `message` por `flowId`. Em vez de uma frase solta cuja resposta cai na fila sem contexto, o contato entra num fluxo que já pergunta o que precisa saber e só chama um humano quando vale a pena.

## 2. O seu sistema avisa o cliente

Pedido aprovado, consulta confirmada, boleto vencendo. O caso mais comum de todos.

Trecho — Uma função para reusar:

```js
async function avisar(telefone, texto) {
  const r = await fetch("https://linkzap.orion.moe/api/v1/messages", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.LINKZAP_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      channelId: process.env.LINKZAP_CHANNEL_ID,
      phone: telefone,
      text: texto,
    }),
  });

  if (r.status === 409) {
    // O número não está pronto para enviar; o motivo vem em palavras.
    const { error } = await r.json();
    throw new Error("canal indisponível: " + error);
  }
  if (r.status === 429) {
    // Respeite o Retry-After em vez de tentar em laço.
    throw new Error("freio: tente em " + r.headers.get("retry-after") + "s");
  }
  if (!r.ok) throw new Error(await r.text());

  const { data } = await r.json();
  return data.messageId;   // guarde: reenviar sem checar manda duas vezes
}
```

> [!WARNING]
> **Na conta oficial, cuidado com a janela**
>
> Se o número é `provider: "cloud"`, texto livre só sai se o contato falou com você nas últimas 24 horas. Para avisos que partem de você, o caminho é um template aprovado — que hoje se dispara pelo painel, por um fluxo, por uma sequência ou por uma campanha. Nos números por QR não há essa restrição.

## 3. Espelhar as conversas no seu banco

Para o seu time comercial ver o histórico de WhatsApp dentro do seu próprio sistema, sem trocar de tela. Escute os eventos e escreva no seu banco — nada de varrer a API de tempos em tempos.

Trecho — O receptor, com assinatura e idempotência:

```js
app.post("/linkzap", express.raw({ type: "application/json" }), async (req, res) => {
  if (!assinaturaConfere(req)) return res.sendStatus(401);   // ver "Webhooks de saída"

  const entrega = req.header("x-linkzap-delivery");
  const { event, data } = JSON.parse(req.body.toString("utf8"));

  // Responda ANTES de processar: o prazo é de 10 segundos.
  res.sendStatus(200);

  // A mesma entrega pode chegar duas vezes — o id é a chave.
  if (await jaProcessei(entrega)) return;
  await marcarProcessado(entrega);

  switch (event) {
    case "message.received":
    case "message.sent":
      await db.mensagens.upsert({
        externo: data.messageId,
        conversa: data.conversationId,
        telefone: data.phone,
        texto: data.text,
        entrada: event === "message.received",
        quando: data.occurredAt,
      });
      break;
    case "contact.opt_out":
      // Respeite no SEU sistema também: nada de incluí-lo no próximo disparo.
      await db.contatos.marcarOptOut(data.phone);
      break;
  }
});
```

Para trazer o que aconteceu antes de você ligar o webhook, percorra `GET /api/v1/conversations` e, para cada uma, `GET /api/v1/messages?conversationId=…`. Faça isso uma vez, na carga inicial — o resto vem pelos eventos.

## 4. Um chatbot seu respondendo

Você já tem a sua própria automação e quer que ela atenda por aqui. Funciona, com um cuidado que economiza um bug difícil.

Trecho — Receber, pensar, responder:

```js
// No receptor de webhook, depois de conferir a assinatura:
if (event === "message.received") {
  const resposta = await meuBot(data.text, data.conversationId);

  await fetch("https://linkzap.orion.moe/api/v1/messages", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.LINKZAP_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      channelId: data.channelId,
      conversationId: data.conversationId,   // responda NA conversa
      text: resposta,
    }),
  });
}
```

> [!CAUTION]
> **Desligue a Aura nesses canais**
>
> Uma mensagem enviada pela API não silencia a automação daqui — quem faz isso é uma pessoa respondendo pelo painel ou pelo celular. Se a Aura ou um fluxo também estiverem atendendo esse número, o contato recebe duas respostas para a mesma pergunta. Escolha um: ou a automação do LinkZap, ou a sua.

Repare também que a sua própria resposta gera um `message.sent` no seu receptor. Se o seu código reage a esse evento, garanta que ele não se responda em laço.

## Continue por aqui

Os detalhes de cada rota estão na [referência](https://linkzap.orion.moe/developers/channels.md), e a verificação da assinatura em três linguagens está em [Webhooks de saída](https://linkzap.orion.moe/developers/webhooks.md). Ficou faltando alguma coisa? O suporte quer saber qual — é assim que a gente decide o que entra primeiro.
