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

# Criar e editar automações

> Como transformar intenção em JSON válido — criar, alterar etapas, templates e validar o fluxo.

Esta página é o **manual operacional** para uma pessoa ou uma LLM montar automações Corvex.

O entregável pode ir para o **painel** ou para a API v1:

```http theme={null}
POST /api/v1/automations/validate
POST /api/v1/automations
PATCH /api/v1/automations/:automationId
```

Automações criadas pela API nascem `active: false`. Para inserir ou reordenar uma etapa sem reenviar o JSON inteiro: `POST /api/v1/automations/:id/steps` e `POST /api/v1/automations/:id/steps/:stepId/move`. `PATCH` com `steps` completo continua válido.

## Duas etapas mentais

```text theme={null}
INTENÇÃO DO USUÁRIO
        ↓
PLANO (trigger, delays, conditions, canais, textos)
        ↓
CONTRATO CORVEX (JSON válido)
```

Não pule o plano. Não invente recurso no contrato.

Exemplo:

```text theme={null}
Usuário: "Quando gerar um PIX, espere 30 minutos e, se ainda não estiver pago,
envie um e-mail. Depois de 24 horas, se continuar pendente, envie outro."

Plano:
  trigger          pix.generated
  delay            30 minutos
  condition        payment_status = pending
  action           send_email  (template de lembrete PIX)
  delay            1440 minutos
  condition        payment_status = pending
  action           send_email  (segundo lembrete)
```

Depois disso, monte o JSON com [steps](/automations-steps) e [templates](/automations-templates).

## Modelo mental

```text theme={null}
Automation
  name
  trigger_event          ← o que inicia (não é um step)
  active
  steps[]                ← 1 a 50
       ├── delay         espera N minutos
       ├── condition     ramifica
       │     ├── if_true / branch
       │     └── if_false / outras branches
       ├── action        envia mensagem (o template vive em data)
       ├── retry         repete steps internos
       ├── loop          itera steps internos
       └── end           encerra o ramo
```

O **trigger não é uma etapa**. Ele fica em `trigger_event`.\
O **template não é uma etapa**. Ele é o conteúdo da action (`data.subject`, `data.body`, `data.message`, …).

O fluxo termina quando não há próximo step, quando um `end` corre, ou quando a condition não tem ramo verdadeiro e não há `if_false`.

## Capability manifesto

| Capacidade          | Valores reais                                                                                          |
| ------------------- | ------------------------------------------------------------------------------------------------------ |
| Triggers            | 14 — ver [Triggers](/automations-triggers)                                                             |
| Steps               | `delay` `condition` `action` `retry` `loop` `end`                                                      |
| Actions que enviam  | `send_email` `send_sms` `send_whatsapp`                                                                |
| Actions extras      | `webhook` (POST HTTPS) `create_coupon` (cria cupom)                                                    |
| Operators           | `=` `!=` `in` `not-in` `empty` `not-empty` `>` `<` `>=` `<=`                                           |
| Compound            | `AND` `OR`                                                                                             |
| Campos de condition | `amount` `customer.*` `lead.*` `tracking.status\|code\|url\|carrier` `payment_status` `payment_method` |
| Canais              | e-mail, SMS, WhatsApp                                                                                  |
| Delay               | 1–10080 minutos (inteiro)                                                                              |
| SMS                 | ≤ 160 caracteres no texto salvo                                                                        |
| Steps por fluxo     | 1–50                                                                                                   |
| Nome                | 3–100 caracteres                                                                                       |
| Metatags            | catálogo por gatilho — [Metatags](/automations-metatags)                                               |
| Lifecycle           | só `active` true/false                                                                                 |

Não existem: `equals`, `contains`, `order.shipped`, `order.created`. Edição incremental: `POST .../steps` e `POST .../steps/:stepId/move`, ou `PATCH` do documento. Templates: `POST /api/v1/automation/templates` + `data.template_id`.

## Trigger → contexto → mensagem

