Documentação

Referência completa da API REST do Apruvly.

Integrações

Primeiros Passos

Tudo o que você precisa para começar a automatizar aprovações em minutos.

A API do Apruvly é uma API RESTful JSON. Todas as requisições devem ser autenticadas com uma chave de API. As respostas são sempre JSON, exceto quando o corpo está vazio (204).

URL Base
https://api.apruvly.io/api/v1
Exemplo Rápido

Crie um workflow de aprovação com um único passo usando um comando curl:

curl -X POST https://api.apruvly.io/api/v1/workflow \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "object": {
    "title": "Q1 Marketing Budget",
    "description": "Marketing budget for Q1, $18k total"
  },
  "expires": "48h",
  "start": "step1",
  "workflow": {
    "step1": {
      "type": "email",
      "data": {
        "to": ["[email protected]"],
        "subject": "Q1 Marketing Budget – $18k",
        "body": "Please review the budget breakdown in the linked document and share your decision."
      }
    }
  }
}'

Autenticação

Todas as requisições à API exigem autenticação via chave de API.

Passe sua chave de API no cabeçalho Authorization como um Bearer token. Você pode criar e gerenciar chaves de API pelo painel.

Nunca exponha sua chave de API em código cliente ou repositórios públicos. Revogue-a imediatamente se for comprometida.
Formato do cabeçalho
Authorization: Bearer wf_YOUR_API_KEY

Você pode gerar uma chave de API na seção Chaves de API do painel.

POST

Criar Workflow

/api/v1/workflow

Cria um novo workflow de aprovação e inicia imediatamente o primeiro passo.

Corpo da Requisição
Campo Tipo Obrigatório Descrição
object object Sim Metadados sobre o item que está sendo aprovado.
object.title string Sim Título legível para o workflow. Máximo de 200 caracteres.
object.description string Não Descrição opcional mais detalhada do que está sendo aprovado.
object.links string[] Não Lista opcional de URLs relacionadas à aprovação (documentos, arquivos, etc.).
object.tags string[] Não Lista opcional de tags para filtragem e organização.
external_id string Não Identificador de correlação opcional (máx. 128 caracteres) — ex.: número de contrato, ticket do CRM, referência de pedido. Requer plano Growth ou superior. Deve ser único por conta.
expires duration Sim Por quanto tempo o workflow permanece aberto antes de expirar. Formato: 30s, 15m, 2h, 7d, 2w.
start string Sim A chave do primeiro passo a executar (deve corresponder a uma chave em workflow).
workflow map[string]Step Sim Mapa de chaves de passo para objetos Step definindo a cadeia de aprovação.
on map[string]Action[] Não Mapa de eventos do ciclo de vida para listas de ações (webhook, email, twilio-sms) disparadas automaticamente. Eventos: workflow_created, workflow_approved, workflow_rejected, workflow_expired, workflow_canceled, workflow_completed, step_approved, step_escalated, user_approval, user_rejection.
disable_email_fallback boolean Não Desativa o fallback de e-mail padrão. Quando omitido (recomendado), a plataforma envia automaticamente a solicitação de aprovação por e-mail se uma notificação via integração (Teams, Slack, WhatsApp) falhar. Defina como true para pular o fallback e aceitar a falha original.
debug boolean Não Ativa o modo de depuração. Todas as notificações (e-mail, Teams, Slack, WhatsApp), webhooks e escalonamentos são suprimidos — o workflow executa toda a sua lógica sem contatar nenhum participante. Útil para testar o fluxo sem disparar comunicações reais.
Mesmo no modo debug, os créditos são consumidos normalmente. O modo debug suprime apenas as comunicações externas — não afeta a cobrança.
Exemplo de Requisição
curl -X POST https://api.apruvly.io/api/v1/workflow \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "object": {
    "title": "Contract Sign-off",
    "description": "Legal review for client contract #4821",
    "links": ["https://drive.example.com/contracts/4821"],
    "tags": ["legal", "contract"]
  },
  "external_id": "CONTRACT-2025-0042",
  "expires": "72h",
  "start": "legal-review",
  "workflow": {
    "legal-review": {
      "type": "email",
      "data": {
        "to": ["[email protected]"],
        "subject": "Approval Request: Contract #4821",
        "body": "Please review and approve contract #4821."
      },
      "approved": "ceo-approval",
      "escalation": {
        "type": "email",
        "after": "24h",
        "data": {
          "to": ["[email protected]"],
          "subject": "Escalation: Contract #4821 pending approval",
          "body": "Contract #4821 has not been reviewed. Please take action."
        }
      }
    },
    "ceo-approval": {
      "type": "email",
      "data": {
        "to": ["[email protected]"],
        "subject": "Final Approval: Contract #4821",
        "body": "Legal review is complete. Please provide final approval."
      }
    }
  }
}'
Exemplo de Resposta 202 Accepted
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "externalId": "CONTRACT-2025-0042"
  }
}

Identificadores de correlação (external_id)

Associe sua própria referência de negócio (número de contrato, ticket do CRM, id de deploy) ao criar um workflow e consulte o status ou cancele sem guardar o UUID da plataforma. Requer plano Growth ou superior. Máx. 128 caracteres; permitidos: letras, dígitos e . _ : / -. Único por conta.

402 quando o plano é inferior ao Growth. 409 quando outro workflow da conta já usa o mesmo external_id.
Exemplo de Resposta 402 Payment Required
{
  "success": false,
  "message": "Seu plano não inclui external_id. Faça upgrade para Growth ou superior para associar um identificador de negócio aos workflows."
}
Criar Workflow — Exemplo de Requisição
curl -X POST https://api.apruvly.io/api/v1/workflow \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "object": {
    "title": "Contract Sign-off",
    "description": "Legal review for client contract #4821"
  },
  "external_id": "CONTRACT-2025-0042",
  "expires": "72h",
  "start": "legal-review",
  "workflow": {
    "legal-review": {
      "type": "email",
      "data": {
        "to": ["[email protected]"],
        "subject": "Approval Request: Contract #4821",
        "body": "Please review and approve contract #4821."
      }
    }
  }
}'
Exemplo de Resposta 202 Accepted
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "externalId": "CONTRACT-2025-0042"
  }
}
Consultar por external_id — Exemplo de Requisição

Retorna o mesmo payload de GET /workflow/{id}, buscando pelo external_id informado na criação. Requer plano Growth ou superior.

curl https://api.apruvly.io/api/v1/workflow/external/CONTRACT-2025-0042 \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Exemplo de Resposta 200 OK
{
  "success": true,
  "data": {
    "id":                  "550e8400-e29b-41d4-a716-446655440000",
    "externalId":          "CONTRACT-2025-0042",
    "status":              "pending",
    "currentStep":         "legal-review",
    "createdAt":           "2025-01-15T10:00:00Z",
    "expiresAt":           "2025-01-18T10:00:00Z",
    "decisions": []
  }
}
Cancelar Workflow — Exemplo de Requisição
curl -X DELETE https://api.apruvly.io/api/v1/workflow/external/CONTRACT-2025-0042 \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Exemplo de Resposta 200 OK
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000"
  }
}
Listar Workflows — Exemplo de Requisição
curl "https://api.apruvly.io/api/v1/workflows/search?external_id=CONTRACT-2025-0042" \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Exemplo de Resposta 200 OK
{
  "success": true,
  "data": [
    {
      "id":             "550e8400-e29b-41d4-a716-446655440000",
      "title":          "Contract Sign-off",
      "external_id":    "CONTRACT-2025-0042",
      "current_status": "pending",
      "current_step":   "legal-review",
      "created_at":     "2025-01-15T10:00:00Z",
      "expires_at":     "2025-01-18T10:00:00Z",
      "completed_at":   null
    }
  ]
}
POST

