Marketing

Automações

Sequências de e-mails e ações disparadas por eventos, contatos novos, segmentos e formulários, com versões e o registro de cada execução.

Automações enviam e-mails e cuidam dos contatos sozinhas, a partir de um gatilho: um evento do seu produto, um contato novo, a entrada num segmento ou uma inscrição por formulário. Cada contato que dispara o gatilho ganha uma execução, que percorre os passos (esperar, enviar e-mail, verificar uma condição, mudar o contato, chamar um webhook) e registra o que aconteceu em cada um. Todos os endpoints exigem uma chave de acesso total.

#Rascunho, ativa e pausada

StatusComo funciona
draftCriada assim. Pode ser salva incompleta (um e-mail sem template, uma condição sem caminhos); o que falta aparece em issues. Não inicia execuções.
activeDepois de ativar: a definição precisa estar completa e vira uma versão (version). Cada gatilho inicia uma execução.
pausedDepois de pausar: não inicia execuções, e as que estão esperando ficam paradas até a automação ser ativada de novo.

Versões. Editar uma automação ativa publica uma nova versão na hora (se o gatilho, os passos ou reentry mudaram). Só as novas execuções seguem a versão nova: as que já estão em andamento terminam na versão em que começaram (version da execução). Mudar só o nome não cria versão.

Reentrada. Com reentry: "once" (padrão), cada contato passa pela automação uma vez só. Com "every_time", cada gatilho inicia uma nova execução, mesmo que outra esteja em andamento.

Limite do plano. As execuções iniciadas no mês (em UTC), somando todas as automações, têm limite por plano (veja Limites e automation_runs em GET /usage). Passou do limite, a execução fica registrada como skipped, com o motivo, e não conta no limite.

#Gatilho e passos

Uma automação é um trigger e uma lista de steps. Os passos rodam em ordem; uma condition fecha a lista e continua num dos caminhos (branches.yes ou branches.no), cada um com a própria lista. O fim de uma lista termina a execução. Uma automação pode ter até 100 passos no total.

Gatilhos

typeCamposQuando iniciaExemplo
eventevent: nome do evento. filters: até 10 comparações com as propriedades do evento, todas precisam bater.Um evento com esse nome chega com um contato.{"type": "event", "event": "order.paid", "filters": [{"key": "total", "operator": "gte", "value": 500}]}
contact.created—Um contato é criado pela API, por um formulário ou por um evento com e-mail novo. Contatos de importação de CSV não disparam.{"type": "contact.created"}
segment.addedsegment_idUm contato entra no segmento: pela API, por um formulário ou por um passo update_contact. Importações não disparam.{"type": "segment.added", "segment_id": "019a1d90-3b4c-7d5e-9f6a-7b8c9d0e1f2a"}
form.submittedform_idAlguém se inscreve pelo formulário (com double opt-in, depois de confirmar).{"type": "form.submitted", "form_id": "019a1da0-7f80-7b91-8c0d-2e3f4a5b6c7d"}

Passos

Cada passo é {"id", "type", "config"}. O id (letras, números, _ e -, até 64 caracteres, único na automação) identifica o passo nas condições e no registro das execuções; sem ele, a Postal gera um como step_k3x9p2qa7m. Chaves desconhecidas são descartadas.

typeO que fazconfig
waitEspera um tempo ou até um horário.{"mode": "duration", "amount": 2, "unit": "days"} (unidades: minutes, hours, days, weeks; até 365 dias) ou {"mode": "until", "time": "09:00", "weekdays": [1, 2, 3, 4, 5], "timezone": "America/Sao_Paulo"}: o próximo 09:00, só nos dias da semana listados (1 = segunda, 7 = domingo; vazio = qualquer dia). Fuso padrão: America/Sao_Paulo.
send_emailEnvia um template publicado para o contato.template_id (ID ou alias, obrigatório), from (padrão: o do template), subject (no lugar do assunto do template), reply_to e variables. Veja Variáveis.
conditionSegue pelo caminho yes ou no.Fica sempre no fim da sua lista; os passos seguintes vão em branches.yes e branches.no. Veja Condições.
update_contactMuda o contato.actions, até 20: {"type": "set_property", "key": "plan", "value": "pro"} (first_name, last_name ou uma propriedade; o valor aceita {{event.*}}), add_to_segment e remove_from_segment (com segment_id), subscribe_topic e unsubscribe_topic (com topic_id), unsubscribe e resubscribe.
webhookEnvia o contato e o evento para uma URL sua.{"url": "https://…"}. Veja Passo de webhook.
exitTermina a execução.Sem configuração; fica no fim da sua lista. O fim de uma lista já termina a execução, então use exit só para deixar claro.

Condições

kindCamposExemplo
contact_propertykey (email, first_name, last_name ou uma propriedade), operator, value{"kind": "contact_property", "key": "plan", "operator": "equals", "value": "pro"}
event_propertykey (caminho na propriedade do evento que iniciou a execução, como items.0.name), operator, value{"kind": "event_property", "key": "total", "operator": "gt", "value": 200}
segmentsegment_id, operator: in ou not_in{"kind": "segment", "segment_id": "019a1d90-3b4c-7d5e-9f6a-7b8c9d0e1f2a", "operator": "in"}
topictopic_id, operator: subscribed ou not_subscribed{"kind": "topic", "topic_id": "019a1d95-4c5d-7e6f-8a7b-8c9d0e1f2a3b", "operator": "subscribed"}
email_activitystep_id de um send_email anterior no mesmo caminho, activity: opened ou clicked. Um clique conta como abertura.{"kind": "email_activity", "step_id": "welcome", "activity": "opened"}

Operadores de comparação (nas condições de propriedade e nos filtros do gatilho): equals, not_equals, contains, not_contains, starts_with, ends_with, gt, gte, lt, lte, is_set e is_not_set (esses dois sem value). Textos são comparados sem diferenciar maiúsculas; números, como números; datas no formato AAAA-MM-DD, em ordem de calendário.

Variáveis nos e-mails

