Gravô MeetAPI v1

API Enterprise — leitura de transcrições

Leia por programa as transcrições das reuniões da sua conta Enterprise — para relatórios, automações ou análise com IA. Somente leitura, no mesmo escopo do site.

Base URLhttps://gravo-meet.com.br/api/v1 — todas as rotas terminam em /
AutenticaçãoAuthorization: Bearer <token> (só no header)
FormatoJSON · chaves em inglês · datas ISO-8601 (UTC)
MétodosApenas GET — a API é somente leitura

Relatórios e painéis

Power BI, Metabase, planilhas — quantas reuniões, duração por time.

Automações

Ligar o Gravô a outras ferramentas (ex.: resumo no Slack).

Análise com IA

Deixar uma IA ler as transcrições em volume (objeções, churn).

Autenticação

Todo request leva um token no header Authorization. Gere e revogue tokens em /conta/api (o token aparece uma única vez; guarde como uma senha). Envie o token apenas no header — nunca na URL, que vaza em logs. Não há CORS: o consumo é servidor-a-servidor.

Shell
curl -H "Authorization: Bearer SEU_TOKEN" \
  "https://gravo-meet.com.br/api/v1/transcripts/"

Sem token válido, a API responde 401:

Resposta · 401
{ "error": "unauthorized", "message": "Token inválido ou revogado." }

Escopo de acesso

O token enxerga exatamente o que a pessoa vê no site — nada além:

  • Administrador — a conta Enterprise inteira.
  • Gerente de time — apenas os times que ele gerencia (membros, grupos e transcrições fora desse recorte não aparecem).

Se a conta sair do Enterprise ou a pessoa perder o papel, o token para de funcionar (403), mesmo válido. Combine filtros com & (AND); dentro de um filtro, valores separados por vírgula são OR.

Limites de uso

Duas cotas por janela de 60 segundos. Ao estourar, a API responde 429.

  • 240 req/min por IP (verificada antes do token).
  • 120 req/min por token.

Listar transcrições

GET/transcripts/

Metadados das transcrições no escopo do token (não retorna o texto). Paginação por cursor: enquanto next_cursor não for null, repita passando cursor=<next_cursor>.

ParâmetroTipoDescrição
sectorcsvIDs de time (veja Times). "none" = sem time. Vários valores = OR.
personcsvE-mails dos donos. Vários = OR. E-mail desconhecido é ignorado.
fromAAAA-MM-DDData inicial, inclusiva.
toAAAA-MM-DDData final, inclusiva.
min_durationnúmeroDuração mínima em minutos. Sem duração registrada fica de fora.
time_fromHH:MMInício da janela de horário do dia (fuso de Brasília, UTC−3), inclusivo.
time_toHH:MMFim da janela de horário do dia (Brasília), inclusivo. Se time_from > time_to, cruza a meia-noite.
cursorstringnext_cursor da página anterior.
limitinteiro1–200. Padrão 50.
titlestringFiltra por trecho do título.
Shell
curl -H "Authorization: Bearer SEU_TOKEN" \
  "https://gravo-meet.com.br/api/v1/transcripts/?person=ana@empresa.com&min_duration=5&time_from=08:00&time_to=12:00"
Resposta · 200
{
  "data": [
    {
      "id": "clx8a1b2c0001",
      "title": "Weekly de Vendas",
      "meeting_date": "2026-08-14T13:02:11.000Z",
      "duration_sec": 2730,
      "owner": { "id": "usr_123", "name": "Ana Souza", "email": "ana@empresa.com" },
      "sector": { "id": "grp_vendas", "name": "Vendas" }
    },
    {
      "id": "clx8a1b2c0002",
      "title": "Call cliente Acme",
      "meeting_date": "2026-08-13T18:40:00.000Z",
      "duration_sec": 1980,
      "owner": { "id": "usr_123", "name": "Ana Souza", "email": "ana@empresa.com" },
      "sector": null
    }
  ],
  "next_cursor": "clx8a1b2c0002"
}
Campos. duration_sec pode ser null; sector é null quando a reunião não está em nenhum time.

