FrameMatcher · Custodis Tech

Documentação da API

Integração server-to-server para acervos de eventos. Duas chamadas: encontre todas as fotos de uma pessoa a partir de uma selfie, ou leia os rostos de uma foto específica.

Autenticação

Todas as chamadas exigem o cabeçalho X-API-Key com a chave fornecida por nós. A chave identifica o seu acesso e delimita quais eventos você enxerga — não compartilhe publicamente nem a exponha em código de front-end.

X-API-Key: sua-chave-de-acesso

O host base é https://busca.framematcher.com. O identificador {evento} usado nas rotas é fornecido junto com a chave.

Sem chave, ou com chave inválida, a resposta é 403. Um evento que não pertence à sua chave responde 404 — nunca 403 — para não revelar a existência de eventos de terceiros.

1 · Busca por selfie

POST /v1/partner/events/{evento}/search

Envie uma selfie e receba a lista de todas as fotos do evento em que aquela pessoa aparece, ordenadas por destaque — fotos individuais, nítidas, frontais e bem enquadradas primeiro.

Requisição

A imagem vai como corpo binário, com o Content-Type correspondente (image/jpeg, image/png ou image/webp) — até 10 MB, contendo um único rosto.

curl -X POST https://busca.framematcher.com/v1/partner/events/{evento}/search \
     -H "X-API-Key: SUA_CHAVE" \
     -H "Content-Type: image/jpeg" \
     --data-binary @selfie.jpg
Também aceitamos multipart/form-data com um campo selfie. Uma selfie por chamada — para um lote, repita a chamada.

Resposta padrão

{
  "count": 41,
  "files": [
    "nr_sam_20260425_03278_414927.jpg",
    "nr_sam_20260425_02143_414927.jpg"
  ]
}

Informações adicionais (opcionais)

Parâmetros de query com =on. Nenhum deles quebra a resposta padrão de quem não os usa.

ParâmetroEfeito
dictfiles vira lista de objetos, com o nome em file.
bboxAdiciona face — posição (x, y) e tamanho (width, height) do rosto em pixels. Implica dict.
sizeAdiciona image — tamanho da foto original, no mesmo referencial de face. Implica dict.
relevantAdiciona dois campos por foto: relevant_persons, quantas pessoas relevantes há na foto (rostos com pelo menos metade do tamanho do rosto da pessoa; inclui a própria, mínimo 1), e relevance, o tamanho deste rosto comparado ao maior rosto do mesmo frame, de 0 a 1. Implica dict.
confidenceAdiciona confidence por foto — o quanto a selfie corresponde à pessoa daquela foto, de 0.0 a 100.0. Implica dict.
qualityAdiciona quality por foto — nitidez do rosto de 0.0 a 100.0. Implica dict.
emotionAdiciona emotion por foto: positive, negative ou neutral. Implica dict.
headposeAdiciona headpose por foto — { yaw, pitch, roll } em graus. Implica dict.
ageAdiciona age_group e underage_risk no topo da resposta.
genderAdiciona gender no topo da resposta (male/female).
gender e age_group descrevem a pessoa — um valor por busca — por isso ficam no topo. Todo o resto é por foto.

Filtrar por precisão — threshold

Diferente dos anteriores: leva um valor, não =on. Usa a mesma escala 0100 em que confidence é devolvido, então quem vê "confidence": 87.4 e quer apenas resultados assim de seguros manda threshold=85. Filtra foto a foto pelo confidence de cada uma: threshold=93 devolve só fotos com confidence ≥ 93.0, e o count já vem filtrado.

Sem o parâmetro não há filtro por foto. Todas as fotos da pessoa voltam, inclusive as de ângulo ruim que pontuam mais baixo — é o padrão, e o que dá o resultado mais completo.
POST /v1/partner/events/{evento}/search?dict=on&confidence=on&threshold=85
Só aperta, nunca afrouxa. Cada evento tem um limiar calibrado abaixo do qual o match não é confiável. Um threshold menor que esse limiar é ignorado — a busca fica no piso calibrado. Afrouxar traria fotos de outras pessoas, então não é uma opção oferecida. Valor não numérico ou fora de 0100 responde 400.

Como confidence é calculado

Para cada selfie avaliamos até 25 rostos candidatos do acervo, cada um com sua própria confiança. Cada candidato é resolvido para o grupo de fotos da pessoa a que pertence, ficando a melhor confiança de cada grupo; todos os grupos acima do limiar do evento entram no resultado. Cada foto pertence a um desses grupos e herda a confiança dele — por isso o valor varia dentro de um mesmo resultado, e não é um número único da busca.

Use confidence para ordenar ou cortar resultados por segurança do match, e relevance para saber se a pessoa é o assunto da foto ou está ao fundo. São coisas diferentes: uma foto pode ter confidence alta e relevance baixa.

Exemplo com todos os campos

POST /v1/partner/events/{evento}/search?dict=on&bbox=on&size=on&relevant=on&emotion=on&headpose=on&quality=on&age=on&gender=on&confidence=on