O send_email usa a versão publicada do template, como um POST /emails com template: mesmas validações, cota de envio e lista de supressão. As variáveis do template ({{{NAME}}}) são preenchidas sozinhas com:

  • EMAIL, FIRST_NAME, LAST_NAME e CONTACT_ID do contato;
  • cada propriedade do contato e cada propriedade de primeiro nível do evento, pela chave e em maiúsculas (plan e PLAN);
  • POSTAL_UNSUBSCRIBE_URL, o link da página de preferências do contato;
  • e as variables do passo, que aceitam referências como {{contact.first_name}}, {{contact.plan}} e {{event.items.0.name}} (valores ausentes ficam vazios).

O subject do passo e os valores de set_property aceitam as mesmas referências {{contact.*}} e {{event.*}}. Os e-mails levam os cabeçalhos List-Unsubscribe com clique único; inclua {{{POSTAL_UNSUBSCRIBE_URL}}} no template para mostrar o link no corpo. Contatos descadastrados (unsubscribed) não recebem: o passo fica skipped e a execução continua. Se o envio falhar (cota esgotada, domínio sem verificação, variável sem valor), o passo e a execução ficam failed.

#Listar automações

GET/automations

Chave de acesso total

Cada automação com a definição, a versão em vigor (null num rascunho nunca ativado), runs_this_month (execuções iniciadas no mês) e runs_in_progress.

Parâmetros de consulta

  • limitinteger
    De 1 a 100. Padrão: 20.
  • afterstring
    Cursor da próxima página.
  • beforestring
    Cursor da página anterior.
  • searchstring
    Busca no nome.
  • statusstring
    draft, active ou paused.
GET /automations

cURL

curl 'https://api.postal.so/automations?status=active' \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/automations?status=active', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/automations",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    params={
        "status": "active",
    },
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('automations', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
    'query' => [
        'status' => 'active',
    ],
]);

$data = json_decode($response->getBody(), true);
200Resposta
{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "object": "automation",
      "id": "019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
      "name": "Boas-vindas do teste grátis",
      "status": "active",
      "trigger": {
        "type": "event",
        "event": "trial.started",
        "filters": [
          {
            "key": "plan",
            "operator": "equals",
            "value": "pro"
          }
        ]
      },
      "reentry": "once",
      "steps": [
        {
          "id": "welcome",
          "type": "send_email",
          "config": {
            "template_id": "trial-welcome",
            "from": "Ana da Loja Exemplo <[email protected]>",
            "subject": null,
            "reply_to": null,
            "variables": {
              "DAYS": "{{event.trial_days}}"
            }
          }
        },
        {
          "id": "wait_2_days",
          "type": "wait",
          "config": {
            "mode": "duration",
            "amount": 2,
            "unit": "days"
          }
        },
        {
          "id": "check_opened",
          "type": "condition",
          "config": {
            "kind": "email_activity",
            "step_id": "welcome",
            "activity": "opened"
          },
          "branches": {
            "yes": [
              {
                "id": "tag_engaged",
                "type": "update_contact",
                "config": {
                  "actions": [
                    {
                      "type": "add_to_segment",
                      "segment_id": "019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c"
                    }
                  ]
                }
              }
            ],
            "no": [
              {
                "id": "wait_morning",
                "type": "wait",
                "config": {
                  "mode": "until",
                  "time": "09:00",
                  "weekdays": [1, 2, 3, 4, 5],
                  "timezone": "America/Sao_Paulo"
                }
              },
              {
                "id": "reminder",
                "type": "send_email",
                "config": {
                  "template_id": "trial-help",
                  "from": null,
                  "subject": "{{contact.first_name}}, posso ajudar com o seu teste?",
                  "reply_to": null,
                  "variables": {}
                }
              },
              {
                "id": "notify_crm",
                "type": "webhook",
                "config": {
                  "url": "https://crm.lojaexemplo.com.br/hooks/postal"
                }
              }
            ]
          }
        }
      ],
      "version": 2,
      "runs_this_month": 318,
      "runs_in_progress": 41,
      "activated_at": "2026-10-15T13:00:00.000000Z",
      "created_at": "2026-10-14T19:22:00.000000Z",
      "updated_at": "2026-10-20T10:31:00.000000Z"
    }
  ]
}

#Criar uma automação

POST/automations

Chave de acesso total

Cria um rascunho. Erros de estrutura recusam o salvamento (um tipo de passo desconhecido, um passo depois de uma condição, um segmento de outro time, um ID repetido); o que está só faltando entra em issues e impede apenas a ativação. Devolve a automação completa, com issues e o webhook_signing_secret usado nos passos de webhook.

Corpo da requisição

  • namestringobrigatório
    Nome, até 255 caracteres.
  • triggerobjectobrigatório
    O gatilho, com type.
  • stepsobject[]
    Os passos. Pode ficar vazio num rascunho.
  • reentrystring
    once (padrão) ou every_time.

Erros

  • 422validation_error
    Campo inválido ou definição com erro. O campo extra errors lista cada problema, com o step_id (ou null, para o gatilho) e a mensagem.
POST /automations

cURL

curl -X POST https://api.postal.so/automations \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Boas-vindas do teste grátis",
    "trigger": {
      "type": "event",
      "event": "trial.started",
      "filters": [
        {
          "key": "plan",
          "operator": "equals",
          "value": "pro"
        }
      ]
    },
    "steps": [
      {
        "id": "welcome",
        "type": "send_email",
        "config": {
          "template_id": "trial-welcome",
          "from": "Ana da Loja Exemplo <[email protected]>",
          "variables": {
            "DAYS": "{{event.trial_days}}"
          }
        }
      },
      {
        "id": "wait_2_days",
        "type": "wait",
        "config": {
          "mode": "duration",
          "amount": 2,
          "unit": "days"
        }
      },
      {
        "id": "check_opened",
        "type": "condition",
        "config": {
          "kind": "email_activity",
          "step_id": "welcome",
          "activity": "opened"
        },
        "branches": {
          "yes": [
            {
              "id": "tag_engaged",
              "type": "update_contact",
              "config": {
                "actions": [
                  {
                    "type": "add_to_segment",
                    "segment_id": "019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c"
                  }
                ]
              }
            }
          ],
          "no": [
            {
              "id": "wait_morning",
              "type": "wait",
              "config": {
                "mode": "until",
                "time": "09:00",
                "weekdays": [1, 2, 3, 4, 5],
                "timezone": "America/Sao_Paulo"
              }
            },
            {
              "id": "reminder",
              "type": "send_email",
              "config": {
                "template_id": "trial-help",
                "subject": "{{contact.first_name}}, posso ajudar com o seu teste?"
              }
            },
            {
              "id": "notify_crm",
              "type": "webhook",
              "config": {
                "url": "https://crm.lojaexemplo.com.br/hooks/postal"
              }
            }
          ]
        }
      }
    ]
  }'