Validar Workflow

/api/v1/workflow/validate

Valida uma configuração de workflow sem criá-lo. Útil para verificar o payload antes de enviá-lo.

Este endpoint não requer autenticação e não consome créditos. Apenas verifica se a configuração é válida.
Exemplo de Requisição
curl -X POST https://api.apruvly.io/api/v1/workflow/validate \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "object": {
    "title": "Test Workflow"
  },
  "expires": "24h",
  "start": "step1",
  "workflow": {
    "step1": {
      "type": "email",
      "data": {
        "to": ["[email protected]"],
        "subject": "Test Approval",
        "body": "Please approve this test request."
      }
    }
  }
}'
Exemplo de Resposta 200 OK
{
  "success": true
}
GET

Obter Workflow

/api/v1/workflow/{id}

Retorna o estado completo de um workflow, incluindo o log de atividades e o histórico de decisões.

Parâmetros de Caminho
Campo Tipo Descrição
id uuid O ID do workflow retornado quando o workflow foi criado.
Exemplo de Requisição
curl https://api.apruvly.io/api/v1/workflow/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Exemplo de Resposta 200 OK
{
  "success": true,
  "data": {
    "id":                  "550e8400-e29b-41d4-a716-446655440000",
    "externalId":          "CONTRACT-2025-0042",
    "status":              "pending",
    "currentStep":         "ceo-approval",
    "currentEscalation":  0,
    "createdAt":           "2025-01-15T10:00:00Z",
    "expiresAt":           "2025-01-18T10:00:00Z",
    "nextTickAt":          "2025-01-16T10:00:00Z",
    "decisions": [
      {
        "user":        "[email protected]",
        "is_approved": true,
        "ip":          "203.0.113.42",
        "decisionAt":  "2025-01-15T14:22:00Z"
      }
    ]
  }
}
GET

Listar Workflows

/api/v1/workflows/search

Retorna uma lista paginada de workflows pertencentes ao usuário autenticado.

Parâmetros de Consulta
Campo Tipo Descrição
status string Filtrar por status: pending, approved, rejected, expired, canceled
query string Busca textual no título do workflow.
step string Filtrar pelo nome da etapa ativa atual (ex.: legal-review).
from RFC3339 Filtrar workflows criados a partir deste timestamp (formato RFC 3339, ex.: 2025-01-01T00:00:00Z).
to RFC3339 Filtrar workflows criados até este timestamp (formato RFC 3339, ex.: 2025-01-31T23:59:59Z).
tags string Filtrar por tags do workflow (separadas por vírgula).
external_id string Correspondência exata no identificador de correlação fornecido pelo chamador. Requer plano Growth ou superior.
limit integer Número máximo de resultados (padrão 50, máximo 500). Max results per page (default 50, max 500).
Exemplo de Requisição
curl "https://api.apruvly.io/api/v1/workflows/search?status=pending&query=contract" \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Exemplo de Resposta 200 OK
{
  "success": true,
  "data": [
    {
      "id":             "550e8400-e29b-41d4-a716-446655440000",
      "title":          "Contract Sign-off",
      "external_id":    "CONTRACT-2025-0042",
      "current_status": "pending",
      "current_step":   "ceo-approval",
      "created_at":     "2025-01-15T10:00:00Z",
      "expires_at":     "2025-01-18T10:00:00Z",
      "completed_at":   null
    }
  ]
}
GET

Workflows Recentes

/api/v1/workflows/recent

Retorna os workflows criados mais recentemente para o usuário autenticado.

Exemplo de Requisição
curl "https://api.apruvly.io/api/v1/workflows/recent" \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
GET

Faturamento

/api/v1/billing

Retorna assinatura, plano, saldo de créditos e resumo de uso do usuário autenticado.

Exemplo de Requisição
curl "https://api.apruvly.io/api/v1/billing" \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
GET

Integrações

/api/v1/integrations

Gerencie credenciais de canais de terceiros (Slack, MS Teams, Twilio, etc.) via a API REST.

MétodoEndpointDescrição
GET/api/v1/integrationsLista o status de configuração de todas as integrações suportadas.
GET/api/v1/integrations/{integration}Retorna o status de configuração de uma integração (segredos nunca são incluídos).
PUT/api/v1/integrations/{integration}Cria ou substitui credenciais de uma integração.
DELETE/api/v1/integrations/{integration}Remove credenciais armazenadas de uma integração.
DELETE

Cancelar Workflow

/api/v1/workflow/{id}

Cancela um workflow pendente. Workflows concluídos ou expirados não podem ser cancelados.

Apenas workflows com status pendente podem ser cancelados. Retorna 406 se o workflow já estiver concluído, rejeitado ou expirado.

Você também pode cancelar pelo identificador de negócio definido na criação — veja Identificadores de correlação (external_id). Identificadores de correlação (external_id)

Parâmetros de Caminho
Campo Tipo Descrição
id uuid O ID do workflow retornado quando o workflow foi criado.
Exemplo de Requisição
curl -X DELETE https://api.apruvly.io/api/v1/workflow/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Exemplo de Resposta 200 OK
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000"
  }
}
PUT

Aprovar / Rejeitar

/api/v1/workflow/{id}/{challenge}/approve ou /api/v1/workflow/{id}/{challenge}/reject

Registra uma decisão de aprovação ou rejeição para uma etapa do workflow. A ação (aprovar ou rejeitar) é determinada pelo sufixo do caminho da URL, não pelo corpo da requisição. Nenhum corpo de requisição é necessário.

O UUID de desafio é único por aprovador e está embutido no link do e-mail de notificação. Nenhum cabeçalho de autenticação é necessário para este endpoint - o token de desafio é a prova de identidade.
Parâmetros de Caminho
Campo Tipo Descrição
id uuid O ID do workflow retornado quando o workflow foi criado.
challenge uuid Token UUID de desafio por aprovador incluído no link do e-mail de notificação.
Exemplo de Requisição
# Approve
curl -X PUT https://api.apruvly.io/api/v1/workflow/550e8400-e29b-41d4-a716-446655440000/7a9f1c2d-4b3e-48f6-9d8c-1a2b3c4d5e6f/approve \
  -H "Authorization: Bearer wf_YOUR_API_KEY"

# Reject
curl -X PUT https://api.apruvly.io/api/v1/workflow/550e8400-e29b-41d4-a716-446655440000/7a9f1c2d-4b3e-48f6-9d8c-1a2b3c4d5e6f/reject \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Exemplo de Resposta 200 OK
{
  "success": true
}
CRUD

Diretório

/api/v1/directory

Gerencia a agenda de áreas (times) e pessoas. Contatos alimentam fallback de e-mail nas notificações e vinculam destinatários para análise cross-channel.

