Documentos de sellers
Lista, consulta, baixa e revisa os documentos de verificação (KYC) enviados pelos sellers, um a um ou em lote.
KYC ("conheça seu cliente") é a verificação de identidade de uma empresa antes de deixá-la vender: contrato social, CNPJ, comprovante de endereço, dados bancários. O seller envia os comprovantes pelo painel dele; aqui o administrador abre cada arquivo e aprova ou recusa. Todas as rotas desta página exigem o módulo vendor-kyc (403 module_disabled caso contrário). Decidir exige manage_documents, manage_kyc ou manage_vendors.
Listar documentos
Devolve os documentos de verificação, do mais recente para o mais antigo, com paginação, e um resumo de quantos há em cada estado. Só aparecem documentos ligados a um seller; os anexados à candidatura não entram aqui (veja a visão geral).
/api/v1/admin/vendor-documentsAdminLista os documentos de verificação dos sellers
Parâmetros de consulta
statusstringpendingapprovedrejectedexpiredallP, A, R, E). all ou ausente lista todos. O status_counts da resposta ignora este filtro.vendor_iduuidvendor_searchstringpageintegerpadrão: 1per_pageintegerpadrão: 20Exemplo de requisição
curl "$BASE_URL/api/v1/admin/vendor-documents?status=pending&per_page=20" \
-H "Authorization: Bearer $TOKEN"Resposta
{
"documents": [
{
"id": "8f6a3b4e-1c2d-4e5f-9a0b-1c2d3e4f5a6b",
"vendor_id": "94bd7e9a-fdad-4d01-8fc2-ba9d677d8b36",
"doc_type": "cnpj",
"file_name": "cartao-cnpj.pdf",
"file_url": "/uploads/vendor-documents/94bd7e9a-fdad-4d01-8fc2-ba9d677d8b36/cartao-cnpj.pdf",
"file_size": 184320,
"status": "P",
"created_at": "2026-10-10T14:20:00Z",
"vendor_name": "Loja Seller Teste"
}
],
"total": 1,
"page": 1,
"per_page": 20,
"total_pages": 1,
"status_counts": { "P": 1, "A": 4, "R": 1 }
}Campos da resposta
documentsarraytotalintegerpageintegerper_pageintegertotal_pagesintegerstatus_countsobjectP, A, R, E, O). Respeita vendor_id e vendor_search, mas não status. Serve para as abas da tela de análise.documents[].iduuiddocuments[].vendor_iduuiddocuments[].doc_typestringdocuments[].file_namestringdocuments[].file_urlstring/uploads/...).documents[].file_sizeintegerdocuments[].statusstringPAREOP pendente, A aprovado, R recusado, E vencido, O pendente (antigo).documents[].notesstringdocuments[].review_notesstringdocuments[].reviewed_atstringdocuments[].reviewed_bystringdocuments[].created_atstringdocuments[].vendor_namestringErros
| Status | Quando | Corpo |
|---|---|---|
| 401 / 403 | Sem token, sem privilégio, ou módulo desligado | {"error":"module_disabled","module":"vendor-kyc"} |
| 500 | Falha interna, ou vendor_id que não é UUID | {"error":"failed to list vendor documents","detail":"..."} |
Consultar um documento
Devolve um documento com o nome do seller, no mesmo formato de cada item da lista.
/api/v1/admin/vendor-documents/{id}AdminDetalha um documento de seller
Parâmetros de caminho
iduuidobrigatórioExemplo de requisição
curl "$BASE_URL/api/v1/admin/vendor-documents/8f6a3b4e-1c2d-4e5f-9a0b-1c2d3e4f5a6b" \
-H "Authorization: Bearer $TOKEN"Resposta
{
"id": "8f6a3b4e-1c2d-4e5f-9a0b-1c2d3e4f5a6b",
"vendor_id": "94bd7e9a-fdad-4d01-8fc2-ba9d677d8b36",
"doc_type": "cnpj",
"file_name": "cartao-cnpj.pdf",
"file_url": "/uploads/vendor-documents/94bd7e9a-fdad-4d01-8fc2-ba9d677d8b36/cartao-cnpj.pdf",
"file_size": 184320,
"status": "A",
"review_notes": "Conferido na Receita.",
"reviewed_at": "2026-10-11T09:00:00Z",
"reviewed_by": "67bf291c-0846-4053-9528-8cfd5ab0ebf1",
"created_at": "2026-10-10T14:20:00Z",
"vendor_name": "Loja Seller Teste"
}Erros
| Status | Quando | Corpo |
|---|---|---|
| 404 | Documento inexistente | {"error":"document not found"} |
| 500 | id que não é UUID, ou documento sem seller ligado (os anexados à candidatura) | {"error":"failed to get document","detail":"..."} |
Baixar o arquivo
Entrega o arquivo enviado pelo seller, com Content-Disposition: attachment. Só funciona para arquivos guardados pela própria plataforma (file_url começando por /uploads/). A rota protege contra caminhos que saiam da pasta de envios.
/api/v1/admin/vendor-documents/{id}/downloadAdminBaixa o arquivo de um documento
Parâmetros de caminho
iduuidobrigatórioExemplo de requisição
curl "$BASE_URL/api/v1/admin/vendor-documents/8f6a3b4e-1c2d-4e5f-9a0b-1c2d3e4f5a6b/download" \
-H "Authorization: Bearer $TOKEN" \
-o cartao-cnpj.pdfResposta
(conteúdo binário do arquivo, por exemplo um PDF)O Content-Type é detectado pela extensão do arquivo, e o nome sugerido é o file_name do documento.
Erros
| Status | Quando | Corpo |
|---|---|---|
| 404 | Documento inexistente, ou arquivo que não está mais no disco | {"error":"document not found"} ou 404 page not found |
| 403 | O caminho do arquivo sai da pasta de envios | {"error":"access denied: path traversal detected"} |
| 500 | id que não é UUID | {"error":"failed to get document","detail":"..."} |
Revisar um documento
Aprova ou recusa um documento. Grava a decisão, a observação, a data e quem decidiu. Não muda o estado da candidatura do seller.
/api/v1/admin/vendor-documents/{id}/reviewAdminAprova ou recusa um documento
Parâmetros de caminho
iduuidobrigatórioCorpo da requisição
statusstringobrigatórioapprovedrejectedreview_notesstringExemplo de requisição
curl -X PUT "$BASE_URL/api/v1/admin/vendor-documents/8f6a3b4e-1c2d-4e5f-9a0b-1c2d3e4f5a6b/review" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"status": "approved", "review_notes": "Conferido na Receita."}'Resposta
{
"message": "document reviewed",
"document_id": "8f6a3b4e-1c2d-4e5f-9a0b-1c2d3e4f5a6b",
"status": "approved"
}Erros
| Status | Quando | Corpo |
|---|---|---|
| 400 | Corpo que não é JSON | {"error":"invalid request body","detail":"..."} |
| 400 | status diferente de approved e rejected | {"error":"status must be 'approved' or 'rejected'"} |
| 500 | Documento inexistente (deveria ser 404) ou id que não é UUID | {"error":"failed to review document","detail":"document 0000... not found"} |
| 401 / 403 | Sem token, sem manage_documents/manage_kyc/manage_vendors, ou módulo desligado | {"error":"module_disabled","module":"vendor-kyc"} |
Revisar vários documentos
Decide vários documentos de uma vez com a mesma decisão. Só altera os que estão pendentes; ids já decididos são ignorados em silêncio.
Há três jeitos de chamar, do mais simples ao mais seguro:
- Lista de ids (
document_ids): decide na hora e responde com a contagem. - Simulação (
simulate: true, comdocument_idsoufilter): não altera nada; devolve quantos documentos seriam afetados, uma amostra e umconfirm_token. - Por critério (
filter): o servidor escolhe os documentos pelos critérios. Exige simular antes e repetir o mesmo corpo com oconfirm_tokenrecebido.
/api/v1/admin/vendor-documents/bulk-reviewAdminAprova ou recusa vários documentos
Corpo da requisição
statusstringobrigatórioapprovedrejecteddocument_idsarrayobrigatóriofilter; lista vazia dá 400.review_notesstringfilterobjectstatus (pending, approved, rejected), pending (true), document_type, vendor_id (UUID), created_after e created_before (YYYY-MM-DD), ids (lista de ids), exclude_ids (ids a deixar de fora) e all (true, para alcançar todos os pendentes). Um filtro sem nenhum recorte é recusado. Chave desconhecida é recusada com 400 invalid_filter.simulatebooleanpadrão: falseconfirm_token.confirm_tokenstringfilter. Vale por pouco tempo e só para o mesmo pedido.Exemplo de requisição
curl -X POST "$BASE_URL/api/v1/admin/vendor-documents/bulk-review" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "approved",
"document_ids": ["8f6a3b4e-1c2d-4e5f-9a0b-1c2d3e4f5a6b", "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"],
"review_notes": "Conferidos"
}'Resposta
{ "message": "documents reviewed", "status": "approved", "reviewed": 2 }{
"simulate": true,
"action": "approved",
"description": "Aprovar documentos de seller",
"total": 12,
"sample": [],
"confirm_token": "tok_exemplo",
"expires_at": "2026-10-11T22:20:00Z",
"async": false,
"by": "filter"
}Campos da resposta
reviewedintegertotalintegersamplearrayconfirm_tokenstringexpires_atstringasyncbooleanNa execução por filter a resposta usa o formato comum das operações em lote: action, by, total_requested, status, affected e failed; um lote parcial vem com partial_failure: true. Quando é grande, responde 202 com async: true e a tarefa em job.
Erros
| Status | Quando | Corpo |
|---|---|---|
| 400 | Corpo que não é JSON | {"error":"invalid request body","detail":"..."} |
| 400 | status diferente de approved e rejected | {"error":"status must be 'approved' or 'rejected'"} |
| 400 | Sem document_ids (nem filter) | {"error":"document_ids is required"} |
| 400 | Filtro com chave desconhecida ou valor inválido | {"error":"invalid_filter","detail":"..."} |
| 409 | confirm_token de outro pedido, ou o recorte cresceu desde a simulação | {"error":"confirm_token_invalid","detail":"..."} |
| 428 | Execução por filter sem simulação prévia | {"error":"simulate_required","detail":"..."} |
| 500 | Falha interna | {"error":"failed to bulk review documents","detail":"..."} |