Primeiros passos com as integrações

Leia reuniões nos seus sistemas, receba avisos quando os resultados estiverem prontos e conecte um assistente pelo MCP. O acesso depende da funcionalidade Integrações no plano da organização.

1. Crie uma chave

Em Configurações → Integrações, escolha Nova chave, informe o nome e marque somente as permissões necessárias. Uma chave pessoal acompanha o acesso da pessoa; uma chave da organização exige administrador e lê o catálogo organizacional. A chave completa aparece uma única vez: guarde-a no cofre de segredos do seu sistema. A data de expiração termina às 23:59:59 UTC do dia escolhido.

2. Faça a primeira chamada

Defina MIORA_API_KEY no ambiente do cliente sem gravá-la no código ou no histórico do terminal. Envie-a apenas no cabeçalho:

curl --fail-with-body 'https://app.mioora.ai/api/v1/eu' \
  -H "Authorization: Bearer $MIORA_API_KEY"

curl --fail-with-body 'https://app.mioora.ai/api/v1/reunioes?limite=10' \
  -H "Authorization: Bearer $MIORA_API_KEY"

A API pública é somente leitura. Os escopos são reunioes:ler, transcricoes:ler, resumos:ler, tarefas:ler e midia:ler. Mídia não é selecionada por padrão. Use o cursor devolvido pela listagem para continuar. Consulte os campos e filtros na referência interativa.

401 indica credencial ausente, expirada ou revogada; 403 indica escopo ou plano sem acesso; 404 preserva a privacidade de reuniões invisíveis; 429 pede espera conforme Retry-After. Os erros REST usam application/problem+json.

3. Receba e valide os avisos

Cadastre um destino HTTPS público na mesma tela, escolha os eventos e guarde o segredo whsec_…. Use Testar para conferir a conexão. Cada entrega inclui webhook-id, webhook-timestamp e webhook-signature, seguindo Standard Webhooks. A mensagem assinada é id.timestamp.corpo-original, com HMAC-SHA256 e chave decodificada de base64 após remover whsec_.

Verifique os bytes originais antes de interpretar JSON, recuse timestamps fora de uma janela de cinco minutos e deduplique por webhook-id em armazenamento durável. Responda 2xx após persistir o recebimento e processe em segundo plano. Pode haver repetição e chegada fora de ordem. Na rotação, aceite qualquer assinatura v1 válida da lista; os dois segredos coexistem temporariamente. O envelope contém referências, e o conteúdo deve ser consultado pela API com escopo adequado.

Go

package receptor

import (
 "crypto/hmac"
 "crypto/sha256"
 "encoding/base64"
 "net/http"
 "strconv"
 "strings"
 "time"
)

// Passe os bytes originais, antes de interpretar o JSON.
func Verificar(segredo string, h http.Header, corpo []byte, agora time.Time) bool {
 id, ts := h.Get("webhook-id"), h.Get("webhook-timestamp")
 segundos, err := strconv.ParseInt(ts, 10, 64)
 if err != nil || id == "" || segundos < agora.Unix()-300 || segundos > agora.Unix()+300 { return false }
 if !strings.HasPrefix(segredo, "whsec_") { return false }
 chave, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(segredo,"whsec_"))
 if err != nil || len(chave) == 0 { return false }
 mac := hmac.New(sha256.New,chave)
 mac.Write([]byte(id+"."+ts+".")); mac.Write(corpo)
 esperada := mac.Sum(nil)
 for _, assinatura := range strings.Fields(h.Get("webhook-signature")) {
  versao, valor, _ := strings.Cut(assinatura,",")
  recebida, err := base64.StdEncoding.DecodeString(valor)
  if versao == "v1" && err == nil && hmac.Equal(recebida,esperada) { return true }
 }
 return false
}

Node.js

import { createHmac, timingSafeEqual } from 'node:crypto';

