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

# Campanhas, públicos e opt-outs

> Construa (build) um público, crie e lance uma campanha, acompanhe a entrega e gerencie palavras-chave de opt-out.

Uma campanha envia um modelo para uma lista de destinatários. Crie e execute
campanhas com `messaging.campaigns`, que identifica um projeto pelo slug dele.
Gerencie públicos, configurações de opt-out e edições de rascunho no cliente de
equipe.

| Tarefa | Permissão |
| - | - |
| Ler campanhas, públicos, destinatários e configurações de opt-out | `campaigns:read` |
| Criar, alterar, lançar, pausar, retomar e parar | `campaigns:manage` |

Uma campanha envia a partir de Números cujo plano inclui Campanhas. Quando
nenhum dos Números elegíveis se qualifica, a criação ou o lançamento falha com
`402 campaigns_not_entitled`. Veja
[Envie uma campanha](/pt-br/guides/campaigns/send-a-campaign).

## Construa (build) um público

Um público é uma lista reutilizável de destinatários. Públicos usam um cliente
de equipe:

```typescript theme={null}
const audience = await platform.audiences.create({
  name: "October newsletter",
  members: [
    { phone: "+14155550100", variables: { firstName: "Ada" } },
    { phone: "+442071838750", variables: { firstName: "Alan" } },
  ],
});

console.log(audience.data.data.id, audience.data.data.invalidRows);
```

`create` aceita até 1.000 membros. Adicione mais com
`audiences.addMembers(audienceId, { members })`. Linhas inválidas aparecem em
`invalidRows` em vez de fazer a solicitação falhar. Percorra os membros página
por página com `audiences.listMembers(audienceId, { cursor })`.

## Crie uma campanha

```typescript theme={null}
const created = await messaging.campaigns.create(
  "<project-slug>",
  {
    name: "October newsletter",
    templateId: "<template-id>",
    recipientListId: "<audience-id>",
    sendWindow: {
      days: ["monday", "tuesday", "wednesday", "thursday", "friday"],
      hours: [{ start: "09:00", end: "18:00" }],
      timeZone: "Europe/Lisbon",
    },
  },
  { idempotencyKey: "campaign-october-newsletter" },
);

const campaignId = created.data.data.id;
```

Passe destinatários diretamente em `recipients`, um público em
`recipientListId`, ou os dois. A campanha começa como rascunho.

`variableMapping` preenche cada `{{variable}}` do conteúdo com um campo do
destinatário, com um valor de fallback para destinatários que não têm valor:

```typescript theme={null}
await messaging.campaigns.update("<project-slug>", campaignId, {
  variableMapping: {
    first_name: { source: "FirstName", fallback: "there" },
  },
});
```

O mapeamento e o modelo só mudam antes do lançamento. Veja
[Variáveis do modelo](/pt-br/guides/campaigns/send-a-campaign).

`sendWindow` limita quando as mensagens saem. Destinatários fora da janela
ficam na fila até ela abrir de novo. `timeZone` usa por padrão o fuso horário
da equipe, ou UTC. Defina `recipientTimeZone: true` para usar o fuso horário de
cada destinatário. Omita `sendWindow` para enviar a qualquer hora.

## Adicione destinatários

```typescript theme={null}
const added = await messaging.campaigns.addRecipients("<project-slug>", campaignId, {
  recipients: [{ phone: "+14155550101", variables: { firstName: "Grace" } }],
});

console.log(added.data.data.added, added.data.data.duplicateCount, added.data.data.invalidRows);
```

Cada chamada adiciona até 1.000 destinatários antes do lançamento. O SDK a
envia uma vez e não tenta novamente. Se a resposta se perder, liste os
destinatários antes de adicioná-los de novo.

## Lance, pause, retome e pare

```typescript theme={null}
const launched = await messaging.campaigns.launch("<project-slug>", campaignId, {
  scheduledAt: Date.parse("2026-10-06T09:00:00Z"),
});
await platform.operations.wait(launched.data.data.operationId);

await messaging.campaigns.pause("<project-slug>", campaignId);
await messaging.campaigns.resume("<project-slug>", campaignId);

const stopped = await messaging.campaigns.stop("<project-slug>", campaignId);
if (stopped.data.data.operationId !== null) {
  await platform.operations.wait(stopped.data.data.operationId);
}
```

