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

# Criar campanha

> Cria a campanha e coloca a importação dos destinatários na fila. A campanha nasce em
`import:waiting` e passa sozinha para `schedule`/`processing` quando a importação termina
e a data de início chega.

Use `application/json` quando os destinatários vêm da base (`type: connecta_contacts`) e
`multipart/form-data` quando há arquivo ou anexo. No multipart, os campos que são objeto
ou lista (`channel`, `queue`, `template`, `messages`, `mapping`, `tags`, `contacts`,
`add_tags`) vão como JSON em texto.




## OpenAPI

````yaml /api-reference/openapi.yaml post /campaigns
openapi: 3.0.3
info:
  title: Connecta DESK API pública
  version: 1.0.0
  description: >
    API pública do Connecta DESK, disponível em `/api/v1`. O acesso é feito com
    um token gerado no módulo de tokens. Cada token tem permissões por **módulo
    × método**, e toda leitura de lista é paginada.


    ## Autenticação


    ```

    Authorization: Bearer sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6

    ```


    O token pertence a uma **empresa**, e não a um usuário. A empresa usada é
    sempre a do token, então enviar `companyId` no corpo não tem efeito. Token
    ausente, inválido, revogado ou expirado recebe a mesma resposta `401`.


    ## Ordem de verificação


    1. **token** → `401`

    2. **empresa ativa** → `403`

    3. **API habilitada no plano** → `403 ERR_API_NOT_ENABLED` (não se aplica a
    on-premise)

    4. **rate limit da empresa** → `429`

    5. **permissão do token** → `403 ERR_API_FORBIDDEN_SCOPE`


    ## Ids de usuário


    Todo id de usuário na API é o id do usuário **nesta empresa**, o mesmo que
    `GET /users` devolve. Vale para o que a API responde (`user.id`,
    `assignedTo.id`, `userCreated.id`) e para o que ela aceita (`userId`,
    `userIds`, `assignedToUserId` e o `{id}` das rotas de usuário).


    A mesma pessoa pode trabalhar em várias empresas, com nome e perfil
    diferentes em cada uma, e tem um id diferente em cada empresa.


    Um id que não pertence a esta empresa responde `404`, com a mesma mensagem
    de um id inexistente.


    ## Paginação


    Todo `GET` de lista é paginado. O `meta` traz apenas `page`, `perPage` e
    `hasMore`, sem o total de registros. Para percorrer tudo, avance `page`
    enquanto `hasMore` for `true`.


    ## Idempotência


    Opcional em `POST`/`PUT`, pelo header `Idempotency-Key`. Se você repetir a
    chamada com a mesma chave e o mesmo corpo, recebe a resposta já gravada (com
    `Idempotent-Replay: true`). Com a mesma chave e um corpo diferente, a
    resposta é `409`.
servers:
  - url: https://api.connectadesk.com/api/v1
    description: Produção
security:
  - apiToken: []
tags:
  - name: contacts
    description: Cadastro de contatos, campos extras e origem de marketing.
  - name: tickets
    x-displayName: Conversas
    description: Abertura, transferência, encerramento e qualificação de conversas.
  - name: messages
    description: Envio assíncrono e leitura de mensagens.
  - name: tags
    description: Tags e vínculo com atendimentos.
  - name: queues
    description: Filas de atendimento e seus atendentes.
  - name: wrapups
    description: Tipos de qualificação.
  - name: users
    description: Atendentes e administradores.
  - name: schedules
    description: Mensagens programadas.
  - name: quick-messages
    description: Respostas rápidas.
  - name: campaigns
    description: Disparos em massa.
  - name: crm
    description: Painéis, etapas, cards e indicadores.
  - name: channels
    description: Canais (somente leitura).
  - name: reports
    description: Relatórios e dashboards.
  - name: products
    description: Catálogo de produtos, categorias e desempenho nas vendas.
  - name: custom-fields
    description: >-
      Campos personalizados de contato e de card, e variáveis globais da
      empresa.
  - name: profiles
    description: Perfis de permissões da empresa (somente leitura).
  - name: webchat
    description: >-
      Webchat nativo pelo seu sistema: abrir sessão de um visitante, enviar e
      ler mensagens. O token precisa do escopo `webchat` (GET e POST).