Node.js

const response = await fetch('https://api.postal.so/automations', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Boas-vindas do teste grátis',
    trigger: {
      type: 'event',
      event: 'trial.started',
      filters: [
        {
          key: 'plan',
          operator: 'equals',
          value: 'pro',
        },
      ],
    },
    steps: [
      {
        id: 'welcome',
        type: 'send_email',
        config: {
          template_id: 'trial-welcome',
          from: 'Ana da Loja Exemplo <[email protected]>',
          variables: {
            DAYS: '{{event.trial_days}}',
          },
        },
      },
      {
        id: 'wait_2_days',
        type: 'wait',
        config: {
          mode: 'duration',
          amount: 2,
          unit: 'days',
        },
      },
      {
        id: 'check_opened',
        type: 'condition',
        config: {
          kind: 'email_activity',
          step_id: 'welcome',
          activity: 'opened',
        },
        branches: {
          yes: [
            {
              id: 'tag_engaged',
              type: 'update_contact',
              config: {
                actions: [
                  {
                    type: 'add_to_segment',
                    segment_id: '019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c',
                  },
                ],
              },
            },
          ],
          no: [
            {
              id: 'wait_morning',
              type: 'wait',
              config: {
                mode: 'until',
                time: '09:00',
                weekdays: [1, 2, 3, 4, 5],
                timezone: 'America/Sao_Paulo',
              },
            },
            {
              id: 'reminder',
              type: 'send_email',
              config: {
                template_id: 'trial-help',
                subject: '{{contact.first_name}}, posso ajudar com o seu teste?',
              },
            },
            {
              id: 'notify_crm',
              type: 'webhook',
              config: {
                url: 'https://crm.lojaexemplo.com.br/hooks/postal',
              },
            },
          ],
        },
      },
    ],
  }),
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/automations",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    json={
        "name": "Boas-vindas do teste grátis",
        "trigger": {
            "type": "event",
            "event": "trial.started",
            "filters": [
                {
                    "key": "plan",
                    "operator": "equals",
                    "value": "pro",
                },
            ],
        },
        "steps": [
            {
                "id": "welcome",
                "type": "send_email",
                "config": {
                    "template_id": "trial-welcome",
                    "from": "Ana da Loja Exemplo <[email protected]>",
                    "variables": {
                        "DAYS": "{{event.trial_days}}",
                    },
                },
            },
            {
                "id": "wait_2_days",
                "type": "wait",
                "config": {
                    "mode": "duration",
                    "amount": 2,
                    "unit": "days",
                },
            },
            {
                "id": "check_opened",
                "type": "condition",
                "config": {
                    "kind": "email_activity",
                    "step_id": "welcome",
                    "activity": "opened",
                },
                "branches": {
                    "yes": [
                        {
                            "id": "tag_engaged",
                            "type": "update_contact",
                            "config": {
                                "actions": [
                                    {
                                        "type": "add_to_segment",
                                        "segment_id": "019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c",
                                    },
                                ],
                            },
                        },
                    ],
                    "no": [
                        {
                            "id": "wait_morning",
                            "type": "wait",
                            "config": {
                                "mode": "until",
                                "time": "09:00",
                                "weekdays": [1, 2, 3, 4, 5],
                                "timezone": "America/Sao_Paulo",
                            },
                        },
                        {
                            "id": "reminder",
                            "type": "send_email",
                            "config": {
                                "template_id": "trial-help",
                                "subject": "{{contact.first_name}}, posso ajudar com o seu teste?",
                            },
                        },
                        {
                            "id": "notify_crm",
                            "type": "webhook",
                            "config": {
                                "url": "https://crm.lojaexemplo.com.br/hooks/postal",
                            },
                        },
                    ],
                },
            },
        ],
    },
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->post('automations', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
    'json' => [
        'name' => 'Boas-vindas do teste grátis',
        'trigger' => [
            'type' => 'event',
            'event' => 'trial.started',
            'filters' => [
                [
                    'key' => 'plan',
                    'operator' => 'equals',
                    'value' => 'pro',
                ],
            ],
        ],
        'steps' => [
            [
                'id' => 'welcome',
                'type' => 'send_email',
                'config' => [
                    'template_id' => 'trial-welcome',
                    'from' => 'Ana da Loja Exemplo <[email protected]>',
                    'variables' => [
                        'DAYS' => '{{event.trial_days}}',
                    ],
                ],
            ],
            [
                'id' => 'wait_2_days',
                'type' => 'wait',
                'config' => [
                    'mode' => 'duration',
                    'amount' => 2,
                    'unit' => 'days',
                ],
            ],
            [
                'id' => 'check_opened',
                'type' => 'condition',
                'config' => [
                    'kind' => 'email_activity',
                    'step_id' => 'welcome',
                    'activity' => 'opened',
                ],
                'branches' => [
                    'yes' => [
                        [
                            'id' => 'tag_engaged',
                            'type' => 'update_contact',
                            'config' => [
                                'actions' => [
                                    [
                                        'type' => 'add_to_segment',
                                        'segment_id' => '019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c',
                                    ],
                                ],
                            ],
                        ],
                    ],
                    'no' => [
                        [
                            'id' => 'wait_morning',
                            'type' => 'wait',
                            'config' => [
                                'mode' => 'until',
                                'time' => '09:00',
                                'weekdays' => [1, 2, 3, 4, 5],
                                'timezone' => 'America/Sao_Paulo',
                            ],
                        ],
                        [
                            'id' => 'reminder',
                            'type' => 'send_email',
                            'config' => [
                                'template_id' => 'trial-help',
                                'subject' => '{{contact.first_name}}, posso ajudar com o seu teste?',
                            ],
                        ],
                        [
                            'id' => 'notify_crm',
                            'type' => 'webhook',
                            'config' => [
                                'url' => 'https://crm.lojaexemplo.com.br/hooks/postal',
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ],
]);

$data = json_decode($response->getBody(), true);
201Resposta
{
  "object": "automation",
  "id": "019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
  "name": "Boas-vindas do teste grátis",
  "status": "draft",
  "trigger": {
    "type": "event",
    "event": "trial.started",
    "filters": [
      {
        "key": "plan",
        "operator": "equals",
        "value": "pro"
      }
    ]
  },
  "reentry": "once",
  "steps": [
    {
      "id": "welcome",
      "type": "send_email",
      "config": {
        "template_id": "trial-welcome",
        "from": "Ana da Loja Exemplo <[email protected]>",
        "subject": null,
        "reply_to": null,
        "variables": {
          "DAYS": "{{event.trial_days}}"
        }
      }
    },
    {
      "id": "wait_2_days",
      "type": "wait",
      "config": {
        "mode": "duration",
        "amount": 2,
        "unit": "days"
      }
    },
    {
      "id": "check_opened",
      "type": "condition",
      "config": {
        "kind": "email_activity",
        "step_id": "welcome",
        "activity": "opened"
      },
      "branches": {
        "yes": [
          {
            "id": "tag_engaged",
            "type": "update_contact",
            "config": {
              "actions": [
                {
                  "type": "add_to_segment",
                  "segment_id": "019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c"
                }
              ]
            }
          }
        ],
        "no": [
          {
            "id": "wait_morning",
            "type": "wait",
            "config": {
              "mode": "until",
              "time": "09:00",
              "weekdays": [1, 2, 3, 4, 5],
              "timezone": "America/Sao_Paulo"
            }
          },
          {
            "id": "reminder",
            "type": "send_email",
            "config": {
              "template_id": "trial-help",
              "from": null,
              "subject": "{{contact.first_name}}, posso ajudar com o seu teste?",
              "reply_to": null,
              "variables": {}
            }
          },
          {
            "id": "notify_crm",
            "type": "webhook",
            "config": {
              "url": "https://crm.lojaexemplo.com.br/hooks/postal"
            }
          }
        ]
      }
    }
  ],
  "version": null,
  "runs_this_month": 0,
  "runs_in_progress": 0,
  "activated_at": null,
  "created_at": "2026-10-14T19:22:00.000000Z",
  "updated_at": "2026-10-14T19:22:00.000000Z",
  "issues": [],
  "webhook_signing_secret": "whsec_YXV0b21hY2FvLWV4ZW1wbG8tYWJjZGVmMTIzNA=="
}
422Resposta com erro
{
  "statusCode": 422,
  "name": "validation_error",
  "message": "A condition must be the last step of its path: continue in its branches.",
  "errors": [
    {
      "step_id": "check_opened",
      "message": "A condition must be the last step of its path: continue in its branches."
    }
  ]
}

#Obter uma automação

GET/automations/{id}

Chave de acesso total

Devolve a automação com issues (o que impede a ativação, cada um com step_id e message) e o webhook_signing_secret.

Parâmetros de caminho

  • idstringobrigatório
    ID da automação.

Erros

  • 404not_found
    O recurso não existe ou é de outro time.
GET /automations/{id}

cURL

curl https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Resposta
{
  "object": "automation",
  "id": "019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
  "name": "Boas-vindas do teste grátis",
  "status": "active",
  "trigger": {
    "type": "event",
    "event": "trial.started",
    "filters": [
      {
        "key": "plan",
        "operator": "equals",
        "value": "pro"
      }
    ]
  },
  "reentry": "once",
  "steps": [
    {
      "id": "welcome",
      "type": "send_email",
      "config": {
        "template_id": "trial-welcome",
        "from": "Ana da Loja Exemplo <[email protected]>",
        "subject": null,
        "reply_to": null,
        "variables": {
          "DAYS": "{{event.trial_days}}"
        }
      }
    },
    {
      "id": "wait_2_days",
      "type": "wait",
      "config": {
        "mode": "duration",
        "amount": 2,
        "unit": "days"
      }
    },
    {
      "id": "check_opened",
      "type": "condition",
      "config": {
        "kind": "email_activity",
        "step_id": "welcome",
        "activity": "opened"
      },
      "branches": {
        "yes": [
          {
            "id": "tag_engaged",
            "type": "update_contact",
            "config": {
              "actions": [
                {
                  "type": "add_to_segment",
                  "segment_id": "019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c"
                }
              ]
            }
          }
        ],
        "no": [
          {
            "id": "wait_morning",
            "type": "wait",
            "config": {
              "mode": "until",
              "time": "09:00",
              "weekdays": [1, 2, 3, 4, 5],
              "timezone": "America/Sao_Paulo"
            }
          },
          {
            "id": "reminder",
            "type": "send_email",
            "config": {
              "template_id": "trial-help",
              "from": null,
              "subject": "{{contact.first_name}}, posso ajudar com o seu teste?",
              "reply_to": null,
              "variables": {}
            }
          },
          {
            "id": "notify_crm",
            "type": "webhook",
            "config": {
              "url": "https://crm.lojaexemplo.com.br/hooks/postal"
            }
          }
        ]
      }
    }
  ],
  "version": 2,
  "runs_this_month": 318,
  "runs_in_progress": 41,
  "activated_at": "2026-10-15T13:00:00.000000Z",
  "created_at": "2026-10-14T19:22:00.000000Z",
  "updated_at": "2026-10-20T10:31:00.000000Z",
  "issues": [],
  "webhook_signing_secret": "whsec_YXV0b21hY2FvLWV4ZW1wbG8tYWJjZGVmMTIzNA=="
}

#Atualizar uma automação

PATCH/automations/{id}

Chave de acesso total

Só os campos enviados mudam; trigger e steps substituem os anteriores por inteiro. Num rascunho ou numa automação pausada, a definição pode ficar incompleta. Numa automação ativa, ela precisa estar completa, e a mudança vira uma nova versão, que vale só para as novas execuções. Devolve a automação completa.

Parâmetros de caminho

  • idstringobrigatório
    ID da automação.

Corpo da requisição (todos opcionais)

  • namestring
    Novo nome.
  • triggerobject
    Novo gatilho.
  • stepsobject[]
    Nova lista de passos.
  • reentrystring
    once ou every_time.

Erros

  • 422validation_error
    Definição com erro ou, numa automação ativa, incompleta. Veja errors.
  • 404not_found
    O recurso não existe ou é de outro time.
PATCH /automations/{id}

cURL

curl -X PATCH https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reentry": "every_time"
  }'

Node.js

const response = await fetch('https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    reentry: 'every_time',
  }),
});

const data = await response.json();

Python

import os
import requests

response = requests.patch(
    "https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    json={
        "reentry": "every_time",
    },
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->patch('automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
    'json' => [
        'reentry' => 'every_time',
    ],
]);