```text theme={null}
trigger_event
    ↓
contextos com metatags naquele gatilho
    ↓
escolher canal (email / sms / whatsapp)
    ↓
escrever template só com {{chaves}} daquele gatilho
```

| Trigger                 | O que pode ir na mensagem (exemplos)                                                                                         |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `pix.generated`         | `{{customer.name}}` `{{order.pix_code}}` `{{order.url_pix_gerado}}` `{{order.total}}`                                        |
| `payment.confirmed`     | `{{customer.name}}` `{{order.total}}` — **sem** PIX                                                                          |
| `cart.abandoned`        | `{{lead.name}}` `{{cart.url_checkout}}` — **sem** `{{order.pix_code}}`                                                       |
| `tracking_code_updated` | `{{tracking.code}}` `{{tracking.url}}`                                                                                       |
| `lead.created`          | `{{lead.name}}` `{{lead.email}}` — dados ainda podem estar vazios                                                            |
| `email.received`        | `{{inbound.subject}}` `{{inbound.from}}`                                                                                     |
| `subscription.*`        | `{{subscription.portalUrl}}` `{{subscription.total}}`                                                                        |
| `boleto.generated`      | `{{customer.name}}` `{{order.boleto_barcode}}` `{{order.boleto_digitable_line}}` `{{order.url_boleto_gerado}}` — **sem** PIX |
| `payment.failed`        | `{{customer.name}}` `{{order.total}}` — **sem** PIX e **sem** chaves de boleto                                               |

Confirme sempre em `GET /api/v1/automation/metatags?triggerType=...`.

## Como a LLM deve trabalhar

<Steps>
  <Step title="Entender a intenção">
    O que dispara? Espera? Condição? Qual canal? Qual tom?
  </Step>

  <Step title="Escolher o trigger">
    Só um dos 14. “Pedido enviado” → `tracking_code_updated`. “PIX gerado” → `pix.generated`.
  </Step>

  <Step title="Desenhar o plano">
    Lista linear: delay, condition, action. Se o recurso não existir, pare e explique.
  </Step>

  <Step title="Escrever as mensagens">
    Ver [Templates](/automations-templates). Só metatags daquele gatilho.
  </Step>

  <Step title="Montar o JSON">
    `name`, `trigger_event`, `active`, `steps`. IDs estáveis se for edição.
  </Step>

  <Step title="Validar">
    Checklist abaixo. Depois mostre o **preview** em português.
  </Step>
</Steps>

## Preview (antes de salvar)

Sempre explique o fluxo assim:

```text theme={null}
Quando: PIX for gerado
Depois de: 30 minutos
Se: o pagamento continuar pendente (payment_status = pending)
Então: enviar e-mail "Seu PIX ainda está disponível"
Depois de: 24 horas
Se: o pagamento continuar pendente
Então: enviar e-mail "Último lembrete do PIX"
```

Peça confirmação do remetente (`remetente_nome` / `remetente_email`) — não invente o e-mail da loja.

## Operações de edição (no JSON)

Editar = `PATCH` no documento **ou** `POST /api/v1/automations/:id/steps` e `POST /api/v1/automations/:id/steps/:stepId/move`. Preserve `id` / `nextId` / `parentId` das etapas que você não pediu para mudar.

| Pedido                    | O que fazer                                                                  |
| ------------------------- | ---------------------------------------------------------------------------- |
| Criar automação           | JSON novo. Pode omitir `id` dos steps.                                       |
| Trocar delay 30 → 60      | Altere só `minutes` daquele step. Preserve `id` e `nextId`.                  |
| Inserir delay entre A e B | Novo step; ajuste `nextId` (formato flat) ou a posição no array / `if_true`. |
| Remover o segundo SMS     | Apague esse step. Religue `nextId` / `parentId` dos vizinhos.                |
| Reordenar                 | Mude `nextId` ou a ordem no array. Não apague actions não pedidas.           |
| Só o texto                | Altere `data.message` / `data.subject` / `data.body`.                        |
| Duplicar fluxo            | Copie o JSON, mude `name`, remova `id` da automação.                         |
| Criar ramificação         | Step `condition` + `if_true` / `if_false` ou `branches` + `parentId`.        |

