Pular para o conteúdo

API Web — contratos completos

Esta é a página de referência da API Web: contrato HTTP completo dos cinco endpoints, com campos, tipos, respostas de sucesso e todos os códigos de erro. Para o passo a passo de integração, comece pela Integração Web.

No fluxo do Web SDK, você chama diretamente POST /web/sessions (criar a sessão) e, quando precisar renovar uma URL expirada do JPEG, GET /web/image/:session_id. O evento uploaded do componente entrega session_id e, sob a política ALWAYS, a URL do JPEG autenticado. O GET /web/session-results/:token é a via do seu backend para o sidecar do manifesto — necessária sob NEVER (a política default), dispensável só sob ALWAYS — busque-o logo após o uploaded: a rota não é garantida depois dos 30 minutos de validade da sessão. Os endpoints GET /web/sessions/:token e POST /web/ingest são chamados internamente pelo componente <provvi-camera>; estão aqui só para você interpretar os erros que chegam no evento error.

Todas as chamadas usam o mesmo host:

https://sessions.provvi.com.br

Nos exemplos de backend abaixo, esse host é referenciado pela variável de ambiente PROVVI_SESSIONS_URL. Configure-a no seu backend em vez de fixar a URL no código.

Terminal window
export PROVVI_SESSIONS_URL="https://sessions.provvi.com.br"

A API de licenciamento (POST /validate) vive em outro host (https://api.provvi.com.br) e é chamada pelo SDK, não pelo seu backend. Ela não serve as rotas /web/*.

Há dois modos de autenticação, conforme o endpoint:

Modo Onde Endpoints
Header x-api-key: pvv_api_... Backend do integrador (nunca no frontend) POST /web/sessions
Token/session_id no path (capability) Backend ou componente GET /web/session-results/:token, GET /web/image/:session_id, GET /web/sessions/:token

A x-api-key é uma credencial de alto privilégio — obtenha-a no Admin Console e mantenha-a apenas no backend.

Os endpoints de consulta usam o token da sessão como capability: não há autenticação forte adicional. Quem tem o token pode ler os resultados daquela sessão — portanto trate o token como um segredo e não o exponha em URLs públicas, logs ou clientes não confiáveis.

As respostas de erro produzidas pelos serviços da Provvi trazem um corpo JSON com o campo error (um 429 de pico pode vir do gateway antes da API, com corpo diferente). Alguns erros de captura acrescentam campos auxiliares:

{
"error": "Descrição legível do erro",
"block_reason": "opcional — presente em alguns bloqueios de captura",
"recapture_risk": "opcional — presente quando a rejeição é por recaptura",
"bytes": "opcional — só no 413 do ingest: tamanho medido da imagem",
"max_asset_bytes": "opcional — só no 413 do ingest: limite vigente por imagem"
}

Os corpos literais de cada código estão nas tabelas de erro de cada endpoint.

Recurso Valor Efeito ao estourar
Criação de sessões por x-api-key 100 por hora 429 em POST /web/sessions
Carregamentos da sessão (contando o primeiro) 20 429 em GET /web/sessions/:token
Validade do token de sessão 30 minutos 410 (sessão expirada)
Validade da URL presigned de upload 5 minutos Upload falha (INGEST_FAILED / 4002). O componente não retenta sozinho: chame open({ token }) de novo — ele recarrega a sessão e recebe uma URL de upload nova (a sessão admite 20 carregamentos no total). Se o upload falha já na primeira captura a partir do seu domínio, a origem ainda não foi habilitada para envio no onboarding — fale com a Provvi; não se resolve repetindo. O mesmo domínio não habilitado também produz 403 com block_reason web_origin_not_allowed (ou web_origin_allowlist_empty) em GET /web/sessions/:token e em POST /web/ingest
Validade das URLs de resultado/asset 7 dias Renove com GET /web/image/:session_id

Sessões são single-use: uma vez concluída ou expirada, o token não pode ser reutilizado (410).


Cria uma sessão de captura. Chamado pelo backend do integrador. Retorna um token de curta duração que o frontend passa ao componente.

Auth: header x-api-key.

Headers

Header Valor
Content-Type application/json
x-api-key Sua API Key (pvv_api_*)

Request body

Campo Tipo Obrigatório Descrição
reference_id string Sim ID do anúncio/entidade no seu sistema (veículo, imóvel, apólice). Texto ASCII de 1 a 512 bytes — letras, dígitos, espaço e . _ : / @ # + - — sem espaço nas pontas; fora disso ⇒ 400
license_key string Sim Sua license (pvv_*) — a mesma usada no frontend. Amarrada à sessão. Formato: prefixo pvv_live_, pvv_stag_ ou pvv_sand_ + 32–33 caracteres base58; ausente ou fora do formato ⇒ 400

A Provvi valida a ownership da license_key no momento da criação: ela precisa pertencer ao mesmo cliente da x-api-key. Se não pertencer, a resposta é 403 com corpo único (anti-enumeração). Depois da ownership, ela confere o ambiente: a license e a x-api-key precisam ser do mesmo ambiente (sandbox ou produção); se diferem, a resposta é 403 com corpo próprio (block_reason: web_license_environment_mismatch).

Exemplo

Terminal window
curl -X POST "$PROVVI_SESSIONS_URL/web/sessions" \
-H "Content-Type: application/json" \
-H "x-api-key: $PROVVI_API_KEY" \
-d '{
"reference_id": "VIN-9BWZZZ377VT004251",
"license_key": "'"$PROVVI_LICENSE_KEY"'"
}'

