Respawn Tech Dev

Base de conhecimento

Busca híbrida (semântica + palavras-chave) nos seus documentos, com rerank e feedback de relevância, para RAG e assistentes de IA.

BetaEm beta: a ferramenta está em fase de testes com contas selecionadas e pode mudar antes do lançamento. Se a sua conta ainda não tiver acesso, as chamadas respondem rag.disabled; fale com o suporte para entrar nos testes.

Envie textos e Markdown para uma base (collection) e faça buscas híbridas (semântica + palavras-chave) com rerank opcional, filtros por metadados e feedback de relevância. Pensada para alimentar assistentes e agentes de IA (RAG).

Base path
/v1/tools/rag
Escopos
tools:rag:readtools:rag:querytools:rag:managetools:manage

Visão geral

Uma base (collection) guarda documentos de texto ou Markdown. Cada documento é dividido em seções (pelos títulos) e trechos (pedaços de ~96 tokens), que são indexados de duas formas: por significado (embeddings) e por palavras-chave. A busca combina as duas e devolve os trechos mais relevantes, prontos para você passar a um modelo de linguagem (RAG) ou mostrar ao usuário.

Crie uma base com o idioma dos documentos (melhora a busca por palavras-chave).

Alimente a base. Envie texto ou Markdown, importe arquivos (PDF, Office, imagens) ou conecte uma fonte que se sincroniza sozinha (site, sitemap, repositório do GitHub, pasta do Google Drive). A indexação é assíncrona: acompanhe o status até ready. Reenviar com o mesmo external_id substitui a versão anterior sem tirar a base do ar.

Busque com a pergunta do usuário e use os trechos devolvidos como contexto da resposta.

Responda com citações (opcional): answer devolve um texto em que cada afirmação aponta para o trecho de origem, ou diz que não sabe. Para o seu site, embuta o widget.

Registre feedback (opcional): trechos confirmados sobem nas próximas buscas parecidas e os rejeitados somem.

OperaçãoRota
Criar basePOST/collections
Listar basesGET/collections
Consultar baseGET/collections/{collection_id}
Filtros disponíveisGET/collections/{collection_id}/facets
Alterar basePATCH/collections/{collection_id}
Excluir baseDELETE/collections/{collection_id}
Reindexar basePOST/collections/{collection_id}/reindex
Adicionar ou substituir documentoPOST/collections/{collection_id}/documents
Listar documentosGET/collections/{collection_id}/documents
Consultar documentoGET/collections/{collection_id}/documents/{document_id}
Alterar título ou metadadosPATCH/collections/{collection_id}/documents/{document_id}
Excluir documentoDELETE/collections/{collection_id}/documents/{document_id}
Reprocessar documento com falhaPOST/collections/{collection_id}/documents/{document_id}/retry
Ver seções indexadasGET/collections/{collection_id}/documents/{document_id}/sections
Buscar na basePOST/collections/{collection_id}/query
Registrar feedback de relevânciaPOST/collections/{collection_id}/feedback
Listar feedbackGET/collections/{collection_id}/feedback
Apagar um grupo de feedbackDELETE/collections/{collection_id}/feedback/{cluster_id}
Reordenar textos (rerank)POST/rerank
Decidir entre opções (roteamento)POST/decide
Consultar preçosGET/pricing
Consultar limitesGET/limits
Painel de saúde da baseGET/collections/{collection_id}/overview
Índice dos documentosGET/collections/{collection_id}/index
Achar duplicados e contradiçõesPOST/collections/{collection_id}/lint
Trocar o modelo de embeddingsPOST/collections/{collection_id}/model
Marcar documentos como desatualizadosPOST/collections/{collection_id}/changes
Responder com citaçõesPOST/collections/{collection_id}/answer
Analytics das perguntasGET/collections/{collection_id}/analytics
Criar chave pública (widget)POST/collections/{collection_id}/public-keys
Listar chaves públicasGET/collections/{collection_id}/public-keys
Revogar chave públicaDELETE/collections/{collection_id}/public-keys/{key_id}
Responder pelo widget (rota pública)POST/v1/public/rag/answer
Script do widgetGET/widget/rag.js
Listar fontes sincronizadasGET/collections/{collection_id}/sources
Criar fonte sincronizadaPOST/collections/{collection_id}/sources
Alterar fontePATCH/collections/{collection_id}/sources/{source_id}
Excluir fonteDELETE/collections/{collection_id}/sources/{source_id}
Sincronizar agoraPOST/collections/{collection_id}/sources/{source_id}/sync
Histórico de sincronizaçõesGET/collections/{collection_id}/sources/{source_id}/syncs
Importar arquivo (PDF, Office, imagem)POST/collections/{collection_id}/documents/file
Consultar importação de arquivoGET/collections/{collection_id}/imports/{import_id}

Custos

Por uso — Valores por unidade. Buscas e rerank têm franquia diária e são cobrados em blocos pré-pagos (tabelas seguintes). A ingestão tem desconto no documento: −20% a partir de 1.000 trechos e −40% a partir de 10.000.

ItemCréditosNotas
Ingestão, por trecho indexado0,02modelo padrão; trecho padrão ≈ 96 tokens
Ingestão Alta precisão, por trecho0,06bases com o modelo Alta precisão
Busca (modo fast)0,25—
Busca Alta precisão0,4substitui a busca padrão nas bases Alta precisão
Busca respondida do cache0,02mesma consulta nos últimos 10 min
Rerank no modo accurate+0,08sem cobrança se cair para fast
Rerank avulso, por chamada0,08—

Franquia diária — Chamadas grátis por conta e por dia (UTC). Depois delas, a cobrança é em blocos pré-pagos.

ItemGrátis por dia
Buscas20
Buscas Alta precisão5
Buscas respondidas do cache50
Rerank no modo accurate5
Rerank avulso5

Blocos pré-pagos — Depois da franquia, a chamada que abre um bloco cobra o bloco inteiro de uma vez; as seguintes do bloco não cobram de novo. Os blocos crescem com o uso pago do dia, igual em todos os serviços. As chamadas não usadas de um bloco expiram à meia-noite UTC, sem estorno.

ItemTamanho do blocoNotas
Primeiro bloco pago do dia10ex.: 10 buscas = 2,5 créditos
Até 200 chamadas pagas no dia20—
A partir de 200 chamadas pagas50—
A partir de 1.000 chamadas pagas100com −40% (desconto por volume)

Desconto por volume diário — Por serviço, conforme as chamadas pagas que os blocos anteriores do dia já somam. Soma-se ao desconto dos pacotes de crédito.

ItemDesconto no bloco
A partir de 1.000 chamadas pagas no dia−40%
A partir de 10.000 chamadas pagas no dia−70%

Armazenamento — Cobrado uma vez por dia sobre o total de trechos guardados na conta.

ItemCréditos
Primeiros 2.000 trechos0,0
Cada bloco iniciado de 10.000 trechos0,1 / dia

Como funcionam os blocos

Buscas e rerank têm uma franquia grátis por dia. Depois dela, a chamada que abre um bloco debita o bloco inteiro de uma vez (10 chamadas no primeiro, depois 20, 50 e 100 conforme o uso pago do dia), e as próximas do mesmo bloco não cobram de novo. Os contadores zeram à meia-noite UTC, e as chamadas não usadas de um bloco expiram sem estorno. A ferramenta MCP rag_get_usage e o dry_run das buscas mostram quanto a próxima chamada cobra. Consultar bases, documentos e feedback é grátis e não entra na franquia diária de leituras.

A ingestão é cobrada quando termina, pelo número real de trechos; o estimate da resposta é uma aproximação. Conteúdo idêntico ao já indexado não é cobrado de novo. Use X-Dry-Run: true no envio de documento para ver a estimativa sem enviar nada.

Bases

Criar base

POST/v1/tools/rag/collections
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage
  • name (obrigatório, até 120 caracteres) e description (até 1.000).
  • language: simple (padrão), portuguese, english, spanish ou french. Define o dicionário da busca por palavras-chave.
  • default_mode: fast (padrão) ou accurate (rerank extra, mais preciso e um pouco mais caro).
  • Ajustes avançados: chunk_size_tokens (16–480, padrão 96), chunk_overlap_tokens (padrão 16), section_max_tokens (padrão 768), max_per_document (0–20, padrão 2), dense_weight e lexical_weight (0–10, padrão 1; não podem ser os dois 0) e feedback_enabled (padrão true).
curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"name": "Central de ajuda",
"description": "Artigos públicos de suporte",
"language": "portuguese",
"default_mode": "fast"
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"name": "Central de ajuda",
"description": "Artigos públicos de suporte",
"language": "portuguese",
"default_mode": "fast"
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"name": "Central de ajuda",
"description": "Artigos públicos de suporte",
"language": "portuguese",
"default_mode": "fast"
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"name": "Central de ajuda",
"description": "Artigos públicos de suporte",
"language": "portuguese",
"default_mode": "fast"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections", strings.NewReader(`{
"name": "Central de ajuda",
"description": "Artigos públicos de suporte",
"language": "portuguese",
"default_mode": "fast"
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 201

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    "name": "Central de ajuda",
    "description": "Artigos públicos de suporte",
    "embedding_model": "intfloat/multilingual-e5-small",
    "language": "portuguese",
    "chunk_size_tokens": 96,
    "chunk_overlap_tokens": 16,
    "section_max_tokens": 768,
    "default_mode": "fast",
    "max_per_document": 2,
    "dense_weight": 1,
    "lexical_weight": 1,
    "feedback_enabled": true,
    "document_count": 0,
    "chunk_count": 0,
    "created_at": "2026-09-20T12:00:00Z",
    "updated_at": "2026-09-24T09:30:00Z"
  }
}

Listar bases

GET/v1/tools/rag/collections
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage

Devolve também o uso da conta em relação aos limites (usage).

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "collections": [
      {
        "id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
        "name": "Central de ajuda",
        "description": "Artigos públicos de suporte",
        "embedding_model": "intfloat/multilingual-e5-small",
        "language": "portuguese",
        "chunk_size_tokens": 96,
        "chunk_overlap_tokens": 16,
        "section_max_tokens": 768,
        "default_mode": "fast",
        "max_per_document": 2,
        "dense_weight": 1,
        "lexical_weight": 1,
        "feedback_enabled": true,
        "document_count": 128,
        "chunk_count": 4210,
        "created_at": "2026-09-20T12:00:00Z",
        "updated_at": "2026-09-24T09:30:00Z"
      }
    ],
    "usage": {
      "collections": 1,
      "max_collections": 50,
      "chunks": 4210,
      "max_chunks": 200000,
      "pending_documents": 0,
      "max_pending_documents": 20
    }
  }
}

Consultar base

GET/v1/tools/rag/collections/{collection_id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    "name": "Central de ajuda",
    "description": "Artigos públicos de suporte",
    "embedding_model": "intfloat/multilingual-e5-small",
    "language": "portuguese",
    "chunk_size_tokens": 96,
    "chunk_overlap_tokens": 16,
    "section_max_tokens": 768,
    "default_mode": "fast",
    "max_per_document": 2,
    "dense_weight": 1,
    "lexical_weight": 1,
    "feedback_enabled": true,
    "document_count": 128,
    "chunk_count": 4210,
    "created_at": "2026-09-20T12:00:00Z",
    "updated_at": "2026-09-24T09:30:00Z"
  }
}

Filtros disponíveis

GET/v1/tools/rag/collections/{collection_id}/facets
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage

Lista as chaves de metadados dos documentos da base e os valores mais comuns de cada uma, para você saber o que pode usar em filters nas buscas. documents é quantos documentos prontos com metadados foram analisados e keys é o total de chaves filtráveis. Se sampled for true, a base tem mais de 5000 documentos e a contagem vem só dos 5000 mais recentes. Em facets, cada item traz a key, os documents que a têm, distinct (total de valores distintos) e values[] (os valores mais comuns, cada um com value e documents). array: true indica que a chave guarda uma lista; filtre com {"chave": ["valor"]}.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/facets' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/facets', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/facets",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/facets');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/facets", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "documents": 128,
    "sampled": false,
    "keys": 2,
    "facets": [
      {
        "key": "categoria",
        "documents": 120,
        "distinct": 3,
        "values": [
          {
            "value": "conta",
            "documents": 64
          },
          {
            "value": "cobranca",
            "documents": 41
          },
          {
            "value": "api",
            "documents": 15
          }
        ]
      },
      {
        "key": "tags",
        "documents": 37,
        "array": true,
        "distinct": 2,
        "values": [
          {
            "value": "faq",
            "documents": 30
          },
          {
            "value": "legado",
            "documents": 7
          }
        ]
      }
    ]
  }
}

Alterar base

PATCH/v1/tools/rag/collections/{collection_id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage

Envie só os campos que quer mudar. O modelo de embeddings não pode ser trocado depois da criação. Mudanças no tamanho dos trechos só valem para documentos enviados depois; para aplicar à base inteira, use a reindexação.

curl -sS -X PATCH 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "default_mode": "accurate" }'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c', {
  method: 'PATCH',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ "default_mode": "accurate" }),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.patch(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={ "default_mode": "accurate" },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{ "default_mode": "accurate" }
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("PATCH", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c", strings.NewReader(`{ "default_mode": "accurate" }`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    "name": "Central de ajuda",
    "description": "Artigos públicos de suporte",
    "embedding_model": "intfloat/multilingual-e5-small",
    "language": "portuguese",
    "chunk_size_tokens": 96,
    "chunk_overlap_tokens": 16,
    "section_max_tokens": 768,
    "default_mode": "fast",
    "max_per_document": 2,
    "dense_weight": 1,
    "lexical_weight": 1,
    "feedback_enabled": true,
    "document_count": 128,
    "chunk_count": 4210,
    "created_at": "2026-09-20T12:00:00Z",
    "updated_at": "2026-09-24T09:30:00Z"
  }
}

Reindexar base

POST/v1/tools/rag/collections/{collection_id}/reindex
Custo
Reprocessa todos os documentos; cada trecho é cobrado como na ingestão
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage

Reprocessa todos os documentos com as configurações atuais da base. Cada trecho é cobrado como numa ingestão nova.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/reindex' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/reindex', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/reindex",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/reindex');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/reindex", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 202

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "documents_enqueued": 128
  }
}

Painel de saúde da base

GET/v1/tools/rag/collections/{collection_id}/overview
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage

Resumo para manter a base em ordem, sem custo: contagem de documentos por status, quantos estão desatualizados (stale), nunca foram consultados ou não têm metadados; uma matriz de documentos por metadado (rows e cols são chaves de metadado, até 20 valores por eixo); a atividade dos últimos days dias (1 a 180, padrão 30); e attention, com até 5 exemplos de documentos com falha, desatualizados, duplicados ou contraditórios e com feedback negativo. A resposta fica em cache por 60 s.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/overview?rows=categoria&days=30' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/overview?rows=categoria&days=30', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/overview?rows=categoria&days=30",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/overview?rows=categoria&days=30');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/overview?rows=categoria&days=30", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "counts": {
      "total": 128,
      "by_status": {
        "pending": 0,
        "processing": 0,
        "ready": 126,
        "failed": 2
      },
      "stale": 4,
      "never_accessed": 31,
      "without_metadata": 8,
      "total_bytes": 912000,
      "total_sections": 540
    },
    "matrix": {
      "rows_key": "categoria",
      "cols_key": "",
      "rows": [
        "conta",
        "api"
      ],
      "cols": [],
      "cells": [
        {
          "row": "conta",
          "col": "",
          "count": 64
        }
      ]
    },
    "activity": {
      "key": "",
      "days": 30,
      "values": [],
      "series": [
        {
          "date": "2026-10-20",
          "total": 12,
          "counts": {}
        }
      ]
    },
    "attention": {
      "failed": {
        "count": 2,
        "items": [
          {
            "id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
            "title": "Como trocar a senha"
          }
        ]
      },
      "stale": {
        "count": 4,
        "items": []
      },
      "lint": {
        "count": 1,
        "items": []
      },
      "negative_feedback": {
        "count": 0,
        "items": []
      }
    },
    "generated_at": "2026-10-20T12:00:00Z"
  }
}

Índice dos documentos

GET/v1/tools/rag/collections/{collection_id}/index
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage

Lista compacta dos documentos ready, sem conteúdo, para o agente escolher o que ler. filters (JSON de metadados), fields (até 20 chaves de metadado a copiar), order (updated_at_desc, padrão, ou title) e max_bytes (padrão 4096, máximo 32768). omitted conta os documentos cortados pelo limite.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/index?fields=categoria&order=title' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/index?fields=categoria&order=title', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/index?fields=categoria&order=title",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/index?fields=categoria&order=title');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/index?fields=categoria&order=title", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "total": 126,
    "omitted": 0,
    "documents": [
      {
        "document_id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
        "external_id": "artigo-42",
        "title": "Como trocar a senha",
        "updated_at": "2026-09-24T09:30:05Z",
        "metadata": {
          "categoria": "conta"
        }
      }
    ]
  }
}

Achar duplicados e contradições

POST/v1/tools/rag/collections/{collection_id}/lint
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage

Compara os 500 documentos mais recentes (opcionalmente filtrados por filters) com os embeddings que já existem; não chama modelo e não escreve nada. duplicate aparece com similaridade a partir de 0,75; possible_contradiction, entre 0,4 e 0,75 quando os dois têm o mesmo metadado tipo. Cada achado diz qual documento manter (keep, o mais novo) e o que fazer (action). limit vai de 1 a 100 (padrão 20) e include_content: true devolve o início de cada documento.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/lint' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "limit": 20 }'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/lint', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ "limit": 20 }),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/lint",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={ "limit": 20 },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/lint');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{ "limit": 20 }
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/lint", strings.NewReader(`{ "limit": 20 }`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "documents": 126,
    "total": 1,
    "truncated": false,
    "found": 1,
    "findings": [
      {
        "kind": "duplicate",
        "similarity": 0.93,
        "newer": {
          "document_id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
          "external_id": "artigo-42",
          "title": "Como trocar a senha",
          "updated_at": "2026-09-24T09:30:05Z"
        },
        "older": {
          "document_id": "9d8c7b6a-5f4e-4d3c-8b2a-1f0e9d8c7b6a",
          "external_id": "artigo-7",
          "title": "Trocar senha",
          "updated_at": "2026-08-02T10:00:00Z"
        },
        "keep": "artigo-42",
        "action": "rewrite `artigo-42` merging the unique content of `artigo-7`, then delete `artigo-7`"
      }
    ]
  }
}

Trocar o modelo de embeddings

POST/v1/tools/rag/collections/{collection_id}/model
Custo
Reindexa a base com desconto de 50%; voltar ao modelo anterior é grátis por 24 h
Dry-run
Suportado (X-Dry-Run: true)
Autenticação
qualquer um detools:rag:managetools:manage

Troca entre intfloat/multilingual-e5-small (padrão) e BAAI/bge-m3 (Alta precisão) reindexando a base em segundo plano; você não precisa chamar a reindexação. A troca custa 50% do preço normal de ingestão, e voltar ao modelo anterior é grátis enquanto ela roda e por 24 h depois, uma vez. Use X-Dry-Run: true para ver a estimativa. Durante a troca a busca continua funcionando (a consulta é embutida com os dois modelos) e documentos novos são recusados com rag.model_switch_in_progress. Acompanhe pelo campo model_switch da base (running, paused ou done); se o saldo acabar, ela pausa com paused_reason: insufficient_credits e retoma quando você recarregar.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/model' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "embedding_model": "BAAI/bge-m3" }'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/model', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ "embedding_model": "BAAI/bge-m3" }),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/model",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={ "embedding_model": "BAAI/bge-m3" },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/model');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{ "embedding_model": "BAAI/bge-m3" }
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/model", strings.NewReader(`{ "embedding_model": "BAAI/bge-m3" }`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 202 — 200 com só estimate em dry-run

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "embedding_model": "BAAI/bge-m3",
    "documents_enqueued": 0,
    "documents_remaining": 128,
    "estimate": {
      "documents": 128,
      "chunks": 4210,
      "credit_units": 421000
    }
  }
}

Marcar documentos como desatualizados

POST/v1/tools/rag/collections/{collection_id}/changes
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage

Para bases ligadas a código ou a arquivos: informe os paths que mudaram (arquivo exato ou prefixo dir/, até 1000) e os documentos que declararam esses paths ao serem enviados ficam com stale: true. Nada é reindexado nem cobrado; reenviar o documento limpa a marca. Use exclude_stale na busca para ignorá-los. commit (até 64 caracteres) evita marcar o que já foi conferido naquele commit.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/changes' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "paths": ["docs/api/", "src/auth.ts"], "commit": "a1b2c3d" }'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/changes', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ "paths": ["docs/api/", "src/auth.ts"], "commit": "a1b2c3d" }),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/changes",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={ "paths": ["docs/api/", "src/auth.ts"], "commit": "a1b2c3d" },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/changes');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{ "paths": ["docs/api/", "src/auth.ts"], "commit": "a1b2c3d" }
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/changes", strings.NewReader(`{ "paths": ["docs/api/", "src/auth.ts"], "commit": "a1b2c3d" }`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "marked": 1,
    "document_ids": [
      "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e"
    ]
  }
}

Excluir base

DELETE/v1/tools/rag/collections/{collection_id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage

A exclusão é assíncrona e apaga documentos, trechos e feedback.

curl -sS -X DELETE 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c', {
  method: 'DELETE',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.delete(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("DELETE", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 202

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    "status": "deleting"
  }
}

Documentos

Adicionar ou substituir documento

POST/v1/tools/rag/collections/{collection_id}/documents
Custo
Por trecho indexado, cobrado quando a ingestão termina; conteúdo idêntico não é cobrado de novo
Dry-run
Suportado (X-Dry-Run: true)
Autenticação
qualquer um detools:rag:managetools:manage
  • content (obrigatório): texto puro ou Markdown em UTF-8, até 5 MB. Para PDF, Office e imagens, use Importar arquivo.
  • external_id (opcional, até 200 bytes): o seu identificador. Reenviar com o mesmo valor substitui o documento; a versão anterior continua respondendo às buscas (processing: true) até a nova ficar pronta.
  • paths (até 50) e commit: os arquivos de onde o documento vem, para marcá-lo como desatualizado quando mudarem.
  • Segredos reconhecidos no texto (chaves de API, tokens) são trocados por [REDACTED:tipo] antes de indexar; redactions conta quantos.
  • metadata: objeto com até 50 chaves (4 KB, até 3 níveis), usado nos filtros da busca. Não é criptografado; não coloque dados sensíveis.
  • Acompanhe com Consultar documento até status: ready (ou failed, com error_code). Antes de aceitar, a API confere se o saldo cobre a estimativa.
curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"external_id": "artigo-42",
"title": "Como trocar a senha",
"content": "# Conta\n\n## Como trocar a senha\n\nAcesse Configurações > Segurança…",
"source_uri": "https://ajuda.example.com/artigos/42",
"metadata": { "categoria": "conta" }
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"external_id": "artigo-42",
"title": "Como trocar a senha",
"content": "# Conta\n\n## Como trocar a senha\n\nAcesse Configurações > Segurança…",
"source_uri": "https://ajuda.example.com/artigos/42",
"metadata": { "categoria": "conta" }
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"external_id": "artigo-42",
"title": "Como trocar a senha",
"content": "# Conta\n\n## Como trocar a senha\n\nAcesse Configurações > Segurança…",
"source_uri": "https://ajuda.example.com/artigos/42",
"metadata": { "categoria": "conta" }
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"external_id": "artigo-42",
"title": "Como trocar a senha",
"content": "# Conta\n\n## Como trocar a senha\n\nAcesse Configurações > Segurança…",
"source_uri": "https://ajuda.example.com/artigos/42",
"metadata": { "categoria": "conta" }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents", strings.NewReader(`{
"external_id": "artigo-42",
"title": "Como trocar a senha",
"content": "# Conta\n\n## Como trocar a senha\n\nAcesse Configurações > Segurança…",
"source_uri": "https://ajuda.example.com/artigos/42",
"metadata": { "categoria": "conta" }
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 202 — ingestão assíncrona; 200 em dry-run (só estimate) e quando o conteúdo é idêntico ao atual (duplicate: true)

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "document_id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
    "status": "pending",
    "estimate": {
      "chunks": 18,
      "credit_units": 1800
    },
    "document": {
      "id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
      "collection_id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
      "external_id": "artigo-42",
      "title": "Como trocar a senha",
      "source_uri": "https://ajuda.example.com/artigos/42",
      "status": "pending",
      "processing": false,
      "byte_size": 5120,
      "section_count": 0,
      "chunk_count": 0,
      "metadata": {
        "categoria": "conta"
      },
      "created_at": "2026-09-24T09:30:00Z",
      "updated_at": "2026-09-24T09:30:05Z"
    }
  }
}

