> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Verify Integration Examples

> Complete integration examples for login, registration, and payment verification flows using Telnyx Verify.

Real-world integration examples showing how to use Telnyx Verify in common application flows. Each example includes complete server-side code, error handling, and frontend UX guidance.

## Login verification

Add phone-based 2FA to your login flow. After the user enters their password, send a verification code to their registered phone number before granting access.

### Sequence diagram

```mermaid theme={null}
sequenceDiagram
    participant U as User
    participant F as Frontend
    participant S as Server
    participant T as Telnyx Verify

    U->>F: Enter email + password
    F->>S: POST /login
    S->>S: Validate credentials
    S->>T: POST /v2/verifications/sms
    T-->>S: verification_id (pending)
    S-->>F: 200 { requires_2fa: true }
    F->>U: Show code input
    U->>F: Enter verification code
    F->>S: POST /login/verify
    S->>T: POST /v2/verifications/by_phone_number/.../verify
    T-->>S: { response_code: "accepted" }
    S->>S: Create session
    S-->>F: 200 { token: "..." }
```

### Server implementation

<Tabs>
  <Tab title="Node.js (Express)">
    ```javascript theme={null}
    import express from 'express';
    import Telnyx from 'telnyx';
    import jwt from 'jsonwebtoken';

    const app = express();
    app.use(express.json());

    const telnyx = new Telnyx({ apiKey: process.env.TELNYX_API_KEY });
    const VERIFY_PROFILE_ID = process.env.TELNYX_VERIFY_PROFILE_ID;
    const JWT_SECRET = process.env.JWT_SECRET;

    // Step 1: User submits credentials
    app.post('/login', async (req, res) => {
      const { email, password } = req.body;

      // Validate credentials against your database
      const user = await db.users.findByEmail(email);
      if (!user || !await bcrypt.compare(password, user.password_hash)) {
        return res.status(401).json({ error: 'Invalid credentials' });
      }

      // Check if user has 2FA enabled
      if (!user.phone_number) {
        // No 2FA — issue token directly
        const token = jwt.sign({ userId: user.id }, JWT_SECRET, { expiresIn: '24h' });
        return res.json({ token });
      }

      try {
        // Send verification code
        const verification = await telnyx.verifications.sms({
          phone_number: user.phone_number,
          verify_profile_id: VERIFY_PROFILE_ID,
        });

        // Store pending verification in session
        req.session.pendingLogin = {
          userId: user.id,
          phoneNumber: user.phone_number,
          verificationId: verification.data.id,
          expiresAt: Date.now() + 300_000, // 5 minutes
        };

        // Mask phone number for display
        const masked = user.phone_number.replace(/(\+\d{1})\d{6}(\d{4})/, '$1******$2');

        res.json({
          requires_2fa: true,
          phone_hint: masked, // "+1******3456"
          timeout_secs: 300,
        });
      } catch (error) {
        console.error('Verification send failed:', error);
        res.status(500).json({ error: 'Failed to send verification code' });
      }
    });

    // Step 2: User submits verification code
    app.post('/login/verify', async (req, res) => {
      const { code } = req.body;
      const pending = req.session.pendingLogin;

      if (!pending) {
        return res.status(400).json({ error: 'No pending verification. Start login again.' });
      }

      if (Date.now() > pending.expiresAt) {
        delete req.session.pendingLogin;
        return res.status(410).json({ error: 'Verification expired. Start login again.' });
      }

      try {
        const result = await telnyx.verifications.verify(pending.phoneNumber, {
          code,
          verify_profile_id: VERIFY_PROFILE_ID,
        });

        if (result.data.response_code === 'accepted') {
          delete req.session.pendingLogin;
          const token = jwt.sign({ userId: pending.userId }, JWT_SECRET, { expiresIn: '24h' });
          return res.json({ token });
        }

        res.status(401).json({
          error: 'Invalid code',
          response_code: result.data.response_code,
        });
      } catch (error) {
        console.error('Verification check failed:', error);
        res.status(500).json({ error: 'Verification failed' });
      }
    });

    // Resend code
    app.post('/login/resend', async (req, res) => {
      const pending = req.session.pendingLogin;

      if (!pending) {
        return res.status(400).json({ error: 'No pending verification' });
      }

      try {
        const verification = await telnyx.verifications.sms({
          phone_number: pending.phoneNumber,
          verify_profile_id: VERIFY_PROFILE_ID,
        });

        pending.verificationId = verification.data.id;
        pending.expiresAt = Date.now() + 300_000;

        res.json({ message: 'Code resent', timeout_secs: 300 });
      } catch (error) {
        res.status(500).json({ error: 'Failed to resend code' });
      }
    });

    app.listen(3000);
    ```
  </Tab>

  <Tab title="Python (Flask)">
    ```python theme={null}
    import os
    import time
    import jwt
    from flask import Flask, request, jsonify, session
    from telnyx import Telnyx

    app = Flask(__name__)
    app.secret_key = os.environ["FLASK_SECRET_KEY"]

    telnyx_client = Telnyx(api_key=os.environ["TELNYX_API_KEY"])
    VERIFY_PROFILE_ID = os.environ["TELNYX_VERIFY_PROFILE_ID"]
    JWT_SECRET = os.environ["JWT_SECRET"]


    @app.route("/login", methods=["POST"])
    def login():
        data = request.json
        email, password = data["email"], data["password"]

        # Validate credentials
        user = db.users.find_by_email(email)
        if not user or not bcrypt.check_password(password, user.password_hash):
            return jsonify({"error": "Invalid credentials"}), 401

        if not user.phone_number:
            token = jwt.encode({"user_id": user.id}, JWT_SECRET, algorithm="HS256")
            return jsonify({"token": token})

        try:
            verification = telnyx_client.verifications.sms(
                phone_number=user.phone_number,
                verify_profile_id=VERIFY_PROFILE_ID,
            )

            session["pending_login"] = {
                "user_id": user.id,
                "phone_number": user.phone_number,
                "verification_id": verification.data.id,
                "expires_at": time.time() + 300,
            }

            masked = user.phone_number[:2] + "******" + user.phone_number[-4:]

            return jsonify({
                "requires_2fa": True,
                "phone_hint": masked,
                "timeout_secs": 300,
            })
        except Exception as e:
            return jsonify({"error": "Failed to send verification code"}), 500


    @app.route("/login/verify", methods=["POST"])
    def login_verify():
        code = request.json["code"]
        pending = session.get("pending_login")

        if not pending:
            return jsonify({"error": "No pending verification"}), 400

        if time.time() > pending["expires_at"]:
            session.pop("pending_login", None)
            return jsonify({"error": "Verification expired"}), 410

        try:
            result = telnyx_client.verifications.verify(
                phone_number=pending["phone_number"],
                code=code,
                verify_profile_id=VERIFY_PROFILE_ID,
            )

            if result.data.response_code == "accepted":
                session.pop("pending_login", None)
                token = jwt.encode({"user_id": pending["user_id"]}, JWT_SECRET, algorithm="HS256")
                return jsonify({"token": token})

            return jsonify({
                "error": "Invalid code",
                "response_code": result.data.response_code,
            }), 401
        except Exception as e:
            return jsonify({"error": "Verification failed"}), 500


    if __name__ == "__main__":
        app.run(port=3000)
    ```
  </Tab>