// headers é um objeto Headers; corpo é Buffer/Uint8Array sem reserializar o JSON.
export function verificar(segredo, headers, corpo, agora = Date.now() / 1000) {
  const id = headers.get('webhook-id'), ts = headers.get('webhook-timestamp');
  if (!id || !ts || !/^\d+$/.test(ts) || Math.abs(agora - Number(ts)) > 300) return false;
  if (!segredo.startsWith('whsec_')) return false;
  const chave = Buffer.from(segredo.slice(6), 'base64');
  if (!chave.length) return false;
  const esperada = createHmac('sha256', chave).update(`${id}.${ts}.`).update(corpo).digest();
  return (headers.get('webhook-signature') ?? '').split(/\s+/).some(parte => {
    const [versao, valor] = parte.split(',');
    if (versao !== 'v1' || !valor) return false;
    const recebida = Buffer.from(valor, 'base64');
    return recebida.length === esperada.length && timingSafeEqual(recebida, esperada);
  });
}

Python

import base64
import hashlib
import hmac
import time


def verificar(segredo, headers, corpo, agora=None):
    """headers com nomes minúsculos; corpo são os bytes originais da requisição."""
    agora = time.time() if agora is None else agora
    identificador = headers.get("webhook-id", "")
    ts = headers.get("webhook-timestamp", "")
    try:
        if not identificador or abs(agora - int(ts)) > 300:
            return False
        if not segredo.startswith("whsec_"):
            return False
        chave = base64.b64decode(segredo[6:], validate=True)
        if not chave:
            return False
        mensagem = f"{identificador}.{ts}.".encode() + corpo
        esperada = hmac.new(chave, mensagem, hashlib.sha256).digest()
        for assinatura in headers.get("webhook-signature", "").split():
            versao, _, valor = assinatura.partition(",")
            try:
                recebida = base64.b64decode(valor, validate=True)
            except ValueError:
                continue
            if versao == "v1" and hmac.compare_digest(recebida, esperada):
                return True
    except (ValueError, TypeError):
        return False
    return False

4. Conecte um assistente pelo MCP

Informe https://app.mioora.ai/api/mcp no cliente. Ele descobre o servidor de autorização, registra o aplicativo e abre a tela do Mioora. Confira aplicativo, endereço de retorno, conta e permissões antes de permitir. Clientes locais podem retornar para localhost em uma porta temporária. Nunca coloque a credencial na URL.

O transporte é Streamable HTTP. As ferramentas de reuniões são listar_reunioes, obter_reuniao, obter_resumo, obter_transcricao, buscar, listar_tarefas e obter_participantes. Todas leem; nenhuma altera dados. Buscar exige os escopos de reuniões, resumos e transcrições porque consulta esses conteúdos.

Comece por obter_contexto: ele informa o nome da organização atual, usuário autenticado, papel, escopos e aliases/bots ativos aos quais a credencial tem acesso. Os aliases exigem reunioes:ler; sem esse escopo, o contexto informa a restrição. O contexto não amplia suas permissões.

Para “minhas tarefas”, use listar_minhas_tarefas com uma credencial pessoal e tarefas:ler. Ela inclui tarefas pessoais sem reunião e compromissos atribuídos ao usuário nas reuniões visíveis. Aceita situacao, atrasadas e reuniao_id. Tarefas pessoais aparecem com reuniao_id: 0. Já listar_tarefas consulta todos os responsáveis das reuniões visíveis. Uma chave de organização não identifica a pessoa que pergunta; o contexto retorna usuario: null e “minhas tarefas” não fica disponível.

Exemplo de pedido: “Consulte meu contexto no Mioora, diga minha organização e os aliases acessíveis e liste minhas tarefas atrasadas.” Se truncado for verdadeiro, apenas parte do histórico de reuniões foi consultada. Após atualizar o servidor, reconecte o cliente MCP se as novas ferramentas ainda não aparecerem.

OAuth usa PKCE S256, códigos de uso único válidos por 60 segundos, acesso de uma hora e renovação rotativa de 30 dias quando o aplicativo solicita offline_access. DCR e CIMD aceitam aplicativos públicos sem segredo de cliente. Também é possível usar uma chave de API no cabeçalho Bearer. Desconectar em Aplicativos conectados revoga o acesso e a renovação.

Operação

Para trocar uma chave, crie outra, atualize o consumidor e revogue a antiga. Para recuperar uma entrega, abra o histórico do destino e use Reenviar após corrigir a causa. É possível listar, ajustar e apagar recursos existentes mesmo após sair do plano. A criação e o consumo da integração exigem plano elegível.