Importar arquivo (PDF, Office, imagem)

POST/v1/tools/rag/collections/{collection_id}/documents/file
Custo
A conversão não cobra; o texto resultante é cobrado por trecho, como na ingestão
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage

Envio multipart/form-data com file (obrigatório, até 50 MB) e, opcionalmente, title, external_id, source_uri, metadata (objeto JSON em texto) e ocr (padrão true; desligue para PDFs que já têm texto). Formatos: .pdf, .docx, .pptx, .xlsx, .html, .md, .csv, .asciidoc e imagens (.png, .jpg, .tiff, .bmp, .webp). O arquivo é convertido em Markdown (tabelas preservadas, imagens só pelo texto do OCR) e depois indexado como qualquer documento, com o mesmo limite de 5 MB para o texto resultante. A resposta é 202 com o id da importação; consulte-a até completed (traz o document_id) ou failed. Sem conversão disponível, a resposta é 503 (rag.service_unavailable).

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/file' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/file', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/file",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/file');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/file", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 202

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "import_id": "5b6c7d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8e",
    "status": "queued"
  }
}

Consultar importação de arquivo

GET/v1/tools/rag/collections/{collection_id}/imports/{import_id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/imports/%7Bimport_id%7D' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/imports/%7Bimport_id%7D', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/imports/%7Bimport_id%7D",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/imports/%7Bimport_id%7D');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/imports/%7Bimport_id%7D", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "5b6c7d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8e",
    "filename": "manual.pdf",
    "status": "completed",
    "document_id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
    "error": null,
    "created_at": "2026-10-20T12:00:00Z",
    "updated_at": "2026-10-20T12:00:40Z"
  }
}

Listar documentos

GET/v1/tools/rag/collections/{collection_id}/documents
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage

Filtro opcional por status (pending, processing, ready, failed, deleting). Paginação por cursor: passe o next_cursor recebido em after. limit padrão 20, máximo 100.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents?status=ready&limit=20' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents?status=ready&limit=20', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents?status=ready&limit=20",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents?status=ready&limit=20');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents?status=ready&limit=20", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "documents": [
      {
        "id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
        "collection_id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
        "external_id": "artigo-42",
        "title": "Como trocar a senha",
        "source_uri": "https://ajuda.example.com/artigos/42",
        "status": "ready",
        "processing": false,
        "byte_size": 5120,
        "section_count": 4,
        "chunk_count": 18,
        "metadata": {
          "categoria": "conta"
        },
        "created_at": "2026-09-24T09:30:00Z",
        "updated_at": "2026-09-24T09:30:05Z"
      }
    ],
    "next_cursor": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e"
  }
}

Consultar documento

GET/v1/tools/rag/collections/{collection_id}/documents/{document_id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
    "collection_id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    "external_id": "artigo-42",
    "title": "Como trocar a senha",
    "source_uri": "https://ajuda.example.com/artigos/42",
    "status": "ready",
    "processing": false,
    "byte_size": 5120,
    "section_count": 4,
    "chunk_count": 18,
    "metadata": {
      "categoria": "conta"
    },
    "created_at": "2026-09-24T09:30:00Z",
    "updated_at": "2026-09-24T09:30:05Z"
  }
}

Alterar título ou metadados

PATCH/v1/tools/rag/collections/{collection_id}/documents/{document_id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage

Não reprocessa o conteúdo e não cobra nada.

curl -sS -X PATCH 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "metadata": { "categoria": "seguranca" } }'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e', {
  method: 'PATCH',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ "metadata": { "categoria": "seguranca" } }),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.patch(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={ "metadata": { "categoria": "seguranca" } },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{ "metadata": { "categoria": "seguranca" } }
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("PATCH", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e", strings.NewReader(`{ "metadata": { "categoria": "seguranca" } }`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
    "collection_id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    "external_id": "artigo-42",
    "title": "Como trocar a senha",
    "source_uri": "https://ajuda.example.com/artigos/42",
    "status": "ready",
    "processing": false,
    "byte_size": 5120,
    "section_count": 4,
    "chunk_count": 18,
    "metadata": {
      "categoria": "conta"
    },
    "created_at": "2026-09-24T09:30:00Z",
    "updated_at": "2026-09-24T09:30:05Z"
  }
}

Ver seções indexadas

GET/v1/tools/rag/collections/{collection_id}/documents/{document_id}/sections
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage

Mostra como o documento foi dividido, útil para ajustar títulos e tamanho dos trechos.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e/sections' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e/sections', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e/sections",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e/sections');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e/sections", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "sections": [
      {
        "id": "b2c4d6e8-0a1b-4c3d-8e5f-6a7b8c9d0e1f",
        "index": 0,
        "heading_path": [
          "Conta",
          "Como trocar a senha"
        ],
        "content": "Acesse Configurações > Segurança e clique em Trocar senha…",
        "token_count": 84
      }
    ]
  }
}

Reprocessar documento com falha

POST/v1/tools/rag/collections/{collection_id}/documents/{document_id}/retry
Custo
Por trecho indexado, como na ingestão
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage

Só para documentos com status: failed; os demais respondem rag.document_not_failed.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e/retry' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e/retry', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e/retry",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e/retry');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e/retry", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 202

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
    "collection_id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    "external_id": "artigo-42",
    "title": "Como trocar a senha",
    "source_uri": "https://ajuda.example.com/artigos/42",
    "status": "pending",
    "processing": false,
    "byte_size": 5120,
    "section_count": 4,
    "chunk_count": 18,
    "metadata": {
      "categoria": "conta"
    },
    "created_at": "2026-09-24T09:30:00Z",
    "updated_at": "2026-09-24T09:30:05Z"
  }
}

Excluir documento

DELETE/v1/tools/rag/collections/{collection_id}/documents/{document_id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage
curl -sS -X DELETE 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e', {
  method: 'DELETE',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.delete(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("DELETE", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/documents/7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 202

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
    "status": "deleting"
  }
}

Fontes sincronizadas

Uma fonte importa páginas de fora e as mantém em dia: a cada sincronização, páginas novas ou alteradas são reindexadas, as inalteradas (mesmo conteúdo) não são cobradas de novo, e as que sumiram da origem são removidas da base. Cada página vira um documento comum (external_id src:<id da fonte>:…, com source_id e source_url nos metadados), cobrado por trecho como numa ingestão manual; se faltar saldo ou cota, a sincronização falha e mostra o motivo.

kindstart_urlO que importa
sitepágina inicialRastreia links do mesmo host até max_depth, respeitando o robots.txt; HTML vira Markdown e arquivos PDF/Office linkados são convertidos.
sitemapURL do sitemap (ou índice)Importa as páginas listadas, até max_pages. max_depth não se aplica.
githubhttps://github.com/dono/repoRepositório público; config.ref (padrão HEAD) e config.paths (prefixos) filtram. Lê .md, .mdx, .txt, .rst e converte os formatos de arquivo suportados.
gdriveURL de uma pasta /folders/<id>Pasta compartilhada como "qualquer pessoa com o link"; Docs viram Markdown. Só existe se o servidor tiver a integração ligada.

Listar fontes sincronizadas

GET/v1/tools/rag/collections/{collection_id}/sources
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "sources": [
      {
        "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f",
        "collection_id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
        "kind": "site",
        "name": "Central de ajuda",
        "start_url": "https://ajuda.example.com",
        "config": {},
        "max_pages": 100,
        "max_depth": 3,
        "frequency_hours": 24,
        "enabled": true,
        "status": "ok",
        "next_sync_at": "2026-10-21T12:00:00Z",
        "last_sync": {
          "id": "e7f8a9b0-c1d2-4e3f-8a4b-5c6d7e8f9a0b",
          "status": "completed",
          "started_at": "2026-10-20T12:00:00Z",
          "finished_at": "2026-10-20T12:03:10Z",
          "pages_total": 42,
          "pages_new": 3,
          "pages_changed": 1,
          "pages_removed": 0,
          "error": null
        },
        "created_at": "2026-10-15T09:00:00Z"
      }
    ]
  }
}