Disponível em todos os planos pagos, mas o cliente precisa ativar a feature em /directory antes. Chamadas retornam 402 (plano não permite) ou 409 (feature desativada) até as duas condições serem atendidas.
A área cliente em /directory aceita uploads de CSV como atalho mais amigável para os endpoints de bulk — útil para usuários menos técnicos. A validação no servidor, os limites do plano e a transação tudo-ou-nada são idênticos aos endpoints bulk em JSON.
Áreas
MétodoEndpointDescrição
GET/api/v1/directory/areasLista todas as áreas ativas.
POST/api/v1/directory/areasCria uma nova área.
POST/api/v1/directory/areas/bulkCria até 100 áreas em uma única chamada.
PUT/api/v1/directory/areas/bulkRenomeia várias áreas de uma vez. Cada item precisa do id da área.
GET/api/v1/directory/areas/{id}Busca uma área pelo id.
PUT/api/v1/directory/areas/{id}Renomeia uma área.
DELETE/api/v1/directory/areas/{id}Remove a área (vínculos com pessoas são removidos; pessoas permanecem).
Pessoas
MétodoEndpointDescrição
GET/api/v1/directory/people?q=&area=&page=Lista paginada de pessoas. Filtros: q (texto), area (uuid), page (1-based).
POST/api/v1/directory/peopleCria uma pessoa com áreas e contatos.
POST/api/v1/directory/people/bulkCria até 1.000 pessoas em uma única chamada (com vínculos e contatos).
PUT/api/v1/directory/people/bulkAtualiza várias pessoas de uma vez (nome, áreas e contatos). Cada item precisa do id da pessoa.
GET/api/v1/directory/people/{id}Busca uma pessoa com áreas e contatos.
PUT/api/v1/directory/people/{id}Substitui nome, áreas e contatos em uma só chamada.
DELETE/api/v1/directory/people/{id}Remove a pessoa (contatos e vínculos são removidos junto).
Exemplo de Requisição — Cria uma pessoa com áreas e contatos.
curl -X POST https://api.apruvly.io/api/v1/directory/people \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "display_name": "Ana Souza",
    "area_ids": ["6c2b6e80-1f74-4cf2-9e2f-0d0e3b9b0001"],
    "contacts": [
      { "provider": "email", "address": "[email protected]", "label": "work" },
      { "provider": "twilio-sms", "address": "+5511999999999" }
    ]
  }'
Exemplo de Resposta 201 Created
{
  "success": true,
  "data": {
    "id": "a4d1f0c6-2d24-49b3-9e3c-7a2e6c4b0001",
    "display_name": "Ana Souza",
    "is_active": true,
    "area_ids": ["6c2b6e80-1f74-4cf2-9e2f-0d0e3b9b0001"],
    "contacts": [
      { "id": "…", "provider": "email", "address": "[email protected]", "label": "work" },
      { "id": "…", "provider": "twilio-sms", "address": "+5511999999999" }
    ]
  }
}
Operações em lote

Os endpoints em lote recebem uma lista no campo "items". A criação tem limite por requisição (100 áreas, 1.000 pessoas) e a atualização é limitada a duas vezes o tamanho que o plano do cliente suporta para o recurso correspondente.

Exemplo de Requisição — Cria até 1.000 pessoas em uma única chamada (com vínculos e contatos).
curl -X POST https://api.apruvly.io/api/v1/directory/people/bulk \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "display_name": "Ana Souza",
        "area_ids": ["6c2b6e80-1f74-4cf2-9e2f-0d0e3b9b0001"],
        "contacts": [
          { "provider": "email", "address": "[email protected]", "label": "work" }
        ]
      },
      {
        "display_name": "Bruno Lima",
        "contacts": [
          { "provider": "twilio-sms", "address": "+5511988887777" }
        ]
      }
    ]
  }'
Exemplo de Resposta 201 Created
{
  "success": true,
  "data": {
    "count": 2,
    "items": [
      { "id": "a4d1f0c6-…", "display_name": "Ana Souza", "area_ids": ["6c2b6e80-…"], "contacts": ["…"] },
      { "id": "f10b2e8a-…", "display_name": "Bruno Lima", "area_ids": [], "contacts": ["…"] }
    ]
  }
}

O lote é processado em conjunto: se qualquer item for inválido, a requisição é rejeitada e nada é gravado.

Escopos necessários

Cada endpoint exige o escopo correspondente na API key. Conceda escopos em Chaves de API no painel.

EscoposDescrição
api:directory:listAPI · Diretório · listar
api:directory:readAPI · Diretório · ler
api:directory:writeAPI · Diretório · criar / atualizar
api:directory:bulkAPI · Diretório · operações em massa
api:directory:deleteAPI · Diretório · excluir
Formatos de endereço por canal

Cada contato é um par (provider, address). Só providers configurados em /integrations (além de e-mail) são aceitos.

CanalEndereço
email, slack, ms-teamsE-mail address
twilio-sms, twilio-whatsapp, whatsappE.164 phone (e.g. +5511999999999)
telegramNumeric chat id
discord17–20 digit snowflake

Robôs de grupo DingTalk não ficam no diretório — eles enviam para um grupo, não para um contato individual.

Erros
StatusDescrição
400Campo obrigatório ausente ou contato inválido (e-mail ou telefone malformado, por exemplo).
402O plano atual não inclui a feature de diretório.
409Diretório está desativado — ative em /directory no painel antes de chamar a API.

Ações

Efeitos colaterais que o engine dispara quando eventos de ciclo de vida do workflow ocorrem.

Use o campo `on` para registrar ações em eventos de ciclo de vida do workflow. Cada ação tem um tipo (webhook, email ou twilio-sms) e um payload de dados. Quando o evento dispara, todas as ações são executadas em ordem.

Formas wrapped e flat

Cada action é um objeto JSON que pode ser serializado em duas formas. A forma wrapped ({"type":"...", "data":{...}}) é a canônica produzida pela API e a única aceita para twilio-sms. A forma flat infere o tipo a partir dos campos do payload (url → webhook, to → email) e é mantida por compatibilidade com clientes antigos.

{
  "on": {
    "workflow_approved": [
      { "type": "webhook",    "data": { "url": "https://example.com/hooks/approved", "method": "POST" } },
      { "type": "email",      "data": { "to": ["[email protected]"], "subject": "Approved", "body": "Workflow ${id} is approved." } },
      { "type": "twilio-sms", "data": { "to": ["+14155552671"], "body": "Workflow ${id} approved" } }
    ]
  }
}
Eventos do ciclo de vida
Evento Descrição
workflow_created Disparado quando um workflow é criado com sucesso.
workflow_approved Disparado quando o workflow inteiro atinge o estado final de aprovado.
workflow_rejected Disparado quando o workflow inteiro é rejeitado.
workflow_expired Disparado quando o workflow expira antes de atingir uma decisão final.
workflow_canceled Disparado quando o workflow é explicitamente cancelado via API.
workflow_completed Disparado quando o workflow atinge qualquer estado terminal (aprovado, rejeitado, expirado ou cancelado).
step_approved Disparado quando um step individual é aprovado e o workflow avança para o próximo step.
step_escalated Disparado quando o timer de escalonamento de um step é acionado e a notificação de escalonamento é enviada.
user_approval Disparado cada vez que um usuário registra um voto de aprovação em um step.
user_rejection Disparado cada vez que um usuário registra um voto de rejeição em um step.
WebhookAction type: "webhook"

Envia uma requisição HTTP para um endpoint externo. Hosts privados e de loopback são rejeitados no momento do envio.