$data = json_decode($response->getBody(), true);
200Resposta
{
  "object": "automation",
  "id": "019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
  "name": "Boas-vindas do teste grátis",
  "status": "active",
  "trigger": {
    "type": "event",
    "event": "trial.started",
    "filters": [
      {
        "key": "plan",
        "operator": "equals",
        "value": "pro"
      }
    ]
  },
  "reentry": "every_time",
  "steps": [
    {
      "id": "welcome",
      "type": "send_email",
      "config": {
        "template_id": "trial-welcome",
        "from": "Ana da Loja Exemplo <[email protected]>",
        "subject": null,
        "reply_to": null,
        "variables": {
          "DAYS": "{{event.trial_days}}"
        }
      }
    },
    {
      "id": "wait_2_days",
      "type": "wait",
      "config": {
        "mode": "duration",
        "amount": 2,
        "unit": "days"
      }
    },
    {
      "id": "check_opened",
      "type": "condition",
      "config": {
        "kind": "email_activity",
        "step_id": "welcome",
        "activity": "opened"
      },
      "branches": {
        "yes": [
          {
            "id": "tag_engaged",
            "type": "update_contact",
            "config": {
              "actions": [
                {
                  "type": "add_to_segment",
                  "segment_id": "019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c"
                }
              ]
            }
          }
        ],
        "no": [
          {
            "id": "wait_morning",
            "type": "wait",
            "config": {
              "mode": "until",
              "time": "09:00",
              "weekdays": [1, 2, 3, 4, 5],
              "timezone": "America/Sao_Paulo"
            }
          },
          {
            "id": "reminder",
            "type": "send_email",
            "config": {
              "template_id": "trial-help",
              "from": null,
              "subject": "{{contact.first_name}}, posso ajudar com o seu teste?",
              "reply_to": null,
              "variables": {}
            }
          },
          {
            "id": "notify_crm",
            "type": "webhook",
            "config": {
              "url": "https://crm.lojaexemplo.com.br/hooks/postal"
            }
          }
        ]
      }
    }
  ],
  "version": 3,
  "runs_this_month": 318,
  "runs_in_progress": 41,
  "activated_at": "2026-10-15T13:00:00.000000Z",
  "created_at": "2026-10-14T19:22:00.000000Z",
  "updated_at": "2026-10-24T16:30:00.000000Z",
  "issues": [],
  "webhook_signing_secret": "whsec_YXV0b21hY2FvLWV4ZW1wbG8tYWJjZGVmMTIzNA=="
}