Criar fonte sincronizada

POST/v1/tools/rag/collections/{collection_id}/sources
Custo
Cada página nova ou alterada é cobrada como uma ingestão
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage
  • name (até 200) e start_url (http ou https) são obrigatórios; kind padrão site.
  • max_pages: 1 a 1000 (padrão 100). max_depth: 1 a 10 (padrão 3).
  • frequency_hours: 0 (só manual), 6, 24 (padrão) ou 168.
  • A primeira sincronização começa na hora. Páginas e arquivos de até 20 MB cada; um arquivo que não converte é pulado sem falhar a sincronização.
curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"kind": "site",
"name": "Central de ajuda",
"start_url": "https://ajuda.example.com",
"max_pages": 100,
"max_depth": 3,
"frequency_hours": 24
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"kind": "site",
"name": "Central de ajuda",
"start_url": "https://ajuda.example.com",
"max_pages": 100,
"max_depth": 3,
"frequency_hours": 24
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"kind": "site",
"name": "Central de ajuda",
"start_url": "https://ajuda.example.com",
"max_pages": 100,
"max_depth": 3,
"frequency_hours": 24
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"kind": "site",
"name": "Central de ajuda",
"start_url": "https://ajuda.example.com",
"max_pages": 100,
"max_depth": 3,
"frequency_hours": 24
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources", strings.NewReader(`{
"kind": "site",
"name": "Central de ajuda",
"start_url": "https://ajuda.example.com",
"max_pages": 100,
"max_depth": 3,
"frequency_hours": 24
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 201 — a primeira sincronização começa na hora (status: syncing)

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f",
    "collection_id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    "kind": "site",
    "name": "Central de ajuda",
    "start_url": "https://ajuda.example.com",
    "config": {},
    "max_pages": 100,
    "max_depth": 3,
    "frequency_hours": 24,
    "enabled": true,
    "status": "syncing",
    "next_sync_at": "2026-10-21T12:00:00Z",
    "last_sync": {
      "id": "e7f8a9b0-c1d2-4e3f-8a4b-5c6d7e8f9a0b",
      "status": "completed",
      "started_at": "2026-10-20T12:00:00Z",
      "finished_at": "2026-10-20T12:03:10Z",
      "pages_total": 42,
      "pages_new": 3,
      "pages_changed": 1,
      "pages_removed": 0,
      "error": null
    },
    "created_at": "2026-10-15T09:00:00Z"
  }
}

Alterar fonte

PATCH/v1/tools/rag/collections/{collection_id}/sources/{source_id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage

Todos os campos são opcionais. Com enabled: false ou frequency_hours: 0, next_sync_at fica nulo.

curl -sS -X PATCH 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "frequency_hours": 168, "enabled": true }'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D', {
  method: 'PATCH',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ "frequency_hours": 168, "enabled": true }),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.patch(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={ "frequency_hours": 168, "enabled": True },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{ "frequency_hours": 168, "enabled": true }
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("PATCH", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D", strings.NewReader(`{ "frequency_hours": 168, "enabled": true }`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f",
    "collection_id": "3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c",
    "kind": "site",
    "name": "Central de ajuda",
    "start_url": "https://ajuda.example.com",
    "config": {},
    "max_pages": 100,
    "max_depth": 3,
    "frequency_hours": 24,
    "enabled": true,
    "status": "ok",
    "next_sync_at": "2026-10-21T12:00:00Z",
    "last_sync": {
      "id": "e7f8a9b0-c1d2-4e3f-8a4b-5c6d7e8f9a0b",
      "status": "completed",
      "started_at": "2026-10-20T12:00:00Z",
      "finished_at": "2026-10-20T12:03:10Z",
      "pages_total": 42,
      "pages_new": 3,
      "pages_changed": 1,
      "pages_removed": 0,
      "error": null
    },
    "created_at": "2026-10-15T09:00:00Z"
  }
}

Sincronizar agora

POST/v1/tools/rag/collections/{collection_id}/sources/{source_id}/sync
Custo
Cada página nova ou alterada é cobrada como uma ingestão
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage

Responde 409 se a fonte já estiver sincronizando. pages_total, pages_new, pages_changed e pages_removed resumem a execução.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D/sync' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D/sync', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D/sync",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D/sync');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D/sync", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 202

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "e7f8a9b0-c1d2-4e3f-8a4b-5c6d7e8f9a0b",
    "status": "completed",
    "started_at": "2026-10-20T12:00:00Z",
    "finished_at": "2026-10-20T12:03:10Z",
    "pages_total": 42,
    "pages_new": 3,
    "pages_changed": 1,
    "pages_removed": 0,
    "error": null
  }
}

Histórico de sincronizações

GET/v1/tools/rag/collections/{collection_id}/sources/{source_id}/syncs
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D/syncs' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D/syncs', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D/syncs",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D/syncs');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D/syncs", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "syncs": [
      {
        "id": "e7f8a9b0-c1d2-4e3f-8a4b-5c6d7e8f9a0b",
        "status": "completed",
        "started_at": "2026-10-20T12:00:00Z",
        "finished_at": "2026-10-20T12:03:10Z",
        "pages_total": 42,
        "pages_new": 3,
        "pages_changed": 1,
        "pages_removed": 0,
        "error": null
      }
    ]
  }
}

Excluir fonte

DELETE/v1/tools/rag/collections/{collection_id}/sources/{source_id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage
curl -sS -X DELETE 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D', {
  method: 'DELETE',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.delete(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("DELETE", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/sources/%7Bsource_id%7D", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200 — os documentos já importados continuam na base

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "deleted": true
  }
}

Busca

Modos de busca e reranker

  • fast (padrão): combina a busca por significado e a por palavras-chave. O score é uma fusão de posições (valores pequenos, perto de 0,03), bom para ordenar, não para comparar com um limiar.
  • accurate: depois da fusão, um reranker relê os 20 melhores candidatos junto com a pergunta e devolve um score calibrado de 0 a 1; só nele min_score tem efeito. Cobra o adicional de rerank. Se o rerank estiver indisponível, a busca cai para fast sem o adicional (mode_used).
  • Reranker: rerank_provider da base (e provider no rerank avulso e no decide) escolhe entre bge (padrão, cross-encoder) e laya, o juiz de relevância da Respawn, que pergunta se o trecho responde à consulta e devolve a probabilidade. O Laya costuma separar melhor trechos que só se parecem com a pergunta, mas é mais lento e, se estiver fora do ar, o accurate cai para fast e o rerank avulso responde 503 (rag.service_unavailable). O preço é o mesmo do bge.
  • Se o serviço de embeddings falhar, a busca ainda responde só por palavras-chave (mode_used: lexical), cobrada como cache.

Buscar na base

POST/v1/tools/rag/collections/{collection_id}/query
Custo
Por consulta, com franquia diária e blocos pré-pagos (veja Custos)
Dry-run
Não
Autenticação
qualquer um detools:rag:querytools:rag:managetools:manage
  • query (obrigatório, até 1.000 caracteres).
  • top_k: quantos trechos devolver (padrão 5, máximo 20).
  • mode: fast ou accurate; sem ele, vale o padrão da base. Se o rerank do modo accurate estiver indisponível, a busca cai para fast sem cobrar o adicional; mode_used mostra o que foi usado.
  • filters: só trechos de documentos cujos metadados contêm estes valores.
  • min_score (só no accurate) e max_per_document (0–20) refinam o resultado.
  • updated_after e updated_before (RFC 3339) filtram pela data de atualização do documento, e exclude_stale: true ignora os marcados como desatualizados. Cada resultado traz updated_at, stale, paths, commit, source_uri e also_in (outros documentos com o mesmo texto, colapsados num só resultado).
  • highlights marca, em posições de caractere Unicode, os termos encontrados em content. Consultas repetidas em até 10 minutos vêm do cache (cached: true) e custam menos.

Conteúdo do usuário

Os trechos devolvidos são conteúdo dos seus documentos. Ao passá-los a um modelo de linguagem, trate-os como dados, não como instruções.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/query' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"query": "como mudo minha senha?",
"top_k": 5,
"filters": { "categoria": "conta" }
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/query', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"query": "como mudo minha senha?",
"top_k": 5,
"filters": { "categoria": "conta" }
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/query",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"query": "como mudo minha senha?",
"top_k": 5,
"filters": { "categoria": "conta" }
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/query');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"query": "como mudo minha senha?",
"top_k": 5,
"filters": { "categoria": "conta" }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/query", strings.NewReader(`{
"query": "como mudo minha senha?",
"top_k": 5,
"filters": { "categoria": "conta" }
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "query_id": "f0e1d2c3-b4a5-4968-8776-5a4b3c2d1e0f",
    "mode_used": "fast",
    "cached": false,
    "results": [
      {
        "section_id": "b2c4d6e8-0a1b-4c3d-8e5f-6a7b8c9d0e1f",
        "document_id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
        "title": "Como trocar a senha",
        "heading_path": [
          "Conta",
          "Como trocar a senha"
        ],
        "section_index": 3,
        "content": "Acesse Configurações > Segurança e clique em Trocar senha…",
        "highlights": [
          {
            "start": 38,
            "end": 49
          }
        ],
        "score": 0.87,
        "signals": {
          "dense_rank": 1,
          "lexical_rank": 2
        },
        "metadata": {
          "categoria": "conta"
        }
      }
    ]
  }
}