Campo Tipo Obrigatório Descrição
type string Sim Deve ser "webhook".
url string Sim A URL de destino. Deve ser uma URI válida.
method string Não Método HTTP: GET, POST, PUT, PATCH ou DELETE. Padrão: POST.
headers object Não Headers HTTP customizados enviados com a requisição. Útil para tokens de autenticação ou chaves de API.
body object|string Não Corpo da requisição. Suporta interpolação de variáveis com sintaxe ${variável}.
timeout duration Não Timeout da requisição (ex: "30s", "5m"). Padrão: configuração do servidor.
async boolean Não Se verdadeiro, a requisição é enviada de forma assíncrona e não bloqueia o workflow.
skipCertVerify boolean Não Se verdadeiro, ignora a verificação do certificado TLS. Use apenas em ambientes de desenvolvimento.
EmailAction type: "email"

Envia um email pelo SMTP customizado (quando configurado) ou pelo postman do sistema.

Campo Tipo Obrigatório Descrição
to string[] Sim Endereços destinatários. Pelo menos um é obrigatório.
subject string Não Assunto do email.
body string Não Corpo do email. Suporta interpolação ${variável}.
cc string[] Não Lista opcional de destinatários em cópia (CC).
bcc string[] Não Lista opcional de destinatários em cópia oculta (BCC).
html boolean Não Se verdadeiro, o corpo é enviado como HTML; caso contrário, como texto simples.
SmsAction type: "twilio-sms"

Dispara um SMS fire-and-forget via Twilio. Apenas informativo — sem correlação por short-code nem rastreio de resposta.

Campo Tipo Obrigatório Descrição
to string[] Sim Números em formato E.164 (ex.: +14155552671). Duplicatas e entradas inválidas são rejeitadas.
body string Sim Texto da mensagem (até 1600 caracteres). Suporta interpolação ${variável}.
Requer plano com Twilio habilitado e integração Twilio configurada no tenant. Destinatários em lista de opt-out são ignorados e a quota diária do tenant é aplicada. Deve usar a forma wrapped ({"type":"twilio-sms", ...}) para evitar ambiguidade com email.
Interpolação de Variáveis

Você pode usar as seguintes variáveis dentro dos valores do body do webhook. Elas são substituídas automaticamente no momento da execução.

Variável Descrição
${id} O UUID único do workflow.
${status} Status atual do workflow (ex: approved, rejected, expired).
${current_step} O identificador do step atualmente ativo.
${escalation_level} Nível de profundidade do escalonamento atual (0 se nenhum escalonamento ocorreu).
Exemplo de Requisição
{
  "on": {
    "workflow_approved": [
      {
        "type": "webhook",
        "data": {
          "url":     "https://api.yourapp.com/webhooks/approved",
          "method":  "POST",
          "headers": { "Authorization": "Bearer your-token" },
          "body": {
            "workflow_id":  "${id}",
            "status":       "${status}",
            "current_step": "${current_step}"
          },
          "timeout": "30s"
        }
      }
    ],
    "workflow_rejected": [
      {
        "type": "webhook",
        "data": {
          "url":   "https://api.yourapp.com/webhooks/rejected",
          "async": true
        }
      }
    ],
    "step_approved": [
      {
        "type": "webhook",
        "data": {
          "url":  "https://api.yourapp.com/webhooks/step-done",
          "body": {
            "step": "${current_step}"
          }
        }
      }
    ]
  }
}
Ações por Step

Além dos eventos no nível do workflow, cada step pode registrar suas próprias ações que disparam quando AQUELE step é aprovado ou rejeitado — independente do resultado final do workflow. Use `step.actions.approved` e `step.actions.rejected` para disparar webhooks ou emails por decisão.

{
  "workflow": {
    "review": {
      "type": "email",
      "data": {
        "to":      ["[email protected]"],
        "subject": "Please review",
        "body":    "Approve or reject ${id}"
      },
      "actions": {
        "approved": [
          {
            "type": "webhook",
            "data": {
              "url":    "https://example.com/hooks/review-approved",
              "method": "POST"
            }
          }
        ],
        "rejected": [
          {
            "type": "email",
            "data": {
              "to":      ["[email protected]"],
              "subject": "Review rejected",
              "body":    "${id} was rejected"
            }
          }
        ]
      }
    }
  }
}

Custo: cada webhook conta como 1 crédito; cada destinatário em ações de email ou twilio-sms conta como 1 crédito por destinatário. CC e BCC em ações de email não são cobrados.

Custo em créditos

Cada step custa 1 crédito mais 1 por nível de escalonamento configurado. Actions de envio externo adicionam um único crédito flat, compartilhado entre webhook e twilio-sms.

Tipo Custo
webhook +1 por workflow (independente da quantidade de webhooks ou eventos).
email Sem custo adicional.
twilio-sms +1 por workflow (compartilhado com webhook — máximo +1 no total).
twilio-whatsapp +1 por workflow (compartilhado com webhook — máximo +1 no total).
discord +1 por workflow (independente da quantidade de webhooks ou eventos).

Os créditos são debitados uma única vez no momento da criação do workflow. Não há cobrança por disparo.

Referência de Objetos

Descrição detalhada de todos os objetos de requisição e resposta.

Step
Campo Tipo Obrigatório Descrição
type string Sim Tipo de notificação. Suportado atualmente: email, ms-teams, slack, whatsapp, telegram, dingtalk, discord, twilio-sms, twilio-whatsapp
data EmailData | MSTeamsData | SlackData | WhatsAppData | TelegramData | DingTalkData | DiscordData | TwilioSMSData | TwilioWhatsAppData Sim Payload de notificação. O formato depende do tipo.
minApprovals integer Não Número mínimo de aprovações necessárias para avançar. Padrão: 1.
minRejections integer Não Número mínimo de rejeições necessárias para rejeitar o workflow. Padrão: 1.
approved string Não Chave do passo a executar quando este for aprovado. Omitir para encerrar o workflow como aprovado.
rejected string Não Chave do passo a executar quando este for rejeitado. Omitir para encerrar o workflow como rejeitado.
escalation Escalation Não Configuração opcional de escalonamento para acionar caso os aprovadores não respondam a tempo.
actions {approved, rejected} Não Ações opcionais disparadas quando ESTE step for aprovado ou rejeitado, independente do resultado final do workflow. Veja a seção Actions para os formatos suportados. (Ações por Step)
Channel delivery

A entrega em canal compartilhado publica uma mensagem de aprovação em canal de equipe, grupo ou chat. Apenas usuários em allowList podem clicar nos botões interativos; o log registra quem clicou, não o ID do canal.