Response 200

Retorna exatamente dois campos:

{
"token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"expires_at": "2026-07-07T12:30:00Z"
}
Campo Tipo Descrição
token string Token da sessão; passe ao componente via camera.open({ token }). Válido por 30 minutos
expires_at string Expiração em ISO-8601 (RFC 3339, UTC)

Erros

HTTP Causa Body
400 Campo obrigatório ausente ou malformado: corpo ilegível, license_key ausente ou fora do formato, reference_id vazio, acima de 512 bytes ou com caractere fora do conjunto permitido { "error": "..." } (com block_reason: web_create_payload_invalid, web_license_key_malformed ou web_reference_id_invalid)
401 x-api-key ausente ou inválida { "error": "API key inválida ou ausente" }
401 x-api-key revogada { "error": "API key inválida ou revogada" }
401 Prefixo de chave incorreto { "error": "API key inválida — apenas pvv_api_* aceito" }
403 license_key não pertence ao cliente da x-api-key (corpo único, byte-idêntico independente da causa) { "error": "License inválida para esta API key" }
403 license_key pertence ao cliente, mas license e x-api-key são de ambientes diferentes (sandbox × produção) { "error": "License e API key pertencem a ambientes diferentes", "block_reason": "web_license_environment_mismatch" }
429 Limite de criação de sessões atingido (100/hora por x-api-key) { "error": "Limite de criação de sessões atingido..." }
500 Falha determinística ao validar a x-api-key ou a license (dado inconsistente do lado da Provvi) — não é transitório, não repita em laço: fale com a Provvi { "error": "Erro na validação de API Key" } ou { "error": "Erro na validação da license" }
503 Indisponibilidade transitória de um serviço interno da Provvi — fail-closed { "error": "Serviço temporariamente indisponível, tente novamente", "block_reason": "web_upstream_unavailable" }

Em 503, a criação falhou fechada por segurança — tente novamente após alguns segundos.


⚠️ Chamado internamente pelo componente — você não chama diretamente. Documentado aqui só para interpretar os erros que chegam no evento error do <provvi-camera>.

O componente busca o estado da sessão e o destino de upload da foto neste endpoint ao abrir a captura. O corpo de sucesso é consumido internamente pelo SDK.