</Tabs>

### Frontend UX guidance

<AccordionGroup>
  <Accordion title="Code input design">
    * Use a **single input field** or **separate digit boxes** (4–6 boxes depending on code length)
    * **Auto-focus** the input when the 2FA screen appears
    * **Auto-submit** when the full code length is entered (no submit button needed)
    * Accept **numeric input only** — set `inputmode="numeric"` and `pattern="[0-9]*"`
    * Enable **paste support** for users copying from SMS notifications
  </Accordion>

  <Accordion title="Countdown timer">
    * Show a **countdown timer** (e.g., "Code expires in 4:32")
    * Disable the **Resend** button for 30 seconds after sending to prevent rapid resends
    * After timeout, show a clear "Code expired" message with a **Resend** button
  </Accordion>

  <Accordion title="Error states">
    * **Wrong code**: "Invalid code. X attempts remaining." Keep the input active for retry.
    * **Expired code**: "Code expired. Click Resend to get a new code."
    * **Max attempts**: "Too many attempts. Please start the login process again."
    * **Network error**: "Could not verify. Check your connection and try again."
  </Accordion>
</AccordionGroup>

***

## Registration verification

Verify phone number ownership during account creation. This confirms the user has access to the phone number before your application creates the account.

### Sequence diagram

```mermaid theme={null}
sequenceDiagram
    participant U as User
    participant F as Frontend
    participant S as Server
    participant T as Telnyx Verify

    U->>F: Fill registration form
    F->>S: POST /register/start
    S->>S: Validate input, check duplicates
    S->>T: POST /v2/verifications/sms
    T-->>S: verification_id (pending)
    S-->>F: 200 { verification_sent: true }
    F->>U: Show code input
    U->>F: Enter verification code
    F->>S: POST /register/verify
    S->>T: POST /v2/verifications/by_phone_number/.../verify
    T-->>S: { response_code: "accepted" }
    S->>S: Create account
    S-->>F: 201 { user_id, token }
```