{
  "gender": "male",
  "age_group": "30-39",
  "underage_risk": false,
  "count": 41,
  "files": [
    {
      "file":             "nr_sam_20260425_03278_414927.jpg",
      "relevant_persons": 3,
      "relevance":        1.0,
      "confidence":       87.4,
      "quality":          93.1,
      "emotion":          "positive",
      "headpose":         { "yaw": -4.2, "pitch": 2.8, "roll": 1.1 },
      "face":             { "x": 812, "y": 340, "width": 220, "height": 260 },
      "image":            { "width": 4000, "height": 6000 }
    }
  ]
}
A ordem dos campos acima é a ordem em que a API responde. Ordem de chaves não altera nada para um parser JSON — é só para a resposta se ler de cima para baixo.

2 · Rostos de uma foto

GET /v1/partner/events/{evento}/faces?file={arquivo}

Dado o nome de um arquivo do acervo, devolve todos os rostos daquela foto — não apenas o de uma pessoa. Útil para montar legendas, escolher fotos de destaque ou avaliar o enquadramento antes de publicar. Não envolve selfie nem busca.

Requisição

O nome do arquivo vai como parâmetro de query file — e não no caminho da URL — porque nomes de arquivo do acervo podem conter barras. Aceitamos tanto o nome completo devolvido pela busca (252670/nr_sam_….jpg) quanto apenas o nome base (nr_sam_….jpg).

curl -G https://busca.framematcher.com/v1/partner/events/{evento}/faces \
     -H "X-API-Key: SUA_CHAVE" \
     --data-urlencode "file=nr_sam_20260425_03278_414927.jpg"

Resposta

Os rostos vêm do mais relevante para o menos relevante.

{
  "file":  "252670/nr_sam_20260425_03278_414927.jpg",
  "image": { "width": 4000, "height": 6000 },
  "count": 2,
  "faces": [
    {
      "relevance":     1.0,
      "gender":        "male",
      "age_group":     "30-39",
      "underage_risk": false,
      "quality":       93.1,
      "emotion":       "positive",
      "headpose":      { "yaw": -4.2, "pitch": 2.8, "roll": 1.1 },
      "bbox":          { "x": 812, "y": 340, "width": 220, "height": 260 }
    },
    {
      "relevance":     0.636,
      "gender":        "female",
      "age_group":     "13-18",
      "underage_risk": true,
      "quality":       71.8,
      "emotion":       "neutral",
      "headpose":      { "yaw": 18.5, "pitch": -3.0, "roll": 0.4 },
      "bbox":          { "x": 1850, "y": 520, "width": 140, "height": 165 }
    }
  ]
}
relevance compara o rosto com o maior rosto da mesma foto, de 0 a 1: o maior sempre vale 1.0 e os demais são uma fração dele. Um rosto com relevance baixo está ao fundo — provavelmente não é o assunto da foto. É o mesmo campo que a busca devolve por foto com relevant=on.

Atributos

Faixa etária

As duas primeiras faixas não são décadas: elas acompanham os limites que importam juridicamente (18 anos e, dentro disso, 13 anos).

FaixaFaixaFaixaFaixa
0-1219-2940-4960-69
13-1830-3950-5970+

Proteção a menores — underage_risk

A estimativa de idade por foto é ruidosa. Uma pessoa menor de idade pode ser estimada acima de 18 em algumas fotos e, na média, cair numa faixa adulta. Como classificar um menor como adulto é o erro caro para quem opera sob regras de proteção a menores, a regra é deliberadamente assimétrica:

Isto é um indicador, não uma verificação de idade. Serve para sinalizar risco e acionar a sua própria conferência — não substitui verificação documental nem dispensa o seu dever legal de checagem.

Emoção

positive (feliz, surpreso), negative (triste, bravo, com medo, com nojo) ou neutral.

Pose da cabeça — headpose

Três ângulos em graus. 0 em todos significa rosto frontal.

Qualidade, confiança e relevância

quality e confidence vão de 0.0 a 100.0, com uma casa decimal; relevance vai de 0 a 1. São três perguntas diferentes sobre a mesma foto:

Qualquer atributo pode vir null quando ainda não foi calculado para aquela foto. Trate null como “desconhecido”, nunca como zero.

Códigos de resposta

CódigoSignificado
200Sucesso.
400Requisição inválida: selfie ausente ou ilegível, ou file não informado.
403Chave de acesso ausente ou inválida.
404Nada encontrado: nenhuma foto para a selfie, arquivo inexistente no evento, ou evento fora do alcance da sua chave.

Erros trazem sempre o mesmo formato:

{ "errors": [ { "code": "forbidden", "message": "missing api key" } ] }
Atenção ao 404 da busca: ele cobre tanto “a pessoa não está no acervo” quanto “a selfie não pôde ser usada” (nenhum rosto, mais de um rosto ou imagem de baixa qualidade). Na sua interface, oriente o usuário a tentar outra selfie antes de afirmar que não há fotos.

Privacidade e retenção