**Invariantes:** não recrie o fluxo inteiro para uma troca pontual; não mude `id` de steps existentes; não altere trigger, nome ou outras actions sem pedido; máximo 50 steps; delay continua 1–10080.

### Exemplo: só o delay

Antes: `"minutes": 30`. Pedido: “troque 30 minutos por 1 hora”.

```json theme={null}
{ "type": "delay", "id": "wait-1", "minutes": 60, "nextId": "send-1" }
```

O resto do JSON permanece igual.

## Validação antes de entregar

* Trigger existe nos 14?
* Cada `step.type` é um dos 6?
* Cada `action.name` é um dos 5? `webhook` tem `url` HTTPS? `create_coupon` tem `coupon_name` + `discountType` + `amount`?
* Operator é `=` (nunca `equals`) / `in` / `empty` / …?
* Campo da condition está na lista curta?
* `payment_status` usa `paid` `pending` `cancelled`?
* Delay em **minutos** inteiros (24 h = **1440**, não `24 hours`)?
* E-mail tem remetente, assunto ≥ 3, `body` ou `html`?
* SMS ≤ 160?
* WhatsApp tem `message` (texto) ou o campo obrigatório do tipo?
* Cada `{{chave}}` existe **naquele** `trigger_event`?
* Tronco sem `parentId`; ramos com `parentId` = `branches[].id`?
* 1–50 steps, nome 3–100?
* Edição: ids antigos preservados?

Se algum item falhar, **não entregue JSON inválido**. Explique a limitação.

## Biblioteca intenção → automação

### Recuperar PIX

**Intent:** “Avise quem gerar PIX e não pagar.”

| Peça      | Valor                                                               |
| --------- | ------------------------------------------------------------------- |
| Trigger   | `pix.generated`                                                     |
| Condition | `payment_status` `=` `pending`                                      |
| Actions   | `send_email` (e opcionalmente `send_sms` / `send_whatsapp`)         |
| Metatags  | `{{customer.name}}` `{{order.pix_code}}` `{{order.url_pix_gerado}}` |

JSON (formato aninhado, válido):

```json theme={null}
{
  "name": "Lembrete PIX pendente",
  "trigger_event": "pix.generated",
  "active": true,
  "steps": [
    {
      "id": "wait-30",
      "type": "delay",
      "minutes": 30,
      "nextId": "still-pending"
    },
    {
      "id": "still-pending",
      "type": "condition",
      "field": "payment_status",
      "operator": "=",
      "value": "pending",
      "if_true": [
        {
          "id": "email-1",
          "type": "action",
          "name": "send_email",
          "data": {
            "remetente_nome": "Nome da loja",
            "remetente_email": "loja@example.com",
            "subject": "Seu PIX ainda está disponível",
            "body": "Olá, {{customer.name}}!\n\nSeu pedido ainda aguarda pagamento.\n\nCódigo PIX:\n{{order.pix_code}}\n\nPagar agora:\n{{order.url_pix_gerado}}"
          },
          "nextId": "wait-24h"
        },
        {
          "id": "wait-24h",
          "type": "delay",
          "minutes": 1440,
          "nextId": "still-pending-2"
        },
        {
          "id": "still-pending-2",
          "type": "condition",
          "field": "payment_status",
          "operator": "=",
          "value": "pending",
          "if_true": [
            {
              "id": "email-2",
              "type": "action",
              "name": "send_email",
              "data": {
                "remetente_nome": "Nome da loja",
                "remetente_email": "loja@example.com",
                "subject": "Último lembrete: PIX em aberto",
                "body": "Olá, {{customer.name}}, o PIX do pedido ainda não foi pago:\n{{order.url_pix_gerado}}"
              }
            }
          ],
          "if_false": [{ "type": "end" }]
        }
      ],
      "if_false": [{ "type": "end" }]
    }
  ]
}
```