#Excluir uma automação

DELETE/automations/{id}

Chave de acesso total

Apaga a automação com as versões e as execuções; as que estavam em andamento param. Para só interromper, prefira pausar.

Parâmetros de caminho

  • idstringobrigatório
    ID da automação.

Erros

  • 404not_found
    O recurso não existe ou é de outro time.
DELETE /automations/{id}

cURL

curl -X DELETE https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.delete(
    "https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->delete('automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Resposta
{
  "object": "automation",
  "id": "019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
  "deleted": true
}

#Ativar

POST/automations/{id}/activate

Chave de acesso total

Ativa um rascunho ou retoma uma automação pausada. A definição precisa estar completa: templates escolhidos e publicados, remetente de domínio verificado, caminhos das condições com ao menos um passo, URLs dos webhooks… Publica a definição como versão (se mudou desde a última) e devolve a automação.

Parâmetros de caminho

  • idstringobrigatório
    ID da automação.

Erros

  • 422validation_error
    A definição tem erros ou ainda está incompleta. errors lista tudo o que falta.
  • 404not_found
    O recurso não existe ou é de outro time.
POST /automations/{id}/activate

cURL

curl -X POST https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/activate \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/activate', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/activate",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->post('automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/activate', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Resposta
{
  "object": "automation",
  "id": "019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
  "name": "Boas-vindas do teste grátis",
  "status": "active",
  "trigger": {
    "type": "event",
    "event": "trial.started",
    "filters": [
      {
        "key": "plan",
        "operator": "equals",
        "value": "pro"
      }
    ]
  },
  "reentry": "once",
  "steps": [
    {
      "id": "welcome",
      "type": "send_email",
      "config": {
        "template_id": "trial-welcome",
        "from": "Ana da Loja Exemplo <[email protected]>",
        "subject": null,
        "reply_to": null,
        "variables": {
          "DAYS": "{{event.trial_days}}"
        }
      }
    },
    {
      "id": "wait_2_days",
      "type": "wait",
      "config": {
        "mode": "duration",
        "amount": 2,
        "unit": "days"
      }
    },
    {
      "id": "check_opened",
      "type": "condition",
      "config": {
        "kind": "email_activity",
        "step_id": "welcome",
        "activity": "opened"
      },
      "branches": {
        "yes": [
          {
            "id": "tag_engaged",
            "type": "update_contact",
            "config": {
              "actions": [
                {
                  "type": "add_to_segment",
                  "segment_id": "019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c"
                }
              ]
            }
          }
        ],
        "no": [
          {
            "id": "wait_morning",
            "type": "wait",
            "config": {
              "mode": "until",
              "time": "09:00",
              "weekdays": [1, 2, 3, 4, 5],
              "timezone": "America/Sao_Paulo"
            }
          },
          {
            "id": "reminder",
            "type": "send_email",
            "config": {
              "template_id": "trial-help",
              "from": null,
              "subject": "{{contact.first_name}}, posso ajudar com o seu teste?",
              "reply_to": null,
              "variables": {}
            }
          },
          {
            "id": "notify_crm",
            "type": "webhook",
            "config": {
              "url": "https://crm.lojaexemplo.com.br/hooks/postal"
            }
          }
        ]
      }
    }
  ],
  "version": 2,
  "runs_this_month": 318,
  "runs_in_progress": 41,
  "activated_at": "2026-10-15T13:00:00.000000Z",
  "created_at": "2026-10-14T19:22:00.000000Z",
  "updated_at": "2026-10-20T10:31:00.000000Z",
  "issues": [],
  "webhook_signing_secret": "whsec_YXV0b21hY2FvLWV4ZW1wbG8tYWJjZGVmMTIzNA=="
}
422Resposta com erro
{
  "statusCode": 422,
  "name": "validation_error",
  "message": "The automation is not complete yet. Choose the template to send.",
  "errors": [
    {
      "step_id": "welcome",
      "message": "Choose the template to send."
    },
    {
      "step_id": null,
      "message": "Choose the event that starts the automation."
    }
  ]
}

#Pausar

POST/automations/{id}/pause

Chave de acesso total

Para de iniciar execuções. As que estão esperando ficam paradas e continuam de onde estavam quando a automação for ativada de novo; uma espera que venceu nesse meio-tempo segue logo depois.

Parâmetros de caminho

  • idstringobrigatório
    ID da automação.

Erros

  • 422validation_error
    A automação não está ativa.
  • 404not_found
    O recurso não existe ou é de outro time.
POST /automations/{id}/pause

cURL

curl -X POST https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/pause \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/pause', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/pause",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->post('automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/pause', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Resposta
{
  "object": "automation",
  "id": "019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
  "name": "Boas-vindas do teste grátis",
  "status": "paused",
  "trigger": {
    "type": "event",
    "event": "trial.started",
    "filters": [
      {
        "key": "plan",
        "operator": "equals",
        "value": "pro"
      }
    ]
  },
  "reentry": "once",
  "steps": [
    {
      "id": "welcome",
      "type": "send_email",
      "config": {
        "template_id": "trial-welcome",
        "from": "Ana da Loja Exemplo <[email protected]>",
        "subject": null,
        "reply_to": null,
        "variables": {
          "DAYS": "{{event.trial_days}}"
        }
      }
    },
    {
      "id": "wait_2_days",
      "type": "wait",
      "config": {
        "mode": "duration",
        "amount": 2,
        "unit": "days"
      }
    },
    {
      "id": "check_opened",
      "type": "condition",
      "config": {
        "kind": "email_activity",
        "step_id": "welcome",
        "activity": "opened"
      },
      "branches": {
        "yes": [
          {
            "id": "tag_engaged",
            "type": "update_contact",
            "config": {
              "actions": [
                {
                  "type": "add_to_segment",
                  "segment_id": "019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c"
                }
              ]
            }
          }
        ],
        "no": [
          {
            "id": "wait_morning",
            "type": "wait",
            "config": {
              "mode": "until",
              "time": "09:00",
              "weekdays": [1, 2, 3, 4, 5],
              "timezone": "America/Sao_Paulo"
            }
          },
          {
            "id": "reminder",
            "type": "send_email",
            "config": {
              "template_id": "trial-help",
              "from": null,
              "subject": "{{contact.first_name}}, posso ajudar com o seu teste?",
              "reply_to": null,
              "variables": {}
            }
          },
          {
            "id": "notify_crm",
            "type": "webhook",
            "config": {
              "url": "https://crm.lojaexemplo.com.br/hooks/postal"
            }
          }
        ]
      }
    }
  ],
  "version": 2,
  "runs_this_month": 318,
  "runs_in_progress": 41,
  "activated_at": "2026-10-15T13:00:00.000000Z",
  "created_at": "2026-10-14T19:22:00.000000Z",
  "updated_at": "2026-10-24T16:35:00.000000Z",
  "issues": [],
  "webhook_signing_secret": "whsec_YXV0b21hY2FvLWV4ZW1wbG8tYWJjZGVmMTIzNA=="
}

#Execuções

StatusO que significa
runningExecutando passos agora.
waitingEsperando até next_run_at: um passo wait ou uma nova tentativa de webhook. current_step_id é o próximo passo.
completedChegou ao fim de um caminho ou a um exit.
failedUm passo falhou; o motivo está em error e no registro do passo.
canceledCancelada pelo painel ou pela API.
skippedNão começou: o limite mensal de execuções do plano tinha acabado.

Cada passo executado fica registrado em steps, com status (running, waiting, completed, failed ou skipped), tentativas, erro e uma saída (output): {"until"} numa espera, {"email_id", "to", "subject"} num envio, {"result": "yes"} numa condição, {"changes": […]} numa mudança de contato e {"status_code"} num webhook.

#Listar execuções

GET/automations/{id}/runs

Chave de acesso total

As execuções da automação, da mais recente para a mais antiga, com a definição da versão que cada uma segue (definition). O registro dos passos só vem em obter uma execução.

Parâmetros de caminho

  • idstringobrigatório
    ID da automação.

Parâmetros de consulta

  • limitinteger
    De 1 a 100. Padrão: 20.
  • afterstring
    Cursor da próxima página.
  • beforestring
    Cursor da página anterior.
  • statusstring
    Um ou mais status separados por vírgula, como running,waiting.
  • contactstring
    ID ou e-mail do contato.

Erros

  • 422validation_error
    Algum campo é inválido. A mensagem diz qual.
  • 404not_found
    O recurso não existe ou é de outro time.
GET /automations/{id}/runs

cURL

curl 'https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/runs?status=waiting,failed' \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/runs?status=waiting,failed', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/runs",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    params={
        "status": "waiting,failed",
    },
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('automations/019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f/runs', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
    'query' => [
        'status' => 'waiting,failed',
    ],
]);