Tipo Descrição
slack to: ID do canal (C…). allowList: IDs Slack (U…) e/ou e-mails do workspace. Exige Signing Secret.
ms-teams to: teamId/channelId. allowList: object IDs Azure AD e/ou e-mails. Posts em canal usam uma API protegida do Microsoft Graph — o tenant precisa conceder Resource-Specific Consent (ex.: ChannelMessage.Send) no app Teams ou permissão de aplicação aprovada pelo administrador. O bot Apruvly deve estar instalado na equipe de destino.
telegram to: chat ID negativo de grupo/canal (-100…). allowList: IDs de usuário Telegram. Bot precisa ser membro do grupo.
discord to: snowflake do canal (17–20 dígitos). allowList: snowflakes de usuário Discord. Exige URL de Interactions e Public Key.
dingtalk DingTalk sempre faz broadcast para o grupo do robot — delivery: "channel" é rejeitado.
CardOverride
Campo Tipo Obrigatório Descrição
title string Não Título opcional que substitui o título da notificação ou embed.
description string Não Texto opcional exibido no corpo da notificação ou na descrição do embed.
links string[] Não URLs opcionais renderizadas como botões de ação (ex: ver solicitação).
EmailData — usado quando type = email
Campo Tipo Obrigatório Descrição
to string[] Sim Lista de endereços de e-mail dos aprovadores para este passo.
subject string Sim Assunto do e-mail de aprovação.
body string Sim Mensagem em texto simples ou HTML para o aprovador. object.title e object.description aparecem automaticamente em um card de resumo; os botões de aprovar/rejeitar são adicionados para você.
cc string[] Não Lista opcional de destinatários em cópia (CC).
bcc string[] Não Lista opcional de destinatários em cópia oculta (BCC).
isHtml boolean Não Defina como true se o body contiver marcação HTML. Padrão: false.
Variáveis do corpo do e-mail

Estes placeholders podem ser usados no assunto e no corpo.

Variável Descrição
${title} Título do objeto do workflow (também exibido no card de resumo).
${description} Descrição do objeto do workflow (também exibida no card de resumo).
${id} O UUID único do workflow.
${user_email} Endereço de e-mail do destinatário.
${user_name} Nome de exibição do destinatário, ou a parte local do e-mail quando não houver nome.
SlackData — usado quando type = slack
Campo Tipo Obrigatório Descrição
delivery string Não Modo de entrega: omitir ou "direct" (padrão) envia uma mensagem por destinatário; "channel" publica uma mensagem em destino compartilhado com lista de autorizados. Suportado em slack, ms-teams, telegram e discord.
allowList string[] Não Quando delivery for "channel", lista de e-mails e/ou IDs nativos do provedor autorizados a clicar em Aprovar/Rejeitar. Obrigatório no modo canal.
to string[] Sim Modo direct: e-mails do workspace (uma DM por destinatário). Modo channel: IDs de canal Slack começando com C.
card CardOverride Não Substituição opcional por step para o título, descrição e links de ação da notificação. Quando omitido, os campos do objeto do workflow são usados.
Para entrega em canal, configure o Signing Secret e a URL de webhook em /integrations. Convide o bot para o canal de destino.
MSTeamsData — usado quando type = ms-teams
Campo Tipo Obrigatório Descrição
delivery string Não Modo de entrega: omitir ou "direct" (padrão) envia uma mensagem por destinatário; "channel" publica uma mensagem em destino compartilhado com lista de autorizados. Suportado em slack, ms-teams, telegram e discord.
allowList string[] Não Quando delivery for "channel", lista de e-mails e/ou IDs nativos do provedor autorizados a clicar em Aprovar/Rejeitar. Obrigatório no modo canal.
to string[] Sim Modo direct: e-mails Azure AD. Modo channel: pares teamId/channelId (uma mensagem por entrada).
card CardOverride Não Substituição opcional por step para o título, descrição e links de ação da notificação. Quando omitido, os campos do objeto do workflow são usados.
A entrega em canal publica Adaptive Cards via Microsoft Graph (POST /teams/{teamId}/channels/{channelId}/messages). É uma API protegida: adicione Resource-Specific Consent no manifesto do app Teams (ex.: ChannelMessage.Send.All) ou obtenha aprovação da Microsoft para permissões de aplicação. Instale o app Apruvly na equipe de destino e defina delivery como channel com allowList.
WhatsAppData — usado quando type = whatsapp
Campo Tipo Obrigatório Descrição
to string[] Sim Lista de telefones dos aprovadores em formato E.164 (ex: +5511999999999).
card CardOverride Não Substituição opcional por step para o título, descrição e links de ação da notificação. Quando omitido, os campos do objeto do workflow são usados.
Requer integração WhatsApp (Meta) configurada. Destinatários são contatados via números E.164.
TelegramData — usado quando type = telegram
Campo Tipo Obrigatório Descrição
delivery string Não Modo de entrega: omitir ou "direct" (padrão) envia uma mensagem por destinatário; "channel" publica uma mensagem em destino compartilhado com lista de autorizados. Suportado em slack, ms-teams, telegram e discord.
allowList string[] Não Quando delivery for "channel", lista de e-mails e/ou IDs nativos do provedor autorizados a clicar em Aprovar/Rejeitar. Obrigatório no modo canal.
to string[] Sim Modo direct: chat IDs positivos de usuário (ex: 123456789). Modo channel: chat IDs negativos de grupo/canal (ex: -1001234567890).
markdown boolean Não Quando verdadeiro, a mensagem é enviada em formato MarkdownV2 do Telegram em vez de HTML. O campo de descrição pode conter sintaxe MarkdownV2 (ex: *negrito*, _itálico_, `código`). Padrão: false.
card CardOverride Não Substituição opcional por step para o título, descrição e links de ação da notificação. Quando omitido, os campos do objeto do workflow são usados.
Requer integração Telegram configurada. Modo direct: destinatários precisam ter iniciado conversa com o bot. Modo channel: bot precisa ser membro do grupo de destino.
DiscordData — usado quando type = discord
Campo Tipo Obrigatório Descrição
delivery string Não Modo de entrega: omitir ou "direct" (padrão) envia uma mensagem por destinatário; "channel" publica uma mensagem em destino compartilhado com lista de autorizados. Suportado em slack, ms-teams, telegram e discord.
allowList string[] Não Quando delivery for "channel", lista de e-mails e/ou IDs nativos do provedor autorizados a clicar em Aprovar/Rejeitar. Obrigatório no modo canal.
to string[] Sim Modo direct: snowflakes de usuário Discord (17–20 dígitos). Modo channel: snowflake do canal. O bot precisa compartilhar servidor com destinatários de DM.
card CardOverride Não Substituição opcional por step para o título, descrição e links de ação da notificação. Quando omitido, os campos do objeto do workflow são usados.
Para entrega em canal, configure a URL de Interactions e a Public Key em /integrations. O bot precisa ter acesso ao canal de destino.
DingTalkData — usado quando type = dingtalk
Campo Tipo Obrigatório Descrição
to string[] Não Celulares opcionais (E.164) para @mention no ActionCard do grupo. DingTalk sempre posta no grupo do robot configurado.
card CardOverride Não Substituição opcional por step para o título, descrição e links de ação da notificação. Quando omitido, os campos do objeto do workflow são usados.
Requer integração DingTalk configurada. Mensagens vão para o grupo do robot; to opcional lista celulares para @mentions.
TwilioSMSData — usado quando type = twilio-sms
Campo Tipo Obrigatório Descrição
to string[] Sim Informe números em formato E.164 (ex: +5511999999999). Os destinatários precisam ter consentido em receber SMS.
card CardOverride Não Substituição opcional por step para o título, descrição e links de ação da notificação. Quando omitido, os campos do objeto do workflow são usados.
Requer que a integração Twilio esteja configurada na sua conta e que o plano permita o Twilio. Os aprovadores são contatados via SMS usando o número E.164 informado.
TwilioWhatsAppData — usado quando type = twilio-whatsapp
Campo Tipo Obrigatório Descrição
to string[] Sim Telefone do WhatsApp Sender registrado na Twilio em formato E.164 (sem o prefixo whatsapp:).
card CardOverride Não Substituição opcional por step para o título, descrição e links de ação da notificação. Quando omitido, os campos do objeto do workflow são usados.
Escalation
Campo Tipo Obrigatório Descrição
type string Sim Tipo de notificação para o escalonamento. Suportado atualmente: email, ms-teams, slack, whatsapp, telegram, dingtalk, discord, twilio-sms, twilio-whatsapp
after duration Sim Quanto tempo aguardar antes de acionar o escalonamento. Mínimo: 5m.
data EmailData | TelegramData | … Sim Payload de notificação enviado aos destinatários do escalonamento.
escalation Escalation Não Escalonamento aninhado opcional para acionar caso este nível de escalonamento também não seja respondido. Profundidade máxima: 5.
Decision — retornado dentro de decisions[] em GET /workflow/{id}
Campo Tipo Descrição
user string Endereço de e-mail do aprovador que submeteu a decisão.
is_approved boolean true se aprovado, false se rejeitado.
ip string Endereço IP de onde a decisão foi submetida.
decisionAt RFC3339 Timestamp RFC 3339 de quando a decisão foi registrada.
SMTP personalizado (integração da conta)