Buscar no texto

GET/transcripts/search/

Busca FULLTEXT no título + corpo de todas as reuniões do escopo. Aceita os mesmos filtros da lista (incluindo time_from/time_to), mais o obrigatório q. Cada resultado traz um snippet ao redor da ocorrência.

ParâmetroTipoDescrição
qobrigatóriostringTermo de busca (linguagem natural).
sectorcsvIDs de time (veja Times). "none" = sem time. Vários valores = OR.
personcsvE-mails dos donos. Vários = OR. E-mail desconhecido é ignorado.
fromAAAA-MM-DDData inicial, inclusiva.
toAAAA-MM-DDData final, inclusiva.
min_durationnúmeroDuração mínima em minutos. Sem duração registrada fica de fora.
time_fromHH:MMInício da janela de horário do dia (fuso de Brasília, UTC−3), inclusivo.
time_toHH:MMFim da janela de horário do dia (Brasília), inclusivo. Se time_from > time_to, cruza a meia-noite.
cursorstringnext_cursor da página anterior.
limitinteiro1–200. Padrão 50.
Shell
curl -H "Authorization: Bearer SEU_TOKEN" \
  "https://gravo-meet.com.br/api/v1/transcripts/search/?q=cancelamento&from=2026-08-01"
Resposta · 200
{
  "data": [
    {
      "id": "clx8a1b2c0001",
      "title": "Weekly de Vendas",
      "meeting_date": "2026-08-14T13:02:11.000Z",
      "duration_sec": 2730,
      "owner": { "id": "usr_123", "name": "Ana Souza", "email": "ana@empresa.com" },
      "sector": { "id": "grp_vendas", "name": "Vendas" },
      "snippet": "...o cliente falou em cancelamento se não resolvermos o SLA..."
    }
  ],
  "next_cursor": null
}

Obter transcrição

GET/transcripts/{id}/

Uma transcrição com o texto integral no campo body.

Atenção ao shape. Aqui o owner vem sem id (só name + email) e o sector só com name — diferente da lista.
ParâmetroTipoDescrição
idobrigatóriopathID da transcrição.
partinteiroOpcional. Devolve só a parte N (~30k caracteres) + part/total_parts. Sem ele, o body vem integral.
Shell
curl -H "Authorization: Bearer SEU_TOKEN" \
  "https://gravo-meet.com.br/api/v1/transcripts/clx8a1b2c0001/"
Resposta · 200
{
  "id": "clx8a1b2c0001",
  "title": "Weekly de Vendas",
  "meeting_date": "2026-08-14T13:02:11.000Z",
  "duration_sec": 2730,
  "owner": { "name": "Ana Souza", "email": "ana@empresa.com" },
  "sector": { "name": "Vendas" },
  "body": "[00:00] Ana: bom dia pessoal...\n[00:12] João: ..."
}

Por parte (clientes com teto de resposta)

?part=N devolve só a parte N. Se total_parts > 1, busque as seguintes. Útil quando o cliente corta respostas longas (ex.: GPT Actions).

Shell
curl -H "Authorization: Bearer SEU_TOKEN" \
  "https://gravo-meet.com.br/api/v1/transcripts/clx8a1b2c0001/?part=1"
Resposta · 200
{
  "id": "clx8a1b2c0001",
  "title": "Weekly de Vendas",
  "meeting_date": "2026-08-14T13:02:11.000Z",
  "duration_sec": 2730,
  "owner": { "name": "Ana Souza", "email": "ana@empresa.com" },
  "sector": { "name": "Vendas" },
  "part": 1,
  "total_parts": 3,
  "body": "[00:00] Ana: bom dia pessoal..."
}

404 not_found para id inexistente, de outra conta ou fora do escopo do gerente (não revela existência).

Membros

GET/members/