Substitua remetente pelos dados reais da loja.

### Recuperar carrinho

**Intent:** “Uma hora depois de abandonar o checkout, envie um lembrete.”

Não existe campo de condition `has_purchased`. O gatilho `cart.abandoned` já significa checkout abandonado. Delay + envio é o fluxo suportado. Opcional: só enviar se houver telefone (`lead.phone` `not-empty`).

```json theme={null}
{
  "name": "Recuperação de carrinho",
  "trigger_event": "cart.abandoned",
  "active": true,
  "steps": [
    { "id": "wait-1h", "type": "delay", "minutes": 60, "nextId": "mail-1" },
    {
      "id": "mail-1",
      "type": "action",
      "name": "send_email",
      "data": {
        "remetente_nome": "Nome da loja",
        "remetente_email": "loja@example.com",
        "subject": "Você esqueceu itens no checkout",
        "body": "Olá, {{lead.name}}!\n\nSeu checkout ainda está aberto:\n{{cart.url_checkout}}"
      }
    }
  ]
}
```

Não use `{{order.pix_code}}` aqui.

### Pós-compra

**Intent:** “Quando o pagamento for confirmado, envie instruções.”

Trigger `payment.confirmed`. Sem delay. Sem PIX.

```text theme={null}
Olá, {{customer.name}}! Recebemos {{order.total}}. Obrigado pela compra.
```

### Rastreio

**Intent:** “Quando o código de rastreio estiver disponível, envie ao cliente.”

Trigger `tracking_code_updated`. WhatsApp ou e-mail com `{{tracking.code}}` e `{{tracking.url}}`.

### O que recusar

| Pedido                                             | Motivo                                                      |
| -------------------------------------------------- | ----------------------------------------------------------- |
| “Quando o pedido for enviado” como trigger próprio | Use `tracking_code_updated`                                 |
| Condition `contains` no e-mail                     | Não existe; use `=` / `in` / `empty`                        |
| Webhook HTTP na automação                          | `webhook` com `data.url` HTTPS                              |
| Cupom automático                                   | `create_coupon` com `coupon_name`, `discountType`, `amount` |
| Delay em horas no JSON                             | Campo é `minutes`                                           |
| Metatag `{{pix.payment_url}}`                      | Não existe; em PIX use `{{order.url_pix_gerado}}`           |

## Matrizes rápidas

### Canal × template

| Canal          | Action          | Obrigatório                                                              |
| -------------- | --------------- | ------------------------------------------------------------------------ |
| E-mail         | `send_email`    | `remetente_nome`, `remetente_email`, `subject` ≥ 3, `body` **ou** `html` |
| SMS            | `send_sms`      | `message` ≤ 160                                                          |
| WhatsApp texto | `send_whatsapp` | `data.type` `text` ou `whatsapp`, `message`                              |

### Campo × operator

| Tipo de dado                           | Operators úteis                                    |
| -------------------------------------- | -------------------------------------------------- |
| Texto (`customer.email`, `lead.phone`) | `=` `!=` `empty` `not-empty` `in` `not-in`         |
| Número (`amount`)                      | `=` `!=` `>` `<` `>=` `<=` (`0` conta como vazio)  |
| Status (`payment_status`)              | `=` `!=` `in` com `paid` / `pending` / `cancelled` |
| Qualquer                               | `empty` `not-empty`                                |

Não há `contains`, `starts_with`, `before`, `after`.

### Trigger × action

Qualquer action pode ser salva em qualquer trigger. O envio **falha** se faltar e-mail (e-mail) ou telefone (SMS/WhatsApp). A restrição real é **metatag × trigger**, não action × trigger.

Próximo: [Templates de comunicação](/automations-templates) e [regras para IA](/automations-llm-rules).