$data = json_decode($response->getBody(), true);
200Resposta (definition encurtado)
{
  "object": "list",
  "has_more": true,
  "data": [
    {
      "object": "automation_run",
      "id": "019a1f70-7182-7d94-9fa0-1b2c3d4e5f60",
      "automation_id": "019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
      "version": 2,
      "contact_id": "019a1e00-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
      "contact_email": "[email protected]",
      "status": "waiting",
      "trigger": {
        "type": "event",
        "event_id": "019a1f40-5f60-7b72-9d8e-9f0a1b2c3d4e",
        "event": "trial.started",
        "properties": {
          "plan": "pro",
          "source": "website",
          "trial_days": 14
        }
      },
      "current_step_id": "check_opened",
      "next_run_at": "2026-10-26T14:20:02.000000Z",
      "error": null,
      "started_at": "2026-10-24T14:20:01.000000Z",
      "finished_at": null,
      "created_at": "2026-10-24T14:20:01.000000Z",
      "definition": [
        {
          "id": "welcome",
          "…": "…"
        }
      ]
    }
  ]
}

#Obter uma execução

GET/automation-runs/{id}

Chave de acesso total

A execução com o que a iniciou (trigger: o tipo e, conforme o gatilho, o evento com as propriedades, o segmento ou o formulário), a definição da versão e o registro de cada passo.

