Docs / Referência da API

Referência da API

Todos os endpoints da API usam formato JSON. A autenticação usa chave de API Bearer aqn_. Consulte Autenticação para detalhes.

URL Base: https://your-instance/api/


Autenticação

Inclua sua chave de API em todas as requisições:

Authorization: Bearer aqn_your_api_key

As chaves de API são criadas e gerenciadas na página Chaves de API (/keys/). Chaves de acesso total veem todas as coleções; chaves restritas veem apenas as coleções concedidas.


Schema OpenAPI

O schema OpenAPI completo está disponível em /api/v1/schema/ em todos os ambientes (incluindo produção). Use-o para integrar com qualquer ferramenta compatível com OpenAPI:

  • Geração de SDK (openapi-generator, kiota, etc.)
  • Ações de GPT Personalizado do ChatGPT
  • Importação para Postman / Insomnia
  • Qualquer ferramenta ou fluxo de trabalho compatível com OpenAPI
GET /api/v1/schema/

Retorna um documento OpenAPI 3.0 válido em JSON. Sem necessidade de autenticação. Swagger UI (/api/v1/docs/) e ReDoc (/api/v1/redoc/) estão disponíveis apenas em ambientes de depuração/desenvolvimento.


Coleções

Listar Coleções

GET /api/v1/collections/

Retorna coleções visíveis para o usuário autenticado (próprias + públicas assinadas).

Resposta: 200 OK

[
  {
    "uuid": "a1b2c3...",
    "name": "Project Docs",
    "slug": "project-docs",
    "description": "Technical documentation",
    "document_count": 15,
    "total_chunks": 342,
    "is_public": false,
    "is_subscribed": false,
    "created_at": "2026-03-01T10:00:00Z"
  }
]

Criar Coleção

POST /api/v1/collections/

Cria uma nova coleção pertencente ao usuário autenticado.

Corpo da Requisição:

Campo Tipo Obrigatório Descrição
name string Sim Nome da coleção (não pode estar vazio)
description string Não Descrição opcional

Resposta: 201 Created — Objeto completo da coleção

{
  "uuid": "a1b2c3...",
  "name": "Project Docs",
  "slug": "project-docs",
  "description": "Technical documentation",
  "document_count": 0,
  "total_chunks": 0,
  "is_public": false,
  "is_subscribed": false,
  "created_at": "2026-03-23T10:00:00Z"
}

Erros:

  • 400 — Nome ausente ou vazio

Exemplo:

curl -X POST https://your-instance/api/v1/collections/ \
  -H "Authorization: Bearer aqn_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Project Docs", "description": "Technical documentation"}'

Obter Coleção

GET /api/v1/collections/{uuid}/

Resposta: 200 OK — Objeto da coleção

Atualizar Coleção

PATCH /api/v1/collections/{uuid}/

Atualiza o nome e/ou descrição de uma coleção. Somente o proprietário.

Corpo da Requisição: Qualquer subconjunto dos seguintes campos:

Campo Tipo Descrição
name string Novo nome da coleção
description string Nova descrição

Resposta: 200 OK — Objeto da coleção atualizado

Erros:

  • 400 — Erro de validação (ex.: nome vazio)
  • 403 — Não é o proprietário da coleção
  • 404 — Coleção não encontrada

Exemplo:

curl -X PATCH https://your-instance/api/v1/collections/{uuid}/ \
  -H "Authorization: Bearer aqn_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Renamed Docs"}'

Excluir Coleção

DELETE /api/v1/collections/{uuid}/

Exclusão suave de uma coleção e todos os seus documentos. Somente o proprietário. As entradas do índice de busca são removidas imediatamente; os blobs são mantidos por um período de carência de 7 dias antes da exclusão permanente.

Resposta: 204 No Content

Erros:

  • 403 — Não é o proprietário da coleção
  • 404 — Coleção não encontrada

Exemplo:

curl -X DELETE https://your-instance/api/v1/collections/{uuid}/ \
  -H "Authorization: Bearer aqn_your_api_key" \
  -w "\nHTTP %{http_code}\n"

Documentos

Listar Documentos

GET /api/v1/documents/

Retorna documentos de todas as coleções visíveis.

Parâmetros de Consulta:

Parâmetro Tipo Descrição
tag string Filtrar por tag (sem distinção de maiúsculas/minúsculas)
collection string Filtrar por slug da coleção

Resposta: 200 OK