### Server implementation

<Tabs>
  <Tab title="Node.js (Express)">
    ```javascript theme={null}
    import express from 'express';
    import Telnyx from 'telnyx';

    const app = express();
    app.use(express.json());

    const telnyx = new Telnyx({ apiKey: process.env.TELNYX_API_KEY });
    const VERIFY_PROFILE_ID = process.env.TELNYX_VERIFY_PROFILE_ID;

    // Step 1: Start registration — validate and send code
    app.post('/register/start', async (req, res) => {
      const { name, email, phone_number, password } = req.body;

      // Validate input
      if (!name || !email || !phone_number || !password) {
        return res.status(400).json({ error: 'All fields required' });
      }

      // Check for existing account
      const existing = await db.users.findByEmailOrPhone(email, phone_number);
      if (existing) {
        return res.status(409).json({
          error: existing.email === email
            ? 'Email already registered'
            : 'Phone number already registered'
        });
      }

      try {
        // Send verification code
        const verification = await telnyx.verifications.sms({
          phone_number,
          verify_profile_id: VERIFY_PROFILE_ID,
        });

        // Store pending registration (use Redis/DB in production)
        req.session.pendingRegistration = {
          name,
          email,
          phone_number,
          password_hash: await bcrypt.hash(password, 12),
          verificationId: verification.data.id,
          expiresAt: Date.now() + 600_000, // 10 minutes
        };

        res.json({ verification_sent: true, timeout_secs: 600 });
      } catch (error) {
        console.error('Verification failed:', error);
        res.status(500).json({ error: 'Failed to send verification code' });
      }
    });

    // Step 2: Verify code and create account
    app.post('/register/verify', async (req, res) => {
      const { code } = req.body;
      const pending = req.session.pendingRegistration;

      if (!pending) {
        return res.status(400).json({ error: 'No pending registration' });
      }

      if (Date.now() > pending.expiresAt) {
        delete req.session.pendingRegistration;
        return res.status(410).json({ error: 'Registration expired. Please start again.' });
      }

      try {
        const result = await telnyx.verifications.verify(pending.phone_number, {
          code,
          verify_profile_id: VERIFY_PROFILE_ID,
        });

        if (result.data.response_code !== 'accepted') {
          return res.status(401).json({
            error: 'Invalid verification code',
            response_code: result.data.response_code,
          });
        }

        // Phone verified — create the account
        const user = await db.users.create({
          name: pending.name,
          email: pending.email,
          phone_number: pending.phone_number,
          password_hash: pending.password_hash,
          phone_verified: true,
          phone_verified_at: new Date(),
        });

        delete req.session.pendingRegistration;

        const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: '24h' });
        res.status(201).json({ user_id: user.id, token });
      } catch (error) {
        console.error('Registration verification failed:', error);
        res.status(500).json({ error: 'Verification failed' });
      }
    });

    app.listen(3000);
    ```
  </Tab>

  <Tab title="Python (Flask)">
    ```python theme={null}
    import os
    import time
    import jwt
    from flask import Flask, request, jsonify, session
    from telnyx import Telnyx

    app = Flask(__name__)
    app.secret_key = os.environ["FLASK_SECRET_KEY"]

    telnyx_client = Telnyx(api_key=os.environ["TELNYX_API_KEY"])
    VERIFY_PROFILE_ID = os.environ["TELNYX_VERIFY_PROFILE_ID"]


    @app.route("/register/start", methods=["POST"])
    def register_start():
        data = request.json
        name = data.get("name")
        email = data.get("email")
        phone_number = data.get("phone_number")
        password = data.get("password")

        if not all([name, email, phone_number, password]):
            return jsonify({"error": "All fields required"}), 400

        existing = db.users.find_by_email_or_phone(email, phone_number)
        if existing:
            field = "Email" if existing.email == email else "Phone number"
            return jsonify({"error": f"{field} already registered"}), 409

        try:
            verification = telnyx_client.verifications.sms(
                phone_number=phone_number,
                verify_profile_id=VERIFY_PROFILE_ID,
            )

            session["pending_registration"] = {
                "name": name,
                "email": email,
                "phone_number": phone_number,
                "password_hash": bcrypt.hash_password(password),
                "verification_id": verification.data.id,
                "expires_at": time.time() + 600,
            }

            return jsonify({"verification_sent": True, "timeout_secs": 600})
        except Exception as e:
            return jsonify({"error": "Failed to send verification code"}), 500


    @app.route("/register/verify", methods=["POST"])
    def register_verify():
        code = request.json["code"]
        pending = session.get("pending_registration")

        if not pending:
            return jsonify({"error": "No pending registration"}), 400

        if time.time() > pending["expires_at"]:
            session.pop("pending_registration", None)
            return jsonify({"error": "Registration expired"}), 410

        try:
            result = telnyx_client.verifications.verify(
                phone_number=pending["phone_number"],
                code=code,
                verify_profile_id=VERIFY_PROFILE_ID,
            )

            if result.data.response_code != "accepted":
                return jsonify({
                    "error": "Invalid code",
                    "response_code": result.data.response_code,
                }), 401

            user = db.users.create(
                name=pending["name"],
                email=pending["email"],
                phone_number=pending["phone_number"],
                password_hash=pending["password_hash"],
                phone_verified=True,
            )

            session.pop("pending_registration", None)
            token = jwt.encode({"user_id": user.id}, os.environ["JWT_SECRET"], algorithm="HS256")
            return jsonify({"user_id": user.id, "token": token}), 201
        except Exception as e:
            return jsonify({"error": "Verification failed"}), 500


    if __name__ == "__main__":
        app.run(port=3000)
    ```
  </Tab>