Auth: token no path (capability).

Erros visíveis ao integrador

HTTP Causa Body
403 Sessão ilegível pelo servidor — não se recupera { "error": "Sessão inválida — recrie a sessão.", "block_reason": "web_session_corrupt" }
403 Origem da página não habilitada para esta licença — web_origin_allowlist_empty quando a licença ainda não tem domínio algum registrado. Não repita a requisição: registre o domínio (Configuração) { "error": "Origem não autorizada para esta licença — fale com a Provvi para habilitar este domínio.", "block_reason": "web_origin_not_allowed" } ou "block_reason": "web_origin_allowlist_empty"
403 Sessão sem licença utilizável — recrie a sessão enviando license_key no create { "error": "Sessão inválida — recrie a sessão.", "block_reason": "web_license_missing" }
403 Licença amarrada à sessão não reconhecida { "error": "License inválida — verifique a licença.", "block_reason": "web_license_invalid" }
403 Acesso não validado pelo servidor (o pedido não se apresentou como um navegador suportado). Recarregue a página pelo link recebido e tente de novo; se persistir, acione o suporte — não recrie a sessão em laço { "error": "Não foi possível validar o acesso. Recarregue a página pelo link recebido e tente de novo." } — sem block_reason
404 Token não encontrado { "error": "Sessão não encontrada" }
410 Sessão já utilizada ou expirada (single-use; mesma mensagem para ambos) { "error": "Sessão expirada ou já utilizada" }
429 Recarregamentos demais na mesma sessão (limite de 20) { "error": "Limite de tentativas atingido para esta sessão" }
503 Indisponibilidade transitória (inclui a emissão da URL de upload) { "error": "Serviço temporariamente indisponível, tente novamente", "block_reason": "web_upstream_unavailable" } ou "block_reason": "web_presign_unavailable"

Esses erros chegam ao seu handler de error como ProvviAPIError — mapeie a ação do usuário (recriar sessão em 410, aguardar em 429/503). O 403 de origem é a exceção: não se resolve repetindo nem recriando a sessão, porque a causa é o domínio não habilitado. No 403 sem block_reason (acesso não validado) a ação é: recarregar a página pelo link recebido e tentar de novo; se persistir, acionar o suporte — e não recriar a sessão em laço. Ver Tratamento de erros.

A origem da página é conferida antes de a sessão ser entregue ao componente — ou seja, a captura nem chega a abrir num domínio não habilitado. A mesma conferência se repete no envio (POST /web/ingest), e a sessão precisa ser enviada da mesma origem em que foi carregada.


Consulta os resultados completos de uma sessão. Endpoint de leitura backend, chamado pelo backend do integrador com o token da sessão. É a via do sidecar do manifesto (manifest_url), que o componente não entrega no evento: necessária sob NEVER (a política default), dispensável só sob ALWAYS. Busque e guarde o manifest_url logo após o uploaded: o registro da sessão vale 30 minutos e a rota não é garantida depois disso — pode responder 404 ou 200 com status: "expired".

Auth: token no path (capability — trate como segredo).

Exemplo

Terminal window
curl "$PROVVI_SESSIONS_URL/web/session-results/$TOKEN"

Response 200

{
"reference_id": "VIN-9BWZZZ377VT004251",
"status": "captured",
"total_photos": 1,
"captured_count": 1,
"created_at": "2026-07-07T12:00:00Z",
"photos": [
{
"order": 1,
"label": "Frente do veículo",
"status": "captured",
"session_id": "sess_abc123",
"heading": 87.4,
"gps_lat": -23.5505,
"gps_lon": -46.6333,
"gps_accuracy": 12.5,
"captured_at_ms": 1751889600000,
"frame_hash_hex": "9f2c...e1a4",
"authenticated_jpeg_url": "https://.../authenticated.jpg?...",
"manifest_url": "https://.../manifest.c2pa?..."
}
]
}

