Guia de integração
Integre a verificação de identidade da YaID
Da criação da conta ao webhook de resultado. Todos os exemplos desta página usam valores fictícios.
Visão geral
A integração tem seis etapas, sempre nesta ordem. As três primeiras acontecem uma vez, no dashboard. As três últimas são o ciclo que sua aplicação repete a cada verificação.
- 01
Criar sua conta
Cadastro da empresa no dashboard, com CNPJ. É o que dá acesso a tudo o que vem depois.
- 02
Criar um app
Cada app é um ponto de integração: tem nome, ambiente e, opcionalmente, uma URL de webhook.
- 03
Guardar a API key
Gerada junto com o app e exibida uma única vez. É o que autentica sua aplicação na YaID.
- 04
Criar a proof request
Seu backend chama o endpoint de verificação com a API key e recebe a sessão do holder.
- 05
Redirecionar o holder
A pessoa abre a URL da sessão, apresenta suas credenciais e decide o que compartilhar.
- 06
Receber o webhook
Com o resultado pronto, a YaID notifica a URL configurada no app e sua aplicação segue o fluxo.
A chamada da etapa 04 é um POST /api/proof-requests autenticado pelo header x-api-key. O contrato completo é detalhado na seção Solicitando uma verificação (Proof Request).
Criando sua conta e seu primeiro app
1. Cadastro da empresa
O cadastro pede quatro dados: E-mail, Senha, Nome da empresa e CNPJ. O e-mail informado vira o login do primeiro usuário, e a empresa criada é a dona de todos os apps — cada app é um ponto de integração distinto, com sua própria API key.
2. Criação do app
A criação do app pede três campos: nome do app, ambiente (homol ou prod) e Webhook HTTPS opcional. Essa URL é o endereço da sua aplicação que a YaID chama automaticamente quando uma verificação é concluída, para entregar o resultado sem que você precise ficar consultando a API (o formato do evento e como validar sua autenticidade estão detalhados na seção Webhooks, adiante).
A criação de apps depende da liberação da sua empresa. Enquanto a flag can_create_apps não estiver habilitada, não é possível criar um novo app e a chamada correspondente responde 403. Fale com o time YaID para liberar o acesso.
3. API key
Ao concluir a criação, a API key é exibida uma única vez, em um modal que só pode ser fechado depois que você confirmar que copiou a chave. Ela não é recuperável: se for perdida, o caminho é criar um novo app. Guarde-a em um gerenciador de segredos — é essa chave que autentica todas as chamadas da sua aplicação à API da YaID, como detalhado na seção Solicitando uma verificação (Proof Request), adiante.
# .env do seu backend — valores fictícios, apenas ilustrativos.
# A chave real aparece uma única vez, no momento da criação do app.
YAID_API_KEY=yaid_sk_xxxxxxxxxxxxxxxxxxxxxxxx
# Toda chamada B2B autentica com o header:
# x-api-key: $YAID_API_KEYAmbientes: Homologação vs Produção
O ambiente é escolhido na criação do app e é imutável no MVP: para trocar, crie outro app. Cada app tem sua própria API key e seu próprio webhook.
Homologação (homol)
- Permite Aprovar ou Reprovar uma verificação manualmente pelo dashboard, sem depender de um holder real.
- A decisão manual dispara o webhook real do app — o mesmo evento, na mesma URL, com o mesmo formato de produção.
- Serve para você exercitar seu handler ponta a ponta antes de subir.
Produção (prod)
- Não expõe as ações manuais. O resultado depende exclusivamente do fluxo real do holder, que apresenta suas credenciais na sessão de verificação.
- O webhook é disparado quando a verificação é concluída pelo holder.
Importante: não há isolamento de dados entre os ambientes. Homologação não é uma sandbox — uma proof request é real nos dois ambientes, fica registrada na mesma base e consome o mesmo fluxo. A diferença está apenas em quem pode decidir o resultado.
Solicitando uma verificação (Proof Request)
A proof request é o pedido de verificação que seu backend cria em POST /api/proof-requests, autenticado pela API key do app. A resposta traz a verificação criada e a sessão do holder, com a URL para onde a pessoa deve ser redirecionada.
Autenticação e requisição
A chamada é autenticada pela API key do app, enviada em Authorization: Bearer. O header x-api-key é aceito como forma equivalente. A chave tem o formato <uuid-do-app>.<segredo> — o app é identificado pela própria chave, então não é preciso mandar appId no corpo.
O corpo tem um campo obrigatório, proofType (personhood ou age_over_18), e um opcional, externalReference: até 255 caracteres do seu lado — id de pedido, de cadastro, do que fizer sentido — devolvido intacto na resposta e no webhook.
# Chamada B2B, feita pelo seu backend. Valores fictícios.
curl -X POST https://<seu-dominio-yaid>/api/proof-requests \
-H "Authorization: Bearer 11111111-1111-4111-8111-111111111111.yaid_sk_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"proofType": "personhood",
"externalReference": "pedido-fake-000123"
}'Resposta
O sucesso é 201 Created. O que interessa para o fluxo está em session: verificationUrl é o link para onde o holder deve ir, deepLinkUrl abre o app da carteira diretamente e expiresAt marca o fim da validade da sessão, hoje 30 minutos após a criação.
HTTP/1.1 201 Created
{
"id": "22222222-2222-4222-8222-222222222222",
"appId": "11111111-1111-4111-8111-111111111111",
"appName": "Checkout Homologação",
"environment": "homol",
"proofType": "personhood",
"status": "pending_user",
"result": null,
"externalReference": "pedido-fake-000123",
"createdAt": "2026-08-28T14:03:11.000Z",
"validatedAt": null,
"session": {
"id": "33333333-3333-4333-8333-333333333333",
"verificationUrl": "https://<seu-dominio-yaid>/v/<token-da-sessao>",
"deepLinkUrl": "yaid://verify?session=<token-da-sessao>",
"expiresAt": "2026-08-28T14:33:11.000Z"
}
}result nasce null e validatedAt também: são preenchidos quando a verificação chega a um estado terminal, não no momento da criação.
Teste manual sem escrever código
Proof requests são criadas exclusivamente pela API — o dashboard não tem um atalho para isso. Para conferir o fluxo antes de integrar, use um cliente HTTP como curl, Postman ou Insomnia com a chamada acima e a API key do seu app: nenhum código precisa ser escrito, e a proof request criada é idêntica à que sua integração vai gerar em produção.
Status da proof request
É o estado que sua aplicação acompanha. Aparece em status na resposta e no webhook.
- pending_user
- Estado inicial, logo após o 201. A sessão existe e ninguém abriu a URL ainda.
- processing
- O holder abriu a sessão de verificação e o desafio criptográfico está em curso.
- approved
- A apresentação foi verificada com sucesso — ou aprovada manualmente em homologação. Estado terminal.
- rejected
- A verificação não passou: o holder cancelou a sessão ou houve reprovação manual em homologação. Estado terminal.
- expired
- A sessão passou de expiresAt sem conclusão. Estado terminal.
Estado da sessão do holder
É um ciclo separado, do lado da pessoa que apresenta as credenciais. Sua aplicação não precisa consumi-lo, mas ele explica por que a proof request muda de estado. São dois conjuntos distintos de nomes — não os misture.
- waiting_user
- Sessão criada e ainda não aberta. Corresponde à proof request em pending_user.
- opened
- O holder abriu a URL e recebeu o desafio. É a transição que leva a proof request para processing.
- approved_by_user
- O holder apresentou as credenciais e aprovou o compartilhamento. Leva a proof request para approved.
- cancelled
- O holder desistiu da sessão. Leva a proof request para rejected.
- expired
- A sessão passou do prazo de 30 minutos definido em expiresAt.
Webhooks
Se o app tiver uma URL HTTPS configurada, a YaID notifica sua aplicação quando a verificação é concluída. É o sinal para liberar o cadastro, o pedido ou o acesso do lado de vocês, sem precisar ficar consultando a API.
O evento entregue
A YaID faz um POST na URL configurada no app, com Content-Type: application/json e mais dois headers: X-YaID-Signature, com a assinatura Ed25519 em base64, e X-YaID-Timestamp, o momento da assinatura em segundos Unix.
POST https://sua-aplicacao.exemplo.com/webhooks/yaid
Content-Type: application/json
X-YaID-Signature: <assinatura-ed25519-em-base64>
X-YaID-Timestamp: 1788012764
{
"proofRequestId": "22222222-2222-4222-8222-222222222222",
"status": "approved",
"proofType": "personhood",
"updatedAt": "2026-08-28T14:12:44.000Z",
"externalReference": "pedido-fake-000123"
}proofRequestId é o id devolvido na criação, updatedAt é o instante ISO 8601 da transição e externalReference só aparece se você tiver enviado um — quando está ausente, a chave é omitida do JSON, não vem como null.
A chave pública de verificação
GET /api/webhook-public-key é público e devolve a chave usada para assinar, em base64, junto com o algoritmo. Busque uma vez e guarde em configuração; não é preciso consultar a cada evento.
GET /api/webhook-public-key
{
"publicKey": "<32-bytes-da-chave-publica-em-base64>",
"algorithm": "Ed25519"
}Verificando a assinatura
A mensagem assinada são os bytes UTF-8 do corpo exatamente como ele chegou. Configure seu framework para expor o corpo bruto: se você deixar um parser JSON transformar e reserializar o payload, a assinatura deixa de bater mesmo sendo legítima.
import * as ed from "@noble/ed25519";
// A assinatura cobre exatamente os bytes UTF-8 do corpo que chegou.
// Leia o corpo bruto e verifique antes de JSON.parse: reserializar o
// objeto muda espaços e ordem de chaves e invalida a assinatura.
// YAID_PUBLIC_KEY é o campo publicKey de GET /api/webhook-public-key,
// buscado uma vez e guardado na configuração da sua aplicação.
export async function handleYaidWebhook(rawBody, headers) {
const signature = Buffer.from(headers["x-yaid-signature"], "base64");
const publicKey = Buffer.from(YAID_PUBLIC_KEY, "base64");
const message = Buffer.from(rawBody, "utf8");
const authentic = await ed.verifyAsync(signature, message, publicKey);
if (!authentic) {
return new Response("invalid signature", { status: 401 });
}
const event = JSON.parse(rawBody);
// O payload não inclui um campo valid: derive o booleano do status.
const approved = event.status === "approved";
await liberarPedido(event.externalReference, approved);
return new Response("ok", { status: 200 });
}Sobre o timestamp: X-YaID-Timestamp serve para observabilidade e para você descartar eventos muito antigos se quiser, mas ele não faz parte da mensagem assinada. Ou seja: a assinatura prova a origem e a integridade do corpo, não a atualidade do envio. Se replay for uma preocupação no seu domínio, trate a idempotência por proofRequestId do seu lado.
Quando dispara, e o que fazer se falhar
- O evento é enviado nas transições terminais da proof request: approved, rejected e expired. Não há evento para pending_user nem processing.
- A entrega é uma tentativa só, com timeout de 10 segundos. Não há retentativa automática: se sua aplicação estiver fora do ar ou responder um erro, a falha é registrada nos logs da YaID e o evento não é reenviado.
- Por isso, trate o handler como caminho rápido: responda 2xx assim que validar a assinatura e processe o resto de forma assíncrona.
- Se um evento se perder, o estado continua consultável no dashboard, na tela de detalhe da proof request. Vale acompanhar as verificações que ficaram sem desfecho no seu lado.
O que o webhook não carrega
O evento não transporta credencial verificável (VC), apresentação verificável (VP), DID do holder, nonce nem dados pessoais. Os cinco campos do payload são tudo o que sai da YaID: identificador, estado, tipo de prova, horário e a sua própria referência. O resultado é comunicado pelo status; se você precisa de um booleano, derive-o com status === "approved". Não existe um campo valid no payload — não escreva um handler que dependa dele.