</Tabs>

***

## Payment verification

Add step-up authentication for high-value transactions. When a user initiates a payment above a threshold, require phone verification before processing.

### Sequence diagram

```mermaid theme={null}
sequenceDiagram
    participant U as User
    participant F as Frontend
    participant S as Server
    participant T as Telnyx Verify
    participant P as Payment Processor

    U->>F: Confirm payment ($500)
    F->>S: POST /payments/initiate
    S->>S: Check amount threshold
    S->>T: POST /v2/verifications/sms
    T-->>S: verification_id (pending)
    S-->>F: 200 { requires_verification: true }
    F->>U: Show verification screen
    U->>F: Enter verification code
    F->>S: POST /payments/confirm
    S->>T: POST /v2/verifications/by_phone_number/.../verify
    T-->>S: { response_code: "accepted" }
    S->>P: Process payment
    P-->>S: Payment successful
    S-->>F: 200 { payment_id, status: "completed" }
```

### Server implementation

<Tabs>
  <Tab title="Node.js (Express)">
    ```javascript theme={null}
    import express from 'express';
    import Telnyx from 'telnyx';

    const app = express();
    app.use(express.json());

    const telnyx = new Telnyx({ apiKey: process.env.TELNYX_API_KEY });
    const VERIFY_PROFILE_ID = process.env.TELNYX_VERIFY_PROFILE_ID;
    const VERIFICATION_THRESHOLD = 100.00; // Require verification above $100

    // Middleware: require authenticated user
    function requireAuth(req, res, next) {
      // Your auth middleware here
      next();
    }

    // Step 1: Initiate payment
    app.post('/payments/initiate', requireAuth, async (req, res) => {
      const { amount, currency, recipient, description } = req.body;
      const user = req.user;

      if (amount <= 0) {
        return res.status(400).json({ error: 'Invalid amount' });
      }

      // Create pending payment record
      const payment = await db.payments.create({
        user_id: user.id,
        amount,
        currency: currency || 'USD',
        recipient,
        description,
        status: 'pending',
      });

      // Check if verification is needed
      if (amount >= VERIFICATION_THRESHOLD) {
        try {
          const verification = await telnyx.verifications.sms({
            phone_number: user.phone_number,
            verify_profile_id: VERIFY_PROFILE_ID,
          });

          await db.payments.update(payment.id, {
            verification_id: verification.data.id,
            verification_required: true,
            verification_expires_at: new Date(Date.now() + 300_000),
          });

          return res.json({
            payment_id: payment.id,
            requires_verification: true,
            amount,
            currency: currency || 'USD',
            timeout_secs: 300,
          });
        } catch (error) {
          await db.payments.update(payment.id, { status: 'failed' });
          return res.status(500).json({ error: 'Failed to send verification' });
        }
      }

      // Low-value payment — process directly
      const result = await processPayment(payment);
      res.json({ payment_id: payment.id, status: result.status });
    });

    // Step 2: Verify and process payment
    app.post('/payments/confirm', requireAuth, async (req, res) => {
      const { payment_id, code } = req.body;
      const user = req.user;

      const payment = await db.payments.findById(payment_id);

      if (!payment || payment.user_id !== user.id) {
        return res.status(404).json({ error: 'Payment not found' });
      }

      if (payment.status !== 'pending') {
        return res.status(400).json({ error: `Payment already ${payment.status}` });
      }

      if (new Date() > payment.verification_expires_at) {
        await db.payments.update(payment.id, { status: 'expired' });
        return res.status(410).json({ error: 'Verification expired. Initiate a new payment.' });
      }

      try {
        const result = await telnyx.verifications.verify(user.phone_number, {
          code,
          verify_profile_id: VERIFY_PROFILE_ID,
        });

        if (result.data.response_code !== 'accepted') {
          return res.status(401).json({
            error: 'Invalid verification code',
            response_code: result.data.response_code,
          });
        }

        // Verification passed — process payment
        await db.payments.update(payment.id, {
          verified_at: new Date(),
          status: 'processing',
        });

        const paymentResult = await processPayment(payment);

        res.json({
          payment_id: payment.id,
          status: paymentResult.status,
          transaction_id: paymentResult.transaction_id,
        });
      } catch (error) {
        console.error('Payment verification failed:', error);
        res.status(500).json({ error: 'Verification failed' });
      }
    });

    async function processPayment(payment) {
      // Integrate with your payment processor (Stripe, etc.)
      // This is a placeholder
      await db.payments.update(payment.id, { status: 'completed' });
      return { status: 'completed', transaction_id: `txn_${Date.now()}` };
    }

    app.listen(3000);
    ```
  </Tab>

  <Tab title="Python (Flask)">
    ```python theme={null}
    import os
    import time
    from flask import Flask, request, jsonify, g
    from telnyx import Telnyx

    app = Flask(__name__)

    telnyx_client = Telnyx(api_key=os.environ["TELNYX_API_KEY"])
    VERIFY_PROFILE_ID = os.environ["TELNYX_VERIFY_PROFILE_ID"]
    VERIFICATION_THRESHOLD = 100.00


    @app.route("/payments/initiate", methods=["POST"])
    @require_auth
    def initiate_payment():
        data = request.json
        amount = data["amount"]
        user = g.user

        payment = db.payments.create(
            user_id=user.id,
            amount=amount,
            currency=data.get("currency", "USD"),
            recipient=data["recipient"],
            description=data.get("description", ""),
            status="pending",
        )

        if amount >= VERIFICATION_THRESHOLD:
            try:
                verification = telnyx_client.verifications.sms(
                    phone_number=user.phone_number,
                    verify_profile_id=VERIFY_PROFILE_ID,
                )

                db.payments.update(payment.id, {
                    "verification_id": verification.data.id,
                    "verification_required": True,
                    "verification_expires_at": time.time() + 300,
                })

                return jsonify({
                    "payment_id": payment.id,
                    "requires_verification": True,
                    "amount": amount,
                    "timeout_secs": 300,
                })
            except Exception:
                db.payments.update(payment.id, {"status": "failed"})
                return jsonify({"error": "Failed to send verification"}), 500

        result = process_payment(payment)
        return jsonify({"payment_id": payment.id, "status": result["status"]})


    @app.route("/payments/confirm", methods=["POST"])
    @require_auth
    def confirm_payment():
        data = request.json
        payment = db.payments.find_by_id(data["payment_id"])
        user = g.user

        if not payment or payment.user_id != user.id:
            return jsonify({"error": "Payment not found"}), 404

        if payment.status != "pending":
            return jsonify({"error": f"Payment already {payment.status}"}), 400

        if time.time() > payment.verification_expires_at:
            db.payments.update(payment.id, {"status": "expired"})
            return jsonify({"error": "Verification expired"}), 410

        try:
            result = telnyx_client.verifications.verify(
                phone_number=user.phone_number,
                code=data["code"],
                verify_profile_id=VERIFY_PROFILE_ID,
            )

            if result.data.response_code != "accepted":
                return jsonify({
                    "error": "Invalid code",
                    "response_code": result.data.response_code,
                }), 401

            db.payments.update(payment.id, {"status": "processing", "verified_at": time.time()})
            payment_result = process_payment(payment)

            return jsonify({
                "payment_id": payment.id,
                "status": payment_result["status"],
            })
        except Exception:
            return jsonify({"error": "Verification failed"}), 500


    if __name__ == "__main__":
        app.run(port=3000)
    ```
  </Tab>
