API V1 para LLMs
API somente de leitura para agentes LLM, scripts de automação e integrações. Dá acesso aos dados do grafo do espaço de trabalho do Notion — busca, detalhes dos nós, conteúdo das páginas e percursos no grafo.
Visão geral
| Propriedade | Valor |
|---|---|
| URL base | /v1/graph/ |
| Autenticação | Token de serviço (Authorization: Bearer ivg_*) |
| Formato | JSON |
| Limites de requisições | 20 req/10s em rajada, 600 req/15min por janela |
| Especificação autodescritiva | GET /v1/ (não exige autenticação) |
Parâmetros comuns
Todos os endpoints exigem workspace_id:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| workspace_id | string (UUID) | sim | UUID do espaço de trabalho do Notion. Deve estar entre os workspace_ids permitidos pelo token. |
Endpoints
GET /v1/graph/search/
Busca nós pelo título em todo o espaço de trabalho. Usa Elasticsearch quando disponível; caso contrário, faz a correspondência em memória.
Escopo: graph:search
Parâmetros:
| Parâmetro | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
| q | string | sim | — | Consulta de busca (máximo de 256 caracteres) |
| workspace_id | string | sim | — | UUID do espaço de trabalho de destino |
| limit | int | não | 20 | Resultados por página (máximo de 50) |
| type | string | não | all | Filtro: page, database ou user |
Exemplo de requisição:
curl -H "Authorization: Bearer ivg_your_token" \
"https://ivgraph.com/v1/graph/search?q=project&workspace_id=abc-123&limit=5"
import requests
resp = requests.get(
"https://ivgraph.com/v1/graph/search",
headers={"Authorization": "Bearer ivg_your_token"},
params={"q": "project", "workspace_id": "abc-123", "limit": 5}
)
data = resp.json()
const resp = await fetch(
"https://ivgraph.com/v1/graph/search?q=project&workspace_id=abc-123&limit=5",
{ headers: { Authorization: "Bearer ivg_your_token" } }
);
const data = await resp.json();
Resposta:
{
"query": "project",
"total": 3,
"results": [
{"id": "550e8400-e29b-41d4-a716-446655440001", "type": "page", "title": "Project Alpha", "score": 0.95},
{"id": "550e8400-e29b-41d4-a716-446655440002", "type": "database", "title": "Projects Tracker", "score": 0.72},
{"id": "550e8400-e29b-41d4-a716-446655440003", "type": "page", "title": "Project Notes", "score": 0.61}
]
}
Erros:
| Status | Significado |
|---|---|
| 400 | q ou workspace_id ausente, consulta muito longa ou caracteres não permitidos |
| 401 | Token de serviço ausente ou inválido |
| 403 | Token sem o escopo graph:search ou espaço de trabalho fora da lista de permitidos |
| 404 | Não há dados sincronizados para este espaço de trabalho |
| 429 | Limite de requisições excedido |
GET /v1/graph/nodes/{node_id}/
Obtém um único nó com todos os campos seguros: título, tipo, URL, ícone, contagens de conexões, pagerank e propriedades.
Escopo: graph:read
Parâmetros:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| node_id | UUID | sim | ID do nó (no caminho da URL) |
| workspace_id | string | sim | UUID do espaço de trabalho de destino |
Exemplo de requisição:
curl -H "Authorization: Bearer ivg_your_token" \
"https://ivgraph.com/v1/graph/nodes/550e8400-e29b-41d4-a716-446655440001/?workspace_id=abc-123"
import requests
node_id = "550e8400-e29b-41d4-a716-446655440001"
resp = requests.get(
f"https://ivgraph.com/v1/graph/nodes/{node_id}/",
headers={"Authorization": "Bearer ivg_your_token"},
params={"workspace_id": "abc-123"}
)
node = resp.json()["node"]
const nodeId = "550e8400-e29b-41d4-a716-446655440001";
const resp = await fetch(
`https://ivgraph.com/v1/graph/nodes/${nodeId}/?workspace_id=abc-123`,
{ headers: { Authorization: "Bearer ivg_your_token" } }
);
const { node } = await resp.json();
Resposta:
{
"node": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"type": "page",
"title": "Project Alpha",
"url": "https://www.notion.so/Project-Alpha-550e8400e29b41d4a716446655440001",
"icon": {"type": "emoji", "emoji": "\ud83d\ude80"},
"connections_in": 5,
"connections_out": 12,
"connections_total": 17,
"pagerank": 0.42,
"properties": {}
}
}
Erros:
| Status | Significado |
|---|---|
| 400 | Formato de node_id inválido ou workspace_id ausente |
| 401 | Token de serviço ausente ou inválido |
| 403 | Token sem o escopo graph:read ou espaço de trabalho não permitido |
| 404 | Nó não encontrado ou não há dados sincronizados para o espaço de trabalho |
| 429 | Limite de requisições excedido |
GET /v1/graph/content/{page_id}/
Obtém o conteúdo da página em Markdown e texto simples. O conteúdo é extraído dos blocos do Notion sincronizados via Airbyte.
Escopo: graph:read
Parâmetros:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| page_id | UUID | sim | ID da página (no caminho da URL) |
| workspace_id | string | sim | UUID do espaço de trabalho de destino |
Exemplo de requisição:
curl -H "Authorization: Bearer ivg_your_token" \
"https://ivgraph.com/v1/graph/content/550e8400-e29b-41d4-a716-446655440001/?workspace_id=abc-123"
import requests
page_id = "550e8400-e29b-41d4-a716-446655440001"
resp = requests.get(
f"https://ivgraph.com/v1/graph/content/{page_id}/",
headers={"Authorization": "Bearer ivg_your_token"},
params={"workspace_id": "abc-123"}
)
content = resp.json()
print(content["markdown"])
const pageId = "550e8400-e29b-41d4-a716-446655440001";
const resp = await fetch(
`https://ivgraph.com/v1/graph/content/${pageId}/?workspace_id=abc-123`,
{ headers: { Authorization: "Bearer ivg_your_token" } }
);
const { markdown, plain_text } = await resp.json();
Resposta:
{
"page_id": "550e8400-e29b-41d4-a716-446655440001",
"title": "Project Alpha",
"markdown": "# Project Alpha\n\nThis is the main project page.\n\n## Goals\n\n- Launch beta by Q2\n- Reach 100 users",
"plain_text": "Project Alpha\nThis is the main project page.\nGoals\nLaunch beta by Q2\nReach 100 users",
"has_content": true
}
Erros:
| Status | Significado |
|---|---|
| 400 | Formato de page_id inválido ou workspace_id ausente |
| 401 | Token de serviço ausente ou inválido |
| 403 | Token sem o escopo graph:read ou espaço de trabalho não permitido |
| 404 | Página não encontrada ou não há dados sincronizados para o espaço de trabalho |
| 429 | Limite de requisições excedido |
GET /v1/graph/neighbors/{node_id}/
Percorre o grafo com BFS e retorna vizinhos e arestas até uma determinada profundidade. Útil para explorar a estrutura local do grafo ao redor de um nó.
Escopo: graph:neighbors
Parâmetros:
| Parâmetro | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
| node_id | UUID | sim | — | ID do nó inicial (no caminho da URL) |
| workspace_id | string | sim | — | UUID do espaço de trabalho de destino |
| depth | int | não | 1 | Profundidade do percurso (máximo de 3) |
| limit | int | não | 20 | Número máximo de vizinhos a retornar (máximo de 50) |
| direction | string | não | both | Direção das arestas: in, out ou both |
Exemplo de requisição:
curl -H "Authorization: Bearer ivg_your_token" \
"https://ivgraph.com/v1/graph/neighbors/550e8400-e29b-41d4-a716-446655440001/?workspace_id=abc-123&depth=2&limit=10"
import requests
node_id = "550e8400-e29b-41d4-a716-446655440001"
resp = requests.get(
f"https://ivgraph.com/v1/graph/neighbors/{node_id}/",
headers={"Authorization": "Bearer ivg_your_token"},
params={"workspace_id": "abc-123", "depth": 2, "limit": 10}
)
data = resp.json()
print(f"Found {data['total']} neighbors")
const nodeId = "550e8400-e29b-41d4-a716-446655440001";
const resp = await fetch(
`https://ivgraph.com/v1/graph/neighbors/${nodeId}/?workspace_id=abc-123&depth=2&limit=10`,
{ headers: { Authorization: "Bearer ivg_your_token" } }
);
const { neighbors, edges, total } = await resp.json();
Resposta:
{
"node_id": "550e8400-e29b-41d4-a716-446655440001",
"depth": 2,
"total": 4,
"neighbors": [
{"id": "550e8400-e29b-41d4-a716-446655440010", "type": "page", "title": "Sprint Planning"},
{"id": "550e8400-e29b-41d4-a716-446655440011", "type": "database", "title": "Tasks"},
{"id": "550e8400-e29b-41d4-a716-446655440012", "type": "page", "title": "Design Doc"},
{"id": "550e8400-e29b-41d4-a716-446655440013", "type": "user", "title": "Alice"}
],
"edges": [
{"source": "550e8400-e29b-41d4-a716-446655440001", "target": "550e8400-e29b-41d4-a716-446655440010", "type": "reference"},
{"source": "550e8400-e29b-41d4-a716-446655440001", "target": "550e8400-e29b-41d4-a716-446655440011", "type": "parent"},
{"source": "550e8400-e29b-41d4-a716-446655440010", "target": "550e8400-e29b-41d4-a716-446655440012", "type": "mention"},
{"source": "550e8400-e29b-41d4-a716-446655440012", "target": "550e8400-e29b-41d4-a716-446655440013", "type": "mention"}
]
}
Erros:
| Status | Significado |
|---|---|
| 400 | Formato de node_id inválido ou workspace_id ausente |
| 401 | Token de serviço ausente ou inválido |
| 403 | Token sem o escopo graph:neighbors ou espaço de trabalho não permitido |
| 404 | Nó não encontrado ou não há dados sincronizados para o espaço de trabalho |
| 429 | Limite de requisições excedido |
POST /v1/graph/traverse/
Encontra o caminho mais curto entre dois nós usando BFS. Retorna o caminho como uma lista ordenada de nós, ou null se não houver um caminho dentro da profundidade máxima.
Escopo: graph:neighbors
Corpo da requisição (JSON):
| Parâmetro | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
| start_id | UUID | sim | — | Nó inicial |
| target_id | UUID | sim | — | Nó de destino |
| workspace_id | string | sim | — | UUID do espaço de trabalho de destino |
| max_depth | int | não | 3 | Profundidade máxima do percurso (máximo de 3) |
Exemplo de requisição:
curl -X POST "https://ivgraph.com/v1/graph/traverse/" \
-H "Authorization: Bearer ivg_your_token" \
-H "Content-Type: application/json" \
-d '{
"start_id": "550e8400-e29b-41d4-a716-446655440001",
"target_id": "550e8400-e29b-41d4-a716-446655440012",
"workspace_id": "abc-123"
}'
import requests
resp = requests.post(
"https://ivgraph.com/v1/graph/traverse/",
headers={
"Authorization": "Bearer ivg_your_token",
"Content-Type": "application/json"
},
json={
"start_id": "550e8400-e29b-41d4-a716-446655440001",
"target_id": "550e8400-e29b-41d4-a716-446655440012",
"workspace_id": "abc-123"
}
)
path = resp.json()["path"]
const resp = await fetch("https://ivgraph.com/v1/graph/traverse/", {
method: "POST",
headers: {
Authorization: "Bearer ivg_your_token",
"Content-Type": "application/json"
},
body: JSON.stringify({
start_id: "550e8400-e29b-41d4-a716-446655440001",
target_id: "550e8400-e29b-41d4-a716-446655440012",
workspace_id: "abc-123"
})
});
const { path, path_length } = await resp.json();
Resposta (caminho encontrado):
{
"start": "550e8400-e29b-41d4-a716-446655440001",
"target": "550e8400-e29b-41d4-a716-446655440012",
"path_length": 2,
"path": [
{"id": "550e8400-e29b-41d4-a716-446655440001", "type": "page", "title": "Project Alpha"},
{"id": "550e8400-e29b-41d4-a716-446655440010", "type": "page", "title": "Sprint Planning"},
{"id": "550e8400-e29b-41d4-a716-446655440012", "type": "page", "title": "Design Doc"}
]
}
Resposta (sem caminho):
{
"start": "550e8400-e29b-41d4-a716-446655440001",
"target": "550e8400-e29b-41d4-a716-446655440099",
"path_length": null,
"path": []
}
Erros:
| Status | Significado |
|---|---|
| 400 | start_id/target_id/workspace_id ausente ou inválido |
| 401 | Token de serviço ausente ou inválido |
| 403 | Token sem o escopo graph:neighbors ou espaço de trabalho não permitido |
| 404 | Nó inicial ou de destino não encontrado, ou não há dados sincronizados |
| 429 | Limite de requisições excedido |
Especificação autodescritiva
GET /v1/ retorna a especificação completa da API em JSON. Não exige autenticação.
curl "https://ivgraph.com/v1/"
Retorna um JSON legível por máquina com todos os endpoints, parâmetros, esquemas de resposta, limites de requisições e escopos. Útil para que agentes LLM descubram a API de forma programática.