Parâmetros de caminho

  • idstringobrigatório
    ID da execução.

Erros

  • 404not_found
    O recurso não existe ou é de outro time.
GET /automation-runs/{id}

cURL

curl https://api.postal.so/automation-runs/019a1f70-7182-7d94-9fa0-1b2c3d4e5f60 \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/automation-runs/019a1f70-7182-7d94-9fa0-1b2c3d4e5f60', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/automation-runs/019a1f70-7182-7d94-9fa0-1b2c3d4e5f60",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('automation-runs/019a1f70-7182-7d94-9fa0-1b2c3d4e5f60', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Resposta
{
  "object": "automation_run",
  "id": "019a1f70-7182-7d94-9fa0-1b2c3d4e5f60",
  "automation_id": "019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
  "automation_name": "Boas-vindas do teste grátis",
  "version": 2,
  "contact_id": "019a1e00-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
  "contact_email": "[email protected]",
  "status": "waiting",
  "trigger": {
    "type": "event",
    "event_id": "019a1f40-5f60-7b72-9d8e-9f0a1b2c3d4e",
    "event": "trial.started",
    "properties": {
      "plan": "pro",
      "source": "website",
      "trial_days": 14
    }
  },
  "current_step_id": "check_opened",
  "next_run_at": "2026-10-26T14:20:02.000000Z",
  "error": null,
  "started_at": "2026-10-24T14:20:01.000000Z",
  "finished_at": null,
  "created_at": "2026-10-24T14:20:01.000000Z",
  "definition": [
    {
      "id": "welcome",
      "type": "send_email",
      "config": {
        "template_id": "trial-welcome",
        "from": "Ana da Loja Exemplo <[email protected]>",
        "subject": null,
        "reply_to": null,
        "variables": {
          "DAYS": "{{event.trial_days}}"
        }
      }
    },
    {
      "id": "wait_2_days",
      "type": "wait",
      "config": {
        "mode": "duration",
        "amount": 2,
        "unit": "days"
      }
    },
    {
      "id": "check_opened",
      "type": "condition",
      "config": {
        "kind": "email_activity",
        "step_id": "welcome",
        "activity": "opened"
      },
      "branches": {
        "yes": [
          {
            "id": "tag_engaged",
            "type": "update_contact",
            "config": {
              "actions": [
                {
                  "type": "add_to_segment",
                  "segment_id": "019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c"
                }
              ]
            }
          }
        ],
        "no": [
          {
            "id": "wait_morning",
            "type": "wait",
            "config": {
              "mode": "until",
              "time": "09:00",
              "weekdays": [1, 2, 3, 4, 5],
              "timezone": "America/Sao_Paulo"
            }
          },
          {
            "id": "reminder",
            "type": "send_email",
            "config": {
              "template_id": "trial-help",
              "from": null,
              "subject": "{{contact.first_name}}, posso ajudar com o seu teste?",
              "reply_to": null,
              "variables": {}
            }
          },
          {
            "id": "notify_crm",
            "type": "webhook",
            "config": {
              "url": "https://crm.lojaexemplo.com.br/hooks/postal"
            }
          }
        ]
      }
    }
  ],
  "steps": [
    {
      "object": "automation_run_step",
      "id": "019a1f70-7183-7ea5-8ab1-2c3d4e5f6071",
      "step_id": "welcome",
      "type": "send_email",
      "status": "completed",
      "attempts": 1,
      "output": {
        "email_id": "019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b",
        "to": "[email protected]",
        "subject": "Ana, seu teste do plano Pro começou"
      },
      "error": null,
      "started_at": "2026-10-24T14:20:01.000000Z",
      "finished_at": "2026-10-24T14:20:02.000000Z"
    },
    {
      "object": "automation_run_step",
      "id": "019a1f70-7184-7fb6-9bc2-3d4e5f607182",
      "step_id": "wait_2_days",
      "type": "wait",
      "status": "waiting",
      "attempts": 1,
      "output": {
        "until": "2026-10-26T14:20:02Z"
      },
      "error": null,
      "started_at": "2026-10-24T14:20:02.000000Z",
      "finished_at": null
    }
  ]
}

#Cancelar uma execução

POST/automation-runs/{id}/cancel

Chave de acesso total

Para uma execução em andamento ou esperando; a espera pendente fica skipped. Devolve a execução.

Parâmetros de caminho

  • idstringobrigatório
    ID da execução.

Erros

  • 422validation_error
    A execução já terminou.
  • 404not_found
    O recurso não existe ou é de outro time.
POST /automation-runs/{id}/cancel