</Tabs>

<Callout type="warning">
  **Security considerations for payment verification:**

  * Always verify the payment amount hasn't been tampered with between initiation and confirmation
  * Set short timeouts (5 minutes) for payment verification codes
  * Log all verification attempts for audit purposes
  * Never expose payment details in verification messages — the SMS should only contain the code
</Callout>

***

## Common patterns across all flows

### Rate limiting resend requests

Prevent abuse by limiting how often users can request new codes:

```javascript theme={null}
// In-memory rate limiter (use Redis in production)
const resendLimits = new Map();

function canResend(phoneNumber) {
  const key = phoneNumber;
  const now = Date.now();
  const limit = resendLimits.get(key);

  if (limit && now - limit.lastSent < 30_000) {
    return { allowed: false, retryAfter: Math.ceil((30_000 - (now - limit.lastSent)) / 1000) };
  }

  if (limit && limit.count >= 5 && now - limit.firstSent < 3600_000) {
    return { allowed: false, retryAfter: Math.ceil((3600_000 - (now - limit.firstSent)) / 1000) };
  }

  return { allowed: true };
}

function recordResend(phoneNumber) {
  const key = phoneNumber;
  const now = Date.now();
  const existing = resendLimits.get(key);

  resendLimits.set(key, {
    lastSent: now,
    firstSent: existing?.firstSent || now,
    count: (existing?.count || 0) + 1,
  });
}
```