[
  {
    "uuid": "d4e5f6...",
    "title": "Annual Report 2025",
    "source_type": "pdf",
    "status": "indexed",
    "tags": ["finance", "annual"],
    "chunks_count": 24,
    "original_filename": "report-2025.pdf",
    "file_size": 102400,
    "collection_name": "Project Docs",
    "collection_slug": "project-docs",
    "created_at": "2026-03-01T10:00:00Z"
  }
]

Enviar Documentos

POST /api/v1/collections/{uuid}/documents/

Envie um ou mais documentos para uma coleção.

Autenticação: Requer permissão de escrita — chaves de acesso total ou chaves restritas com permissão de escrita na coleção.

Requisição: multipart/form-data

Campo Tipo Obrigatório Descrição
file file Um entre file/files Envio de arquivo único
files file[] Um entre file/files Envio em lote (múltiplos arquivos)
title string Não Título do documento (padrão: nome do arquivo)
tags string Não Lista de tags separadas por vírgula
source_type string Não Tipo de arquivo manual (detectado automaticamente pela extensão se omitido)

Resposta para arquivo único: 201 Created

{
  "uuid": "d4e5f6...",
  "title": "Annual Report 2025",
  "source_type": "pdf",
  "status": "pending",
  "original_filename": "report-2025.pdf",
  "file_size": 102400,
  "tags": ["finance", "annual"],
  "collection_name": "Project Docs",
  "created_at": "2026-03-22T10:00:00Z"
}

Resposta para envio em lote: 201 Created

{
  "uploaded": [
    {
      "uuid": "d4e5f6...",
      "title": "Annual Report 2025",
      "source_type": "pdf",
      "status": "pending",
      "original_filename": "report-2025.pdf",
      "file_size": 102400,
      "tags": [],
      "collection_name": "Project Docs",
      "created_at": "2026-03-22T10:00:00Z"
    }
  ],
  "skipped": [
    {
      "filename": "image.png",
      "reason": "Unsupported file type."
    }
  ],
  "total_uploaded": 1,
  "total_skipped": 1
}

Erros:

  • 400 — Nenhum arquivo fornecido, tipo de arquivo não suportado ou arquivo muito grande
  • 403 — Acesso de escrita necessário
  • 404 — Coleção não encontrada

Exemplo — arquivo único:

curl -X POST https://your-instance/api/v1/collections/{uuid}/documents/ \
  -H "Authorization: Bearer aqn_your_api_key" \
  -F "file=@report-2025.pdf" \
  -F "title=Annual Report 2025" \
  -F "tags=finance,annual"

Exemplo — envio em lote:

curl -X POST https://your-instance/api/v1/collections/{uuid}/documents/ \
  -H "Authorization: Bearer aqn_your_api_key" \
  -F "files=@report-2025.pdf" \
  -F "files=@summary.docx" \
  -F "tags=finance"

Substituir Documento

POST /api/v1/documents/{uuid}/replace/

Substitui o arquivo de um documento e o reprocessa. O UUID do documento é preservado; as entradas de busca antigas são removidas e o novo arquivo é processado do zero.

Autenticação: Requer permissão de escrita — chaves de acesso total ou chaves restritas com permissão de escrita na coleção.

Requisição: multipart/form-data

Campo Tipo Obrigatório Descrição
file file Sim Arquivo de substituição
title string Não Substituir título do documento (mantém o título existente se omitido)
tags string Não Lista de tags separadas por vírgula (substitui as tags existentes se fornecidas)
source_type string Não Tipo de arquivo manual (detectado automaticamente pela extensão se omitido)

Resposta: 200 OK — Objeto do documento com status: "pending"

{
  "uuid": "d4e5f6...",
  "title": "Annual Report 2026",
  "source_type": "pdf",
  "status": "pending",
  "original_filename": "report-2026.pdf",
  "file_size": 110592,
  "tags": ["finance", "annual"],
  "collection_name": "Project Docs",
  "created_at": "2026-03-01T10:00:00Z"
}

Erros:

  • 400 — Nenhum arquivo fornecido ou tipo de arquivo não suportado
  • 403 — Acesso de escrita necessário
  • 404 — Documento não encontrado

Exemplo:

curl -X POST https://your-instance/api/v1/documents/{uuid}/replace/ \
  -H "Authorization: Bearer aqn_your_api_key" \
  -F "file=@report-2026.pdf" \
  -F "title=Annual Report 2026"

Baixar Documento

GET /api/v1/documents/{uuid}/download/