Campos da resposta

Campo Tipo Descrição
reference_id string ID informado na criação da sessão
status string Estado da sessão — ver tabela abaixo
total_photos number Total de fotos previstas na sessão
captured_count number Fotos já capturadas
created_at string Criação da sessão (ISO-8601)
photos array Fotos da sessão — objeto Photo abaixo

Objeto Photo

Campo Tipo Descrição
order number Ordem da foto no perfil (1-based)
label string Rótulo da foto (ex.: “Frente do veículo”)
status string "pending" ou "captured"
session_id string ID da captura
heading number Direção da bússola em graus (pode ser ausente se o usuário pulou a bússola)
gps_lat number Latitude WGS84 (0 se a localização não foi obtida)
gps_lon number Longitude WGS84 (0 se a localização não foi obtida)
gps_accuracy number Precisão em metros (9999 se a localização não foi obtida)
captured_at_ms number Timestamp da captura em epoch ms
frame_hash_hex string Hash SHA-256 do frame, em hexadecimal
authenticated_jpeg_url string | null URL presigned do JPEG autenticado. null quando o cliente não armazena o asset (política NEVER)
manifest_url string URL presigned do manifesto C2PA (sidecar)

Estados da sessão (status)

Status Descrição
pending Nenhuma foto capturada
partial Algumas fotos capturadas
captured Todas as fotos capturadas
expired Prazo da sessão venceu sem concluir — derivado no momento da consulta: uma sessão que não chegou a captured e cujo prazo passou responde expired
qualquer outro valor Trate como estado desconhecido — não assuma o conjunto acima como fechado

Erros

HTTP Causa Body
403 Sessão ilegível pelo servidor — não se recupera { "error": "Sessão inválida — recrie a sessão.", "block_reason": "web_session_corrupt" }
404 Token não encontrado, ou registro da sessão já removido (a rota não é garantida depois dos 30 minutos de validade da sessão) { "error": "Sessão não encontrada" }

As URLs em authenticated_jpeg_url e manifest_url são presigned e expiram em 7 dias. Para renovar a do JPEG autenticado (contas ALWAYS), use GET /web/image/:session_id; para o manifesto não há renovação — baixe-o e guarde no seu storage. Quando authenticated_jpeg_url é null, a prova da assinatura está apenas no manifest_url (cliente zero-knowledge), obtido aqui logo após o uploaded (a rota não é garantida depois dos 30 minutos de validade da sessão) — ver Resultados.


Regera uma URL presigned fresca (nova validade de 7 dias) para o asset autenticado de uma captura. Use quando a URL retornada em session-results já expirou.

Auth: session_id no path (capability — trate como segredo).

Exemplo

Terminal window
curl "$PROVVI_SESSIONS_URL/web/image/$SESSION_ID"

Retorna uma URL presigned GET nova para o JPEG autenticado da captura. Se o cliente não armazena o asset (política NEVER), não há JPEG a servir — nesse caso a prova é o manifest_url de session-results.


⚠️ Chamado internamente pelo componente — você não chama diretamente. O SDK monta e envia o payload da captura (imagem, hash, GPS, nonce). Documentado aqui só para interpretar os erros que chegam no evento error do <provvi-camera>.

Auth: contexto da sessão (interno ao SDK).

Campos do request — usando o <provvi-camera>, o payload é montado por ele e você não precisa desta tabela. Ela interessa a quem monta a própria UI com as primitivas exportadas (captureFrames, hashBuffer, postIngest): aí estes campos passam a ser contrato seu. Estão listados alguns campos com regra de forma própria — não é o payload inteiro, e os demais erros de forma aparecem na tabela de erros abaixo.