paths:
  /campaigns:
    post:
      tags:
        - campaigns
      summary: Criar campanha
      description: >
        Cria a campanha e coloca a importação dos destinatários na fila. A
        campanha nasce em

        `import:waiting` e passa sozinha para `schedule`/`processing` quando a
        importação termina

        e a data de início chega.


        Use `application/json` quando os destinatários vêm da base (`type:
        connecta_contacts`) e

        `multipart/form-data` quando há arquivo ou anexo. No multipart, os
        campos que são objeto

        ou lista (`channel`, `queue`, `template`, `messages`, `mapping`, `tags`,
        `contacts`,

        `add_tags`) vão como JSON em texto.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CampaignInput'
            examples:
              base_por_tags:
                summary: Destinatários da base, por tags, com template do WhatsApp
                value:
                  send_name: Black Friday 2026
                  slug: black-friday-2026
                  channel:
                    id: 4
                  type: connecta_contacts
                  import_contacts_mode: tags
                  tags:
                    - 7
                    - 12
                  tags_mode: only
                  tags_operator: or
                  message_type: template
                  template:
                    name: promocao_black_friday
                    parameters:
                      body:
                        - Maria
                        - 30%
                  init_timestamp: '2026-11-24T09:00:00.000Z'
                  send_avg_time: 30
                  open_ticket: true
                  queue:
                    id: 7
                  add_tags:
                    - 19
              base_por_contatos:
                summary: Destinatários escolhidos um a um, com texto livre
                value:
                  send_name: Aviso de manutenção
                  slug: aviso-manutencao
                  channel:
                    id: 9
                  type: connecta_contacts
                  import_contacts_mode: contacts
                  contacts:
                    - 4821
                    - 4822
                  message_type: message
                  messages:
                    - Olá {{name}}, o sistema ficará indisponível hoje às 22h.
                  init_timestamp: '2026-10-01T12:00:00.000Z'
                  send_avg_time: 15
                  open_ticket: false
                  queue:
                    id: 3
          multipart/form-data:
            schema:
              allOf:
                - $ref: '#/components/schemas/CampaignInput'
                - type: object
                  properties:
                    file:
                      type: string
                      format: binary
                      description: >
                        Planilha com os destinatários (CSV, XLS ou XLSX),
                        obrigatória quando

                        `type: file`. O separador do CSV (`,` ou `;`) é
                        detectado pelo cabeçalho.

                        O tamanho máximo vem de `FILE_MAX_SIZE` (padrão 5 MB).
                    template_media:
                      type: string
                      format: binary
                      description: >
                        Mídia do cabeçalho do template (imagem, vídeo, documento
                        ou áudio). Só

                        faz sentido quando o template aprovado tem cabeçalho de
                        mídia.
                    message_attachment_0:
                      type: string
                      format: binary
                      description: >
                        Anexo da mensagem de mesma posição em `messages`
                        (`message_attachment_0`

                        para a primeira, `message_attachment_1` para a segunda,
                        e assim por

                        diante). Vale só para `message_type: message`.
      responses:
        '201':
          description: Criado
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Campaign'
        '403':
          description: >
            Erro `ERR_CAMPAIGN_MODULE_DISABLED`, quando o módulo de campanhas
            não está habilitado

            para a empresa. É a mesma trava da tela: sem o módulo, a campanha
            não seria disparada.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
