Integração de Apps do Marketplace
Se você está desenvolvendo um aplicativo e deseja integrá-lo ao Workflow, esta documentação mostra como fazer isso.
Um app se integra ao Workflow publicando um manifesto de ações (iugu.actions/v1): um documento JSON com as
ações (actions) que o Workflow pode chamar e os gatilhos (triggers) que podem iniciar um fluxo. O mesmo manifesto é
lido pelo Iugu for AI (onde cada ação vira uma ferramenta) e pela CLI iugu — você descreve sua API uma vez só.
Para que o Workflow encontre o seu app, são necessárias duas coisas no Console:
- o entitlement
actions_providerno app (Apps › Entitlements, ouiugu app entitlements set actions_provider); - a
service_api_urldo app apontando para a base da sua API. O manifesto fica emGET {service_api_url}/actions.
Compatibilidade: apps publicados antes desta especificação definiram
service_api_urlcomo a própria rota do manifesto (…/service/workflow/actions). Quandoservice_api_urljá termina em/actions, o Workflow a busca como está; caso contrário, acrescenta/actions. Um manifesto que responde um array de ações (semactions/triggers) também continua sendo lido; um manifesto sem o blocoauthorizationé aceito com um aviso no log do Workflow.
Transformando funções do seu app em actions ou triggers
Nem toda funcionalidade precisa ser reescrita para ser integrada ao Workflow. Muitas vezes, você já possui métodos prontos que podem ser adaptados com facilidade para funcionar como actions ou triggers.
Exemplo 1 — Transformando uma função “baixa em conta corrente” em uma action
Suponha que você tenha a seguinte função no seu backend:
func BaixarConta(id string, valor float64) error {
// lógica de baixa no sistema financeiro
}
Para que essa funcionalidade seja exposta ao Workflow como uma action, você deve:
- Criar uma rota HTTP, por exemplo:
/api/contas/:id/baixa - Estruturar os parâmetros como
ParamInput, indicando se vêm dopath,queryoubody - Declarar em
authorizationa permissão (<tag>:<ação>) que quem chama precisa ter no workspace — uma dasimplemented_actionsdo seu app no Console — e, se for o caso, o nível de autenticação exigido (acr) - Adicionar essa definição em
actionsdo JSON servido em{service_api_url}/actions:
{
"name": "baixar_conta",
"title": "Baixar Conta Corrente",
"label": "Realiza a baixa de uma conta corrente no sistema financeiro",
"description": "Baixa o saldo devedor de uma conta corrente. O valor é em reais e a operação não pode ser desfeita.",
"icon": "https://seusistema.com/icons/finance.svg",
"authorization": { "action": "seusistema:contas.baixar", "acr": "informations" },
"url": "https://seusistema.com/api/contas/:id/baixa",
"method": "POST",
"parameters": [
{
"name": "id",
"type": "string",
"required": true,
"direction": "ParamInput",
"description": "ID da conta a ser baixada",
"source": "path"
},
{
"name": "valor",
"type": "number",
"required": true,
"direction": "ParamInput",
"description": "Valor a ser baixado",
"source": "body"
},
{
"name": "mensagem",
"type": "string",
"required": false,
"direction": "ParamOutput",
"description": "Confirmação de baixa"
}
]
}
📬 Exemplo 2 — Transformando uma função “ao receber mensagem” em um trigger
Se o seu app já possui uma funcionalidade que recebe mensagens (via webhook ou API), você pode transformá-la em um trigger para o Workflow.
Função original:
func ReceberMensagem(mensagem string) {
// salva no banco, envia alerta, etc.
}
O que você precisa fazer:
- Quando a mensagem for recebida, envie um evento para o Workflow:
POST https://workflow.iugu.com/services/event
Authorization: Bearer <access_token com audience Iugu.Platform.3X3OZfVdfhohOZfO2f2Ndq>
Content-Type: application/json
{
"event": "on_new_message",
"workspace_id": "<short id do workspace>",
"payload": {
"message": "Texto da mensagem recebida"
}
}
- Exponha esse trigger em
triggersdo manifesto:
{
"name": "on_new_message",
"title": "Ao receber nova mensagem",
"label": "Dispara quando uma nova mensagem for recebida",
"icon": "https://seusistema.com/icons/chat.svg",
"authorization": { "action": "seusistema:mensagens.ler" },
"parameters": [
{
"name": "message",
"type": "string",
"required": true,
"direction": "ParamOutput",
"description": "Conteúdo da mensagem recebida"
}
]
}
🧠 Resumo
| Tipo | Definição |
|---|---|
| Action | Executa uma operação mediante chamada do Workflow com inputs definidos. |
| Trigger | Emite um evento do seu sistema para o Workflow com dados de saída (output). |
Onde o manifesto fica
| Regra | |
|---|---|
| Endereço | GET {service_api_url}/actions. Se a service_api_url cadastrada no Console já termina em /actions, ela mesma é o manifesto (apps antigos). |
| Requisição | Accept: application/json. O Workflow envia Authorization: Bearer <token client_credentials com aud Iugu.Platform.<seu app>>; o manifesto deve ser público (não coloque segredos nele) — o token só permite personalizar ou limitar a resposta. |
| Cache | Envie Cache-Control: max-age=300 e ETag. O Workflow guarda o manifesto em memória por pelo menos 60 s (5 min quando você não diz nada, no máximo 1 h), revalida com If-None-Match e, se o seu app não responder, continua usando a última cópia boa. O manifesto nunca é buscado a cada execução de fluxo. |
| Limites | Resposta de até 256 KB em até 4 s; redirecionamentos só são seguidos dentro da mesma origem. |
Um exemplo real e público: o manifesto da Central de cobranças (Billing), com 21 ações — 🔗 https://billing.iugu.com/api/actions.
Estrutura do manifesto
{
"spec": "iugu.actions/v1",
"app": {
"client_id": "1qwBQ0DnzRCgtUOItzxMl1",
"tag": "seusistema",
"name": "Seu Sistema",
"icon": "https://seusistema.com/icon.png",
"service_api_url": "https://seusistema.com/api",
"docs_url": "https://seusistema.com/docs"
},
"actions": [ /* lista de ações disponíveis */ ],
"triggers": [ /* lista de eventos disponíveis */ ]
}
| Campo | Obrigatório | Descrição |
|---|---|---|
spec |
Sim | Sempre iugu.actions/v1. Mudanças dentro da v1 são apenas aditivas; consumidores ignoram chaves desconhecidas. |
app |
Recomendado | client_id, tag, name, icon, service_api_url, docs_url do seu app. |
actions |
Sim (pode ser vazio) | Operações que o Workflow poderá executar. |
triggers |
Sim (pode ser vazio) | Eventos que poderão iniciar um fluxo. |
Campos de uma ação
| Campo | Obrigatório | Descrição |
|---|---|---|
name |
Sim | Identificador estável, snake_case, único no manifesto (ex.: insert_data). É por ele que o Workflow encontra a ação de um fluxo salvo — mude a url à vontade, não mude o name. |
title |
Sim | Nome curto para exibição (Title Case). |
label |
Sim | Descrição de uma linha, mostrada nas listas. |
description |
Não | Texto longo, mostrado no inspetor do nó e usado como descrição da ferramenta pelo Iugu for AI. |
icon |
Não | URL absoluta de um ícone SVG/PNG. |
authorization |
Sim | action: permissão GIA <tag>:<ação> que quem chama precisa ter no workspace (uma das implemented_actions do app). acr (opcional): informations (padrão), config ou transfers — nível de autenticação que a pessoa precisa ter. Veja Autorização. |
url |
Sim | URL absoluta, na mesma origem da service_api_url (o Workflow recusa qualquer outra). Use :nome para parâmetros com source: path. |
method |
Sim | GET, POST, PUT, PATCH ou DELETE. Sem method, o Workflow assume POST. |
annotations |
Não | Anotações de ferramenta MCP (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), usadas pelo Iugu for AI. |
parameters |
Sim | Entradas e saídas (abaixo). |
input_schema, output_schema |
Não | JSON Schema que substitui a derivação a partir de parameters (para corpos que não são objetos planos). O Workflow não os usa. |
Campos de um trigger
name (é o valor de event que o app envia em POST /services/event), title, label, icon, description,
authorization.action (permissão que o workspace concede ao app para o evento ser aceito — informativo na v1) e
parameters, todos ParamOutput.
Detalhamento dos parâmetros (parameters)
Cada item de parameters define um campo necessário para execução da ação ou um dado do evento gerado pelo trigger.
| Campo | Obrigatório | Descrição |
|---|---|---|
name |
Sim | Nome interno, snake_case (ex.: spreadsheet_id). Para source: path, corresponde ao :name da url. |
type |
Sim | string · textarea · number · integer · boolean · datetime · json · select · color · lookup (tabela abaixo). |
required |
Sim | Indica se o campo é obrigatório. |
direction |
Sim | ParamInput ou ParamOutput. |
description |
Sim | Explicação do que o parâmetro representa. |
source |
Só em ParamInput |
query, path ou body. Quando omitido: body (ou query em ações GET). |
default |
Não | Valor inicial do campo no editor (value é aceito como sinônimo). |
options |
Em select |
[{ "value", "label" }]. |
lookup |
Em lookup |
{ "endpoint", "method", "params" } — opções dinâmicas, consultadas com um token aud Iugu.Platform.<seu app>. |
hidden, disabled, alias |
Não | Dicas para o editor: hidden esconde o campo (e o exclui das entradas da ferramenta MCP), disabled bloqueia a edição, alias é o rótulo exibido. |
Tipos e como o Workflow os envia
type |
O Workflow envia | JSON Schema (Iugu for AI / CLI) |
|---|---|---|
string, textarea, select, color, lookup |
texto | {"type":"string"} (select: enum com os options[].value; color: pattern ^#[0-9a-fA-F]{6}$) |
number |
número JSON (10.5) |
{"type":"number"} |
integer |
número inteiro JSON (10) |
{"type":"integer"} |
boolean |
booleano JSON (true/false) |
{"type":"boolean"} |
datetime |
string RFC 3339 (2026-09-20T10:00:00-03:00) |
{"type":"string","format":"date-time"} |
json |
o valor interpretado como JSON (objeto ou array) | {"type":["object","array"]} |
Em query e path os valores vão como texto (true, 10, data em RFC 3339). Um valor que não corresponde ao tipo
(ex.: abc em number) faz o nó falhar antes de chamar o seu app.
direction — Input vs Output
ParamInput: são dados que o Workflow precisa fornecer para que a ação seja executada.ParamOutput: são dados gerados ou retornados após a execução da ação ou trigger. A resposta da ação deve ser um objeto JSON cujas chaves de primeiro nível têm os nomes dosParamOutput; cada uma vira uma variável do fluxo.
Em
triggers, todos os parâmetros devem serParamOutput.
source — De onde vem o dado?
Para ParamInput, o campo source define a localização do dado dentro da requisição HTTP:
query: query string (?status=open)path: parâmetro de caminho (/api/sheets/:spreadsheet_id/insert)body: corpo da requisição, um objeto JSON com um campo por parâmetro
Em
ParamOutput, o camposourcepode ser omitido.
Como o Workflow chama uma ação
Toda chamada leva:
<method> <url com os parâmetros de path substituídos e os de query acrescentados>
Authorization: Bearer <JWT com aud Iugu.Platform.<seu app>>
Workspace: <short id do workspace do fluxo>
Content-Type: application/json
- O workspace vem no cabeçalho
Workspace. Um parâmetroworkspace_iddeclarado no manifesto continua sendo preenchido durante a transição, mas prefira o cabeçalho. - O corpo (em
POST,PUT,PATCHe, quando há entradas para ele,DELETE) é um objeto JSON com os parâmetrossource: body, já convertidos para o tipo declarado. - A resposta deve ser JSON. Erros devem seguir o formato problem JSON (RFC 9457):
{ "error": "...", "error_description": "..." }com o status HTTP adequado; o Workflow registra o corpo no log do fluxo.
Autorização de uma ação
O bloco authorization diz o que uma chamada precisa, e é lido antes de o Workflow chamar você:
action— o Workflow consultaPOST /verifydo Console para o seu próprio principal (app:3X3OZfVdfhohOZfO2f2Ndq) nessa ação, no workspace do fluxo. Se o Console responderfalse, o nó falha e o seu app não é chamado. Você deve fazer a mesma verificação do seu lado (semântica AND — veja Deveres do provedor).acr—configetransfersexigem uma autenticação recente da pessoa (segundo fator). O Workflow executa fluxos com o token do próprio app, sem pessoa, e por isso não chama ações com esses níveis: o editor marca o nó (“precisa de autorização humana — não roda sem supervisão”) e a execução falha com essa mensagem. Useinformations(o padrão) em tudo que pode rodar automaticamente.
Autenticação e segurança
Deveres do provedor ao receber uma chamada
Sempre que o Workflow chamar uma action do seu aplicativo, valide o token antes de processar a requisição:
- assinatura pelo JWKS do Console (
https://console.iugu.com/.well-known/jwks.json),iss,expetypat+JWT; audigual aIugu.Platform.<seu app>;POST /verifyno Console comprincipals: [token.sub]eactions: [authorization.action]da ação chamada: o principal (uma pessoa, ou um app agindo como ele mesmo — no caso do Workflow,app:3X3OZfVdfhohOZfO2f2Ndq) precisa ter a permissão no workspace do cabeçalhoWorkspace. Oclient_iddo token é atribuição para registro, não algo a autorizar;- para subjects
user:, exija oacrdeclarado. Quando o contexto de autenticação for insuficiente, responda401comWWW-Authenticate: Bearer error="insufficient_user_authentication", acr_values="<nível>", max_age="<segundos>"(RFC 9470) — é assim que o Iugu for AI sabe que precisa pedir um segundo fator à pessoa.
Isso protege sua aplicação contra chamadas não autorizadas e garante que a permissão seja verificada dos dois lados.
Geração de access token ao executar um trigger
Quando seu app disparar uma trigger para o Workflow, é sua responsabilidade gerar um token de acesso válido
(client_credentials com audience=Iugu.Platform.3X3OZfVdfhohOZfO2f2Ndq) e incluí-lo no header da requisição:
POST https://workflow.iugu.com/services/event
Authorization: Bearer <access_token com audience Iugu.Platform.3X3OZfVdfhohOZfO2f2Ndq>
Content-Type: application/json
{
"event": "on_new_message",
"workspace_id": "<short id do workspace>",
"payload": {
"message": "Texto da mensagem recebida"
}
}
O Workflow valida a assinatura e o aud do token e consulta o Console (/verify) para confirmar que o seu app tem a
permissão workflow:event.create no workspace informado — ela precisa estar entre as consumed_actions do seu app.
⚠️ Triggers disparadas sem um token válido, ou por um app sem
workflow:event.createno workspace, são rejeitadas.
Resumo
| Situação | O que fazer |
|---|---|
| Recebendo chamada do Workflow | Validar o JWT, chamar /verify com token.sub e authorization.action |
| Disparando trigger para Workflow | Gerar token com audience do Workflow; ter workflow:event.create no workspace |
Boas práticas
- Use nomes de parâmetro curtos e significativos, em
snake_case; useTitle Caseemtitle. - Descreva cada parâmetro de forma objetiva — a
descriptionaparece para a pessoa no editor e para o modelo no Iugu for AI. - Declare
authorizationem toda ação, com o menoracrpossível; reserveconfig/transferspara o que realmente exige uma pessoa. - Nunca mude o
namede uma ação publicada; mude aurlquando precisar. - Envie
Cache-ControleETagno manifesto. - Inclua um
iconválido, especialmente para interfaces visuais.