Enviando verificações
Verificar um usuário exige duas chamadas. POST /v1/verify/verifications envia um código de verificação para um endereço de e-mail ou número de telefone. POST /v1/verify/verifications/check submete o valor que o usuário digitou e informa se houve correspondência. Bird gera o código, não o retorna em uma resposta API e aplica os limites de expiração e tentativas.
Enviar um código
A menor solicitação válida é um destinatário to:
const verification = await bird.verify.verifications.create({
to: { phone_number: "+15551234567" },
});
console.log(verification.id, verification.status);verification = client.verify.verifications.create(to={"phone_number": "+15551234567"})
print(verification.id, verification.status)verification, err := client.Verify.Verifications.Create(context.Background(), bird.VerifyVerificationsCreateParams{
To: bird.VerificationTo{PhoneNumber: bird.String("+15551234567")},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(verification.Id, *verification.Status)$verification = $bird->verify->verifications->create(
(new VerificationCreateRequest())->setTo((new VerificationTo())->setPhoneNumber('+15551234567')),
);
echo $verification->getId(), ' ', $verification->getStatus();bird verify verifications create --body-file - <<'JSON'
{
"to": {
"phone_number": "+15551234567"
},
"metadata": {
"correlation_id": "signup-7f3a"
}
}
JSONcurl -X POST https://us1.platform.bird.com/v1/verify/verifications \
-H "Authorization: Bearer bk_us1_..." \
-H "Content-Type: application/json" \
-d '{
"to": { "phone_number": "+15551234567" }
}'Use seu host regional (https://us1.platform.bird.com ou https://eu1.platform.bird.com) com uma chave bk_{region}_... correspondente.
Destinatário
to identifica o destinatário com um email, um phone_number no formato E.164, ou ambos. Um endereço de e-mail habilita a entrega por e-mail. Um número de telefone resolve para os canais disponíveis no país de destino, na ordem definida pela configuração de país. A maioria dos países tenta WhatsApp antes de SMS, enquanto alguns tentam SMS primeiro; o Telegram segue ambos na ordem de fallback da plataforma. Quando você fornece os dois endereços, uma tentativa que falhou pode avançar para outro canal disponível.
Opções
options sobrepõe configurações apenas para esta solicitação:
code_length: comprimento do código de verificação para esta verificação, 4 a 8 dígitos, sobrepondo o padrão.channels: reordena ou restringe os canais de entrega para esta solicitação. Liste os nomes dos canais (sms,whatsapp,email,telegram) na ordem em que devem ser tentados; um canal omitido não é usado, e um nome que não faz parte do plano resolvido do destinatário é ignorado. Você não pode adicionar um canal dessa forma, apenas reduzir ou reordenar o que o destinatário e a configuração de país já permitem, e uma lista que não deixe nenhum canal utilizável faz a solicitação falhar com422.language: uma tag BCP 47 comofroupt-BRque escolhe qual tradução integrada a mensagem com o código usa. Omita-a e o idioma segue o número de telefone do destinatário; veja Idioma da mensagem.
Metadados
metadata é um objeto de formato livre retornado em toda leitura; use-o para carregar seu próprio ID de usuário ou referência de sessão. As escolhas de remetente e as configurações de verificação não vão na solicitação: elas vêm da configuração do seu espaço de trabalho, gerenciada no painel (veja Configurações de verificação).
A resposta
{
"id": "vrf_01ky7q1fdze3695yvyz7z9nm3a",
"status": "pending",
"reason": null,
"to": { "phone_number": "+15551234567" },
"channels": [{ "channel": "whatsapp" }, { "channel": "sms" }],
"last_channel": "whatsapp",
"expires_at": "2026-07-23T14:55:58Z",
"verified_at": null,
"created_at": "2026-07-23T14:45:58Z",
"updated_at": "2026-07-23T14:45:58Z"
}channels é o plano de entrega ordenado para o qual esta verificação resolveu (um destinatário telefônico lista seus canais de telefone na ordem de tentativa), e last_channel é para onde o código mais recente foi enviado. expires_at é quando a verificação expira se nenhum código correto chegar; reenvios não estendem esse prazo.
Idioma da mensagem
As mensagens de SMS, e-mail e WhatsApp compartilhado do Bird são enviadas com 40 traduções integradas. Um remetente WhatsApp personalizado usa os idiomas aprovados do template de autenticação selecionado. O Telegram escreve a própria mensagem, então a configuração não tem efeito nesse canal.
Sem options.language, o idioma vem do número de telefone do destinatário. Um número francês recebe francês e um número japonês recebe japonês, sem que você precise pedir. Uma verificação sem número de telefone envia em inglês, assim como uma cujo país não tem tradução.
Defina options.language para escolher você mesmo, por exemplo para usar o idioma que o usuário selecionou no seu aplicativo em vez do país do número dele:
{
"to": { "phone_number": "+15551234567" },
"options": { "language": "es" }
}Uma tag sem tradução integrada própria recorre ao idioma base e, depois, ao inglês: en-GB envia em inglês, pt-BR envia em português. Apenas uma tag malformada é rejeitada, com 422. Estas são as traduções integradas disponíveis, todas em SMS e e-mail, e todas exceto mongol no remetente WhatsApp compartilhado do Bird:
| Idioma | Tag |
|---|---|
| Árabe | ar |
| Búlgaro | bg |
| Chinês (simplificado) | zh |
| Chinês (tradicional) | zh-TW |
| Croata | hr |
| Tcheco | cs |
| Dinamarquês | da |
| Holandês | nl |
| Inglês | en |
| Finlandês | fi |
| Francês | fr |
| Alemão | de |
| Grego | el |
| Hebraico | he |
| Hindi | hi |
| Húngaro | hu |
| Indonésio | id |
| Italiano | it |
| Japonês | ja |
| Coreano | ko |
| Letão | lv |
| Lituano | lt |
| Macedônio | mk |
| Malaio | ms |
| Mongol | mn |
| Norueguês | no |
| Norueguês Bokmål | nb-NO |
| Polonês | pl |
| Português | pt |
| Romeno | ro |
| Russo | ru |
| Sérvio | sr |
| Eslovaco | sk |
| Esloveno | sl |
| Espanhol | es |
| Sueco | sv |
| Tailandês | th |
| Turco | tr |
| Ucraniano | uk |
| Vietnamita | vi |
A referência de criação de verificação é a lista oficial.
O idioma é fixado quando a verificação é criada, então um reenvio ou uma troca para outro canal chega no mesmo idioma da primeira mensagem. Chamar create novamente para o mesmo destinatário com um language diferente reutiliza a verificação em andamento e não a altera.
A tradução usada no envio pode diferir da tag que você enviou quando houve fallback. Abra a verificação na página Verificações para confirmar: cada tentativa mostra o idioma renderizado como uma tag Template. O remetente WhatsApp compartilhado do Bird não tem template de mongol (mn), então envia em inglês para esse idioma, enquanto SMS e e-mail mantêm o mongol. Seu próprio template WhatsApp segue os idiomas aprovados e a política de idioma; um idioma que ele não consegue enviar pode fazer a tentativa WhatsApp falhar.
Você pode selecionar um idioma por solicitação, mas não pode enviar o texto da mensagem nessa solicitação. Um remetente WhatsApp personalizado usa o texto do template de autenticação selecionado. Remetentes e identidade visual mostra as opções de remetente e o texto da mensagem do Bird.
Verificar o código
Envie o que o usuário digitou para POST /v1/verify/verifications/check, usando o mesmo destinatário; não é necessário ID de verificação. Forneça exatamente o conjunto de to com que você criou a verificação: uma criada com ambos os endereços não é encontrada por nenhum dos endereços isoladamente.
const result = await bird.verify.verifications.check({
to: { phone_number: "+15551234567" },
code: "123456",
});
console.log(result.success);result = client.verify.verifications.check(
to={"phone_number": "+15551234567"}, code="123456"
)
print(result.success)result, err := client.Verify.Verifications.Check(context.Background(), bird.VerifyVerificationsCheckParams{
To: bird.VerificationTo{PhoneNumber: bird.String("+15551234567")},
Code: "123456",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(*result.Success)$result = $bird->verify->verifications->check(
(new VerificationCheckRequest())
->setTo((new VerificationTo())->setPhoneNumber('+15551234567'))
->setCode('123456'),
);
echo $result->getSuccess() ? 'verified' : 'failed';bird verify verifications check 123456 --phone-number +15551234567curl -X POST https://us1.platform.bird.com/v1/verify/verifications/check \
-H "Authorization: Bearer bk_us1_..." \
-H "Content-Type: application/json" \
-d '{
"to": { "phone_number": "+15551234567" },
"code": "123456"
}'A resposta indica se houve correspondência:
{
"success": false,
"reason": "incorrect_code",
"attempts_remaining": 4,
"verification": {
"id": "vrf_01ky7q1fdze3695yvyz7z9nm3a",
"status": "pending",
"reason": null,
"to": { "phone_number": "+15551234567" },
"channels": [{ "channel": "whatsapp" }, { "channel": "sms" }],
"last_channel": "whatsapp",
"expires_at": "2026-07-23T14:55:58Z",
"verified_at": null,
"created_at": "2026-07-23T14:45:58Z",
"updated_at": "2026-07-23T14:46:38Z"
}
}Trate estes dois comportamentos de resposta:
- Um código errado retorna
200. Tratesuccess: falsecom umreason(incorrect_code,expired,attempts_exhausted) como uma resposta normal.attempts_remaininginforma quantas tentativas restam. Reserve o tratamento de erros para falhas na solicitação. - Uma verificação final não pode ser checada novamente. Depois que uma verificação atinge qualquer estado final, novas checagens retornam
404. Armazene o primeiro resultado definitivo em vez de checar novamente.
Se o usuário pediu um novo código, chame o endpoint de criação novamente com o mesmo destinatário: a verificação em andamento é reutilizada em vez de substituída. Quando o intervalo de reenvio expirar (60 segundos por padrão), um novo código é enviado; dentro do intervalo, a chamada retorna a verificação ativa sem enviar novamente. Todo código enviado para a verificação ativa permanece válido até que ela seja resolvida ou expire, então o usuário pode digitar qualquer um que tenha chegado.
Enviar o código por outro canal
Quando o usuário informa que nenhum código chegou, POST /v1/verify/verifications/next-channel avança a verificação para o próximo canal no plano e envia um novo código por lá. Este é o endpoint por trás de um botão "I didn't receive my code": seu aplicativo decide trocar de canal em vez de esperar um sinal de status de entrega.
Use o mesmo destinatário com que você criou a verificação, assim como na checagem:
const verification = await bird.verify.verifications.nextChannel({
to: { phone_number: "+15551234567" },
});
console.log(verification.last_channel);verification = client.verify.verifications.next_channel(
to={"phone_number": "+15551234567"}
)
print(verification.last_channel)verification, err := client.Verify.Verifications.NextChannel(context.Background(), bird.VerifyVerificationsNextChannelParams{
To: bird.VerificationTo{PhoneNumber: bird.String("+15551234567")},
})
if err != nil {
log.Fatal(err)
}
if verification.LastChannel != nil {
fmt.Println(*verification.LastChannel)
}$verification = $bird->verify->verifications->nextChannel(
(new VerificationNextChannelRequest())->setTo((new VerificationTo())->setPhoneNumber('+15551234567')),
);
echo $verification->getLastChannel();bird verify verifications next-channel --phone-number +15551234567curl -X POST "https://{region}.platform.bird.com/v1/verify/verifications/next-channel" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": {
"phone_number": "+15551234567"
}
}'A resposta é a verificação, com last_channel indicando o canal para o qual o novo código foi enviado. Todo código já enviado permanece válido, então uma mensagem que chegue atrasada ainda pode ser checada.
Duas coisas diferenciam isso de um reenvio:
- O intervalo de reenvio não se aplica. Uma troca deliberada de canal é um ato diferente de pedir o mesmo canal novamente, então o envio sai imediatamente.
- Apenas o canal avança. A expiração, o limite de tentativas e o ID da verificação permanecem como estavam.
Use um reenvio quando o usuário quer outra tentativa em um canal que funciona, e este endpoint quando o próprio canal parece ser o problema. Um número de telefone cujo plano é WhatsApp e depois SMS avança para SMS; um destinatário com apenas um canal utilizável não tem para onde ir.
Quatro respostas precisam de tratamento em vez de uma simples nova tentativa:
| Status | O que aconteceu | O que fazer |
|---|---|---|
404 | Não há verificação em andamento para esse destinatário | Crie uma |
422 NoNextChannel | O plano não tem mais nenhum canal para avançar | Reenvie no canal atual chamando create novamente |
422 NoAvailableChannel | Todos os canais restantes falharam ao enviar | Mostre a falha ao usuário; a verificação não pode ser entregue |
429 | Envios para a conta estão sendo solicitados rápido demais | Aguarde o período indicado no header Retry-After |
Cada código enviado por este endpoint é cobrado como qualquer outro envio do Verify; veja Custo e cobrança.
Status
Uma verificação fica pending até ser resolvida em um estado final, com reason indicando o motivo:
| Status | Significado | Razão |
|---|---|---|
verified | Um código correto chegou a tempo | nenhuma |
failed | Tentativas incorretas demais, ou o plano de entrega terminou com falhas indicando que nenhum código de verificação foi enviado | attempts_exhausted, undeliverable |
expired | A janela expirou antes de um código correto | ttl_elapsed |
reason é um enum aberto. Preserve um valor não reconhecido em vez de tratar a resposta como inválida.
Um bounce, rejeição da operadora ou timeout de entrega pode deixar a sessão pendente porque o destinatário ainda pode ter um código válido. O esgotamento do plano de entrega por si só não significa que a sessão falhou. Consulte Eventos do Verify para as condições de falha.
Acompanhe verificações no dashboard
A página Verifications lista todas as verificações que o espaço de trabalho criou, filtrável por status. Cada linha abre o destinatário, plano de canais, último canal, horários de expiração e verificação, e metadados. O código gerado não é exibido.