Baixa o arquivo original enviado. Retorna um redirecionamento 302 para uma URL assinada com tempo limitado (válida por 1 hora).

Autenticação: Qualquer chave de API válida ou autenticação de sessão que possa ver o documento — coleções próprias ou coleções públicas assinadas.

Resposta: 302 Found — Redirecionamento para URL SAS do Azure Blob Storage

Erros:

  • 404 — Documento não encontrado ou nenhum arquivo disponível (documentos somente texto ou URL não possuem arquivo armazenado)

Exemplo:

curl -L -H "Authorization: Bearer aqn_..." \
  https://aqoon.ai/api/v1/documents/{uuid}/download/ \
  -o file.pdf

Use a flag -L para seguir o redirecionamento automaticamente. A URL assinada expira após 1 hora.

Obter Detalhes do Documento

GET /api/v1/documents/{uuid}/

Resposta: 200 OK — Inclui content_text, error_message e array de chunks.

{
  "uuid": "d4e5f6...",
  "title": "Annual Report 2025",
  "source_type": "pdf",
  "status": "indexed",
  "tags": ["finance", "annual"],
  "chunks_count": 24,
  "original_filename": "report-2025.pdf",
  "file_size": 102400,
  "content_text": "Full extracted text...",
  "error_message": "",
  "collection_name": "Project Docs",
  "collection_slug": "project-docs",
  "created_at": "2026-03-01T10:00:00Z",
  "chunks": [
    {
      "id": "uuid",
      "content": "Chunk text content...",
      "chunk_index": 0,
      "embedding_model": "text-embedding-3-small"
    }
  ]
}

POST /api/v1/search/

Corpo da Requisição:

{
  "query": "payment terms",
  "collection": "project-docs",
  "limit": 5
}
Campo Tipo Obrigatório Padrão
query string Sim
collection slug Não Todas as coleções visíveis
limit int Não 5 (max: 50)

Resposta: 200 OK

{
  "query": "payment terms",
  "count": 3,
  "results": [
    {
      "content": "Matching chunk text...",
      "title": "Contract Document",
      "document_id": "uuid",
      "collection_name": "Legal",
      "tags": ["contract"],
      "score": 0.89
    }
  ]
}

Assinaturas de Coleções

Assinar uma Coleção Pública

POST /api/v1/collections/{slug}/subscribe/

Resposta: 200 OK

{
  "status": "subscribed",
  "collection": "project-docs"
}

Erros:

  • 404 — Coleção não encontrada ou não pública

Cancelar Assinatura de uma Coleção

DELETE /api/v1/collections/{slug}/subscribe/

Resposta: 200 OK

{
  "status": "unsubscribed",
  "collection": "project-docs"
}

Erros:

  • 404 — Assinatura não encontrada

Gerenciamento de Chaves de API (KaaS)

As chaves de API KaaS permitem que desenvolvedores externos pesquisem suas coleções. Gerenciadas pela página Chaves de API na interface web ou pela API REST.

Listar / Criar Chaves de API

GET /api/v1/keys/
POST /api/v1/keys/

Corpo da Requisição de Criação:

{
  "name": "Acme Corp Key"
}

Resposta de Criação: 201 Created

{
  "uuid": "key-uuid",
  "name": "Acme Corp Key",
  "prefix": "aqn_abc123...",
  "key": "aqn_full_key_here",
  "is_active": true,
  "created_at": "2026-03-01T10:00:00Z"
}

O campo key é retornado apenas no momento da criação.

Rotacionar Chave de API

POST /api/v1/keys/{uuid}/rotate/

Revoga a chave de API existente e cria uma nova com o mesmo nome e concessões de acesso a coleções. A chave antiga é desativada imediatamente.

Resposta: 201 Created

{
  "uuid": "new-key-uuid",
  "name": "Acme Corp Key",
  "prefix": "aqn_abc123...",
  "key": "aqn_new_full_key_here",
  "is_active": true,
  "is_full_access": false,
  "created_at": "2026-03-13T10:00:00Z"
}

O campo key é retornado apenas no momento da rotação. Armazene-o com segurança — ele não pode ser recuperado novamente.

Erros:

  • 404 — Chave de API não encontrada ou não pertence ao usuário autenticado

Conceder / Revogar Acesso a Coleções

POST /api/v1/keys/{uuid}/collections/
DELETE /api/v1/keys/{uuid}/collections/{collection-slug}/

Corpo da Requisição de Concessão:

Campo Tipo Obrigatório Descrição
collection slug Sim Slug da coleção para conceder acesso
permission string Não "read" (padrão) ou "write"
{
  "collection": "my-collection",
  "permission": "write"
}

Se já existir uma concessão para esta chave e coleção, o nível de permissão é atualizado.

Resposta da Listagem de Concessões: GET /api/v1/keys/{uuid}/collections/200 OK

[
  {
    "collection": "my-collection",
    "permission": "write"
  },
  {
    "collection": "public-docs",
    "permission": "read"
  }
]

Estatísticas de Uso

GET /api/v1/keys/usage/?days=30
GET /api/v1/keys/{uuid}/usage/

Webhooks

Webhooks permitem receber notificações em tempo real quando o processamento de documentos é concluído. Configure uma URL de webhook por organização para receber eventos document.indexed e document.failed. Os payloads são assinados com HMAC-SHA256 e entregues com retentativas com backoff exponencial em caso de falha.

Obter Configuração do Webhook

GET /api/v1/webhooks/

Retorna a configuração atual do webhook para a organização.

Resposta: 200 OK

{
  "configured": true,
  "url": "https://your-app.example.com/hooks/aqoon",
  "is_active": true
}

O segredo nunca é retornado após a criação inicial.

curl https://your-instance/api/v1/webhooks/ \
  -H "Authorization: Bearer aqn_your_api_key"

Criar ou Atualizar Webhook

POST /api/v1/webhooks/

Cria um novo webhook ou atualiza a URL de um existente.

Corpo da Requisição:

{
  "url": "https://your-app.example.com/hooks/aqoon"
}

Na criação: 201 Created — secret returned once, store it securely.

{
  "configured": true,
  "url": "https://your-app.example.com/hooks/aqoon",
  "is_active": true,
  "secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

Na atualização (webhook já existe): 200 OK — secret is not returned.

{
  "configured": true,
  "url": "https://your-app.example.com/hooks/aqoon-updated",
  "is_active": true
}
# Create
curl -X POST https://your-instance/api/v1/webhooks/ \
  -H "Authorization: Bearer aqn_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-app.example.com/hooks/aqoon"}'

# Update URL
curl -X POST https://your-instance/api/v1/webhooks/ \
  -H "Authorization: Bearer aqn_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-app.example.com/hooks/aqoon-v2"}'

Excluir Webhook

DELETE /api/v1/webhooks/

Remove a configuração do webhook. Nenhum evento será mais entregue.

Resposta: 200 OK

curl -X DELETE https://your-instance/api/v1/webhooks/ \
  -H "Authorization: Bearer aqn_your_api_key"

Enviar Evento de Teste

POST /api/v1/webhooks/test/

Enfileira um evento de teste para ser entregue à URL do webhook configurada imediatamente. Retorna 404 se nenhum webhook estiver configurado.

Resposta: 200 OK

curl -X POST https://your-instance/api/v1/webhooks/test/ \
  -H "Authorization: Bearer aqn_your_api_key"

Formato do Payload

Cada evento é entregue como um POST JSON para sua URL de webhook:

{
  "event": "document.indexed",
  "timestamp": "2026-03-23T10:00:00Z",
  "data": {
    "uuid": "a1b2c3...",
    "status": "indexed",
    "title": "Q1 Report",
    "source_type": "pdf",
    "collection_uuid": "d4e5f6...",
    "collection_name": "Finance Docs",
    "chunks_count": 42,
    "tags": "finance,quarterly",
    "error_message": null,
    "original_filename": "q1-report.pdf",
    "file_size": 204800
  }
}

O campo event é document.indexed (processamento bem-sucedido) ou document.failed (processamento falhou). Em caso de falha, error_message contém uma descrição.

Verificação de Assinatura

Cada requisição de webhook inclui dois cabeçalhos de segurança:

  • X-Aqoon-Signature: sha256=<hex-digest>
  • X-Aqoon-Timestamp: <unix-timestamp>

A assinatura é um HMAC-SHA256 de {timestamp}.{raw-body} usando seu segredo do webhook. Sempre verifique a assinatura antes de processar o payload.

import hashlib
import hmac

def verify_signature(secret: str, timestamp: str, body: bytes, signature: str) -> bool:
    message = f"{timestamp}.".encode() + body
    expected = hmac.new(secret.encode(), message, hashlib.sha256).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)
import { createHmac, timingSafeEqual } from 'crypto';