Feedback de relevância

Registrar feedback de relevância

POST/v1/tools/rag/collections/{collection_id}/feedback
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:querytools:rag:managetools:manage
  • label: positive (o trecho responde à pergunta) ou negative.
  • end_user_ref (opcional): identifica quem avaliou, quando o voto vem do seu usuário final. É guardado só como hash.
  • Até 30 votos por minuto. Perguntas parecidas são agrupadas, e o voto passa a valer para todo o grupo.
curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"query": "como mudo minha senha?",
"section_id": "b2c4d6e8-0a1b-4c3d-8e5f-6a7b8c9d0e1f",
"label": "positive",
"end_user_ref": "usuario-123"
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"query": "como mudo minha senha?",
"section_id": "b2c4d6e8-0a1b-4c3d-8e5f-6a7b8c9d0e1f",
"label": "positive",
"end_user_ref": "usuario-123"
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"query": "como mudo minha senha?",
"section_id": "b2c4d6e8-0a1b-4c3d-8e5f-6a7b8c9d0e1f",
"label": "positive",
"end_user_ref": "usuario-123"
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"query": "como mudo minha senha?",
"section_id": "b2c4d6e8-0a1b-4c3d-8e5f-6a7b8c9d0e1f",
"label": "positive",
"end_user_ref": "usuario-123"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback", strings.NewReader(`{
"query": "como mudo minha senha?",
"section_id": "b2c4d6e8-0a1b-4c3d-8e5f-6a7b8c9d0e1f",
"label": "positive",
"end_user_ref": "usuario-123"
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "recorded": true
  }
}

Listar feedback

GET/v1/tools/rag/collections/{collection_id}/feedback
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "groups": [
      {
        "id": "a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
        "sample_query": "como mudo minha senha",
        "query_count": 12,
        "updated_at": "2026-09-24T18:00:00Z",
        "votes": [
          {
            "document_id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
            "section_hash": "5f2c…",
            "label": "positive",
            "source": "end_user",
            "confirmations": 7,
            "updated_at": "2026-09-24T18:00:00Z",
            "answer": {
              "section_id": "b2c4d6e8-0a1b-4c3d-8e5f-6a7b8c9d0e1f",
              "section_index": 3,
              "document_title": "Como trocar a senha",
              "heading_path": "Conta › Como trocar a senha",
              "preview": "Acesse Configurações > Segurança e clique em Trocar senha…"
            }
          }
        ]
      }
    ]
  }
}

Apagar um grupo de feedback

DELETE/v1/tools/rag/collections/{collection_id}/feedback/{cluster_id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage
curl -sS -X DELETE 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback/a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback/a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d', {
  method: 'DELETE',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.delete(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback/a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback/a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("DELETE", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/feedback/a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "deleted": true
  }
}

Rerank avulso

Reordenar textos (rerank)

POST/v1/tools/rag/rerank
Custo
Por chamada, com franquia diária e blocos pré-pagos (veja Custos)
Dry-run
Não
Autenticação
qualquer um detools:rag:querytools:rag:managetools:manage

Ordena a sua lista de textos pela relevância à pergunta, sem base envolvida. Até 100 textos por chamada (cada um é cortado em 2.000 caracteres). index aponta para a posição no array enviado.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/rerank' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"query": "prazo de reembolso",
"documents": ["Entregas em até 5 dias úteis.", "Frete grátis acima de R$ 200.", "Reembolso em até 7 dias após a devolução."],
"top_k": 2
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/rerank', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"query": "prazo de reembolso",
"documents": ["Entregas em até 5 dias úteis.", "Frete grátis acima de R$ 200.", "Reembolso em até 7 dias após a devolução."],
"top_k": 2
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/rerank",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"query": "prazo de reembolso",
"documents": ["Entregas em até 5 dias úteis.", "Frete grátis acima de R$ 200.", "Reembolso em até 7 dias após a devolução."],
"top_k": 2
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/rerank');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"query": "prazo de reembolso",
"documents": ["Entregas em até 5 dias úteis.", "Frete grátis acima de R$ 200.", "Reembolso em até 7 dias após a devolução."],
"top_k": 2
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/rerank", strings.NewReader(`{
"query": "prazo de reembolso",
"documents": ["Entregas em até 5 dias úteis.", "Frete grátis acima de R$ 200.", "Reembolso em até 7 dias após a devolução."],
"top_k": 2
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "results": [
      {
        "index": 2,
        "score": 0.93
      },
      {
        "index": 0,
        "score": 0.41
      }
    ]
  }
}

Resposta com citações

Responder com citações

POST/v1/tools/rag/collections/{collection_id}/answer
Custo
Como uma busca no modo `accurate` (veja Custos)
Dry-run
Não
Autenticação
qualquer um detools:rag:querytools:rag:managetools:manage

Faz uma busca accurate e responde só com trechos de score igual ou acima de min_score (0 a 1, padrão 0,35, um ponto de partida que vale calibrar na sua base).

  • Com resposta, answered: true e cada [n] do texto aponta para uma citations[] (section_id, document_id, title, heading_path, source_uri, score, excerpt). Nunca há resposta sem citação.
  • Sem trecho acima do limiar, answered: false, reason: no_passage_above_threshold, nenhuma citação, e o webhook rag.question.unanswered é disparado. Se o rerank não pôde conferir a relevância, reason: relevance_unverified (não afirma nada e não dispara o webhook).
  • generate: false (padrão) monta a resposta citando os 3 melhores trechos. Com generate: true, o provedor de IA padrão da plataforma escreve o texto a partir dos trechos; sem marcador de citação válido ou sem provedor, volta ao modo extrativo (generated: false). Com texto gerado, os trechos da base seguem para o provedor de IA da plataforma.
  • Com Accept: text/event-stream, a resposta vem em SSE: citations, vários delta (pedaços do texto) e done (o resultado completo). O texto é gerado inteiro antes, o SSE só o fatia.
  • Cobrança de uma busca accurate; a geração não tem cobrança à parte. Use o query_id no feedback para alimentar o CTR do analytics.
curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/answer' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"query": "como mudo minha senha?",
"top_k": 5,
"min_score": 0.35,
"generate": false
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/answer', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"query": "como mudo minha senha?",
"top_k": 5,
"min_score": 0.35,
"generate": false
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/answer",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"query": "como mudo minha senha?",
"top_k": 5,
"min_score": 0.35,
"generate": False
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/answer');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"query": "como mudo minha senha?",
"top_k": 5,
"min_score": 0.35,
"generate": false
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/answer", strings.NewReader(`{
"query": "como mudo minha senha?",
"top_k": 5,
"min_score": 0.35,
"generate": false
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200 — JSON, ou text/event-stream com Accept: text/event-stream (eventos citations, delta e done)

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "query_id": "f0e1d2c3-b4a5-4968-8776-5a4b3c2d1e0f",
    "answered": true,
    "answer": "Acesse Configurações > Segurança e clique em Trocar senha… [1]",
    "generated": false,
    "citations": [
      {
        "marker": 1,
        "section_id": "b2c4d6e8-0a1b-4c3d-8e5f-6a7b8c9d0e1f",
        "document_id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
        "title": "Como trocar a senha",
        "heading_path": "Conta › Como trocar a senha",
        "source_uri": "https://ajuda.example.com/artigos/42",
        "score": 0.91,
        "excerpt": "Acesse Configurações > Segurança e clique em Trocar senha…"
      }
    ]
  }
}

Widget de chat embutível

O widget é um botão de chat em JavaScript puro (sem CDN, em shadow DOM, só escreve texto) que responde com citações usando a sua base. Ele usa uma chave pública (rpk_…) que só consegue perguntar numa base: não lê outras, não escreve nada.

<script src="https://api.respawntech.dev/widget/rag.js" data-key="rpk_..." async></script>

Atributos: data-key (obrigatório), data-title, data-placeholder e data-dont-know (texto quando não há resposta). As perguntas feitas pelo widget são cobradas do dono da base, como o answer.

Criar chave pública (widget)

POST/v1/tools/rag/collections/{collection_id}/public-keys
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage
  • allowed_origins (obrigatório, 1 a 20): https://site.com ou https://*.site.com, sem caminho. O servidor recusa pedidos cujo Origin não esteja na lista.
  • rate_per_minute: 1 a 600 (padrão 30), por chave. generate liga o texto gerado por IA nas respostas dessa chave.
  • Até 20 chaves por base. A key aparece uma única vez; guardamos só o hash.

Origin não é autenticação

Só o navegador respeita o Origin; um cliente fora dele pode forjá-lo. O que limita o abuso é o limite por minuto da chave, e o custo recai sobre você. Revogue a chave se vir uso estranho.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"name": "Site institucional",
"allowed_origins": ["https://www.example.com", "https://*.example.com"],
"rate_per_minute": 30,
"generate": false
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"name": "Site institucional",
"allowed_origins": ["https://www.example.com", "https://*.example.com"],
"rate_per_minute": 30,
"generate": false
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"name": "Site institucional",
"allowed_origins": ["https://www.example.com", "https://*.example.com"],
"rate_per_minute": 30,
"generate": False
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"name": "Site institucional",
"allowed_origins": ["https://www.example.com", "https://*.example.com"],
"rate_per_minute": 30,
"generate": false
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys", strings.NewReader(`{
"name": "Site institucional",
"allowed_origins": ["https://www.example.com", "https://*.example.com"],
"rate_per_minute": 30,
"generate": false
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 201

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6",
    "name": "Site institucional",
    "key_prefix": "rpk_Ab3dEf",
    "allowed_origins": [
      "https://www.example.com",
      "https://*.example.com"
    ],
    "rate_per_minute": 30,
    "generate": false,
    "created_at": "2026-10-20T12:00:00Z",
    "key": "rpk_Ab3dEf…"
  }
}

Listar chaves públicas

GET/v1/tools/rag/collections/{collection_id}/public-keys
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "public_keys": [
      {
        "id": "d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6",
        "name": "Site institucional",
        "key_prefix": "rpk_Ab3dEf",
        "allowed_origins": [
          "https://www.example.com",
          "https://*.example.com"
        ],
        "rate_per_minute": 30,
        "generate": false,
        "created_at": "2026-10-20T12:00:00Z"
      }
    ]
  }
}

Revogar chave pública

DELETE/v1/tools/rag/collections/{collection_id}/public-keys/{key_id}
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:managetools:manage
curl -sS -X DELETE 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys/%7Bkey_id%7D' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys/%7Bkey_id%7D', {
  method: 'DELETE',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.delete(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys/%7Bkey_id%7D",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys/%7Bkey_id%7D');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("DELETE", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/public-keys/%7Bkey_id%7D", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "revoked": true
  }
}

Responder pelo widget (rota pública)

POST/v1/public/rag/answer
Custo
Cobrada do dono da base, como o `answer` (veja Custos)
Dry-run
Não
Autenticação
Pública (sem token)

Sem token de API: envie a chave no header X-Respawn-Public-Key e o navegador manda o Origin. A base vem da chave, e top_k, min_score e generate não são aceitos no pedido. Responde como o answer (JSON ou SSE), com CORS liberado para a origem permitida. Erros: 401 (chave ausente, desconhecida ou revogada), 403 (origem não permitida) e 429 (limite por minuto).

curl -sS -X POST 'https://api.respawntech.dev/v1/public/rag/answer' \
  -H 'Content-Type: application/json' \
  -d '{ "query": "como mudo minha senha?" }'
const response = await fetch('https://api.respawntech.dev/v1/public/rag/answer', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ "query": "como mudo minha senha?" }),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/public/rag/answer",
    headers={

    },
    json={ "query": "como mudo minha senha?" },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/public/rag/answer');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{ "query": "como mudo minha senha?" }
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/public/rag/answer", strings.NewReader(`{ "query": "como mudo minha senha?" }`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "query_id": "f0e1d2c3-b4a5-4968-8776-5a4b3c2d1e0f",
    "answered": true,
    "answer": "Acesse Configurações > Segurança e clique em Trocar senha… [1]",
    "generated": false,
    "citations": [
      {
        "marker": 1,
        "section_id": "b2c4d6e8-0a1b-4c3d-8e5f-6a7b8c9d0e1f",
        "document_id": "7a1f2e9c-5b3d-4c8a-9e0f-1d2c3b4a5f6e",
        "title": "Como trocar a senha",
        "heading_path": "Conta › Como trocar a senha",
        "source_uri": "https://ajuda.example.com/artigos/42",
        "score": 0.91,
        "excerpt": "Acesse Configurações > Segurança e clique em Trocar senha…"
      }
    ]
  }
}

Script do widget