Campo Tipo Obrigatório Regra
extra_frame_hashes array de string Sim, na prática Hashes SHA-256 (64 caracteres hex) de frames capturados depois do frame principal. Precisa de pelo menos 2, distintos entre si, no máximo 8. Menos de 2 ⇒ 400 web_liveness_insufficient; iguais entre si ⇒ 400 web_liveness_static; fora da forma ⇒ 400 web_liveness_malformed; acima de 8 ⇒ 400 web_liveness_too_many
gps_lat, gps_lon, gps_accuracy number Sim Posição como o navegador a reporta (coords.latitude, coords.longitude, coords.accuracy), sem transformar. Fora da forma ⇒ 400 "Localização inválida.", antes de a sessão ser carregada
label string Não Rótulo apresentado ao usuário (o overlay.label), assinado no manifesto como photo_label. Até 64 bytes, sem caracteres de controle ou de formato (inclusive marcas bidi) e sem <, >, &, ", ' nem crase. Fora disso ⇒ 400 web_label_invalid, antes de a sessão ser carregada
user_agent string Não Vai ao manifesto saneado — caracteres de controle e de formato são removidos e o texto é cortado em 512 bytes
media_stream_settings object Não MediaStreamTrack.getSettings() do vídeo. Só telemetria, nunca bloqueia: apenas width, height e frameRate são lidos, e chaves desconhecidas são ignoradas. O <provvi-camera> publicado hoje não o envia

Os frames extras são um sinal client-attested de que a câmera estava ao vivo: eles dissuadem stream congelado ou injetado. Não provam cena ao vivo nem detectam foto de tela — isso é o gate de recaptura (422), e o tier segue sendo fraud deterrence.

Response de sucesso

{
"session_id": "sess_abc123",
"photo_order": 1,
"authenticated_jpeg_url": "https://.../authenticated.jpg?...",
"manifest_url": "https://.../manifest.c2pa?...",
"complete": true,
"signed_image_base64": "/9j/4AAQSkZJRg..."
}
Campo Tipo Descrição
session_id string ID da captura
photo_order number Ordem da foto que acabou de ser capturada
authenticated_jpeg_url string | null URL presigned do JPEG autenticado; null quando o cliente não armazena o asset (política NEVER)
manifest_url string URL presigned do manifesto C2PA (sidecar)
complete boolean true ao concluir a captura (o Web SDK é single-photo)
signed_image_base64 string O JPEG assinado — manifesto C2PA e assinatura ICP-Brasil A1 embutidos —, em base64, entregue inline em qualquer política de armazenamento (desde 2026-09-20). Sob NEVER é a única cópia que existe: a Provvi não o retém. Se a resposta com ele passasse do tamanho entregável, a captura é recusada com 502 web_signed_payload_too_large (abaixo). Leia a nota antes de contar com este campo

O componente não repassa todos esses campos ao integrador. No evento uploaded, o <provvi-camera> surfaça apenas { session_id, authenticated_jpeg_url } — e isso inclui signed_image_base64: o componente publicado recebe o JPEG assinado e o descarta, sem expô-lo ao seu código. Uma versão futura do componente vai entregá-lo; esta referência e as páginas do guia serão atualizadas junto. Até lá, para a integração pelo componente vale o que segue: quando o JPEG autenticado é servido (ALWAYS), o manifesto C2PA vai embutido nele (auto-verificável); sob NEVER, o sidecar é obtido pelo seu backend em GET /web/session-results/:token, logo após o uploaded (não garantido depois dos 30 minutos de validade da sessão). Ver Passo 5 · Resultados.

Erros visíveis ao integrador

Toda resposta de erro produzida por este endpoint traz error e, em alguns casos, block_reason e/ou recapture_risk; no 413, também bytes e max_asset_bytes.