components:
  schemas:
    CampaignInput:
      type: object
      description: >
        Configuração da campanha. Os campos obrigatórios variam com `type` (de
        onde vêm os

        destinatários) e `message_type` (o que será enviado).
      required:
        - send_name
        - slug
        - channel
        - queue
        - type
        - message_type
        - init_timestamp
        - send_avg_time
      properties:
        send_name:
          type: string
          description: Nome da campanha, como aparece na listagem.
          example: Black Friday 2026
        slug:
          type: string
          description: Identificador curto da campanha, usado nos relatórios.
          example: black-friday-2026
        channel:
          type: object
          description: Canal de saída. Veja os disponíveis em `GET /channels`.
          required:
            - id
          properties:
            id:
              type: integer
              example: 4
        type:
          type: string
          description: >
            De onde vêm os destinatários:

            `file` (planilha enviada no campo `file`) ou `connecta_contacts`
            (base de contatos).
          enum:
            - file
            - connecta_contacts
          example: connecta_contacts
        import_contacts_mode:
          type: string
          description: >-
            Obrigatório com `type: connecta_contacts`. Escolhe contatos um a um
            ou por tags.
          enum:
            - contacts
            - tags
          example: tags
        contacts:
          type: array
          description: >
            Ids dos contatos, com `import_contacts_mode: contacts`. Não precisa
            enviar arquivo:

            a lista vira a base de destinatários da campanha.


            Todos os ids precisam ser desta empresa — um id de fora responde
            `422`

            (`ERR_API_CAMPAIGN_IDS_NOT_FOUND`) com a lista do que não confere.
          items:
            type: integer
          example:
            - 4821
            - 4822
        tags:
          type: array
          description: >
            Ids das tags, com `import_contacts_mode: tags`. Os destinatários são
            os contatos que

            casam com as tags, conforme `tags_mode` e `tags_operator`. Também
            não precisa de

            arquivo, e os ids precisam ser desta empresa.
          items:
            type: integer
          example:
            - 7
            - 12
        tags_mode:
          type: string
          description: >
            Como as tags filtram a base: `only` (só quem tem), `except` (quem
            não tem) ou `all`

            (toda a base, ignorando as tags).
          enum:
            - all
            - except
            - only
          example: only
        tags_operator:
          type: string
          description: 'Com mais de uma tag: `and` exige todas, `or` aceita qualquer uma.'
          enum:
            - and
            - or
          example: or
        mapping:
          type: array
          description: >
            De-para entre as colunas da planilha e os campos do sistema, com
            `type: file`.


            **Pode ser omitido.** Sem ele, o de-para é montado automaticamente a
            partir do

            cabeçalho: cada coluna é comparada (sem acento e sem diferenciar
            maiúsculas) com os

            nomes conhecidos de cada campo — por exemplo `telefone`, `celular`,
            `whatsapp`,

            `fone`, `numero` e `phone` viram `contact_number`; `nome`, `contato`
            e `cliente`

            viram `contact_name`; `cpf`, `cnpj` e `documento` viram
            `contact_cpfcnpj`. Para os

            campos personalizados, o cabeçalho é comparado com a `key` e com o
            nome do campo.

            Coluna que não casa com nada entra como `dont_import`, e a primeira
            coluna vence

            quando duas apontariam para o mesmo campo.


            Telefone e nome são obrigatórios. Se o automático não reconhecer uma
            dessas colunas,

            ou se o `mapping` enviado não tiver `contact_number` e
            `contact_name`, a criação

            responde `422` (`ERR_API_CAMPAIGN_MAPPING_PHONE_REQUIRED` ou

            `ERR_API_CAMPAIGN_MAPPING_NAME_REQUIRED`) em vez de criar uma
            campanha que falharia

            na importação.
          items:
            $ref: '#/components/schemas/CampaignMappingItem'
        message_type:
          type: string
          description: >
            O que será enviado: `message` (texto livre, só em canal não oficial)
            ou `template`

            (template aprovado do WhatsApp oficial). Outro valor responde `422`

            (`ERR_API_CAMPAIGN_MESSAGE_TYPE_INVALID`).
          enum:
            - message
            - template
          example: template
        messages:
          type: array
          description: >
            Textos da campanha, com `message_type: message`. Mais de um texto
            faz o sistema

            alternar entre eles a cada disparo. Aceita as variáveis do contato
            (`{{name}}`,

            `{{email}}`…). O anexo de cada mensagem vai em
            `message_attachment_<posição>`.
          items:
            type: string
          example:
            - Olá {{name}}, temos uma novidade para você!
        template:
          type: object
          description: >
            Template aprovado, com `message_type: template`. Informe só o nome e
            as variáveis —

            o sistema monta o restante e confere contra os templates REAIS do
            canal, então um

            nome errado ou uma variável faltando aparece aqui e não no dia do
            disparo. Consulte

            os disponíveis em `GET /channels/{id}/templates`.
          properties:
            name:
              type: string
              example: promocao_black_friday
            language:
              type: string
              description: Só quando o template existe em mais de um idioma.
              example: pt_BR
            parameters:
              type: object
              description: Valores das variáveis, na ordem em que aparecem no template.
              properties:
                header:
                  type: array
                  items:
                    type: string
                body:
                  type: array
                  items:
                    type: string
                  example:
                    - Maria
                    - 30%
        init_timestamp:
          type: string
          format: date-time
          description: >
            Quando o disparo começa. Precisa ser no futuro.


            **Sem fuso, vale o fuso da sua empresa.** `2026-11-24T09:00:00`
            dispara às nove da

            manhã no fuso configurado na empresa — que é o que você vê no
            painel. Se preferir

            ser explícito, mande com fuso (`2026-11-24T09:00:00-03:00`) ou em
            UTC

            (`2026-11-24T12:00:00.000Z`), e aí o valor é respeitado como está.
          example: '2026-11-24T09:00:00-03:00'
        pause_timestamp:
          type: string
          format: date-time
          description: >
            Início da janela de pausa diária (por exemplo, para não disparar de
            madrugada).

            Mesma regra de fuso do `init_timestamp`.
          example: '2026-11-24T21:00:00-03:00'
        restart_timestamp:
          type: string
          format: date-time
          description: >
            Fim da janela de pausa. Obrigatório quando `pause_timestamp` é
            informado.

            Mesma regra de fuso do `init_timestamp`.
          example: '2026-11-25T09:00:00-03:00'
        send_avg_time:
          type: integer
          description: >-
            Intervalo médio entre os envios, em segundos. Quanto maior, mais
            lento e mais seguro para o número.
          example: 30
        open_ticket:
          type: boolean
          description: >
            Abre a conversa no momento do disparo: o atendimento entra como
            `pending` na fila de

            `queue` e já aparece para os atendentes. Sem isso o disparo sai com
            o atendimento

            fechado, e a conversa só abre se o contato responder.
          example: true
        queue:
          type: object
          description: >
            Fila do atendimento que o disparo cria. **Obrigatória.** Vale nos
            dois casos: com

            `open_ticket: true` a conversa abre já nessa fila; sem ele, o
            atendimento fica

            fechado, mas na fila.


            É o `queueId` que decide onde o atendimento entra. Sem fila ele
            nasceria solto, sem

            aparecer para nenhum time — e você só descobriria depois da campanha
            rodar. Por isso

            criar ou editar sem `queue` responde `422`

            (`ERR_API_CAMPAIGN_QUEUE_REQUIRED`). Veja as filas em `GET /queues`.
          required:
            - id
          properties:
            id:
              type: integer
              example: 7
        add_tags:
          type: array
          description: Tags aplicadas a cada contato que a campanha atinge.
          items:
            type: integer
          example:
            - 19
    Campaign:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
          description: Nome exibido.
        status:
          type: string
          enum:
            - import:waiting
            - import:start
            - import:fail_retry
            - import:failed
            - waiting
            - schedule
            - processing
            - failed
            - completed
            - canceled
            - pause:manual
            - pause:automatic
            - pause:no_balance
            - pause:active_contacts_limit
        scheduledAt:
          type: string
          format: date-time
          nullable: true
        completedAt:
          type: string
          format: date-time
          nullable: true
        contactListId:
          type: integer
          nullable: true
        channelId:
          type: integer
          nullable: true
          example: 4
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      example:
        id: 77
        name: Promoção de inverno
        status: processing
        scheduledAt: '2026-08-19T12:00:00.000Z'
        completedAt: null
        contactListId: 12
        channelId: 11
        createdAt: '2026-08-17T18:20:00.000Z'
        updatedAt: '2026-08-19T12:00:03.221Z'
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Código fixo do erro, para você tratar cada caso no seu sistema.
              example: ERR_API_FORBIDDEN_SCOPE
            message:
              type: string
            details: {}
    CampaignMappingItem:
      type: object
      description: Uma coluna da planilha e o campo do sistema que ela preenche.
      required:
        - header
        - value
      properties:
        header:
          type: string
          description: Cabeçalho da coluna, exatamente como está escrito no arquivo.
          example: Telefone
        value:
          type: string
          description: >
            Campo que recebe o conteúdo da coluna:


            | Valor | Preenche |

            |---|---|

            | `contact_number` | Telefone com DDI. **Obrigatório** — é o
            destinatário do disparo |

            | `contact_name` | Nome. **Obrigatório** |

            | `contact_email` | E-mail |

            | `contact_cpfcnpj` | CPF/CNPJ (a máscara é aplicada na importação)
            |

            | `contact_code` | Código do contato no seu sistema |

            | `contact_origin` | Origem |

            | `contact_instagram` | Usuário do Instagram (o `@` é removido) |

            | `contact_lid` | LID do WhatsApp |

            | `contact_source_url` | Página de origem |

            | `contact_source_id` | Id da origem |

            | `contact_headline` | Título do anúncio |

            | `contact_media_type` | Tipo da mídia de origem |

            | `contact_media_url` | URL da mídia de origem |

            | `contact_utm_source` | utm_source |

            | `contact_utm_medium` | utm_medium |

            | `contact_utm_campaign` | utm_campaign |

            | `contact_utm_id` | utm_id |

            | `contact_fbclid` | fbclid |

            | `contact_gclid` | gclid |

            | `contact_ctwa_clid` | ctwa_clid |

            | `custom_field:<id>` | Campo personalizado de contato — o `<id>`
            vem de `GET /custom-fields?application=contact` |

            | `dont_import` | Ignora a coluna |


            Coluna em branco nunca sobrescreve dado já gravado no contato. Campo
            personalizado

            de sistema (`isSystem`) é somente leitura e é ignorado.


            Linha com telefone ou nome em branco não é importada: ela é
            registrada nas falhas da

            importação e as demais linhas seguem normalmente.
          example: contact_number
  responses:
    UnprocessableEntity:
      description: >-
        O corpo está bem formado, mas falta um campo obrigatório ou algum valor
        não é aceito. Por exemplo, `application` diferente de `contact`/`card`,
        `orderedIds` vazio ou `name` em branco.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: ERR_API_VALIDATION
              message: >-
                O parâmetro `application` é obrigatório e aceita "contact" ou
                "card".
  securitySchemes:
    apiToken:
      type: http
      scheme: bearer
      description: Token da API no formato `sk_live_…`.

````

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