# Documentação da API da Runds

Esta é a referência pública para integrar sistemas e IAs com o **Runds Flow**. Ela foi escrita para ser lida por pessoas e também para ser colada inteira no Claude, no Cursor ou em qualquer outra IA, que passa a conseguir integrar e operar os seus Flows sozinha.

> **Para IAs:** este documento é autossuficiente. Para conectar, comece por [Começar pelo seu agente](#comecar-pelo-seu-agente). O caminho principal é o servidor MCP com login da Runds: a pessoa adiciona `https://api.runds.io/mcp` no cliente, entra ou cria a conta na tela da Runds e autoriza. Ele vale para chat (ChatGPT, Claude) e para ferramenta de código (Claude Code, Cursor, Codex). Antes de escrever código, leia o [Guia para IAs integradoras](#guia-para-ias-integradoras). Todas as URLs partem de `https://api.runds.io`.
>
> **Se você é um chat** (ChatGPT, Claude.ai, Gemini) ou não consegue fazer um `POST` HTTP daqui, use só o conector. Não chame a API, não peça nome nem e-mail e não monte comando para a pessoa rodar: a conta nasce na própria tela da Runds. Diga à pessoa para adicionar o servidor MCP `https://api.runds.io/mcp` com autenticação OAuth, do jeito que o seu produto já faz. Não descreva o menu do cliente: você o conhece, e esta documentação não. Um convite `cv_…` no pedido não muda isso.

O arquivo bruto desta documentação fica em `/docs/api.md`, no mesmo domínio desta página. Aponte a sua IA para ele quando ela aceitar ler uma URL.

---

## Visão geral

Um **Flow** é uma automação desenhada num canvas: uma sequência de **nós** ligados por setas. Os dados entram por um **gatilho**, atravessam os nós e saem por uma resposta, um callback, uma gravação no banco do Flow ou uma chamada a outro sistema.

Existem três formas de falar com a Runds por API:

| Forma | Para quê | Credencial |
|---|---|---|
| **Webhook de entrada** | Mandar dados para um Flow começar a trabalhar | URL secreta + Bearer opcional do nó |
| **Entrada de API** | Transformar um Flow num endpoint seu, que responde na hora com o que você montar | URL do nó + token do nó (obrigatório) |
| **MCP** | Criar, editar, provar, publicar, rodar e inspecionar Flows com a sua IA | Login da Runds (OAuth) ou URL do agente (`rk_…`) |

As duas primeiras são **portas de produção**: cada uma pertence a um nó de um Flow e vale só para ele. A terceira é a **porta de construção**: pelo [MCP](#operar-pelo-mcp), o Claude Code, o Codex, o Cursor ou outro cliente chama direto as ferramentas que a Run usa, em nome de um usuário, dentro da empresa ativa dele.

---

## Começar pelo seu agente

Este é o caminho para quem chegou sem conta, ou para a IA que a pessoa mandou ler a Runds. No fim a IA da pessoa opera os Flows pelo MCP. A senha não passa por você.

### Conectar pelo login da Runds (qualquer cliente)

O servidor MCP fica em `https://api.runds.io/mcp` e usa o OAuth do próprio protocolo MCP. A pessoa adiciona essa URL no cliente, com autenticação OAuth, e o cliente abre a tela da Runds no navegador. Nela a pessoa entra, ou cria a conta ali mesmo, e clica em **Autorizar**. O cliente recebe a credencial sozinho. Este caminho não precisa de nome, e-mail, convite nem cabeçalho.

Cada cliente tem o próprio lugar para adicionar um servidor MCP remoto. Use o que você já conhece desse cliente. Para quem configura por comando ou arquivo, o mínimo é este:

| Cliente | O que informar |
|---|---|
| Claude Code | `claude mcp add --transport http run https://api.runds.io/mcp`, depois `/mcp` para entrar |
| Cursor, VS Code e outros | No arquivo de MCP, só a URL: `{ "mcpServers": { "run": { "url": "https://api.runds.io/mcp" } } }` |

Se você é um chat, este é o único caminho que funciona para você: o seu ambiente não alcança a API para criar a conta, e a pessoa cria a conta na tela que o conector abre. Responda com a URL e com OAuth, numa resposta curta, sem descrever o menu do cliente. Depois que ela autorizar, as ferramentas da Run aparecem na conversa.

O acesso aparece na página Tokens com o nome do cliente, e a pessoa revoga quando quiser. Conectar de novo o mesmo cliente substitui o acesso anterior.

Para quem roda comandos no próprio ambiente (Claude Code, Codex, Cursor) e prefere abrir o acesso por API, as etapas abaixo fazem o mesmo caminho com a URL do agente. Nos dois casos a chave só sai depois que a pessoa clica em **Autorizar**, logada na conta dela.

| A pessoa | Comece por |
|---|---|
| Ainda não tem conta | [Etapa 1](#1-abrir-o-acesso): você cria a conta, ela define a senha e autoriza no mesmo link |
| Já tem conta (o pedido diz "já tenho conta") | [Etapa 1b](#1b-pedir-acesso-a-uma-conta-que-ja-existe): você abre o pedido, ela autoriza no link |

### 1. Abrir o acesso

Peça à pessoa só o nome e o e-mail. Não peça senha e não invente uma.

Se o pedido da pessoa trouxe um convite (`cv_…`), mande-o em `convite`, com o nome do seu cliente em `agente`. A página que ela deixou aberta fica sabendo que o acesso abriu.

```bash
curl -X POST https://api.runds.io/usuario/criar-acesso \
  -H "Content-Type: application/json" \
  -d '{"nome": "Maria Souza", "login": "maria@empresa.com", "origem": "agente", "convite": "cv_…", "agente": "Claude Code"}'
```

```json
{ "success": 1, "senhaPendente": true, "creditoCentavos": 0,
  "link": "https://runds.io/definir-senha/ds_…?pedido=pa_…",
  "usuario": { "id": 41, "nome": "Maria Souza", "login": "maria@empresa.com", "empresaAtivaId": 12, "empresasIds": [12] },
  "convite": true,
  "autorizacao": { "codigo": "pa_…", "segredo": "…", "expiraEm": "2026-11-14T09:00:00.000Z" } }
```

- Devolva o `link` na conversa. Nele a pessoa define a senha, já entra logada e autoriza você na mesma sequência. Não abra o link e não escolha a senha por ela. A resposta não traz sessão (`token`). O link vale 12 horas e uma vez.
- Guarde o `segredo` da `autorizacao` só com você e siga para a [etapa 2](#2-esperar-a-autorizacao). Com `"convite": false`, o convite venceu; a conta existe do mesmo jeito, e o `link` segue valendo.
- A conta nasce com uma empresa própria e R$ 20 de crédito de entrada, para a Run e para as execuções com skill do Flow. Os 10 primeiros dias de cada Flow no ar são grátis.
- Se a pessoa disser que o link venceu, chame este mesmo pedido de novo, com o mesmo e-mail e sem senha. A resposta traz um `link` novo e uma `autorizacao` nova: passe a consultar a nova.
- `409`: a senha dessa conta já foi definida. Não peça a senha. Siga pela [etapa 1b](#1b-pedir-acesso-a-uma-conta-que-ja-existe).
- `400`: nome ou e-mail fora do formato. A mensagem diz qual.
- Limite de 5 contas por minuto por IP.

### 1b. Pedir acesso a uma conta que já existe

Quando a pessoa já tem conta, não peça e-mail nem senha. Abra o pedido com o nome do seu cliente:

```bash
curl -X POST https://api.runds.io/usuario/pedidos-de-acesso \
  -H "Content-Type: application/json" \
  -d '{"agente": "Claude Code"}'
```

```json
{ "codigo": "pa_…", "segredo": "…", "link": "https://runds.io/autorizar?pedido=pa_…", "expiraEm": "2026-11-13T21:30:00.000Z" }
```

- Devolva o `link` na conversa. A pessoa abre, entra se ainda não estiver logada e clica em **Autorizar**. O pedido vale 30 minutos.
- Guarde o `segredo` só com você e siga para a [etapa 2](#2-esperar-a-autorizacao).
- Limite de 10 pedidos por minuto por IP.

### 2. Esperar a autorização

Consulte a cada 5 segundos com o `codigo` e o `segredo` da autorização:

```bash
curl -X POST https://api.runds.io/usuario/pedidos-de-acesso/estado \
  -H "Content-Type: application/json" \
  -d '{"codigo": "pa_…", "segredo": "…"}'
```

```json
{ "status": "aguardando" }
```

Depois que a pessoa autorizar:

```json
{ "status": "autorizado", "chave": { "id": 3, "nome": "Claude Code", "token": "rk_…", "url": "https://api.runds.io/conectar/rk_…" } }
```

- A `chave` volta uma vez só. Depois dela o pedido some, e a próxima consulta devolve `404`.
- `404` antes da chave: o pedido venceu. Abra outro e entregue o link novo.
- `400` com a mensagem dos 10 tokens: a conta chegou ao limite. Peça à pessoa para revogar um na página Tokens e consulte de novo, o pedido continua de pé.
- O `rk_…` não expira. Ele é a credencial da conta: guarde como segredo (variável de ambiente ou a configuração do seu cliente MCP) e nunca cole num código que outras pessoas leem.

### 3. Ler a skill da conta

```
GET https://api.runds.io/conectar/rk_…
```

A resposta é markdown com os comandos de conexão já preenchidos e esta documentação inteira. Use-a como a sua instrução para esta conta.

### 4. Conectar o MCP

```bash
claude mcp add --transport http run https://api.runds.io/mcp --header "Authorization: Bearer rk_…"
```

Em outros clientes, o mesmo bloco de [Operar pelo MCP](#conectar). A partir daqui você constrói, prova, publica e lê execuções com as ferramentas do MCP, sem gastar a conversa da Run.

### O que contar para a pessoa

- O `link` para ela definir a senha e autorizar você, ou só autorizar quando a conta já existe. Depois disso, o mesmo e-mail entra em `https://runds.io/login`.
- Que o Flow só vai ao ar quando ela pedir para publicar, e que cada Flow no ar tem o [preço](#preco) mensal.
- Que credencial de terceiro (senha, chave do ERP) ela cola na tela da Runds, no link que o MCP devolver em `aguardandoPessoa`. Nunca na conversa com você.

---

## Preço

| O que | Quanto |
|---|---|
| Criar e editar Flows, provar, ler dados e execuções | Sem custo fixo |
| Flow no ar (ativo e publicado) | 10 dias grátis. Depois, R$ 200 a cada 30 dias, descontados da carteira |
| Conversa com a Run | Os tokens do turno, no preço baixo do modelo da Runds |
| Nó de Prompt dentro do Flow | Os tokens da execução, no mesmo preço baixo. Sem Prompt, a execução não gasta token |
| Construir pelo MCP com a sua IA | Sem tokens da Run: quem pensa é o modelo que você já paga |

- O vencimento dos 10 dias fica no Flow. Passada a data, começa o período de R$ 200.
- Vencido o período sem saldo, o Flow segue no ar por 3 dias e então pausa. Recarregada a carteira, ele volta sozinho.
- O custo de cada turno da Run volta em `custoUsd`. O extrato completo fica na Carteira, dentro da conta.

---

## Conceitos

### Flow
A automação inteira. Tem um **rascunho** (o que está na tela do editor) e uma **versão publicada** (o que roda em produção). Editar não muda produção até alguém **publicar**. Um Flow pode estar `ativo` ou `pausado`; pausado, as portas de entrada recusam chamadas.

### Nó
Uma etapa do Flow. Os tipos disponíveis no canvas são:

| Tipo (`tipo`) | Nome na tela | Categoria | O que faz |
|---|---|---|---|
| `cron` | Rotina | Gatilho | Roda de novo no horário (expressão cron) |
| `webhook` | Webhook | Gatilho | Recebe dados de fora por HTTP |
| `api` | Entrada de API | Gatilho | Vira um endpoint que responde a quem chamou |
| `parametros` | Definir dados | Ação | Constantes em JSON que entram nos registros |
| `code` | Código | Ação | Script JavaScript sobre os registros |
| `prompt` | Prompt | IA | Uma instrução executada pela Run sobre os registros |
| `if_else` | Condição | Lógica | Divide os registros em "sim" e "não" |
| `retorno` | Retorno | Lógica | Volta para uma etapa anterior |
| `comment` / `borda` | Anotação / Borda | Recurso | Só visual, não executa |

### Aresta (seta)
Liga a saída de um nó à entrada de outro. **O caminho dos dados é a seta**: o que um nó faz com o resultado depende de para onde a seta dele aponta. Nós com mais de uma saída usam `sourceHandle` para dizer de qual saída a seta parte: `true` / `false` na Condição (com vários ramos, cada ramo usa o próprio id e `false` é o "senão").

### Registro e partição
Os dados viajam como uma **lista de registros** (objetos JSON), chamada partição. Um webhook que recebe um objeto produz uma partição com um registro; um que recebe uma lista produz um registro por item.

### Base de dados
O banco do próprio Flow: uma tabela de registros JSON com uma **chave de identidade** (o campo que identifica cada registro). Gravar um registro com uma chave que já existe **atualiza** o registro (upsert). Um Flow pode ter várias bases de dados. Nada é gravado sozinho: quem grava é o nó de Código (`dataset().gravar`) ou o nó de gravação.

### Execução
Cada vez que um Flow roda nasce uma **execução**, com id numérico, status e trilha de passos. Status possíveis incluem `na_fila`, `rodando`, `sucesso`, `erro` e os de lote (`aguardando-fatias`, `aguardando-arquivo`).

### Key (identidade do processo)
Toda execução tem uma `key`: uma string sua (até 200 caracteres) que identifica o processo, por exemplo o id do pedido no seu sistema. Se você não mandar, a Runds gera `flow-<12 hex>`. **Uma key vale por uma execução**: é ela que evita processar duas vezes a mesma coisa.

### Rascunho (`?rascunho=1`)
As portas de entrada rodam a **versão publicada**. Acrescentar `?rascunho=1` à URL roda a versão da tela, para testar antes de publicar. Execuções de rascunho ficam marcadas com a origem `webhook-rascunho` ou `api-rascunho`.

---

## URL base, formato e erros

**URL base:** `https://api.runds.io`

Todas as rotas aceitam e devolvem JSON (`Content-Type: application/json`), salvo onde indicado. O corpo da requisição pode ter até 50 MB no transporte, mas cada porta tem o seu próprio teto (veja [Limites](#limites)).

### Formato de erro
Os erros seguem o formato padrão:

```json
{ "statusCode": 400, "message": "Este Flow está pausado — reative para receber dados", "error": "Bad Request" }
```

Alguns erros trazem um corpo próprio, documentado na seção de cada porta (por exemplo o `410` de processo encerrado e o `429` de concorrência).

### Status usados

| Status | Significado na Runds |
|---|---|
| `200` | Recebido e processado (ou a resposta montada pelo seu Flow) |
| `202` | Aceito: a execução segue em segundo plano; consulte depois |
| `400` | Pedido inválido para o estado do Flow (pausado, não publicado, campo faltando) |
| `401` | Credencial ausente ou inválida |
| `402` | A carteira da conta está sem saldo (Run) |
| `403` | Sem permissão (ex.: senha de segurança errada) |
| `404` | Slug, Flow, nó ou execução não encontrados |
| `409` | Conflito: key já usada, Flow travado, nó não publicado |
| `410` | O processo daquela key já terminou |
| `413` | Corpo ou quantidade de registros acima do teto |
| `429` | Chamadas demais (por IP, por Flow ou por concorrência do nó) |
| `500` / `502` | O Flow falhou ou terminou sem resposta |

---

## Credenciais

| Credencial | Onde nasce | Formato | Vale para |
|---|---|---|---|
| **Slug do webhook** | Ao criar o nó Webhook | 32 caracteres hex na URL | Aquele nó |
| **Bearer do webhook** | Painel do nó → "gerar" | 43 caracteres base64url | O nó e as rotas de leitura das execuções dele |
| **Slug da API** | Ao criar o nó Entrada de API | 32 caracteres hex na URL | Aquele nó |
| **Token da API** | Painel do nó → "Token" | 24 a 128 caracteres `[A-Za-z0-9._~-]` | O nó e a consulta das execuções dele |
| **URL do agente (`rk_…`)** | Autorização da pessoa no pedido de acesso, ou "Gerar token" na página Tokens | `rk_` + 43 caracteres base64url | Só o MCP (`/mcp`), na empresa em que foi gerada |
| **Sessão do App (`bfs_…`)** | Login no App publicado do Flow | Começa com `bfs_`, vale 7 dias | Entradas de API com "Aceitar login do site" |

Há dois tipos de credencial e um não substitui o outro:

- **Da conta:** a URL do agente (`rk_…`). Abre o MCP, onde a sua IA opera os Flows direto. Tudo o que é da conta (Flows, execuções, dados) passa por ele. A sua IA nunca precisa do login e da senha da pessoa.
- **Do nó:** o slug e o Bearer do Webhook, o slug e o token da Entrada de API. Abrem só aquele nó, em produção. O sistema que manda dados ao Flow usa estas, e o `rk_…` não entra no lugar delas.

Regras importantes:

- **A URL do webhook é um segredo.** Quem tem a URL consegue mandar dados se o nó não tiver Bearer. Gere um Bearer em produção.
- O **Bearer do webhook aparece uma única vez**, na hora em que é gerado; o servidor guarda só o hash. Perdeu, gere outro.
- O **token da API fica sempre visível** no painel do nó e pode ser trocado por um valor seu.
- "Trocar URL" no painel gera um slug novo e **a URL antiga para de funcionar na hora**. Na Entrada de API, trocar a URL mantém o token.
- Mande o Bearer como `Authorization: Bearer <segredo>`. O valor cru (sem a palavra `Bearer`) também é aceito.
- O cofre de **Keys do Flow** (`chave("NOME")` no nó de Código) guarda segredos de **terceiros** que o seu script usa. Ele não é uma credencial de acesso à Runds.

---

## Webhook de entrada

O nó **Webhook** é a porta para mandar dados a um Flow. O que acontece com os dados depende do nó ligado depois dele (veja [Comportamento pela seta](#comportamento-pela-seta)).

### Endpoint do webhook

```
POST https://api.runds.io/api/flows/ingest/{slug}
```

| Parte | Descrição |
|---|---|
| `{slug}` | O slug do nó, mostrado no painel em "URL de ingestão" |
| `?rascunho=1` | Opcional. Roda a versão da tela em vez da publicada |
| `Authorization` | `Bearer <segredo>`, obrigatório só se o nó tiver Bearer |
| `Content-Type` | `application/json` ou `multipart/form-data` |

Resposta de sucesso: **HTTP 200**. Limite de 120 chamadas por minuto por IP.

### Exemplo mínimo

```bash
curl -X POST https://api.runds.io/api/flows/ingest/SEU_SLUG \
  -H "Authorization: Bearer SEU_SEGREDO" \
  -H "Content-Type: application/json" \
  -d '{"id": "123", "nome": "Maria", "telefone": "+5511999990000"}'
```

```json
{ "sucesso": true, "key": "flow-3f9a1c2b7d4e", "status": "sucesso", "mensagem": "…" }
```

### Como o corpo vira registros
A Runds procura a lista de registros no corpo nesta ordem:

1. Se o corpo é um **array**, cada item é um registro.
2. Se o nó tem **Raiz da lista** configurada (ex.: `dados.itens`), usa esse caminho. Um objeto nesse caminho vira um registro.
3. Senão procura, até dois níveis de profundidade, uma lista em `registros`, `data`, `items`, `results`, `rows` ou `records`.
4. Senão o próprio objeto é **um** registro.

Lista vazia é recusada com `400`. O teto é **2.000 registros por chamada** (`413` acima disso).

```json
{ "registros": [ { "id": "1", "valor": 10 }, { "id": "2", "valor": 20 } ] }
```

### Campos reservados do corpo

| Campo | Tipo | Uso |
|---|---|---|
| `key` | string (até 200) | Identidade do processo. Sem ela, a Runds gera uma |
| `callbackUrl` (ou `callback_url`) | URL http/https (até 500) | Para onde a Runds manda a conclusão |
| `anexos` | lista | Arquivos junto da chamada (veja abaixo) |

### Headers da sua chamada
Os headers que você manda ficam disponíveis no Flow como `processo.headers` (até 40 headers; nome até 80 caracteres, valor até 512). Por segurança **não** chegam ao Flow: `authorization`, `proxy-authorization`, `cookie`, `set-cookie` e headers de transporte.

### Anexos e planilhas
`anexos` aceita até 10 itens, cada um em uma destas formas:

```json
{
  "id": "pedido-77",
  "anexos": [
    "https://seu-sistema.com/bases/planilha.xlsx",
    { "url": "https://seu-sistema.com/contrato.pdf", "papel": "contrato" },
    { "nome": "base.csv", "base64": "aWQsdmFsb3IKMSwxMAo=", "mimeType": "text/csv" }
  ]
}
```

- Planilhas (`xlsx`, `xls`, `xlsm`, `csv`, `tsv`) viram a **base da rodada**: o nó de Prompt lê e agrega essas linhas no servidor.
- Arquivo embutido (base64) que não é planilha é recusado com `400`; mande outros arquivos por URL.

### Upload em multipart
Quem tem o arquivo no disco pode mandá-lo no próprio webhook, no campo `file` (até 200 MB):

```bash
curl -X POST https://api.runds.io/api/flows/ingest/SEU_SLUG \
  -H "Authorization: Bearer SEU_SEGREDO" \
  -F "id=pedido-77" \
  -F "file=@planilha.xlsx"
```

Em multipart todo campo chega como texto. Campos com JSON são convertidos de volta, e um campo chamado `payload` (ou `corpo`) com JSON vira o corpo inteiro.

### Comportamento pela seta
O nó ligado logo depois do webhook decide o que a chamada faz:

| Ligado em | Comportamento | Resposta |
|---|---|---|
| **Prompt** | Assíncrono: a Run processa em segundo plano | `modo: "prompt"`, `status: "na_fila"` ou `"rodando"` |
| **Qualquer outro** | Síncrono: os registros percorrem o grafo antes da resposta | `status: "sucesso"` |

Respostas típicas:

```json
{ "sucesso": true, "modo": "prompt", "key": "pedido-77", "status": "na_fila", "mensagem": "…" }
```

### Roteamento pela key
Antes de qualquer outra regra, se o corpo traz uma `key`, a Runds procura um processo com ela neste Flow:

| Situação da key | O que acontece | Resposta |
|---|---|---|
| Nunca usada | Começa uma execução nova | Conforme a seta |
| Já usada, processo ainda rodando | Recusada | `409` |
| Processo já terminou | Recusada | `410` (corpo abaixo) |

```json
{ "sucesso": false, "modo": "encerrado", "tipo": "conclusao", "key": "pedido-77",
  "status": "sucesso", "mensagem": "…" }
```

### Erros do webhook

| Status | Mensagem (resumo) | O que fazer |
|---|---|---|
| `404` | Webhook não encontrado | Confira o slug; a URL pode ter sido trocada |
| `401` | Credencial inválida para este webhook | Mande o Bearer certo |
| `400` | Este Flow está pausado | Reative o Flow |
| `400` | Este Flow ainda não foi publicado | Publique, ou chame com `?rascunho=1` |
| `409` | A key "X" já foi usada neste Flow | Mande outra key, ou omita o campo |
| `409` | O Flow está travado por outra execução | Tente de novo em instantes |
| `410` | Processo encerrado | A key terminou; comece com uma key nova |
| `413` | Máximo de 2000 registros por chamada / corpo grande demais | Divida em lotes |

---

## Entrada de API

O nó **Entrada de API** transforma o Flow num endpoint seu: quem chama manda um JSON, o Flow roda, e a resposta que você montou volta na mesma chamada.

### Endpoint da API

```
POST https://api.runds.io/api/flows/api/{slug}
```

| Parte | Descrição |
|---|---|
| `{slug}` | O slug do nó, mostrado em "URL da API" |
| `?rascunho=1` | Opcional. Roda a versão da tela |
| `Authorization` | `Bearer <token>`. **Sempre obrigatório**, salvo nas exceções do App (abaixo) |
| Corpo | JSON (objeto ou lista), até 256.000 caracteres |

Só existe **POST**: os parâmetros vão no corpo. Limite de 120 chamadas por minuto por IP, além do limite de concorrência do nó.

### Exemplo

```bash
curl -X POST https://api.runds.io/api/flows/api/SEU_SLUG \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cpf": "12345678900"}'
```

A resposta é exatamente o que o seu Flow montou (status, corpo e headers), mais o header `X-Flow-Execucao` com o id da execução.

### Como o corpo entra no Flow
- Um objeto vira **um** registro; uma lista vira um registro por item.
- O corpo inteiro também fica disponível nos scripts como `entrada`.
- Os headers da chamada ficam em `processo.headers`.

### Montando a resposta
A resposta é configurada na seção **Resposta** do próprio nó (ou num nó Responder, nos Flows antigos). O primeiro ponto do Flow que responder ganha.

| Campo | Padrão | Regras |
|---|---|---|
| **Status HTTP** | `200` | Número ou `{{campo}}`, entre 100 e 599 |
| **Corpo** | O registro que chegou ao fim (ou a lista, se houver mais de um) | Até 50.000 caracteres no modelo; resposta final até 6 MB |
| **Headers extras** | nenhum | Até 20, um por linha (`Nome: valor`) |

O corpo aceita marcadores `{{campo}}`, preenchidos com os campos do **primeiro registro** que chegou ao fim, e `{{registros}}` com a lista inteira:

| Corpo configurado | O que sai |
|---|---|
| (vazio) | O registro como está |
| `{{cliente}}` | O valor de `cliente` com o tipo dele (objeto, número…) |
| `{"ok": true, "nome": {{nome}}, "itens": {{registros}}}` | JSON com cada campo inserido como JSON |
| `Olá, {{nome}}!` | Texto, devolvido como `text/plain` |

Headers que o Flow **não pode** definir: `set-cookie`, `content-length`, `transfer-encoding`, `connection`, `keep-alive`, `host`, `upgrade`, `te`, `trailer`, `date`, `server`, `access-control-allow-origin`, `access-control-allow-credentials` e `proxy-*`.

### Tempo de espera e 202
O nó espera a resposta por **Tempo de espera** segundos (padrão 20, máximo 25). Se o Flow não terminar a tempo, a chamada volta **202** e a execução continua:

```json
{
  "key": "flow-9c2e4a1b0f3d",
  "execucaoId": 4812,
  "status": "rodando",
  "consulta": "https://api.runds.io/api/flows/api/SEU_SLUG/execucoes/4812"
}
```

Consulte a URL de `consulta` com o mesmo token (veja [Acompanhar execuções](#acompanhar-execucoes)).

### Entrega por callback
Com **Entrega da resposta** em "No callbackUrl", a chamada volta `202` com `status: "aceito"` na hora, e a resposta chega depois no `callbackUrl` que você mandou no corpo, dentro do evento `conclusao` (campo `resposta`):

```bash
curl -X POST https://api.runds.io/api/flows/api/SEU_SLUG \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id": "123", "callbackUrl": "https://seu-sistema.com/retorno"}'
```

Sem `callbackUrl` nesse modo, a chamada é recusada com `400`.

### Concorrência
**Chamadas em andamento (máx.)** limita quantas execuções desta API rodam ao mesmo tempo (padrão 20, máximo 200). Acima disso:

```json
{ "statusCode": 429, "message": "Esta API já tem 20 chamada(s) em curso (limite 20) — tente de novo em instantes" }
```

### Acesso pelo App publicado
Duas opções do nó permitem chamar a API a partir do App (site) publicado do Flow:

- **Aceitar login do site:** aceita o token de sessão do App (`bfs_…`, obtido em `POST /api/flows/front/{flowId}/auth/entrar` com `{ "email", "senha" }`). O Flow recebe o usuário em `processo.headers` (`x-runds-usuario-id`, `-email`, `-papel`, `-nome`).
- **Aberta para a página pública do App:** aceita chamadas sem token vindas do domínio do App, com limite de 10 por minuto por visitante e 120 por minuto por Flow.

Nesses dois casos a consulta de execução exige `?key=` com a key da execução.

### Restrições do desenho
- O primeiro nó depois da Entrada de API não pode ser um Prompt.

### Erros da Entrada de API

| Status | Mensagem (resumo) | O que fazer |
|---|---|---|
| `404` | API não encontrada | Confira o slug |
| `401` | Esta API ainda não tem segredo | Gere o token no painel do nó |
| `401` | Credencial inválida para esta API | Mande o token certo |
| `401` | Entre de novo no App | A sessão do App acabou |
| `409` | Esta entrada de API ainda não foi publicada | Publique, ou use `?rascunho=1` |
| `409` | Este Flow está pausado | Reative o Flow |
| `400` | Esta API entrega por callback — mande "callbackUrl" | Inclua o `callbackUrl` |
| `413` | Corpo grande demais (máximo 256000 caracteres) | Reduza o corpo |
| `429` | Chamadas em curso acima do limite / consultas demais | Espere e tente de novo |
| `500` | O fluxo falhou — veja a execução #N | Leia a execução #N pelo MCP (`get_steps`), ou abra no painel |
| `502` | O fluxo terminou sem nada chegando no fim do caminho | Ligue o último nó ao fim / revise as condições |
| `500` | A resposta passou de 6MB | Pagine a resposta |

---

## Callbacks

Quando você manda um `callbackUrl`, a Runds avisa o seu sistema com um `POST` JSON a cada evento relevante.

### Entrega
- `Content-Type: application/json`, `User-Agent: runds-flow/1.0`.
- Todo corpo traz `timestamp` (ISO 8601).
- **Retentativas:** até 3 tentativas, 15 s de timeout cada, esperando 1 s, 4 s e 16 s. Só reenvia em erro de rede, `5xx`, `408` ou `429`. Outros `4xx` não são reenviados.
- **Ordem:** os eventos de uma mesma key saem espaçados (cerca de 2 s), na ordem em que aconteceram.
- **Disjuntor:** 5 falhas seguidas na mesma URL pausam os envios para ela por 60 s.
- Responda `2xx` rápido e processe depois.

> **Segurança:** os callbacks não são assinados. Use uma URL difícil de adivinhar ou ponha um token seu na query (`https://seu-sistema.com/retorno?token=…`) e confira-o ao receber.

### Evento `conclusao`
O processo terminou. Enviado **uma única vez** por execução:

```json
{
  "tipo": "conclusao",
  "key": "pedido-77",
  "flowId": 2,
  "workflowId": 2,
  "execucaoId": 4812,
  "status": "sucesso",
  "erro": null,
  "relato": "…",
  "variaveis": { "cpf": "12345678900", "plano": "anual" },
  "variables": { "cpf": "12345678900", "plano": "anual" },
  "registros": [ { "id": "pedido-77", "status": "aprovado" } ],
  "resposta": null,
  "timestamp": "2026-10-26T17:41:12.000Z"
}
```

- `variaveis` é um mapa plano de strings (`variables` é o mesmo, para compatibilidade).
- `registros` traz até 500 registros do fim do caminho.
- `resposta` só aparece na Entrada de API com entrega por callback: é a resposta montada (status, corpo, headers).

### Evento `fatia`
Em execuções grandes, divididas em fatias, cada fatia concluída gera um aviso:

```json
{ "tipo": "fatia", "key": "lote-9", "flowId": 2, "workflowId": 2, "execucaoId": 4812,
  "itemId": 991, "indice": 3, "total": 10, "status": "sucesso", "registros": [ … ] }
```

---

## Acompanhar execuções

**Quem consulta é o MCP.** Histórico de execuções, erros, passos de uma execução, registros e bases de dados de um Flow: `list_executions`, `get_steps` e `list_records`. Na tela da conta, a pessoa também pode perguntar à Run. Não existe rota REST pública para listar execuções ou ler dados de um Flow.

As duas rotas abaixo são a exceção: servem para acompanhar **a execução que a sua chamada abriu** num nó de entrada, com a credencial daquele nó e o `execucaoId` (ou a `key`) que voltou na chamada.

| Você quer | Caminho |
|---|---|
| Saber se a execução que você disparou terminou | A rota do nó, abaixo |
| Ver o histórico, os erros ou os passos de um Flow | O MCP |
| Ler registros ou bases de dados de um Flow | O MCP |
| Que o seu sistema leia dados do Flow em produção | Uma Entrada de API que devolve esses dados (veja [Consultar dados como uma API](#consultar-dados-como-uma-api)). Se o Flow ainda não tem, monte pelo MCP |

### Execução de webhook

```
GET https://api.runds.io/api/flows/ingest/{slug}/execucoes/{execucaoId}
Authorization: Bearer <segredo do webhook>
```

```json
{
  "id": 4812, "status": "sucesso", "key": "pedido-77", "origem": "webhook",
  "erro": null, "relato": "…", "registrosGravados": 120,
  "fatiasProcessadas": 10, "fatiasTotal": 10,
  "startedAt": "2026-10-26T17:40:00.000Z", "finishedAt": "2026-10-26T17:41:12.000Z",
  "filhas": [ { "id": 4813, "status": "sucesso", "registrosGravados": 12, "fatiasProcessadas": 1, "fatiasTotal": 1, "erro": null } ]
}
```

Itens (fatias) da execução, paginados por cursor:

```
GET https://api.runds.io/api/flows/ingest/{slug}/execucoes/{execucaoId}/itens?status=erro&limite=100&cursor=0
```

```json
{ "itens": [ { "id": 991, "indice": 3, "rodada": 1, "status": "erro", "tentativas": 2, "erro": "…", "saida": null,
               "startedAt": "…", "finishedAt": "…" } ],
  "proximoCursor": 991 }
```

`limite` vai de 1 a 500 (padrão 100). Passe `proximoCursor` como `cursor` para a próxima página; `null` é o fim.

### Execução da Entrada de API

```
GET https://api.runds.io/api/flows/api/{slug}/execucoes/{execucaoId}
Authorization: Bearer <token da API>
```

```json
{
  "execucaoId": 4812, "key": "flow-9c2e4a1b0f3d", "status": "sucesso",
  "resposta": { "status": 200, "corpo": { "ok": true }, "headers": {}, "em": "2026-10-26T17:40:21.000Z" },
  "startedAt": "…", "finishedAt": "…"
}
```

`resposta` é `null` enquanto o Flow não respondeu. Para respostas grandes, o corpo pode vir omitido (`corpoOmitido`).

**Estratégia de polling recomendada:** consulte a cada 1–2 s nos primeiros 10 s, depois a cada 5 s, até `status` ser `sucesso` ou `erro`.

---

## Operar pelo MCP

O MCP põe a sua IA no lugar da Run: Claude Code, Codex, Cursor ou outro cliente MCP chama direto as ferramentas que a Run usa para construir, provar, publicar, executar e analisar Flows. É a única porta para a sua IA operar a estrutura de Flows da conta.

### Conectar

```
POST https://api.runds.io/mcp
Authorization: Bearer rk_…
```

É um servidor MCP por HTTP (Streamable HTTP, respostas em JSON, sem stream). Ele aceita duas credenciais:

- **Login da Runds (OAuth 2.1).** Sem credencial, o `/mcp` responde `401` com `WWW-Authenticate: Bearer resource_metadata="…"`. O cliente segue a descoberta (`/.well-known/oauth-protected-resource` e `/.well-known/oauth-authorization-server`), se registra sozinho em `/oauth/register`, abre `/oauth/authorize` no navegador com PKCE (S256) e troca o código em `/oauth/token`. É o caminho de [Conectar pelo login da Runds](#conectar-pelo-login-da-runds-qualquer-cliente).
- **URL do agente.** O `rk_…` no cabeçalho, como abaixo. No Claude Code:

```bash
claude mcp add --transport http run https://api.runds.io/mcp --header "Authorization: Bearer rk_…"
```

Em outros clientes, no arquivo de configuração de MCP:

```json
{ "mcpServers": { "run": { "type": "http", "url": "https://api.runds.io/mcp", "headers": { "Authorization": "Bearer rk_…" } } } }
```

O texto de `/conectar/rk_…` já traz os dois comandos com o token preenchido.

### O que a sua IA recebe

- **No `initialize`:** as regras de comportamento do Flow e do servidor (ciclo de trabalho, o que exige a pessoa, o que o servidor recusa).
- **Em `tools/list`:** as ferramentas, com o schema de cada uma e as anotações MCP (`readOnlyHint`, `destructiveHint`, `openWorldHint`). O seu cliente usa as anotações para pedir permissão antes do que muda dados ou chama sistemas de fora.
- **Na ferramenta `read_flow_guide`:** o guia completo de construção (peças, regras de desenho, provas e edição). É o mesmo guia que a Run segue.

### Ferramentas

| Grupo | Ferramentas |
|---|---|
| Achar e ler | `list_flows`, `get_flow`, `search_flow`, `read_flow_guide` |
| Construir | `create_flow`, `update_flow`, `patch_node`, `manage_dataset`, `manage_queue`, `set_flow_theme` |
| Provar sem efeito | `test_script`, `dry_run_flow` |
| Publicar e desfazer | `publish_flow`, `list_backups`, `restore_backup` |
| Executar valendo | `run_flow`, `simulate_webhook` |
| Dados e execuções | `list_records`, `upsert_records`, `delete_records`, `list_executions`, `get_steps`, `get_queue`, `enqueue_message` |
| Acesso a sistemas de fora | `register_connection`, `request_secret` |
| App do Flow | `get_app`, `read_app_file`, `write_app_files`, `edit_app_file`, `configure_app_access`, `build_app`, `publish_app` |

### Regras

- **Rascunho e publicação.** Toda escrita cai no rascunho. Webhook, cron e Entrada de API continuam rodando a versão publicada até `publish_flow`. Cada resposta de escrita traz `publicacao` com `rascunho`, `impedimento` (se houver) e o próximo passo.
- **Laudo.** Toda escrita volta com a conferência do grafo. Com `[ERRO]` na última escrita da sessão naquele Flow, `publish_flow` recusa. `aceitarLaudo: true` publica mesmo assim, só por decisão do usuário. Desenho incompleto (sem dataset, nó vazio no meio) é sempre recusado.
- **Trava de edição.** Um Flow é editado por uma sessão de cada vez. Se a Run ou outro cliente estiver editando, a escrita volta recusada. A trava expira em 5 minutos sem escrita e é solta ao publicar.
- **Backup.** Cada sessão tira um backup do Flow antes da primeira escrita nele.
- **Credenciais.** `register_connection` e `request_secret` nunca recebem o segredo. A resposta traz `aguardandoPessoa` com o link da tela onde a pessoa cola o valor.
- **Exclusão de registros.** Dois passos: a primeira chamada mostra o que seria apagado e devolve `confirmacaoToken` (10 minutos). A segunda, com o token, apaga. Peça a confirmação ao usuário entre as duas.
- **Excluir um Flow** não existe no MCP: exige a senha da conta, na tela.
- **Sessão.** O servidor devolve `Mcp-Session-Id` no `initialize`. Mande o cabeçalho nas chamadas seguintes para manter o backup e o laudo da sessão.

### Erros

- `401`: a URL foi revogada. Peça uma nova à pessoa.
- `429`: chamadas demais. Espere um minuto.
- Erro de ferramenta volta como resultado com `isError: true` e `{"error": "…"}` no texto. Nada foi feito.

---

## A URL do agente

A pessoa gera a URL na página Tokens, dentro da conta, ou o próprio agente recebe a chave ao abrir o acesso. Na página Tokens ela também vê o token cru e pode nomear, renovar ou revogar cada um.

```
GET https://api.runds.io/conectar/rk_…
```

A resposta é uma skill em markdown: o Bearer já preenchido, os comandos para registrar o MCP e esta documentação inteira logo abaixo.

- O `rk_…` vale só no MCP (`/mcp`). Em qualquer outra rota ele volta `401`.
- Quem tem a URL opera como o dono da conta, na empresa em que ela foi gerada. Não expira.
- Revogar invalida na hora. Perdeu a URL, gere outra e revogue a antiga.

A Run, a assistente da Runds, fica dentro do produto: a pessoa conversa com ela na tela da conta. Não existe API para um agente conversar com a Run.

---

## Construindo Flows

Esta seção ensina a desenhar Flows que funcionam — vale para você e para a sua IA.

### Regras de ouro
1. **Todo Flow começa num gatilho** (Rotina, Webhook ou Entrada de API) e segue pelas setas.
2. **Nada é gravado sozinho.** Se os dados precisam ficar guardados, um nó de Código grava com `dataset().gravar`.
3. **O destino decide.** O mesmo webhook se comporta diferente conforme o nó ligado nele.
4. **Uma key por processo.** Use o id do seu sistema como key e a Runds cuida de deduplicar e avisar.
5. **Teste no rascunho, publique depois.** `?rascunho=1` e a prova do Flow não mexem em produção.

### O nó de Código
Roda JavaScript (async, modo estrito) num ambiente isolado, sem acesso ao servidor. O valor do `return` vira os registros que seguem pela seta.

Variáveis e funções disponíveis no script:

| Nome | O que é |
|---|---|
| `registros` | A lista de registros que chegou no nó |
| `parametros` | As constantes do Flow |
| `processo` | O processo atual: `key`, `headers` da chamada, mensagem da fila etc. |
| `entrada` | O corpo original da Entrada de API |
| `bases` | As planilhas da rodada (id, papel, nome) |
| `fetch(url, opções)` | Chamada HTTP livre a qualquer API pública |
| `chamarConexao(slug, req)` | Chamada a uma Conexão da empresa (a credencial fica no servidor) |
| `chave("NOME")` | Lê um segredo do cofre de Keys do Flow |
| `dataset(nome)` | Uma base de dados do Flow (veja abaixo) |
| `fila(nome)` | A fila do Flow (veja abaixo) |

**O retorno mescla com a entrada:** devolva só os campos que criou ou mudou. Um campo devolvido como `null` é removido do registro. Devolver menos registros do que entraram funciona como filtro. Um objeto sozinho vale como um registro.

```js
// Enriquece cada registro com o CEP consultado numa API pública
const saida = [];
for (const r of registros) {
  const res = await fetch(`https://viacep.com.br/ws/${r.cep}/json/`);
  if (!res.ok) { saida.push({ cep_erro: `HTTP ${res.status}` }); continue; }
  const cep = await res.json();
  saida.push({ cidade: cep.localidade, uf: cep.uf, cep_erro: null });
}
return saida;
```

#### `dataset(nome)`

| Função | Descrição |
|---|---|
| `buscar({ onde, limite, ordem })` | Registros que casam com `onde` (`{ campo: valor }`); `ordem: "recentes"` inverte |
| `contar({ onde })` | Quantos registros casam |
| `porChave(chave)` | O registro com aquela chave de identidade, ou `null` |
| `gravar(registros)` | Upsert pela chave de identidade; aceita um objeto ou uma lista |
| `assumir(chave, quando, virar)` | Troca o estado (`virar`) só se o registro ainda estiver em `quando` — trava otimista |
| `assumirLote(quantos, onde, virar, { ordem, paradoHaMin })` | Pega um lote e marca como seu numa tacada, sem disputar com outros consumidores |
| `apagar(chaves)` | Remove registros pela chave |

A base de dados precisa ter a chave de identidade definida (página Dados do Flow) antes de ser usada no script. `buscar` devolve no máximo 5.000 registros e não pagina: acima disso, filtre com `onde` ou use `contar` para saber o tamanho antes.

```js
// Fila de trabalho numa base de dados: cada rodada do cron pega 50 pendentes
const lote = await dataset('pedidos').assumirLote(50, { status: 'pendente' }, { status: 'processando' });
for (const p of lote) {
  // … processa …
}
await dataset('pedidos').gravar(lote.map((p) => ({ id: p.id, status: 'feito' })));
return lote;
```

#### `fila(nome)`

| Função | Descrição |
|---|---|
| `enfileirar(valor)` | Põe um JSON na fila |
| `remover(id)` | Confirma que a mensagem foi tratada |
| `contar()` | Quantas mensagens esperam |

O Flow consumidor (uma Rotina ligada à fila) recebe uma mensagem por caminhada em `processo.mensagem` e confirma com `remover(id)`.

### Receitas

#### Receber pedidos e guardar
`Webhook` → `Código` (valida e grava com `dataset('pedidos').gravar(registros)`).
Chamada: `POST /api/flows/ingest/{slug}` com o pedido ou uma lista de pedidos.

#### Consultar dados como uma API
`Entrada de API` → `Código` (`return await dataset('clientes').buscar({ onde: { cpf: registros[0].cpf }, limite: 1 })`).
Resposta configurada no nó: `{{registros}}` ou um JSON com os campos.

#### Rotina diária
`Rotina` (`0 8 * * *`) → `Código` (busca no ERP com `chamarConexao`) → `Prompt` (resume) → `Código` (grava).

---

## Guia para IAs integradoras

Esta seção é escrita para você, IA, que recebeu esta documentação para integrar um sistema com a Runds.

### Antes de escrever código, descubra
1. **Qual porta usar.** Dados entrando num processo → Webhook. Um endpoint que responde na hora → Entrada de API. Criar, mudar, rodar ou inspecionar o Flow (execuções, erros, registros) → o MCP (`/mcp`). Se o seu cliente não registra servidor MCP, peça à pessoa para conectar num cliente que registre. Não crie Flow, nó ou seta por rota REST, e não procure rota para listar execuções ou dados.
2. **A URL e a credencial.** Peça ao usuário a URL do nó (em "URL de ingestão" ou "URL da API") e o Bearer/token. Nunca invente slugs.
3. **O formato dos dados.** Pergunte ao usuário, ou leia o Flow pelo MCP (`get_flow`), quais campos ele espera.

### Ao integrar
- Use uma **key estável** por processo (id do pedido, telefone, id do ticket). Isso evita duplicidade.
- Trate `409` (key repetida) e `410` (processo encerrado) como estados normais, não como falha genérica.
- Trate `202` na Entrada de API: guarde `execucaoId` e faça polling na URL de `consulta`. Essa é a única leitura de execução com a credencial do nó; o resto é pelo MCP.
- No callback, responda `2xx` imediatamente e processe em segundo plano; deduplique por `execucaoId` + `tipo`.
- Use `?rascunho=1` enquanto testa e remova ao ir para produção.
- Guarde segredos em variáveis de ambiente, nunca no código.

### Ao operar Flows pelo MCP
- Se você recebeu uma URL `/conectar/rk_…`, ela já é a credencial: registre o MCP com o Bearer que está no texto dela.
- Leia `read_flow_guide` antes da primeira construção.
- Prove com `dry_run_flow` antes de `publish_flow`. A edição fica em rascunho até a publicação.
- Se vier `aguardandoPessoa`, mande ao seu usuário o link que veio na resposta. Credencial ele cola na tela da Runds, não na conversa com você.
- Para ver execuções, erros, passos ou registros de um Flow, use `list_executions`, `get_steps` e `list_records`. As rotas `…/execucoes/{id}` dos nós só servem para a execução que a sua chamada abriu.
- Antes de publicar mudança num Flow em produção, exclusão de registros ou restauração de backup, peça confirmação explícita ao usuário.

### Esqueleto de cliente (TypeScript)

```ts
const BASE = 'https://api.runds.io';

export async function enviarAoWebhook(slug: string, segredo: string, corpo: unknown) {
  const res = await fetch(`${BASE}/api/flows/ingest/${slug}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${segredo}` },
    body: JSON.stringify(corpo),
  });
  const json = await res.json().catch(() => null);
  if (res.status === 409 || res.status === 410) return { repetido: true, json };
  if (!res.ok) throw new Error(`Runds ${res.status}: ${json?.message ?? 'erro'}`);
  return json;
}

export async function chamarApi(slug: string, token: string, corpo: unknown) {
  const res = await fetch(`${BASE}/api/flows/api/${slug}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
    body: JSON.stringify(corpo),
  });
  if (res.status !== 202) return { status: res.status, corpo: await res.json().catch(() => null) };
  const { consulta } = await res.json();
  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, i < 5 ? 2000 : 5000));
    const r = await fetch(consulta, { headers: { Authorization: `Bearer ${token}` } });
    const exec = await r.json();
    if (exec.status === 'sucesso' || exec.status === 'erro') return exec.resposta ?? exec;
  }
  throw new Error('A execução não terminou a tempo');
}
```

---

## Limites

| Limite | Valor |
|---|---|
| Chamadas por IP (geral) | 600 por minuto |
| Webhook de entrada, por IP | 120 por minuto |
| Entrada de API, por IP | 120 por minuto |
| Login | 10 por minuto por IP |
| Chamadas ao MCP (`/mcp`) | 240 por minuto |
| Abrir a URL do agente (`/conectar`) | 30 por minuto |
| Tokens de agente ativos por usuário | 10 |
| Registros por chamada de webhook | 2.000 |
| Corpo da Entrada de API | 256.000 caracteres |
| Corpo de webhook ligado num Prompt | 256.000 caracteres |
| Upload em multipart | 200 MB |
| Anexos por chamada | 10 |
| Tamanho da `key` | 200 caracteres |
| Tamanho do `callbackUrl` | 500 caracteres |
| Headers repassados ao Flow | 40 (nome 80, valor 512 caracteres) |
| Tempo de espera da Entrada de API | padrão 20 s, máximo 25 s |
| Chamadas simultâneas por Entrada de API | padrão 20, máximo 200 |
| Resposta da Entrada de API | 6 MB |
| Headers extras na resposta | 20 |
| Registros no evento `conclusao` | 500 |
| Itens por página em `…/itens` | 1 a 500 (padrão 100) |
| Validade da sessão do usuário (JWT) | 24 horas |
| Validade da sessão do App (`bfs_`) | 7 dias |
| Retentativas de callback | 3 (1 s, 4 s, 16 s) |
