Como colocar um fluxo de aprovação no seu produto

Passo a passo para integrar workflows de aprovação multi-step e multi-canal no seu SaaS usando a API REST do Apruvly, com exemplo JSON válido e limites por plano

Como colocar um fluxo de aprovação no seu produto

Adicionar "uma camadinha de aprovação" no produto costuma parecer simples — uma tabela com status pending / approved / rejected. Na prática, o escopo cresce: escalação por timeout, notificações em vários canais, idempotência de cliques, trilha para auditoria, webhooks de retorno. Este guia mostra como delegar esse motor ao Apruvly via API REST, sem implementar tudo do zero.

O exemplo abaixo cobre um cenário comum: despesa acima de um limite passa pelo gestor e depois pelo financeiro; se o financeiro não responder em 48 horas, a solicitação escala para o CFO. Fluxos com mais de um step exigem plano Starter ou superior ($19/mês). No plano Free você pode validar a integração com um workflow de step único.

Pré-requisitos

  • Conta no Apruvly (plano Free: 180 créditos/mês, sem cartão).
  • API key criada em /api-keys após o login.
  • Integrações configuradas no console para canais que não sejam e-mail do sistema (ex.: Slack em /integrations).

Recomendamos validar o JSON antes de criar o workflow:

curl -X POST https://api.apruvly.io/api/v1/workflow/validate \
  -H "Authorization: Bearer $APRUVLY_KEY" \
  -H "Content-Type: application/json" \
  -d @workflow.json

POST /api/v1/workflow/validate não consome créditos; apenas verifica sintaxe e regras do WorkflowConfig.

Estrutura do WorkflowConfig

A API não usa um array steps. A configuração segue este formato:

Campo Função
object Título, descrição, links e tags do que está sendo aprovado
expires Prazo máximo do workflow (ex.: "72h", entre 5 minutos e 7 dias)
start Nome do primeiro step
workflow Mapa de steps nomeados (manager-review, finance-review, …)
on Ações disparadas em eventos (workflow_approved, workflow_rejected, …)

Cada step define:

  • type — canal: email, slack, ms-teams, whatsapp, telegram, discord, twilio-sms, twilio-whatsapp, dingtalk
  • data — payload do canal (destinatários, assunto, corpo, etc.)
  • minApprovals — quorum de aprovações (padrão: 1)
  • approved / rejected — próximo step ou término do workflow
  • escalation — objeto único com after, type e data (cadeia aninhada até 5 níveis)

Passo 1 — Criar o workflow

curl -X POST https://api.apruvly.io/api/v1/workflow/ \
  -H "Authorization: Bearer $APRUVLY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "object": {
    "title": "Despesa #4471 — R$ 7.200 — Viagem cliente São Paulo",
    "description": "Solicitação acima do limite automático; requer gestor e financeiro."
  },
  "expires": "72h",
  "start": "manager-review",
  "workflow": {
    "manager-review": {
      "type": "email",
      "data": {
        "to": ["[email protected]"],
        "subject": "Aprovar despesa #4471",
        "body": "Despesa de R$ 7.200 para viagem ao cliente. Aprovar ou rejeitar pelo link."
      },
      "minApprovals": 1,
      "approved": "finance-review"
    },
    "finance-review": {
      "type": "slack",
      "data": {
        "to": ["U01234567"]
      },
      "minApprovals": 1,
      "escalation": {
        "after": "48h",
        "type": "email",
        "data": {
          "to": ["[email protected]"],
          "subject": "Aprovação escalada — despesa #4471",
          "body": "Financeiro não respondeu em 48h. Sua decisão é necessária."
        }
      }
    }
  },
  "on": {
    "workflow_approved": [
      {
        "type": "webhook",
        "data": {
          "method": "POST",
          "url": "https://api.seuproduto.com/expenses/4471/approved"
        }
      }
    ],
    "workflow_rejected": [
      {
        "type": "webhook",
        "data": {
          "method": "POST",
          "url": "https://api.seuproduto.com/expenses/4471/rejected"
        }
      }
    ]
  }
}'

Resposta típica (HTTP 202 Accepted):

{
  "success": true,
  "data": {
    "id": "0192a3f4-..."
  }
}

Os créditos são debitados na criação, conforme UnitCost do config (1 crédito por destinatário notificado em cada step e nível de escalation, com piso de 1). O designer e a documentação em /documentation mostram a estimativa antes do envio.

Marina recebe e-mail com links de aprovação/rejeição; o financeiro recebe mensagem no Slack — sem login no seu produto nem no Apruvly.

Passo 2 — Receber a decisão

Há três formas de saber quando o workflow terminou:

A) Webhooks no campo on

Quando o workflow atinge estado terminal (approved, rejected, expired, canceled), o Apruvly executa as ações configuradas em on.workflow_*. Para webhooks HTTP, há retry automático; URLs apontando para IPs privados ou loopback são bloqueadas (proteção SSRF).

B) Webhook do integrador na API key (Starter+)

Em /api-keys, configure notify_url e o segredo HMAC. A cada mudança relevante de status, o Apruvly envia um POST assinado com payload no formato:

{
  "id": "uuid-do-evento",
  "event": "workflow_approved",
  "workflow_id": "0192a3f4-...",
  "status": "approved",
  "current_step": "finance-review",
  "occurred_at": "2026-06-19T14:22:08Z"
}

Útil quando você quer um único endpoint para todos os workflows criados com aquela key, sem repetir URLs em cada on.

C) Polling

curl https://api.apruvly.io/api/v1/workflow/0192a3f4-... \
  -H "Authorization: Bearer $APRUVLY_KEY"

A resposta inclui status, current_step, decisions (quem decidiu, quando, comentário, IP/user-agent conforme o plano) e aprovadores pendentes.

Passo 3 — Casos de borda já cobertos pelo motor

  • Timeout: escalation dispara automaticamente conforme after no step.
  • Duplo clique: cada aprovador tem challenge UUID; segunda resposta no mesmo challenge é rejeitada.
  • Concorrência: transições de estado usam SELECT FOR UPDATE no Postgres — dois cliques simultâneos não geram decisão duplicada.
  • Cancelamento: DELETE /api/v1/workflow/:id interrompe o fluxo e emite workflow_canceled.

Passo 4 — Reutilizar configurações com o designer

Para evitar montar JSON grande a cada solicitação, use o designer visual em /workflow/designer: salve configs na conta, ajuste steps e teste o UnitCost estimado. O submit do designer chama a mesma API de criação. Não existe endpoint template com variables — a reutilização é via designs salvos ou geração do JSON na sua aplicação.

Cobrança e isolamento

  • Créditos: 1 por destinatário em step/escalation; ações on com webhook ou canal de entrega somam +1 flat quando aplicável. Detalhes em pricing e em docs/pricing.md no repositório.
  • Isolamento: cada API key pertence a uma conta (user_id). Workflows de um cliente não vazam para outro, mesmo com erro na sua camada de roteamento.

O que não está no escopo deste guia

  • SSO: login no console via OAuth (Google, Microsoft, GitHub) — não SAML no painel de auditoria.
  • Relatório de SLA de aprovação: não há dashboard dedicado; use GET /api/v1/workflow/:id, listagens (/workflows/recent, /workflows/search) ou export de auditoria (Business+).
  • MCP para agentes: disponível no Growth+; ver artigo sobre agentes de IA e documentação MCP.

Próximo passo

Crie a conta em apruvly.io, gere a key em /api-keys, ajuste os e-mails e IDs do Slack no exemplo acima e execute o curl. Para fluxo single-step no Free, remova finance-review e o campo approved do primeiro step.