### Handling user cancellation

Always clean up pending verifications when users navigate away:

```javascript theme={null}
// Frontend: clean up on unmount
useEffect(() => {
  return () => {
    if (pendingVerification) {
      fetch('/verify/cancel', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ verification_id: pendingVerification }),
        keepalive: true, // Ensures the request completes even during navigation
      });
    }
  };
}, [pendingVerification]);
```

### Webhook-driven verification

Instead of polling, use webhooks for real-time verification status updates:

```javascript theme={null}
app.post('/webhooks/verify', (req, res) => {
  const event = req.body.data;

  if (event.event_type === 'verification.completed') {
    const { phone_number, status } = event.payload;
    // Update your UI via WebSocket or SSE
    notifyClient(phone_number, { verified: status === 'accepted' });
  }

  res.sendStatus(200);
});
```

<Callout type="tip">
  For more on webhooks, see [Receiving Webhooks for Telnyx Verify](/docs/identity/verify/receiving-webhooks).
</Callout>

## Next steps

<CardGroup cols={2}>
  <Card title="Verify Quickstart" icon="rocket" href="/docs/identity/verify/quickstart">
    Get started with the Verify API basics
  </Card>

  <Card title="Security Best Practices" icon="shield" href="/docs/identity/verify/security-best-practices">
    Protect against SMS pumping and fraud
  </Card>

  <Card title="Rate Limiting & Fraud Prevention" icon="gauge" href="/docs/identity/verify/rate-limiting-fraud-prevention">
    Implement rate limiting and anomaly detection
  </Card>

  <Card title="Custom Templates" icon="palette" href="/docs/identity/verify/custom-templates">
    Create branded verification messages
  </Card>
</CardGroup>