Planos Business e Professional podem enviar e-mails de aprovação pelo seu SMTP em vez do mailer da plataforma. Configure em Configurações → Integrações → SMTP personalizado (não no JSON do workflow).

  • Host, porta, remetente e usuário/senha opcionais. Use Enviar e-mail de teste antes de workflows em produção.
  • Porta 587 com STARTTLS (interruptor TLS desligado) ou porta 465 com TLS implícito (interruptor TLS ligado). IPs privados e reservados são bloqueados.
  • Use um remetente que seu servidor aceite relayar (em geral uma caixa em domínio com SPF/DKIM autenticado).
  • Credenciais criptografadas em repouso (AES-256-GCM). Conexões exigem TLS 1.2+. E-mails de teste vão apenas para o e-mail da sua conta.
  • Entrega, bounces e alinhamento SPF/DKIM/DMARC são impostos pelo seu servidor SMTP — a Apruvly não verifica o domínio de envio.
Regras de Identificador de Etapa

As chaves de etapa (usadas nos campos start, approved e rejected, e como chaves do mapa workflow) devem corresponder ao seguinte padrão - letra minúscula seguida de letras minúsculas, dígitos, hífens ou underscores:

^[a-z][a-z0-9_-]+$
Formato de Duração

Durações são expressas como um número seguido de um sufixo de unidade:

30s — 30 segundos 15m — 15 minutos 2h — 2 horas 7d — 7 dias 2w — 2 semanas

A expiração do workflow deve estar entre 5 minutos (mínimo) e 7 dias (máximo).

Erros

A API usa códigos de status HTTP padrão. Respostas de erro incluem um corpo JSON com os campos error e code.

Código de Status Significado
200 Requisição realizada com sucesso.
202 Accepted - o workflow foi criado e está em execução.
400 Bad Request - o corpo ou parâmetros da requisição são inválidos.
401 Unauthorized - chave de API ausente ou inválida.
402 Payment Required - sem assinatura ativa, créditos insuficientes ou o plano atual não inclui a feature solicitada.
403 Forbidden - a chave de API não tem permissão para este recurso (ex.: você não é o dono do workflow).
404 Not Found - o workflow ou recurso não existe.
406 Not Acceptable - a operação não pode ser realizada no estado atual do workflow (ex.: cancelar um workflow já concluído).
429 Too Many Requests - limite de requisições excedido.
500 Internal Server Error - algo deu errado do nosso lado.
Corpo da Resposta de Erro
{
  "success": false,
  "message": "Invalid workflow ID.",
  "data": {
    "field": "id",
    "value": "not-a-valid-uuid"
  }
}

Casos de uso comuns com descrições amigáveis para ajudá-lo a começar rapidamente.

01
Aprovação Simples em Uma Etapa

O caso de uso mais básico: uma única pessoa precisa aprovar algo antes de você prosseguir. Ideal para aprovações de despesas, revisão de conteúdo ou qualquer cenário com um único aprovador.

single approver expense beginner
02
Cadeia de Aprovação Multinível

Encaminhe uma aprovação por várias pessoas em sequência - Jurídico → Gerente → CEO. Cada etapa deve ser aprovada antes que a próxima comece. Perfeito para assinaturas de contratos ou aprovações de políticas.

multi-step contract sequential
03
Aprovação com Escalonamento Automático

Se o aprovador designado não responder dentro de um prazo, notifique automaticamente um contato substituto. Mantém os processos em andamento sem acompanhamento manual.

escalation auto-escalate deadline
04
Votação em Grupo (Aprovação por Quórum)

Exija um número mínimo de aprovações de um grupo - qualquer N de M membros pode aprovar. Útil para decisões de diretoria, aprovações de comitê ou revisões por pares.

quorum committee group vote
05
Notificação por Webhook na Conclusão

Envie automaticamente um POST para o seu backend quando um workflow atingir uma decisão final. Acione automação subsequente sem fazer polling da API.

webhook automation integration
06
Validar Payload Antes de Enviar

Verifique se a configuração do seu workflow é válida antes de criá-lo. Não requer autenticação, não consome créditos - apenas uma verificação rápida de sintaxe e lógica.

validate no auth dry run
07
Cadeia de Onboarding de Funcionário

Encaminhe a aprovação de um novo contratado pelo RH, gerente de contratação e provisionamento de TI em sequência. Cada equipe só recebe a solicitação após a etapa anterior ser concluída.

hr onboarding sequential
08
Solicitação de Folga com Escalonamento

Uma solicitação de folga enviada ao gestor direto. Se não houver resposta em 24 horas, o RH é notificado automaticamente. Um webhook é disparado quando a decisão é tomada.

hr time-off simple
09
Aprovação de Deploy em Produção

Condicione um deploy em produção a três aprovações sequenciais: revisão de código pelo líder técnico, sign-off do QA e autorização de operações. Um webhook aciona o pipeline de CI/CD após aprovação.

devops deployment webhook
10
Solicitação de Orçamento com Duplo Escalonamento

Cadeia de aprovação em dois níveis (gerente e depois CFO), cada um com seu próprio escalonamento. Se o gerente não responder, o VP assume; se o CFO atrasar, o CEO é notificado. Webhooks cuidam da automação financeira.

budget escalation webhook multi-step
11
Aprovação em Canal Slack Compartilhado

Publica uma mensagem de aprovação em um canal Slack compartilhado. Configure delivery: "channel", o ID do canal em to e uma allowList de usuários autorizados a clicar em Aprovar/Rejeitar.

slack channel delivery allow-list

Servidor MCP

Endpoint JSON-RPC 2.0 para agentes de IA e pipelines de automação

O endpoint MCP segue a especificação do Model Context Protocol usando JSON-RPC 2.0 sobre HTTP. Permite que agentes de IA e ferramentas de automação pausem a execução e solicitem aprovação humana antes de realizar ações críticas.

Endpoint
POST https://mcp.apruvly.io/mcp
Autenticação Obrigatório
Authorization: Bearer wf_YOUR_API_KEY
Content-Type: application/json
Descoberta Opcional

Clientes MCP-aware podem buscar um documento de descoberta público em GET /.well-known/mcp para auto-detectar a URL do endpoint, transports e versões de protocolo suportadas, esquema de autenticação, e o catálogo de ferramentas disponíveis. Não requer autenticação.