Omita `scheduledAt` para começar agora. Um lançamento recusa, com
`422 campaign_variables_missing`, destinatários que não têm valor nem fallback
para uma variável; passe `skipMissingVariables: true` para ignorá-los. Cada
chamada retorna assim que a mudança é aceita; o envio continua em segundo plano
como uma [operação](/pt-br/sdks/typescript/events#aguarde-uma-operação). Uma
parada que cancela a campanha na hora retorna `operationId: null`, então
verifique isso antes de aguardar.

Esses quatro métodos criam uma chave de idempotência quando você não passa uma.
Se uma resposta se perder, leia a campanha antes de tentar novamente.

Mude o horário de uma campanha lançada que ainda não começou a enviar, ou
inicie-a agora:

```typescript theme={null}
await messaging.campaigns.reschedule("<project-slug>", campaignId, {
  scheduledAt: Date.parse("2026-10-07T09:00:00Z"),
});
```

`scheduledAt: null` inicia a campanha agora. `reschedule` envia uma chave de
idempotência e faz uma única tentativa, a menos que você defina
`maxNetworkRetries`.

## Acompanhe a entrega

```typescript theme={null}
const stats = await messaging.campaigns.analytics("<project-slug>", campaignId);
console.log(stats.data.data.sentCount, stats.data.data.deliveredCount);

let cursor: string | undefined;
do {
  const page = await messaging.campaigns.listRecipients("<project-slug>", campaignId, {
    status: "failed",
    cursor,
  });
  for (const recipient of page.data.data) console.log(recipient.phone, recipient.status);
  cursor = page.data.page.hasMore ? page.data.page.nextCursor ?? undefined : undefined;
} while (cursor);
```

Os webhooks informam cada mudança do ciclo de vida como `campaign.launched`,
`campaign.paused`, `campaign.resumed` e `campaign.stopped`. Veja
[Eventos de campanha](/api/webhooks#campaign-events).

A primeira entrega, a primeira leitura e a primeira resposta de um destinatário
que recebeu o envio chegam como `campaign.recipient_delivered`,
`campaign.recipient_read` e `campaign.recipient_replied`. Esses eventos trazem
metadados de tempo, não o conteúdo da resposta, e exigem a inscrição da equipe
no beta. A versão `0.1.0-dev.20261004041625` do SDK os tipa como
`CampaignRecipientDeliveredPayload`, `CampaignRecipientReadPayload` e
`CampaignRecipientRepliedPayload`. Em versões anteriores, leia os
[campos documentados](/api/webhooks#campaign-events) de `event.payload`.

As solicitações de criação e atualização de campanhas aceitam
[links rastreados](/pt-br/guides/campaigns/link-tracking) em `trackedLinks`, e
`CampaignRecipientLinkOpenedPayload` tipa `campaign.recipient_link_opened`. O
relatório de aberturas de links ainda não tem método no SDK; chame a API para
obtê-lo.

Baixe os destinatários em CSV, uma página por vez:

```typescript theme={null}
let cursor: string | undefined;
do {
  const page = await messaging.campaigns.exportRecipients("<project-slug>", campaignId, {
    status: "failed",
    cursor,
  });
  process.stdout.write(page.data.csv);
  cursor = page.data.nextCursor ?? undefined;
} while (cursor);
```

Um destinatário de uma campanha com várias mensagens informa o progresso em
`messagesSent`, `nextMessageAt` e `sequenceError`.

Envie de novo para os destinatários que falharam com
`messaging.campaigns.requeue("<project-slug>", campaignId)`. Passe
`{ includeSkippedError: true }` para também recolocar na fila os destinatários
ignorados com erro.

## Altere um rascunho

Altere um rascunho com `messaging.campaigns.update(projectSlug, campaignId, body)`,
ou altere o público ou a janela de envio dele com o cliente de equipe:

```typescript theme={null}
await platform.campaigns.update(
  campaignId,
  { sendWindow: null },
  { projectId: "<project-id>" },
);
```

`sendWindow: null` remove a janela. O público e o agendamento só podem mudar
antes do lançamento. A janela de envio pode mudar enquanto a campanha é um
rascunho ou está pausada.

## Gerencie palavras-chave de opt-out

Quando a captura de palavras-chave está ativada, um contato que responde a uma
mensagem de campanha com uma palavra-chave de opt-out entra na lista de opt-out
da equipe, e as campanhas o ignoram. Uma palavra-chave de opt-in o remove de
novo.

```typescript theme={null}
const settings = await platform.optOuts.getSettings();
console.log(settings.data.data.enabled, settings.data.data.optOutKeywords);

await platform.optOuts.updateSettings({
  enabled: true,
  optOutKeywords: ["STOP", "UNSUBSCRIBE"],
  optInKeywords: ["START"],
});
```

`updateSettings` substitui os três campos. Os métodos de opt-out precisam de
uma chave da equipe; credenciais de projeto são recusadas. Veja
[Opt-outs](/pt-br/guides/campaigns/opt-outs).

## Confirmações opcionais de STOP

Para as [confirmações opcionais de STOP](/pt-br/guides/campaigns/opt-outs#confirmações-de-saída-opcionais),
use `optOuts.getConfirmationSettings`, `optOuts.updateConfirmationSettings` e
`optOuts.getConfirmationSummary`, disponíveis a partir da versão
`0.1.0-dev.20261005233122` do SDK. Esses métodos do cliente da organização
preservam o envelope da API em `response.data.data`. Use o `teamId` e a
`revision` retornados ao gravar uma preferência e escolha `en`, `pt-BR` ou `es`
antes de ativar. Uma revisão desatualizada exige uma nova leitura. Nunca tente
novamente de forma automática um salvamento de preferência incerto; leia a
preferência salva para confirmar o resultado. O acesso ao beta e a ativação
pelo cliente continuam separados.

## Crie um público a partir de uma campanha

```typescript theme={null}
const followUp = await platform.audiences.createFromCampaign({
  name: "Did not read October",
  campaignId,
  outcome: "not_read",
});
console.log(followUp.data.data.recipientCount, followUp.data.data.optedOutCount);
```

O público é um retrato dos destinatários com esse resultado. Números que estão
na lista de opt-out ficam de fora. O SDK envia essa solicitação uma vez; depois
de uma resposta perdida, liste os públicos antes de criar outro. Veja
[Públicos](/pt-br/guides/campaigns/audiences).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.