cURL

curl -X POST https://api.postal.so/automation-runs/019a1f70-7182-7d94-9fa0-1b2c3d4e5f60/cancel \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/automation-runs/019a1f70-7182-7d94-9fa0-1b2c3d4e5f60/cancel', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/automation-runs/019a1f70-7182-7d94-9fa0-1b2c3d4e5f60/cancel",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->post('automation-runs/019a1f70-7182-7d94-9fa0-1b2c3d4e5f60/cancel', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Resposta
{
  "object": "automation_run",
  "id": "019a1f70-7182-7d94-9fa0-1b2c3d4e5f60",
  "automation_id": "019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
  "automation_name": "Boas-vindas do teste grátis",
  "version": 2,
  "contact_id": "019a1e00-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
  "contact_email": "[email protected]",
  "status": "canceled",
  "trigger": {
    "type": "event",
    "event_id": "019a1f40-5f60-7b72-9d8e-9f0a1b2c3d4e",
    "event": "trial.started",
    "properties": {
      "plan": "pro",
      "source": "website",
      "trial_days": 14
    }
  },
  "current_step_id": "check_opened",
  "next_run_at": null,
  "error": "Canceled from the dashboard or API.",
  "started_at": "2026-10-24T14:20:01.000000Z",
  "finished_at": "2026-10-25T09:12:00.000000Z",
  "created_at": "2026-10-24T14:20:01.000000Z",
  "definition": [
    {
      "id": "welcome",
      "type": "send_email",
      "config": {
        "template_id": "trial-welcome",
        "from": "Ana da Loja Exemplo <[email protected]>",
        "subject": null,
        "reply_to": null,
        "variables": {
          "DAYS": "{{event.trial_days}}"
        }
      }
    },
    {
      "id": "wait_2_days",
      "type": "wait",
      "config": {
        "mode": "duration",
        "amount": 2,
        "unit": "days"
      }
    },
    {
      "id": "check_opened",
      "type": "condition",
      "config": {
        "kind": "email_activity",
        "step_id": "welcome",
        "activity": "opened"
      },
      "branches": {
        "yes": [
          {
            "id": "tag_engaged",
            "type": "update_contact",
            "config": {
              "actions": [
                {
                  "type": "add_to_segment",
                  "segment_id": "019a1d91-4c5d-7e6f-8a7b-8c9d0e1f2a3c"
                }
              ]
            }
          }
        ],
        "no": [
          {
            "id": "wait_morning",
            "type": "wait",
            "config": {
              "mode": "until",
              "time": "09:00",
              "weekdays": [1, 2, 3, 4, 5],
              "timezone": "America/Sao_Paulo"
            }
          },
          {
            "id": "reminder",
            "type": "send_email",
            "config": {
              "template_id": "trial-help",
              "from": null,
              "subject": "{{contact.first_name}}, posso ajudar com o seu teste?",
              "reply_to": null,
              "variables": {}
            }
          },
          {
            "id": "notify_crm",
            "type": "webhook",
            "config": {
              "url": "https://crm.lojaexemplo.com.br/hooks/postal"
            }
          }
        ]
      }
    }
  ],
  "steps": [
    {
      "object": "automation_run_step",
      "id": "019a1f70-7183-7ea5-8ab1-2c3d4e5f6071",
      "step_id": "welcome",
      "type": "send_email",
      "status": "completed",
      "attempts": 1,
      "output": {
        "email_id": "019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b",
        "to": "[email protected]",
        "subject": "Ana, seu teste do plano Pro começou"
      },
      "error": null,
      "started_at": "2026-10-24T14:20:01.000000Z",
      "finished_at": "2026-10-24T14:20:02.000000Z"
    },
    {
      "object": "automation_run_step",
      "id": "019a1f70-7184-7fb6-9bc2-3d4e5f607182",
      "step_id": "wait_2_days",
      "type": "wait",
      "status": "skipped",
      "attempts": 1,
      "output": {
        "until": "2026-10-26T14:20:02Z"
      },
      "error": null,
      "started_at": "2026-10-24T14:20:02.000000Z",
      "finished_at": "2026-10-25T09:12:00.000000Z"
    }
  ]
}

#Passo de webhook

O passo webhook faz um POST com JSON para a sua URL (HTTPS e pública), com o contato e o evento que iniciou a execução:

automation.webhook
{
  "type": "automation.webhook",
  "created_at": "2026-10-28T12:00:03.410Z",
  "data": {
    "automation_id": "019a1f60-6071-7c83-8e9f-0a1b2c3d4e5f",
    "automation_name": "Boas-vindas do teste grátis",
    "run_id": "019a1f70-7182-7d94-9fa0-1b2c3d4e5f60",
    "step_id": "notify_crm",
    "trigger": "event",
    "contact": {
      "id": "019a1e00-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
      "email": "[email protected]",
      "first_name": "Ana",
      "last_name": "Souza",
      "unsubscribed": false,
      "properties": {
        "plan": "pro",
        "city": "Recife"
      },
      "created_at": "2026-10-24T14:00:00.000Z",
      "updated_at": "2026-10-24T14:00:00.000Z"
    },
    "event": {
      "id": "019a1f40-5f60-7b72-9d8e-9f0a1b2c3d4e",
      "name": "trial.started",
      "properties": {
        "plan": "pro",
        "source": "website",
        "trial_days": 14
      }
    }
  }
}

A requisição é assinada como os webhooks da Postal, com os cabeçalhos webhook-id, webhook-timestamp e webhook-signature (e os equivalentes svix-*), mas usando o webhook_signing_secret da automação, que aparece em GET /automations/{id}. O mesmo código de verificação serve. O webhook-id é o ID do registro do passo e se repete nas novas tentativas, para você descartar duplicatas.

  • Responda com 2xx em até 15 segundos. Redirecionamentos não são seguidos e endereços de rede privada são recusados.
  • Qualquer outra resposta conta como falha. São 3 tentativas: a segunda 1 minuto depois, a terceira 10 minutos depois. Depois disso, o passo e a execução ficam failed.
  • As entregas usam o User-Agent Postal-Webhooks/1.0.