GET https://mcp.apruvly.io/.well-known/mcp
{
  "endpoint": "https://mcp.apruvly.io/mcp",
  "transports": ["streamable-http"],
  "protocolVersions": ["2025-03-26"],
  "auth": { "scheme": "bearer" },
  "tools": ["create_approval_request", "get_approval_status", "cancel_approval_request"]
}
Como funciona

Seu agente de IA chama create_approval_request com um título, descrição e os emails dos aprovadores.

Apruvly envia um email de aprovação para cada aprovador contendo links de aprovar/rejeitar.

O agente consulta get_approval_status até o status mudar para aprovado, rejeitado ou expirado.

Integrações

Exemplos de configuração para ferramentas de IA populares

Adicione a seguinte entrada de servidor MCP ao arquivo .mcp.json do seu projeto ou nas configurações globais:

{
  "mcpServers": {
    "apruvly": {
      "type": "streamable-http",
      "url": "https://mcp.apruvly.io/mcp",
      "headers": {
        "Authorization": "Bearer wf_YOUR_API_KEY"
      }
    }
  }
}

Adicione o seguinte à seção mcpServers no arquivo de configuração do Claude Desktop:

{
  "mcpServers": {
    "apruvly": {
      "url": "https://mcp.apruvly.io/mcp",
      "headers": {
        "Authorization": "Bearer wf_YOUR_API_KEY"
      }
    }
  }
}

Adicione o servidor MCP nas configurações do Cursor em Features > MCP Servers, ou adicione ao .cursor/mcp.json no seu projeto:

{
  "mcpServers": {
    "apruvly": {
      "url": "https://mcp.apruvly.io/mcp",
      "headers": {
        "Authorization": "Bearer wf_YOUR_API_KEY"
      }
    }
  }
}

Adicione a seguinte entrada de servidor MCP ao arquivo .mcp.json do seu projeto ou nas configurações globais:

// .vscode/mcp.json
{
  "servers": {
    "apruvly": {
      "type": "http",
      "url": "https://mcp.apruvly.io/mcp",
      "headers": {
        "Authorization": "Bearer wf_YOUR_API_KEY"
      }
    }
  }
}

Qualquer cliente compatível com MCP pode se conectar ao endpoint Apruvly usando transporte Streamable HTTP. Envie requisições JSON-RPC 2.0 diretamente:

curl -X POST https://mcp.apruvly.io/mcp \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-03-26",
      "clientInfo": {"name": "my-agent", "version": "1.0"},
      "capabilities": {}
    }
  }'

Ferramentas

Ferramentas disponíveis que agentes de IA podem invocar via tools/call

create_approval_request

Cria uma solicitação de aprovação humana e retorna um workflow_id que pode ser usado para consultar a decisão. A notificação é enviada pelo canal escolhido em `channel` (padrão email); canais não-email precisam estar configurados na conta.

Parâmetros
Campo Tipo Descrição
title string Obrigatório Título curto (máx 200 caracteres) descrevendo o que requer aprovação.
description string Opcional Descrição detalhada da ação que requer aprovação humana (máx 4000 caracteres).
channel string Opcional Canal de entrega. Padrão: "email". Permitidos: email, slack, ms-teams, whatsapp, telegram, dingtalk, discord, twilio-sms, twilio-whatsapp. Canais que não sejam email exigem que a integração correspondente esteja configurada em /integrations.
recipients array Opcional Lista uniforme de destinatários, uma entrada por aprovador. Use para mirar qualquer canal. O formato de address depende do canal (email/slack/ms-teams = endereço de email, whatsapp/twilio-sms/twilio-whatsapp = telefone E.164, telegram = chat ID numérico, discord = snowflake de 17-20 dígitos). Mutuamente exclusivo com approvers e steps.
approvers array Opcional Aprovadores (emails separados por vírgula) — {"email":"…","name":"…"}. Email-only shortcut; for other channels use recipients.
steps array Opcional Cadeia opcional de aprovações sequenciais. Cada step precisa ser aprovado antes do próximo rodar; qualquer rejeição encerra o workflow. Requer plano Growth, Business ou Professional. Mutuamente exclusivo com recipients/approvers no nível superior.
expires string Opcional String de duração: "1h", "24h", "7d". Padrão: "24h". Mínimo: 5 minutos — valores menores são rejeitados antes de qualquer débito de crédito.
links array Opcional Lista de URLs relacionadas (documentos, arquivos, links).
tags array Opcional Lista de rótulos para filtragem e categorização.
idempotency_key string Opcional Identificador opcional fornecido pelo cliente (máx 128 caracteres) que torna a chamada idempotente. Repetir a mesma chave em até 24h retorna o workflow_id original sem recriar workflow nem cobrar créditos. Equivalente ao header HTTP Idempotency-Key.
callback_url string Opcional URL https opcional que recebe um POST assinado quando o workflow chega a um estado terminal. Útil para agentes em batch que não conseguem manter uma conexão de polling ou SSE aberta.
external_id string Opcional Identificador opcional fornecido pelo chamador (máx 128 caracteres) — ex: run_id do agente, tool_call_id externo, ticket id interno. Requer plano Growth ou superior. Persistido na linha do workflow e ecoado em get_approval_status.
Corpo da Requisição
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "create_approval_request",
    "arguments": {
      "title": "Deploy to production",
      "description": "Requesting approval to deploy v2.5.0 to production.",
      "channel": "slack",
      "recipients": [
        { "address": "[email protected]" }
      ],
      "expires": "24h",
      "idempotency_key": "agent-run-2026-05-03-00042",
      "external_id": "deploy-pipeline-7831"
    }
  }
}
Resposta 200
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      { "type": "text", "text": "Approval request created…" },
      { "type": "text", "text": "{\"workflow_id\":\"550e8400-…\",\"status\":\"pending\",\"expires_at\":\"2026-05-04T12:00:00Z\",\"external_id\":\"deploy-pipeline-7831\"}" }
    ],
    "structuredContent": {
      "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
      "status": "pending",
      "expires_at": "2026-05-04T12:00:00Z",
      "external_id": "deploy-pipeline-7831"
    }
  }
}

As respostas das tools também carregam um campo structuredContent espelhando o snapshot JSON do segundo content — declarado pelo outputSchema da tool para que clientes MCP-aware façam parse tipado sem varrer o payload em texto.

Exemplo — multi-step + escalation

A two-step chain: the manager has 24h to approve before the request escalates to the director, and only after the manager approves does the VP get the second-level request.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "create_approval_request",
    "arguments": {
      "title": "Vendor Contract – Novatek",
      "channel": "email",
      "steps": [
        {
          "name": "manager",
          "recipients": [{ "address": "[email protected]" }],
          "escalate_after": "24h",
          "escalate_to": [{ "address": "[email protected]" }]
        },
        {
          "name": "vp",
          "recipients": [{ "address": "[email protected]" }]
        }
      ],
      "expires": "7d"
    }
  }
}
get_approval_status

Retorna o status atual e as decisões de etapa de uma solicitação de aprovação. Consulte após create_approval_request até o status mudar para aprovado, rejeitado ou expirado.