GET/widget/rag.js
Custo
Grátis
Dry-run
Não
Autenticação
Pública (sem token)
curl -sS -X GET 'https://api.respawntech.dev/widget/rag.js'
const response = await fetch('https://api.respawntech.dev/widget/rag.js', {
  method: 'GET',
  headers: {

  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/widget/rag.js",
    headers={

    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/widget/rag.js');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/widget/rag.js", nil)
	if err != nil {
		panic(err)
	}

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200 — application/javascript, com cache de 5 minutos

Analytics de perguntas

Analytics das perguntas

GET/v1/tools/rag/collections/{collection_id}/analytics
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage

Mostra o que os usuários perguntam e o que a base não sabe responder, a partir das chamadas de answer e do widget. days vai de 1 a 90 (padrão 30).

  • answer_rate: respondidas ÷ total de perguntas.
  • feedback_ctr: respondidas que receberam voto (pelo query_id) ÷ respondidas.
  • positive_rate: votos positivos ÷ votos.
  • top_questions e unanswered_questions: até 20 perguntas agrupadas cada, para você descobrir o que escrever na base.

As perguntas ficam cifradas com a chave da base. O widget não tem voto próprio: o CTR só conta votos enviados pela API.

curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/analytics?days=30' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/analytics?days=30', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/analytics?days=30",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/analytics?days=30');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/collections/3c9e7a52-1b4d-4f0e-9a6c-2d8e5f7a1b3c/analytics?days=30", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "days": 30,
    "questions": 340,
    "unanswered": 41,
    "answer_rate": 0.88,
    "feedback_ctr": 0.12,
    "positive_rate": 0.9,
    "top_questions": [
      {
        "question": "como mudo minha senha",
        "count": 52,
        "unanswered": 0,
        "last_asked": "2026-10-20T11:40:00Z"
      }
    ],
    "unanswered_questions": [
      {
        "question": "tem integração com zapier",
        "count": 9,
        "unanswered": 9,
        "last_asked": "2026-10-20T10:02:00Z"
      }
    ]
  }
}

Roteamento

Decidir entre opções (roteamento)

POST/v1/tools/rag/decide
Custo
Por chamada, como o rerank avulso (veja Custos)
Dry-run
Não
Autenticação
qualquer um detools:rag:querytools:rag:managetools:manage

Classifica um texto entre 2 e 50 opções sem usar um LLM, pontuando cada label: description com o reranker (provider: bge ou laya). Serve para rotear pedidos. Se a melhor opção não passar de threshold (padrão 0,5) ou não ficar min_margin (padrão 0,1) à frente da segunda, decided é false: trate como "não sei". O ranking completo vem sempre. Preço e franquia do rerank avulso.

curl -sS -X POST 'https://api.respawntech.dev/v1/tools/rag/decide' \
  -H "X-API-Token: $RESPAWN_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
"text": "quero cancelar minha assinatura",
"options": [
  { "label": "cobranca", "description": "pagamentos, faturas e cancelamentos" },
  { "label": "suporte", "description": "problemas técnicos" }
],
"threshold": 0.5,
"min_margin": 0.1
}'
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/decide', {
  method: 'POST',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
"text": "quero cancelar minha assinatura",
"options": [
  { "label": "cobranca", "description": "pagamentos, faturas e cancelamentos" },
  { "label": "suporte", "description": "problemas técnicos" }
],
"threshold": 0.5,
"min_margin": 0.1
}),
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.post(
    "https://api.respawntech.dev/v1/tools/rag/decide",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    json={
"text": "quero cancelar minha assinatura",
"options": [
  { "label": "cobranca", "description": "pagamentos, faturas e cancelamentos" },
  { "label": "suporte", "description": "problemas técnicos" }
],
"threshold": 0.5,
"min_margin": 0.1
},
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/decide');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
"text": "quero cancelar minha assinatura",
"options": [
  { "label": "cobranca", "description": "pagamentos, faturas e cancelamentos" },
  { "label": "suporte", "description": "problemas técnicos" }
],
"threshold": 0.5,
"min_margin": 0.1
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.respawntech.dev/v1/tools/rag/decide", strings.NewReader(`{
"text": "quero cancelar minha assinatura",
"options": [
  { "label": "cobranca", "description": "pagamentos, faturas e cancelamentos" },
  { "label": "suporte", "description": "problemas técnicos" }
],
"threshold": 0.5,
"min_margin": 0.1
}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "decided": true,
    "label": "cobranca",
    "score": 0.92,
    "margin": 0.61,
    "ranking": [
      {
        "label": "cobranca",
        "score": 0.92
      },
      {
        "label": "suporte",
        "score": 0.31
      }
    ]
  }
}

Preços e limites da conta

Consultar preços

GET/v1/tools/rag/pricing
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/pricing' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/pricing', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/pricing",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/pricing');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/pricing", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "collection_free": true,
    "feedback_free": true,
    "ingest": {
      "unit_cost": 200,
      "volume_discounts": [
        {
          "min_quantity": 1000,
          "discount_percentage": 20
        }
      ]
    },
    "calls": [
      {
        "service_code": "rag_query_search",
        "unit_cost": 2500,
        "free_per_day": 20,
        "first_block_size": 10,
        "block_size": 20
      }
    ]
  }
}

Consultar limites

GET/v1/tools/rag/limits
Custo
Grátis
Dry-run
Não
Autenticação
qualquer um detools:rag:readtools:rag:managetools:readtools:manage
curl -sS -X GET 'https://api.respawntech.dev/v1/tools/rag/limits' \
  -H "X-API-Token: $RESPAWN_API_TOKEN"
const response = await fetch('https://api.respawntech.dev/v1/tools/rag/limits', {
  method: 'GET',
  headers: {
    'X-API-Token': process.env.RESPAWN_API_TOKEN,
  },
});

if (!response.ok) throw new Error((await response.json()).error.code);
console.log(await response.json());
import os
import requests

response = requests.get(
    "https://api.respawntech.dev/v1/tools/rag/limits",
    headers={
        "X-API-Token": os.environ["RESPAWN_API_TOKEN"],
    },
    timeout=30,
)
if not response.ok:
    raise RuntimeError(response.json()["error"]["code"])
print(response.json())
<?php
$ch = curl_init('https://api.respawntech.dev/v1/tools/rag/limits');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('RESPAWN_API_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException(json_decode($body, true)['error']['code']);
}
print_r(json_decode($body, true));
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.respawntech.dev/v1/tools/rag/limits", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Token", os.Getenv("RESPAWN_API_TOKEN"))

	client := &http.Client{Timeout: 30 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode >= 400 {
		panic(string(data))
	}
	fmt.Println(string(data))
}

Resposta 200

{
  "success": true,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "max_collections": 50,
    "max_chunks": 200000,
    "max_pending_documents": 20,
    "max_document_bytes": 5242880,
    "max_query_chars": 1000,
    "max_top_k": 20
  }
}

Valores vigentes da sua conta (já com o bônus do plano), úteis para validar um envio antes de fazê-lo.

Eventos (webhooks)

Cadastre um endpoint no dashboard para receber:

  • rag.document.ready e rag.document.failed: collection_id, document_id, external_id e version; o de falha traz também error_code. Valem para documentos enviados, importados de arquivo e vindos de fontes.
  • rag.question.unanswered: collection_id, question, query_id e source (api ou widget), quando nenhum trecho passou do min_score. Bom para alimentar uma fila de "o que escrever".

O envio é de melhor esforço, como nos demais eventos. Veja a lista de eventos.

Usar pelo MCP

As mesmas operações estão disponíveis como ferramentas MCP do grupo rag (lista completa): rag_answer, rag_decide, rag_index, rag_lint, rag_mark_changed e rag_retry_document são as novas. As de leitura (rag_index, rag_lint) são gratuitas; use rag_access=query na conexão para esconder as que alteram a base.

Erros

CódigoHTTPQuando
rag.disabled403Base de conhecimento ainda não liberada para a conta.
rag.document_too_large413Conteúdo acima de 5 MB.
rag.chunk_quota_exceeded403A conta passaria de 200.000 trechos indexados.
rag.collection_limit_reached403Limite de 50 bases por conta.
rag.too_many_pending_documents429Já há 20 documentos em processamento; aguarde alguns terminarem.
rag.capacity_exhausted429Serviço de busca sem capacidade no momento; tente de novo em alguns segundos.
rag.embedding_failed502Falha no serviço de embeddings.
rag.feedback_rate_limited429Mais de 30 votos de feedback por minuto.
rag.document_not_failed409Só documentos com status failed podem ser reprocessados.
rag.collection_create_restricted403A conexão MCP está limitada a bases específicas e não pode criar bases novas.
rag.model_switch_in_progress409A base está trocando de modelo de busca; envie documentos quando a troca terminar ou cancele-a.
rag.service_unavailable503Serviço de rerank (inclusive o Laya), conversão de arquivo, analytics ou chaves públicas indisponível no momento.
rag.decrypt_failed500Falha ao ler o conteúdo guardado. Informe o trace_id ao suporte.
embedding_failedassíncronoA indexação do documento falhou; use o reprocessamento.
insufficient_creditsassíncronoSaldo ou limite diário insuficiente para cobrar a ingestão ao terminar.
empty_documentassíncronoO documento não tem texto indexável.
chunk_quota_exceededassíncronoA ingestão passaria do limite de trechos da conta.
persist_failedassíncronoFalha ao gravar o resultado; a cobrança é estornada.
enqueue_failedassíncronoFalha ao enfileirar a ingestão.

Os códigos sem status HTTP aparecem no campo error_code de um documento com status: failed.

Limites

LimiteValor
Tamanho de um documento5 MB
Bases por conta50
Trechos indexados por conta200.000
Documentos em processamento ao mesmo tempo20
Tamanho da pergunta1.000 caracteres
Trechos por busca (top_k)20
Textos por rerank avulso100
Votos de feedback por minuto30
Arquivo importado50 MB
Páginas por fonte1.000 (padrão 100)
Chaves públicas por base20

As rotas da base de conhecimento ignoram o header X-Idempotency-Key: elas já são idempotentes (conteúdo repetido não é reindexado nem cobrado). Uma chave restrita a bases específicas só enxerga essas bases e não pode criar novas (forbidden).

Atualizado em