HTTP Causa Body
400 Payload inválido ou frame_hash ausente { "error": "..." }
400 Frames de câmera ao vivo reprovados — quatro casos, um block_reason cada (ver Campos do request) { "error": "...", "block_reason": "web_liveness_static" }, "web_liveness_insufficient", "web_liveness_malformed" ou "web_liveness_too_many"
400 label acima de 64 bytes ou com caractere não aceito — conferido antes de a sessão ser carregada { "error": "label inválido — até 64 bytes, sem caracteres de controle/formato nem <>&\"'`.", "block_reason": "web_label_invalid" }
400 Coordenadas GPS inválidas — conferidas antes de a sessão ser carregada { "error": "Localização inválida." }
400 Imagem ausente, ilegível ou fora do que o SDK produz (envie os bytes de captureFrames sem convertê-los) { "error": "Imagem ausente ou inválida" }
400 Ordem da foto diferente da que a sessão espera (não ocorre pelo componente: a sessão web é de uma foto e o componente envia a ordem que ela informa) { "error": "photo_order não corresponde à foto pendente desta sessão.", "block_reason": "web_photo_order_mismatch" }
403 License revalidada e reprovada (revogada/suspensa/expirada) { "error": "..." }
403 Origem da página não habilitada para esta licença — web_origin_allowlist_empty quando a licença ainda não tem domínio algum registrado. Não repita a requisição { "error": "Origem não autorizada para esta licença — fale com a Provvi para habilitar este domínio.", "block_reason": "web_origin_not_allowed" } ou "block_reason": "web_origin_allowlist_empty"
403 Sessão carregada em uma origem e enviada de outra { "error": "Sessão carregada de outra origem — recarregue a sessão.", "block_reason": "web_origin_session_mismatch" }
403 Relógio do dispositivo fora de sincronia { "error": "...verifique data e hora" }
403 Nonce ausente, fora da forma ou já utilizado (web_nonce_missing, web_nonce_malformed, web_nonce_replay) { "error": "...recarregue a sessão" }
403 Sessão ilegível pelo servidor { "error": "Sessão inválida — recrie a sessão.", "block_reason": "web_session_corrupt" }
403 Acesso não validado pelo servidor (o envio não se apresentou como um navegador suportado). Recarregue a página pelo link recebido e tente de novo; se persistir, acione o suporte — não recrie a sessão em laço { "error": "Não foi possível validar o acesso. Recarregue a página pelo link recebido e tente de novo." } — sem block_reason
404 Sessão não encontrada { "error": "Sessão não encontrada" }
404 Imagem enviada não encontrada (a sessão continua válida — o componente repete o upload com open({ token })) { "error": "Imagem não encontrada — refaça o upload" }
409 Reuso de sessão já concluída { "error": "Sessão já utilizada" }
409 Captura não processável (corpo opaco — a sub-causa não é revelada) { "error": "Esta captura não pôde ser processada.", "block_reason": "web_duplicate" }
410 Sessão expirada { "error": "Sessão expirada" }
413 Imagem acima do limite por foto (bytes maior que max_asset_bytes; o texto traz o limite) { "error": "Imagem acima do tamanho máximo aceito (... bytes).", "block_reason": "web_asset_too_large", "bytes": ..., "max_asset_bytes": ... }
422 Recaptura detectada { "error": "Imagem rejeitada — possível recaptura", "recapture_risk": "HIGH" }
422 Localização da captura não validada { "error": "Não foi possível validar a localização da captura." }
502 Serviço de assinatura indisponível, recusou a assinatura ou respondeu fora da forma — nada foi entregue e a captura não conta como assinada. Com web_signer_rejected nada foi assinado; nos outros dois a assinatura pode ter ocorrido do lado da Provvi sem ser entregue, e o mesmo frame pode ser recusado como duplicata (409) por alguns minutos — refaça a captura com um frame novo. Recarregue a sessão (open({ token })) e refaça a captura { "error": "Serviço de assinatura indisponível — refaça a captura.", "block_reason": "web_signer_unavailable" }; { "error": "A assinatura foi recusada — refaça a captura.", "block_reason": "web_signer_rejected" }; { "error": "Resposta do serviço de assinatura inválida — refaça a captura.", "block_reason": "web_signer_response_invalid" }
502 Armazenamento da prova, acesso a ela ou registro anti-replay indisponíveis — nada entregue. Recarregue a sessão e refaça a captura { "error": "Serviço de armazenamento da prova indisponível — refaça a captura.", "block_reason": "web_prova_store_unavailable" }; { "error": "Falha ao gerar o acesso à prova — refaça a captura.", "block_reason": "web_ingest_presign_failed" }; { "error": "Serviço temporariamente indisponível — refaça a captura.", "block_reason": "web_ingest_presign_config_failed" }; { "error": "Serviço de registro indisponível — refaça a captura.", "block_reason": "web_hash_store_unavailable" }
502 Falha ao ler a imagem enviada (o upload existe; a leitura falhou). Repetir o mesmo envio não resolve: recarregue a sessão e refaça o upload { "error": "Falha ao ler a imagem enviada — recarregue a sessão e refaça o upload.", "block_reason": "web_raw_read_failed" }
502 O JPEG assinado passaria do tamanho entregável da resposta — nada persistido. Não é esperado com o limite atual por imagem; se ocorrer, refaça com resolução menor e fale com a Provvi { "error": "Imagem assinada acima do tamanho entregável — reduza a resolução da captura.", "block_reason": "web_signed_payload_too_large" }
502 A licença da sessão não permitiu registrar a captura (dado de configuração ausente do lado da Provvi) — nada assinado. Recarregue a sessão e refaça; se persistir, fale com a Provvi { "error": "Serviço temporariamente indisponível — recarregue a sessão e refaça a captura.", "block_reason": "web_ledger_client_id_unauthoritative" }
502 A captura foi assinada e não entregue: o registro probatório não pôde ser gravado. A mesma imagem não é aceita de novo (volta como 409); recarregue a sessão e refaça com uma foto nova { "error": "Serviço temporariamente indisponível — recarregue a sessão e refaça a captura.", "block_reason": "web_ledger_write_failed" }
502 Erro interno ao montar a resposta — não é transitório do seu lado. Repita uma vez; se persistir, fale com a Provvi { "error": "Erro interno ao montar a resposta.", "block_reason": "web_response_serialization_failed" }
503 Indisponibilidade transitória de um serviço interno da Provvi — fail-closed, a captura não foi assinada. Repita com backoff { "error": "Serviço temporariamente indisponível — tente novamente.", "block_reason": "web_nonce_store_unavailable" }
503 Indisponibilidade transitória ao ler a imagem enviada — fail-closed. Repetir o mesmo envio não resolve: recarregue a sessão (open({ token })) e refaça a captura { "error": "Serviço temporariamente indisponível — recarregue a sessão e tente novamente.", "block_reason": "web_raw_store_unavailable" }

Ao receber um 422 de localização, oriente o usuário a permitir a localização e refazer a captura; o nível da verificação de localização é configurado por conta — ver Configuração.

Como isso chega no componente: o SDK entrega qualquer erro deste endpoint como ProvviAPIError com código INGEST_FAILED (4002) e error.details.status igual ao HTTP acima. Mapeie details.status para a ação do usuário. Ver Tratamento de erros e a Referência do SDK.


O resultado da captura chega no evento uploaded do componente: o session_id e, sob a política ALWAYS, a URL do JPEG autenticado com o manifesto C2PA + assinatura ICP-Brasil embutidos. Sob NEVER, o sidecar do manifesto sai por GET /web/session-results/:token. A verificação do manifesto assinado está em Resultados.

A assinatura da captura web é server-side ICP-Brasil A1 sobre os bytes recebidos (assurance_level: "fraud_deterrence") — dissuasão de fraude com identidade legal brasileira. Não há âncora de proveniência de hardware no dispositivo: não é uma cadeia de prova com origem device-side. Para esse nível, use o SDK mobile.


← Integração Web