# Anti-abuse & code security · How Bird Verify protects codes

**✦ Verification flow •••**

Your account

Confirm it’s you.

Enter the code sent to

Example verification code

Code verified

Send a code. Confirm the recipient.

## Security that's on by default, not an add-on.

Every verification on the [Bird Verify API](/verify-api) carries the same protections: the code is generated server-side, never returned, and stored only as a hash; checks run in constant time and against a bounded attempt budget; and sends are capped per recipient and per workspace. You don't opt in or wire these up: they're how the API behaves, whether you run it as [two-factor login](/verify-api/features/2fa) or [passwordless sign-in](/verify-api/features/passwordless).

## Five protections on every verification.

No setup step, no add-on SKU.

- **01** Cryptographic generation. Codes are drawn from a cryptographic random source, uniform across the code space, not a predictable counter or timestamp.
- **02** Hashed at rest, never on the wire out. Only an HMAC-SHA256 of each code is stored; the plaintext is never returned by the API and never written to your stack or our logs.
- **03** Constant-time comparison. Submitted codes are compared in constant time, so an attacker learns nothing from how long a check takes.
- **04** Attempt lockout. Each session has a bounded number of checks (5 by default). Once they're spent the session fails, so guessing can't run forever.
- **05** Send caps. A per-recipient send cap and a resend cooldown bound the spend and the abuse surface, each a 429 with Retry-After.

## Guessing runs out before your users do.

A wrong code comes back with the attempts remaining, and the session fails once the budget is spent, so a brute-force loop hits a wall long before it finds the code.

**lockout.ts**

```typescript
const { data, error } = await bird.verify.verifications.check({
  to:   { phone_number: "+15551234567" },
  code: guess,
}).safe();
if (error) throw error;

// wrong code, attempts left → { success: false, reason: "incorrect_code", attempts_remaining: 2 }
// budget spent, session done → { success: false, reason: "attempts_exhausted", attempts_remaining: null }
```

## Coming next: fraud signals and SMS-pumping protection.

The per-send history Verify records today is the groundwork for a fraud layer we're building now. It rides the same create and check calls, so adopting it later is a config change, not a re-integration.

Risk signals on create. Pass device, IP, and request context on a verification, and high-risk attempts get a blocked outcome before a code is ever sent, so you're not paying to message an attacker.

SMS-pumping and AIT protection. Per-country and per-prefix send caps plus a per-workspace spend ceiling shut down the artificially-inflated-traffic attack that drives OTPs to premium number ranges for carrier revenue share.

Built on what's already there. Risk decisioning reads the attempt history Verify keeps from day one, and the blocked outcome is already part of the status model, so the fraud layer lands without reshaping your integration.

## The rest of the Verify platform

One API, one set of keys. Explore the other capabilities.

- [SMS OTP](/verify-api/features/sms): One-time passcodes over SMS, with global reach and built-in rate limits.
- [Email OTP](/verify-api/features/email): Verify by email on the network that already carries your transactional mail.
- [WhatsApp OTP](/verify-api/features/whatsapp): Codes on WhatsApp as an orderable channel in the same plan.
- [Voice OTP](/verify-api/features/voice): Rolling out: a spoken code for landlines and hard-to-reach users.
- [Channel orchestration](/verify-api/features/orchestration): Per-country channel order and senders, resolved automatically and tunable per request.
- [Verify API overview](/verify-api): The full Verify API: create-or-retry, check by target, and advance to the next channel.

## Scale without  losing control.

Organize teams in workspaces, control API access, and trace changes through audit logs.

Harbor Organization
Workspaces Production Sandbox

### Delivery agent

API key · Customer operations team
Active
Permissions Access
Email Read & write
SMS Read & write
WhatsApp Read Read & write
AL Alex Lee Admin  Permissions updated

### Audit log

Production
 API key updated Alex Lee · 09:42:18 UTC

Workspace
Production

Resource
Delivery agent

WhatsApp
Read Read & write

Succeeded

 [Workspaces](/docs/guides/workspaces)[Team roles](/docs/guides/users-teams-roles)[API authentication](/docs/guides/authentication)
[Explore Enterprise](/enterprise)

## Start with Verify. Build across channels with Bird.

[Get started](/dashboard/signup?returnTo=%2Fdashboard%2Fw%2Fverify) · [Contact Sales](/demo?product=verify)

[Email](/email-api) · [SMS](/sms-api) · [WhatsApp](/whatsapp-api) · [Apple Messages](/apple-messages-api) · [Voice](/voice-api)



## Related resources

- [Verify phone numbers at signup](/learn/series/verify-phone-numbers-at-signup) (video)
- [Verify your first customer](/docs/get-started/verify-your-first-customer) (docs)
- [What does OTP mean? One-time passwords explained](/explained/verify/what-does-otp-mean) (answer)
- [Build your first integration](/learn/paths/integration) (course)

[Get an implementation brief](/learn/workspace?topic=verify)