Parâmetros
Campo Tipo Descrição
workflow_id string Obrigatório O ID do workflow retornado quando o workflow foi criado.
wait string Opcional Duração opcional de long-poll (ex: "30s", "60s", "1m"). Quando setado, a chamada bloqueia até o workflow sair do estado pendente ou a duração esgotar, o que vier primeiro. Limitado a 60s. Reduz o número de round-trips de polling.
Corpo da Requisição
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "get_approval_status",
    "arguments": {
      "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
      "wait": "60s"
    }
  }
}
Resposta 200
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      { "type": "text", "text": "Approval status retrieved." },
      { "type": "text", "text": "{\"workflow_id\":\"550e8400-…\",\"status\":\"approved\",\"current_step\":\"approval\",\"external_id\":\"deploy-pipeline-7831\",\"decisions\":[…]}" }
    ],
    "structuredContent": {
      "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
      "status": "approved",
      "current_step": "approval",
      "created_at": "2026-05-03T11:00:00Z",
      "expires_at": "2026-05-04T12:00:00Z",
      "external_id": "deploy-pipeline-7831",
      "decisions": [{ "user": "[email protected]", "is_approved": true, "decided_at": "2026-05-03T11:42:18Z", "step": "manager" }]
    }
  }
}

Cada entrada em decisions pode incluir um campo step opcional com o nome do step no momento da decisão. Workflows single-step legados podem omiti-lo.

cancel_approval_request

Cancela uma solicitação de aprovação pendente. Para os lembretes, notifica os aprovadores em todos os canais configurados que a solicitação foi cancelada e marca o workflow como cancelado em estado terminal. Idempotente: uma segunda chamada em um workflow já cancelado retorna sucesso com already_canceled=true.

Parâmetros
Campo Tipo Descrição
workflow_id string Obrigatório O ID do workflow retornado quando o workflow foi criado.
reason string Opcional Motivo opcional em texto livre para o cancelamento (máx 500 caracteres). Registrado no log de atividades do workflow para auditoria do motivo da retirada.
Corpo da Requisição
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "cancel_approval_request",
    "arguments": {
      "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
      "reason": "agent retry resolved the action without human approval"
    }
  }
}
Resposta 200
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      { "type": "text", "text": "Approval request canceled." },
      { "type": "text", "text": "{\"workflow_id\":\"550e8400-…\",\"status\":\"canceled\",\"already_canceled\":false,\"canceled_at\":\"2026-05-03T12:34:56Z\"}" }
    ],
    "structuredContent": {
      "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
      "status": "canceled",
      "already_canceled": false,
      "canceled_at": "2026-05-03T12:34:56Z"
    }
  }
}

Referência do Protocolo

Métodos JSON-RPC 2.0, handshake e códigos de erro

Métodos
Método Descrição
initialize Inicializa uma sessão MCP. Negocia a versão do protocolo (ecoa a versão do cliente quando suportada, faz downgrade para a maior versão suportada abaixo dela, ou retorna -32602 com a lista suportada quando nenhuma versão compatível existe) e retorna informações do servidor e capacidades.
ping Verificação de saúde. Retorna um objeto de resultado vazio.
tools/list Retorna a lista de ferramentas disponíveis, suas definições de esquema JSON de entrada e um outputSchema descrevendo o structuredContent que cada ferramenta retorna.
tools/call Invoca uma ferramenta pelo nome com os argumentos fornecidos.
notifications/* Métodos iniciados com notifications/ são aceitos com HTTP 202 e sem corpo de resposta, conforme exigido pela especificação. notifications/cancelled é honrado para abortar uma tools/call em vôo (veja "Notificações" abaixo); o restante é descartado silenciosamente.
Exemplo — initialize
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-03-26",
    "clientInfo": { "name": "my-agent", "version": "1.0" },
    "capabilities": {}
  }
}
Resposta 200
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-03-26",
    "serverInfo": { "name": "apruvly", "version": "1.0.0" },
    "capabilities": { "tools": {} },
    "instructions": "Apruvly is a human-in-the-loop approval service…"
  }
}
Requisições em lote

O endpoint aceita um array JSON de requisições no corpo (máx. 50 itens) e retorna um array de respostas. Itens são processados sequencialmente; wait em get_approval_status é limitado a 5s dentro de um lote. Entradas notifications/cancelled no mesmo array são aplicadas antes de qualquer tools/call. Notificações não geram entrada no array; um lote contendo apenas notificações retorna 202 Accepted com corpo vazio. Um array vazio é rejeitado com -32600 Invalid Request.

Corpo da Requisição
[
  { "jsonrpc": "2.0", "id": 1, "method": "ping" },
  { "jsonrpc": "2.0", "id": 2, "method": "tools/call",
    "params": { "name": "get_approval_status",
      "arguments": { "workflow_id": "550e8400-e29b-41d4-a716-446655440000" } } }
]
Resposta 200
[
  { "jsonrpc": "2.0", "id": 1, "result": {} },
  { "jsonrpc": "2.0", "id": 2, "result": { "content": [ … ], "structuredContent": { … } } }
]
Notificações honradas

notifications/cancelled aborta uma chamada tools/call em vôo para que o agente encurte um long-poll sem esperar o timer disparar. Combine o campo requestId com o id da requisição que se quer cancelar; a chamada em execução devolve o snapshot atual imediatamente. Dentro de um lote, inclua a notificação no mesmo array — ela é honrada antes dos itens tools/call. Para abortar um long-poll já em vôo em outra conexão, envie notifications/cancelled como POST sibling. Cancelar um requestId que não está em vôo é um no-op silencioso.

Exemplo — notifications/cancelled
{
  "jsonrpc": "2.0",
  "method": "notifications/cancelled",
  "params": {
    "requestId": 2,
    "reason": "agent changed its mind"
  }
}

Resposta 202 Accepted — empty body, per the JSON-RPC notification convention. The matching tools/call wakes from its long-poll and returns its current snapshot to the original caller.

Códigos de Erro JSON-RPC

Erros no nível da aplicação usam o código -32000 com um slug estável em data.code para que agentes possam ramificar programaticamente sem fazer parse do texto da mensagem.

Código Significado
-32700 Parse error — invalid JSON body.
-32600 Invalid Request — missing jsonrpc or method.
-32601 Method not found.
-32602 Invalid params — missing or malformed arguments. Also returned by initialize when the client requests a protocol version older than anything the server supports (the response carries data.supported with the list of acceptable versions).
-32603 Internal error.
-32000 Application error — branch on the stable slug under data.code (see table below).
data.code slugs (application errors)
data.code Significado extra data fields
subscription_required The caller has no active subscription.
plan_feature_required The current plan does not include the requested feature (MCP access, multi-step approval, …). feature
integration_not_configured The chosen channel needs an integration that the tenant has not configured at /integrations. channel, integration
trial_expired Trial period has expired; upgrade to continue.
approver_limit_exceeded The workflow lists more approvers than the plan allows. max
escalation_limit_exceeded The escalation chain is deeper than the plan allows. max
concurrent_workflow_limit The plan's cap on simultaneously-pending workflows was reached. max
rate_limited Too many requests in the current window. Retry after retry_after_seconds. window, retry_after_seconds
insufficient_credits Account balance cannot cover the cost of the workflow.
workflow_not_found The workflow_id does not exist for the calling account. Cross-tenant lookups intentionally return the same slug to avoid leaking existence.
workflow_not_cancelable cancel_approval_request was called on a workflow already in a non-pending terminal state (approved, rejected, expired, error). status
Corpo da Resposta de Erro
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "Rate limit exceeded, try again in a moment",
    "data": {
      "code": "rate_limited",
      "window": "minute",
      "retry_after_seconds": 60
    }
  }
}