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 URL | https://gravo-meet.com.br/api/v1 — todas as rotas terminam em / |
| Autenticação | Authorization: Bearer <token> (só no header) |
| Formato | JSON · chaves em inglês · datas ISO-8601 (UTC) |
| Métodos | Apenas 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.
curl -H "Authorization: Bearer SEU_TOKEN" \
"https://gravo-meet.com.br/api/v1/transcripts/"Sem token válido, a API responde 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
/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âmetro | Tipo | Descrição |
|---|---|---|
sector | csv | IDs de time (veja Times). "none" = sem time. Vários valores = OR. |
person | csv | E-mails dos donos. Vários = OR. E-mail desconhecido é ignorado. |
from | AAAA-MM-DD | Data inicial, inclusiva. |
to | AAAA-MM-DD | Data final, inclusiva. |
min_duration | número | Duração mínima em minutos. Sem duração registrada fica de fora. |
time_from | HH:MM | Início da janela de horário do dia (fuso de Brasília, UTC−3), inclusivo. |
time_to | HH:MM | Fim da janela de horário do dia (Brasília), inclusivo. Se time_from > time_to, cruza a meia-noite. |
cursor | string | next_cursor da página anterior. |
limit | inteiro | 1–200. Padrão 50. |
title | string | Filtra por trecho do título. |
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"{
"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"
}duration_sec pode ser null; sector é null quando a reunião não está em nenhum time.Buscar no texto
/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âmetro | Tipo | Descrição |
|---|---|---|
qobrigatório | string | Termo de busca (linguagem natural). |
sector | csv | IDs de time (veja Times). "none" = sem time. Vários valores = OR. |
person | csv | E-mails dos donos. Vários = OR. E-mail desconhecido é ignorado. |
from | AAAA-MM-DD | Data inicial, inclusiva. |
to | AAAA-MM-DD | Data final, inclusiva. |
min_duration | número | Duração mínima em minutos. Sem duração registrada fica de fora. |
time_from | HH:MM | Início da janela de horário do dia (fuso de Brasília, UTC−3), inclusivo. |
time_to | HH:MM | Fim da janela de horário do dia (Brasília), inclusivo. Se time_from > time_to, cruza a meia-noite. |
cursor | string | next_cursor da página anterior. |
limit | inteiro | 1–200. Padrão 50. |
curl -H "Authorization: Bearer SEU_TOKEN" \
"https://gravo-meet.com.br/api/v1/transcripts/search/?q=cancelamento&from=2026-08-01"{
"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
/transcripts/{id}/Uma transcrição com o texto integral no campo body.
owner vem sem id (só name + email) e o sector só com name — diferente da lista.| Parâmetro | Tipo | Descrição |
|---|---|---|
idobrigatório | path | ID da transcrição. |
part | inteiro | Opcional. Devolve só a parte N (~30k caracteres) + part/total_parts. Sem ele, o body vem integral. |
curl -H "Authorization: Bearer SEU_TOKEN" \
"https://gravo-meet.com.br/api/v1/transcripts/clx8a1b2c0001/"{
"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).
curl -H "Authorization: Bearer SEU_TOKEN" \
"https://gravo-meet.com.br/api/v1/transcripts/clx8a1b2c0001/?part=1"{
"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
/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.
curl -H "Authorization: Bearer SEU_TOKEN" \
"https://gravo-meet.com.br/api/v1/members/"{
"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
/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.
curl -H "Authorization: Bearer SEU_TOKEN" \
"https://gravo-meet.com.br/api/v1/groups/"{
"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
/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.
curl -H "Authorization: Bearer SEU_TOKEN" \
"https://gravo-meet.com.br/api/v1/context/"{
"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âmetro | Tipo | Descrição |
|---|---|---|
400 | invalid_* | Parâmetro inválido: invalid_date, invalid_min_duration, invalid_limit, invalid_cursor, invalid_time, invalid_part, missing_q. |
401 | unauthorized | Token ausente, inválido ou revogado. |
403 | forbidden | Sem conta Enterprise ou sem papel de admin/gerente. |
404 | not_found | Transcrição inexistente ou fora do escopo. |
429 | rate_limited | Cota 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).
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"])