Toda rota abaixo é HTTP com JSON, responde à mesma credencial e devolve os seus próprios identificadores. Se o seu sistema já sabe enviar uma imagem para algum lugar, ele já sabe conversar com a LumaVision.
Você cria uma coleção, manda as suas fotos para dentro dela e depois faz perguntas. É só isso. As respostas voltam com os seus próprios identificadores, então nada aqui vira uma segunda base de dados para a sua equipe manter.
Coleção
Uma pasta. Você cria uma para cada evento, cliente ou portaria, e escolhe o nome dela. Tudo acontece dentro de uma: a busca procura ali, o agrupamento roda ali, e apagar a coleção apaga tudo o que está dentro.
external_id
O rótulo que VOCÊ dá a cada imagem que manda. Pode ser o nome do arquivo, o id da foto no seu banco, o que fizer sentido aí. Ele volta em toda resposta, para você casar com o seu registro — mas não apaga nada.
image_id
O nome que NÓS damos a cada envio. A mesma foto mandada duas vezes gera dois. É por ele que você apaga a foto depois, com todos os rostos dela.
face_id
O nome que NÓS damos a cada rosto encontrado. Uma foto com três pessoas gera três. Serve para apagar um rosto sem apagar a foto, e para perguntar por um rosto já guardado.
person_id
O nome que nós damos a uma pessoa depois de agrupar o acervo. Ele não muda: você anota no seu cadastro uma vez — “p0001 é a Maria” — e ele continua significando a Maria.
cosine
O quanto dois rostos se parecem, de 0 a 1. Nós medimos, você decide. Não existe um número certo para todo mundo: numa galeria de evento, uma foto a mais não machuca; numa portaria, machuca.
Casos de uso
Quatro coisas que as pessoas montam com esta API, na ordem em que as chamadas acontecem. Cada passo aponta para a rota que faz o trabalho.
Vender as fotos de um evento
Você fotografou um evento e quer que cada participante encontre as fotos dele sozinho, com uma selfie.
01/v1/collectionsCrie uma coleção para o evento. Uma vez, no começo.
02/v1/processMande cada foto do evento. Uma chamada por foto; a resposta vem por webhook, então você pode mandar milhares sem segurar conexão.
03/v1/searchQuando o participante manda a selfie, procure por ela na coleção. Cada resultado traz o external_id da foto em que ele aparece — os seus próprios nomes de arquivo.
Separar o acervo por pessoa, sem ninguém perguntar
Você quer montar a galeria de cada pessoa antes de alguém pedir, e não tem foto de referência de ninguém.
01/v1/collections/{collection_id}/clusterDispare o agrupamento depois de mandar as fotos. Ele responde na hora e trabalha por alguns minutos.
02/v1/collections/{collection_id}/peopleLeia os grupos. Cada um é uma pessoa, com quantas fotos tem e um rosto representativo para você mostrar.
03/v1/collections/{collection_id}/people/{person_id}Guarde o person_id junto do seu cadastro. Depois, é por ele que você pergunta de novo.
Conferir quem entra
Você tem uma lista de pessoas autorizadas e uma câmera na entrada.
01/v1/collections/{collection_id}/facesCadastre o rosto de cada pessoa autorizada, uma vez. Guarde do seu lado o face_id que a resposta devolve — é ele que apaga o rosto e pergunta por ele depois.
02/v1/liveness/analyzeNa entrada, mande alguns quadros da câmera. A resposta ajuda a separar uma pessoa presente da foto de uma pessoa.
03/v1/identifyMande o quadro e receba quem é. Aqui o número importa: escolha o seu limite e deixe uma pessoa decidir os casos de dúvida.
Atender um pedido de exclusão
Alguém pediu para sair do seu acervo e você precisa apagar e conseguir provar que apagou.
01/v1/collections/{collection_id}/facesListe o que está indexado para saber o que ainda existe sobre a pessoa. Cada linha traz o image_id da foto e o FaceId do rosto.
02/v1/collections/{collection_id}/faces/delete-by-image-idApague as fotos dela pelos image_id. A resposta separa o que saiu do que já não estava lá — é o seu recibo.
03/v1/collections/{collection_id}/people/{person_id}O identificador que você tinha anotado passa a responder GONE, em vez de sumir. Assim o seu banco continua sabendo o que aconteceu.
Autenticação
O cabeçalho
Authorization: Bearer lvk_… em toda requisição. A chave começa com lvk_ e é o único jeito de provar quem chama — não há parâmetro de query, não há cookie e não há sessão.
De onde ela vem
Do cadastro: você preenche o formulário em /signup, confirma o e-mail com o código que chega nele, e a chave aparece na tela ao fim. Não há fila, não há aprovação e não há uma rota de API para isso — a conta nasce no navegador.
Onde ela vive
Guardamos apenas o hash da sua chave, então ela é mostrada uma vez, quando é emitida, e não é legível depois. Perdeu, revoga e emite outra: não existe recuperar.
O que ela alcança
Só o seu espaço. Uma coleção que não é sua não responde “sem permissão”, ela simplesmente não existe para a sua chave — a fronteira está na consulta, não numa verificação que alguém possa esquecer de escrever.
Erros comuns
401 Chave ausente, revogada ou de uma conta inativa.
404 O recurso não existe para a sua chave.
422 O corpo não bate com o contrato. A resposta diz qual campo e por quê.
O que a API aceita
Tamanho do arquivo
5 MB · 25 MB
Padrão de 5 MB por imagem nas rotas que indexam ou buscam, e 25 MB em /v1/detect, que existe para medir uma fotografia inteira. O teto vale sobre os bytes DECODIFICADOS: base64 infla cerca de um terço, então uma string de 6,6 MB não passa num teto de 5 MB.
Dimensão da imagem
8000 px · 10000 px
Padrão do maior lado, nas mesmas duas famílias de rota. Uma imagem acima disso é recusada, nunca reduzida em silêncio.
Corpo da requisição
40 MB
O total de uma chamada, o que importa quando ela carrega vários quadros de uma vez. É recusado antes de o corpo ser lido inteiro.
Rosto mínimo
32 px
O lado da caixa do rosto. Abaixo disso o rosto é descartado — e é por isso que uma foto de 8000 px com um rosto de 30 px é recusada pelo rosto, não pela foto.
O serviço não redimensiona
Mande a imagem no tamanho em que ela foi feita, dentro do teto: aqui ela é aceita ou recusada, nunca reencodada. Uma cópia reencodada deixa de ser o arquivo do seu cliente, e é o arquivo dele que um pedido de exclusão fala sobre.
O que decide é o rosto
Não o tamanho da imagem. Uma foto grande com gente pequena e distante rende rostos pequenos; uma foto modesta com a pessoa em primeiro plano rende um rosto grande. É a segunda que responde melhor.
Os tetos são por conta e podem ser ampliados. Quando um é atingido, a resposta diz qual limite e qual valor estava em vigor — que é a única cópia de um limite que não envelhece.
Coleções
A coleção é a fronteira de tudo: da busca, do agrupamento e da exclusão. Apagar é por coleção, e uma pessoa que atravessa duas atravessa a fronteira de exclusão — por isso a chave que você escolhe aqui é uma decisão de produto, não um detalhe.
POST/v1/collections
Cria uma coleção
A coleção nunca nasce sozinha: mandar imagem para uma chave desconhecida é erro, não criação implícita. O identificador é seu — use a chave que já significa alguma coisa no seu sistema, porque é ela que volta em toda resposta.
No corpo
collection_idstringobrigatório
A chave, sua. Letras, números, ponto, dois-pontos, hífen e sublinhado.
metadataobject
O que você quiser pendurar nela. Guardado e devolvido, nunca interpretado.
Esquece a coleção e todos os rostos dentro dela — o pedido de exclusão mais amplo que esta API aceita. Devolve um recibo, não um 204: quem precisa provar conformidade tem de poder dizer o que foi apagado e quanto. Idempotente, e a segunda chamada diz mais que a primeira — o identificador volta em `not_found`, que é a resposta honesta tanto para “já apaguei” quanto para “nunca tive”.
Um evento inteiro, um cliente inteiro. POST e não DELETE com corpo: corpo em DELETE é legal e é descartado por proxies o bastante para um pedido de exclusão chegar vazio e ser respondido 200. A resposta separa o que foi apagado do que não existia, porque quem precisa provar conformidade tem de poder dizer qual dos dois aconteceu.
No corpo
collection_idsstring[]obrigatório
As chaves. Um lote longo demais é recusado, nunca truncado.
Todo envio aceita a imagem inline ou uma URL para buscá-la, nunca as duas. O caminho síncrono responde na mesma conexão; o assíncrono devolve um identificador e avisa por webhook.
POST/v1/process/sync
Processa uma imagem, agora
Roda os modelos na mesma conexão e devolve o resultado. Use quando alguém está esperando na tela. Para um acervo inteiro, a fila é mais barata e não segura conexão nenhuma.
No corpo
image_b64string
A imagem em base64. Cada chamada aceita exatamente uma forma de mandar o rosto.
image_urlstring
Uma URL assinada de onde buscar a imagem, em vez de mandá-la inline.
collection_idstring
Obrigatório quando `index` for true.
external_idstring
O seu rótulo para a imagem. Guardado e devolvido em toda resposta; quem apaga depois são os identificadores que a resposta devolve.
indexbooleanpadrão false
Se os rostos encontrados entram no índice da coleção.
O que foi medido na imagem. Guarde o `image_id` e os `FaceId` — são eles que apagam depois.
422
Pediu para indexar sem dizer em qual coleção, ou a imagem não pôde ser lida.
POST/v1/process
Processa uma imagem pela fila
Responde na hora com o identificador da requisição e entrega o resultado por webhook minutos depois. É o caminho para volume: as imagens são agrupadas em lotes antes de chegar à GPU, então mil chamadas custam menos tempo do que mil chamadas síncronas.
No corpo
image_b64string
A imagem em base64. Cada chamada aceita exatamente uma forma de mandar o rosto.
image_urlstring
Uma URL assinada de onde buscar a imagem, em vez de mandá-la inline.
external_idstring
O seu rótulo para a imagem. Volta no webhook para você casar a resposta.
collection_idstring
A coleção onde indexar.
webhook_endpoint_idinteger
Para onde avisar. Sem ele, o resultado fica para você buscar pelo job.
Aceita. Não é o resultado — o resultado chega por webhook. O `image_id` já endereça a submissão, mesmo antes de ele chegar.
POST/v1/detect
Mede uma imagem sem guardar nada
Todo rosto da imagem e tudo o que os modelos mediram sobre ele. Nada é indexado e nada é endereçado depois — por isso a resposta traz só os blocos de medição, sem `FaceId`: nomear uma linha que nunca foi escrita seria mentira.
No corpo
image_b64string
A imagem em base64. Cada chamada aceita exatamente uma forma de mandar o rosto.
image_urlstring
Uma URL assinada de onde buscar a imagem, em vez de mandá-la inline.
Duas perguntas diferentes sobre a mesma medida, e escolher a errada não dá erro — dá uma resposta plausível para outra pergunta. Nenhuma decide por você: o limiar é sempre seu, escrito sobre o que cada casamento devolve — o cosseno cru e a pose do rosto encontrado, para quem calibra o corte por ângulo. Toda resposta traz as duas escalas: `cosine` é o cosseno cru, e `Similarity` é o mesmo casamento mapeado para 0–100. Prefira o cosseno para calibrar limiar: a escala 0–100 satura, e acima de cosseno 0,6 quase tudo nela lê como 100.
POST/v1/search
Onde mais essa pessoa aparece
Os vizinhos mais próximos de um rosto, em várias coleções de uma vez. Uma coleção que falha faz a CHAMADA falhar: devolver a lista sem ela seria indistinguível de “não tem ninguém seu nessas fotos”, e é a leitura errada que custa caro. Nenhum corte de qualidade é aplicado, então o último resultado da lista pode perfeitamente ser um estranho — o limiar é seu, escrito sobre o `cosine` de cada par, com a `pose` ao lado para calibrar por ângulo.
No corpo
collection_idsstring[]obrigatório
Onde procurar. A ordem não importa; os resultados vêm ordenados por similaridade.
image_b64string
A imagem em base64. Cada chamada aceita exatamente uma forma de mandar o rosto.
image_urlstring
Uma URL assinada de onde buscar a imagem, em vez de mandá-la inline.
embeddingnumber[]
Um vetor que esta API já devolveu. Evita reprocessar a imagem quando você vai perguntar duas vezes sobre o mesmo rosto.
face_idstring
A quarta forma de mandar o rosto: o identificador de um rosto que esta API já guarda. Vai sozinho, sem coleção ao lado — o identificador nunca é reaproveitado, então o serviço acha a linha e confere que ela é sua. `collection_ids` acima segue dizendo onde PROCURAR, e não precisa incluir a coleção do rosto-pergunta.
Os pares encontrados, do mais parecido para o menos.
404
Nenhum rosto com esse `face_id` — ou ele está numa coleção que não é sua. A mesma resposta para os dois: um erro diferente confirmaria que o identificador existe.
409
O rosto-pergunta foi indexado por outro modelo de embedding. O serviço recusa em vez de comparar dois espaços — o número sairia plausível e não significaria nada.
POST/v1/identify
Quem está nesta foto
O rosto mais próximo em uma coleção, devolvido como a submissão de origem — o seu `external_id` e o nosso `image_id`, a resposta plana que uma consulta quer, sem nomear rosto nenhum. O limiar de aceitação é seu: devolvemos a medida, não o veredito. Aceita imagem, URL ou vetor — não a pergunta por `face_id`, que é da rota acima.
No corpo
collection_idstringobrigatório
Onde procurar.
image_b64string
A imagem em base64. Cada chamada aceita exatamente uma forma de mandar o rosto.
image_urlstring
Uma URL assinada de onde buscar a imagem, em vez de mandá-la inline.
embeddingnumber[]
Um vetor que esta API já devolveu. Evita reprocessar a imagem quando você vai perguntar duas vezes sobre o mesmo rosto.
O mais próximo — ou os campos vazios, quando a coleção não tem ninguém.
Pessoas
O agrupamento roda dentro da coleção e demora minutos, então dispara e avisa. O identificador que ele emite é contrato público: você grava contra o seu cadastro uma vez, e ele não passa a significar outra pessoa depois.
POST/v1/collections/{collection_id}/cluster
Agrupa o acervo por pessoa
Sem foto de referência e sem ninguém para perguntar. O trabalho leva minutos e roda um de cada vez, então a resposta é sempre 202 — uma segunda chamada entra na fila atrás da primeira em vez de ser recusada, e a resposta diz quantas estão na frente. Os grupos aparecem depois em `GET …/people`.
No caminho
collection_idstringobrigatório
A chave que você escolheu ao criar a coleção.
No corpo
modestringpadrão bootstrap
`bootstrap` agrupa do zero, `refresh` refaz o mesmo trabalho. O mesmo esforço; a palavra fica registrada na execução porque as duas significam coisas diferentes para quem pediu.
also_collectionsstring[]
Outras coleções que entram no mesmo escopo, para um evento partido em várias. Escopo maior custa recall: quanto mais gente no mesmo balde, mais alto o limiar precisa ficar.
Uma coleção nunca agrupada responde 200 com a lista vazia, não 404 e não um agrupamento implícito: um GET não deveria começar minutos de CPU. `unassigned_faces` é a medida honesta de cobertura — é o número que diz se as conferências estão apertadas demais.
No caminho
collection_idstringobrigatório
A chave que você escolheu ao criar a coleção.
Na query
limitintegerpadrão 1000
Quantas pessoas por página. Um valor acima do teto é recusado, não reduzido em silêncio.
A rota para a qual o seu banco aponta. Nunca 404 para um identificador que esta API emitiu: um grupo fundido responde apontando para o sucessor, um apagado responde `GONE`. É isso que deixa o `person_id` ser contrato — ele não passa a significar outra pessoa, e não some sem resposta.
O que está no índice, e como tirar de lá. As chaves são as que esta API devolveu ao indexar: o `image_id` nomeia o envio e o `FaceId` nomeia cada rosto dele — uma imagem pode ter vários, então “imagens apagadas” e “rostos apagados” não são o mesmo número, e um relatório de conformidade precisa dos dois. O seu `external_id` volta em toda resposta, mas não apaga nada: ele é rótulo, não chave.
POST/v1/collections/{collection_id}/faces
Indexa um rosto
Aceita uma imagem — e aí o serviço detecta o rosto dominante e o embute — ou um vetor pronto com o que você já mediu. Cada chamada é um envio novo: nada é substituído, e a mesma foto mandada duas vezes cria dois registros. Guarde o que volta — o `FaceId` é o que apaga esse rosto e o que pergunta por ele depois, e o `image_id` é o que apaga o envio.
No caminho
collection_idstringobrigatório
A chave que você escolheu ao criar a coleção.
No corpo
image_b64string
A imagem em base64. Cada chamada aceita exatamente uma forma de mandar o rosto.
image_urlstring
Uma URL assinada de onde buscar a imagem, em vez de mandá-la inline.
embeddingnumber[]
Um vetor que esta API já devolveu. Evita reprocessar a imagem quando você vai perguntar duas vezes sobre o mesmo rosto.
external_idstring
O seu rótulo para o envio. Guardado e devolvido em toda resposta que nomeia o rosto — e lido por nada: não é único, não filtra e não apaga.
poseobject
A pose, quando você manda o vetor pronto. Ela é conferida do nosso lado de qualquer jeito — ninguém indexa passando por cima da conferência simplesmente por não medir.
Indexado. Os dois identificadores que importam vêm juntos.
422
O rosto não passou na conferência de pose, ou não havia rosto na imagem.
GET/v1/collections/{collection_id}/faces
O que está indexado
A única forma de enumerar a memória do serviço sobre uma pessoa — o que tanto a depuração (“aquela foto entrou?”) quanto um pedido de exclusão (“o que vocês ainda guardam sobre mim?”) realmente perguntam. Paginado por cursor e não por offset: offset desloca a janela quando uma linha some no meio da paginação, e numa superfície de exclusão isso significa pular um rosto.
No caminho
collection_idstringobrigatório
A chave que você escolheu ao criar a coleção.
Na query
limitintegerpadrão 100
Quantos por página.
after_idinteger
O `next_after_id` da página anterior.
person_idstring
Só os rostos que o agrupamento pôs nessa pilha — a galeria de uma pessoa, sem uma segunda busca. Página vazia é “ela não tem rostos aqui”; um identificador que nunca existiu responde 404.
A coleção não existe — ou o `person_id` do filtro nunca existiu. Numa listagem, “você não guarda nada” e “você digitou a chave errada” não podem parecer a mesma coisa.
Um rosto só, pelo identificador que esta API devolveu ao indexá-lo. Devolve o MESMO recibo da rota em lote, e não um 204: a prova de uma exclusão não pode depender de quantos identificadores o chamador resolveu nomear, senão o pedido mais estreito — o que chega como “esqueça esta pessoa” — é justamente o mudo.
No caminho
collection_idstringobrigatório
A chave que você escolheu ao criar a coleção.
face_idstringobrigatório
O rosto a esquecer. O `FaceId` que a indexação devolveu.
Todos os rostos de UM envio — “apaguem aquela foto”, que é o pedido que de fato chega. O `image_id` foi emitido por esta API quando a imagem entrou e nomeia exatamente um envio; o seu `external_id` não serve aqui, porque ele nunca foi único e apagar por ele levaria junto o que mais carregasse o mesmo rótulo.
No caminho
collection_idstringobrigatório
A chave que você escolheu ao criar a coleção.
image_idstringobrigatório
O envio a esquecer. O `image_id` que a indexação ou o processamento devolveu.
Um ensaio inteiro de uma vez, pelos `image_id` dos envios. A resposta separa o que foi apagado do que não estava lá — uma contagem sozinha não distingue “já apagado semana passada” de “o seu identificador estava errado”. Um lote longo demais é recusado, nunca truncado.
O mesmo, pelos identificadores de rosto. É rota separada de propósito: um `image_id` é um envio e pode ter vários rostos, um `face_id` é uma linha — e “imagens apagadas” e “rostos apagados” não são o mesmo número, e um relatório de conformidade precisa dos dois.
Quadros de câmera, sinais por quadro. O que separa uma pessoa presente da foto de uma pessoa é medido aqui; o que fazer com essa medida é decidido aí.
POST/v1/liveness/analyze
Confere se é uma pessoa ao vivo
Quadros de webcam, sinais por quadro. A lógica de sessão — o desafio, o veredito, quantos quadros bastam — fica do seu lado: esta rota mede, ela não decide. Cada quadro passa pelos mesmos limites de upload de qualquer outra imagem.
No corpo
frames_b64string[]obrigatório
Os quadros, em base64. Um lote curto, não um vídeo.
want_embeddingsbooleanpadrão false
Se cada quadro volta com o vetor do rosto, para você comparar sem uma segunda chamada.
Um objeto por quadro, na ordem em que você mandou.
Webhooks e jobs
As rotas assíncronas respondem minutos depois. Registre o endereço uma vez e receba; ou pergunte pelo job, se preferir perguntar a esperar.
POST/v1/webhook-endpoints
Registra um callback
Para onde avisar quando um trabalho assíncrono termina. O segredo de assinatura é devolvido UMA VEZ, na criação, e não é legível depois — guarde-o para conferir a assinatura das entregas.
Desativar um que já estava inativo responde igual — uma exclusão repetida tem de responder como a primeira.
No caminho
endpoint_idintegerobrigatório
O identificador devolvido no registro.
204
Desativado. Sem corpo.
404
A sua chave não tem esse endereço.
GET/v1/jobs
Os trabalhos da sua chave
Do mais novo para o mais antigo, paginado por cursor — “o que está rodando”, “o que falhou hoje”, “o lote da manhã terminou?”. Os filtros são exatos e validados: um valor desconhecido responde 422 em vez de uma página vazia, porque uma página vazia por erro de digitação leria como “nada falhou”.
Na query
statusstring
Só os trabalhos nesse estado. Um estado desconhecido é recusado, nunca ignorado.
kindstring
Só os trabalhos desse tipo.
before_idinteger
O `next_before_id` da página anterior.
limitintegerpadrão 50
Quantos por página.
include_supersededbooleanpadrão false
Se as tentativas que já foram substituídas por um retry também aparecem.
A resposta diz o que parar SIGNIFICOU, porque a verdade difere por caso: um agrupamento para no próximo checkpoint; um trabalho ainda não despachado nem começa; um que já está na GPU não pode ser chamado de volta — ele roda até o fim e o resultado é descartado quando chega. Um trabalho que já terminou responde 409: não havia o que parar, e um 200 diria que havia.
Só a partir de FAILED — um trabalho rodando ainda não falhou, e um cancelado foi parado de propósito. A tentativa que falhou fica como estava, porque ela é a evidência do que deu errado: um agrupamento ganha um trabalho novo apontando para ela, e as imagens de um lote voltam para a fila e respondem cada uma no seu webhook.
O trabalho não está em FAILED — ou não sobrou nada para tentar de novo.
422
O insumo não existe mais: o upload já foi liberado, ou a coleção do agrupamento foi apagada. Mande de novo.
Consumo
Estas quatro não entram na sua conta: ler quanto você gastou nunca é cobrado. O resto é — toda requisição que a API atende conta como uma chamada, inclusive a que responde que não encontrou ninguém, porque ela custou o mesmo trabalho.
GET/v1/usage
Chamadas por período
Agrupadas por rota. É o número da fatura. Sem janela, responde os últimos trinta dias — uma varredura ilimitada do extrato nunca deve ser a consulta acidental.
O corpo que você enviou e a resposta que recebeu. As imagens aparecem como quantos bytes tinham, e não como bytes: este serviço não pode acabar guardando uma cópia das fotos dos seus clientes, e um extrato que as guardasse seria exatamente isso.
Sem versão e sem chave — é a única coisa aqui que você precisa poder perguntar quando a chave é justamente o que está em dúvida. Não conta como chamada.
200
{ "ok": true }
De pé.
Crie a conta, a chave sai na tela.
As primeiras 10.000 requisições por mês são de graça, sem cartão.