Membros da conta. sectors é uma lista (um membro pode estar em vários times; vazia = sem time). name pode ser null (convite não aceito). Gerente vê só membros de times que gerencia.

Shell
curl -H "Authorization: Bearer SEU_TOKEN" \
  "https://gravo-meet.com.br/api/v1/members/"
Resposta · 200
{
  "data": [
    {
      "id": "mbr_1",
      "name": "Ana Souza",
      "email": "ana@empresa.com",
      "role": "admin",
      "status": "active",
      "sectors": [ { "id": "grp_vendas", "name": "Vendas" } ]
    },
    {
      "id": "mbr_2",
      "name": null,
      "email": "novo@empresa.com",
      "role": "member",
      "status": "invited",
      "sectors": []
    }
  ]
}

Times

GET/groups/

Times internos, para montar o filtro sector. O context (opcional) é o texto de fundo do setor, cadastrado pelo admin — serve para interpretar as reuniões daquele time, não é conteúdo de reunião.

Shell
curl -H "Authorization: Bearer SEU_TOKEN" \
  "https://gravo-meet.com.br/api/v1/groups/"
Resposta · 200
{
  "data": [
    { "id": "grp_vendas", "name": "Vendas", "member_count": 8, "context": "Inside sales; ICP são PMEs de varejo. Siglas: MQL, SQL." },
    { "id": "grp_cs", "name": "Customer Success", "member_count": 5, "context": null }
  ]
}

Contexto por empresa

GET/context/

Texto de fundo por domínio (cada domínio é uma empresa). Para interpretar uma reunião, aplique o contexto do domínio do e-mail do dono. Só vêm domínios com contexto cadastrado.

Shell
curl -H "Authorization: Bearer SEU_TOKEN" \
  "https://gravo-meet.com.br/api/v1/context/"
Resposta · 200
{
  "data": [
    { "domain": "acme.com", "context": "Acme: e-commerce de moda. PDP = página de produto; GMV = volume de vendas." },
    { "domain": "empresa.com", "context": "Nossa empresa; SaaS B2B." }
  ]
}

Erros

Toda falha responde { "error": "<slug>", "message"?: "<humano>" }.

ParâmetroTipoDescrição
400invalid_*Parâmetro inválido: invalid_date, invalid_min_duration, invalid_limit, invalid_cursor, invalid_time, invalid_part, missing_q.
401unauthorizedToken ausente, inválido ou revogado.
403forbiddenSem conta Enterprise ou sem papel de admin/gerente.
404not_foundTranscrição inexistente ou fora do escopo.
429rate_limitedCota de requisições excedida — aguarde.

Exemplo: exportar reuniões por turno

A janela de horário é filtrada no servidor com time_from/time_to (fuso de Brasília). Cada turno é uma chamada com sua janela — sem baixar tudo e converter fuso no cliente. Corte: manhã 00:00–11:59, tarde 12:00–23:59 (ambos inclusivos).

Python
import requests

BASE = "https://gravo-meet.com.br/api/v1"
H = {"Authorization": "Bearer SEU_TOKEN"}

def listar(params):
    """Pagina a lista aplicando os filtros (inclusive time_from/time_to)."""
    cursor, todas = None, []
    while True:
        page = requests.get(
            f"{BASE}/transcripts/",
            headers=H,
            params={**params, "limit": 200, **({"cursor": cursor} if cursor else {})},
        ).json()
        todas += page["data"]
        cursor = page["next_cursor"]
        if not cursor:
            break
    return todas

turnos = {
    "manha": {"time_from": "00:00", "time_to": "11:59"},
    "tarde": {"time_from": "12:00", "time_to": "23:59"},
}

for nome, janela in turnos.items():
    reunioes = listar({"from": "2026-08-01", "to": "2026-08-31", **janela})
    for t in reunioes:
        detalhe = requests.get(f"{BASE}/transcripts/{t['id']}/", headers=H).json()
        salvar(nome, detalhe["title"], detalhe["body"])