function verifySignature(secret: string, timestamp: string, body: Buffer, signature: string): boolean {
  const message = Buffer.concat([Buffer.from(`${timestamp}.`), body]);
  const expected = 'sha256=' + createHmac('sha256', secret).update(message).digest('hex');
  return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

Para se proteger contra ataques de replay, rejeite eventos onde X-Aqoon-Timestamp tem mais de 5 minutos de atraso.


Endpoint MCP

O servidor MCP está acessível em /mcp usando transporte HTTP Streamable.

Autenticação: Authorization: Bearer aqn_<key>

Ferramentas Disponíveis:

Ferramenta Descrição
search_documents Busca híbrida de texto + vetor com filtro de coleção e limite de resultados opcionais
list_collections Listar todas as coleções com contagem de documentos e descrições
get_document_info Obter detalhes completos do documento e trechos de conteúdo por UUID
search_by_tag Encontrar todos os documentos com uma tag específica

Tratamento de Erros

Códigos de Status HTTP

Código Significado
200 Sucesso
201 Criado
400 Requisição inválida (erro de validação)
401 Não autorizado (token/chave de API ausente ou inválida)
404 Recurso não encontrado
429 Limite de requisições excedido
500 Erro do servidor

Formato de Resposta de Erro

Todos os erros usam um envelope consistente com um campo error e um campo code legível por máquina:

{
  "error": "Collection not found.",
  "code": "COLLECTION_NOT_FOUND"
}

Erros de validação incluem um objeto fields com detalhes por campo:

{
  "error": "Validation failed.",
  "code": "VALIDATION_FAILED",
  "fields": {
    "name": ["This field is required."],
    "collection": ["Collection not found."]
  }
}

Use code para tratamento programático de erros (ex.: lógica switch / if no seu cliente). Use error para exibição ao usuário final.

Códigos de Erro

401 — Autenticação

Código Descrição
INVALID_API_KEY Chave de API não encontrada ou incompatibilidade de hash
API_KEY_EXPIRED A chave de API passou da data de expiração
USER_ACCOUNT_DISABLED A conta do usuário da chave está inativa
AUTHENTICATION_REQUIRED Nenhuma credencial válida fornecida

403 — Autorização

Código Descrição
WRITE_ACCESS_REQUIRED Chave restrita precisa de permissão de escrita para esta coleção
NOT_COLLECTION_OWNER Apenas o proprietário da coleção pode atualizar ou excluir
SCOPED_KEY_FORBIDDEN Chaves restritas não podem executar esta ação

404 — Não Encontrado

Código Descrição
COLLECTION_NOT_FOUND A coleção não existe ou não é visível para esta chave
DOCUMENT_NOT_FOUND O documento não existe ou não está acessível
DOCUMENT_FILE_NOT_FOUND O documento existe, mas o arquivo original está ausente do armazenamento
API_KEY_NOT_FOUND Registro de chave de API não encontrado
GRANT_NOT_FOUND Concessão de acesso à coleção não encontrada
SUBSCRIPTION_NOT_FOUND Assinatura de coleção não encontrada
WEBHOOK_NOT_CONFIGURED Nenhum webhook foi configurado para esta conta

400 — Validação

Código Descrição
VALIDATION_FAILED Um ou mais campos falharam na validação (veja o objeto fields)
NO_FILES_PROVIDED A requisição de envio em lote não incluiu arquivos
NO_FILE_PROVIDED A requisição de envio único não incluiu arquivo
UNSUPPORTED_FILE_TYPE Extensão do arquivo ou tipo MIME não é suportado
FILE_TOO_LARGE O arquivo excede o limite de 50 MB
INVALID_FILE_CONTENT O conteúdo do arquivo não corresponde ao tipo declarado (verificação de bytes mágicos)
URL_REQUIRED Um tipo de origem URL foi especificado, mas nenhuma URL foi fornecida
NAME_REQUIRED Um campo de nome obrigatório estava vazio ou ausente

429 — Limite de Requisições

Código Descrição
RATE_LIMIT_EXCEEDED Cota de requisições excedida; verifique os cabeçalhos X-RateLimit-* para horários de reinício

500 — Erros do Servidor

Código Descrição
SEARCH_UNAVAILABLE O Azure AI Search está temporariamente indisponível
UPLOAD_FAILED O arquivo não pôde ser gravado no armazenamento blob
WEBHOOK_TEST_FAILED A entrega do evento de teste para a URL do webhook configurada falhou