Configurações de verificação
A página Configure define o ciclo de verificação do espaço de trabalho. Cada campo mostra o valor efetivo: sua substituição onde você definiu uma, caso contrário o padrão de plataforma do Bird.
- Duration: por quanto tempo um código permanece válido. Padrão 10 minutos; 1 minuto a 999 minutos.
- Maximum Retries: quantas tentativas de verificação antes que a verificação falhe com
attempts_exhausted. Padrão 5; 1 a 10. - Retry Delay: o intervalo de espera antes que um novo código possa ser enviado ao mesmo destinatário. Padrão 60 segundos; 0 a 3.600.

O tamanho do código não é um campo nesta página: os códigos têm 6 dígitos numéricos por padrão, e options.code_length define de 4 a 8 dígitos por solicitação.
Proteções contra abuso
Independentemente das suas configurações, o Verify impõe limites de plataforma para impedir que o tráfego de OTP seja explorado, seja contra a sua carteira (bombeamento de SMS) ou contra a caixa de entrada de uma vítima:
- 5 envios por endereço por hora corrida, entre iniciar e reenviar verificações. Quando
tocontém ambos os endereços, cada um tem seu próprio orçamento. - 10 verificações por conjunto de endereços do destinatário por minuto, além do limite de tentativas da verificação.
O plano de canais, e não o limite por hora, delimita as trocas de canal. Cada chamada avança estritamente para frente, então uma verificação envia no máximo uma vez por canal restante.
Atingir um limite retorna 429; aguarde e tente novamente após o período no cabeçalho Retry-After. Os limites gerais de solicitação da sua conta são separados e proporcionais ao plano; consulte Limites de requisições.
Tentando novamente com segurança
Os três endpoints aceitam o cabeçalho Idempotency-Key. Envie um valor único por solicitação lógica. Após um timeout ou conexão perdida, tentar novamente com a mesma chave reproduz a resposta original. Uma reprodução não envia outro código nem consome outra tentativa de verificação, e inclui um cabeçalho Idempotency-Replay. Consulte idempotência para formato e retenção da chave.
Custo e cobrança
A cobrança se aplica a cada código enviado. Cada código enviado é debitado da sua carteira pela tarifa do canal para o destino. Um reenvio ou fallback para outro canal adiciona uma cobrança por envio. A taxa própria do Bird é cobrada enquanto o envio é processado e vale independentemente de o código chegar; no SMS e no WhatsApp uma taxa de terceiros vem em seguida quando a mensagem é entregue. Rotas gratuitas e verificações não custam nada; um envio rejeitado antes da cobrança não é cobrado. Métodos de pagamento e carteira cobre saldo e recargas.
O Telegram cobra em um ponto diferente do envio. Antes de uma mensagem sair, o Telegram é consultado sobre se o número pode recebê-la; a cobrança é vinculada quando a resposta é sim, a uma tarifa fixa mundial, e um número que não pode ser alcançado é gratuito e avança para o próximo canal sem cobrança. Portanto, uma cobrança do Telegram significa que a mensagem foi aceita para entrega, não que chegou: um código que depois não é entregue continua cobrado, e a verificação paga novamente pelo canal para o qual cai. Quando você não quer essa segunda cobrança, remova o Telegram da ordem de canais para esses países na página Countries.
Próximos passos
| Página | O que cobre |
|---|---|
| Remetentes e identidade visual | Como são as mensagens de código e como enviar a partir do seu próprio domínio |
| Configuração por país | Ordem de canais por país, habilitação e substituições de remetente |
| Eventos | O ciclo de vida da verificação e os eventos de entrega, e seus payloads de webhook |
| Idempotência | Tentativas seguras com o cabeçalho Idempotency-Key |
| Referência API: criar uma verificação | Schema e detalhes de erro do endpoint de envio |
| Referência API: verificar um código | Schema e detalhes de erro do endpoint de verificação |
| Referência API: avançar para o próximo canal | Schema e detalhes de erro do próximo canal |
Recursos relacionados
Continue com a documentação, guias e exemplos sobre este tópico.