Your AI agent just accepted "john@gmial.com" as a valid email and processed a payment to a credit card number that fails the Luhn check. Now you're dealing with bounced emails and failed transactions. Here's how to build validation into your AI workflows that actually works.
Input Validation Challenges in AI Agents
Traditional software has well-defined input paths with explicit validation. AI agents are different - users provide freeform input that the agent must parse, validate, and act on. This creates unique challenges.
Why LLMs Fail at Validation
- Pattern approximation: LLMs recognize patterns but don't apply validation algorithms
- No checksum verification: Credit cards use Luhn algorithm; LLMs can't compute it
- RFC complexity: Email rules are complex; LLMs simplify them incorrectly
- Regional variations: Phone formats vary by country in complex ways
Real-World Validation Failures
// LLM says valid, but actually invalid:
"test@domain" // Missing TLD
"4111111111111112" // Fails Luhn check
"+1-555-1234" // Invalid US number (555 prefix)
// LLM says invalid, but actually valid:
"user+tag@example.com" // Plus addressing is valid!
"o'connor@email.com" // Apostrophes are allowed
"+91 98765 43210" // Valid Indian mobile format
Email, Phone, and Credit Card Validation
Email Validation
Email validation is more complex than most developers realize. The RFC 5321 specification allows many surprising characters and formats.
GET https://api.tinyfn.io/v1/validate/email?email=user@example.com
{
"email": "user@example.com",
"is_valid": true,
"parts": {
"local": "user",
"domain": "example.com"
},
"checks": {
"syntax_valid": true,
"domain_format_valid": true
}
}
Phone Number Validation
Phone validation must handle international formats, country codes, and regional numbering rules.
GET https://api.tinyfn.io/v1/validate/phone
?phone=+1-212-555-1234
&country=US
{
"phone": "+1-212-555-1234",
"is_valid": true,
"country_code": "1",
"national_number": "2125551234",
"formatted": {
"international": "+1 212-555-1234",
"national": "(212) 555-1234",
"e164": "+12125551234"
},
"type": "fixed_line_or_mobile"
}
Credit Card Validation
Credit card validation uses the Luhn algorithm and card type detection based on BIN ranges.
GET https://api.tinyfn.io/v1/validate/credit-card?number=4111111111111111
{
"number": "4111111111111111",
"is_valid": true,
"luhn_valid": true,
"card_type": "visa",
"card_brand": "Visa",
"length_valid": true,
"masked": "4111 **** **** 1111"
}
Using TinyFn Validation Tools
Available Validation Tools
| Tool | Validates |
|---|---|
validate/email |
Email addresses (RFC 5321 compliant) |
validate/phone |
Phone numbers (international formats) |
validate/credit-card |
Credit/debit cards (Luhn + BIN) |
validate/url |
URLs (protocol, domain, path) |
validate/uuid |
UUIDs (all versions) |
validate/iban |
IBANs (international bank accounts) |
validate/ssn |
US Social Security Numbers |
validate/vin |
Vehicle Identification Numbers |
validate/isbn |
Book ISBNs (10 and 13 digit) |
validate/zip-code |
Postal/ZIP codes by country |
MCP Configuration
{
"mcpServers": {
"tinyfn-validate": {
"url": "https://api.tinyfn.io/mcp/validate/",
"headers": {
"X-API-Key": "your-api-key"
}
}
}
}
Building Robust Agent Workflows
Pattern: Validate Before Processing
Never process user input without validation. Build your agent to validate first, then proceed only if valid.
When collecting user information:
1. Email addresses: ALWAYS validate using validate/email before proceeding
2. Phone numbers: ALWAYS validate using validate/phone before proceeding
3. Credit cards: ALWAYS validate using validate/credit-card before processing
If validation fails:
- Explain what's wrong with the input
- Ask the user to provide a corrected value
- Do NOT proceed until valid input is received
Pattern: Graceful Correction Flow
User: "My email is john@gmial.com"
// Agent validates via MCP
Tool call: validate/email { "email": "john@gmial.com" }
Result: { "is_valid": true, "domain": "gmial.com" }
// Agent recognizes common typo in domain
Agent: "I see your email is john@gmial.com. Did you mean
john@gmail.com? The domain 'gmial.com' looks like
it might be a typo."
User: "Oh yes, john@gmail.com"
// Agent re-validates
Tool call: validate/email { "email": "john@gmail.com" }
Result: { "is_valid": true }
Agent: "Perfect! I've noted your email as john@gmail.com."
Pattern: Multi-Field Validation
// User provides multiple fields at once
User: "Ship to john@example.com, call me at 555-1234,
and charge card 4111111111111112"
// Agent validates all fields
validate/email { "email": "john@example.com" }
// Result: valid
validate/phone { "phone": "555-1234", "country": "US" }
// Result: invalid - 555 is not a real exchange
validate/credit-card { "number": "4111111111111112" }
// Result: invalid - fails Luhn check
Agent: "I found some issues with your information:
Email: john@example.com - Valid
Phone: 555-1234 - Invalid. US phone numbers can't
use the 555 prefix. Please provide your real
phone number.
Card: ending in 1112 - Invalid card number. Please
double-check and re-enter.
Please correct the phone and card to proceed."
Error Handling Best Practices
Clear Error Messages
When validation fails, tell users exactly what's wrong and how to fix it.
// Bad: Vague
"Invalid email address"
// Good: Specific and helpful
"The email 'john@domain' is missing a domain extension
like .com or .org. Did you mean john@domain.com?"
// Bad: Technical
"Phone validation failed: E164 format error"
// Good: Human-friendly
"The phone number format isn't recognized. Please include
your country code, like +1 for US or +44 for UK."
Fallback Handling
If the validation API is temporarily unavailable, have a fallback strategy:
async function validateEmailWithFallback(email) {
try {
const result = await validateEmail(email); // TinyFn API
return result;
} catch (error) {
// API unavailable - use basic regex as fallback
const basicValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
return {
is_valid: basicValid,
warning: "Full validation unavailable. Basic check only.",
needs_verification: true
};
}
}
Complete Examples
Customer Onboarding Agent
import requests
class ValidationAgent:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://api.tinyfn.io/v1"
def validate(self, validation_type, value, **kwargs):
params = {validation_type.split('/')[-1]: value, **kwargs}
response = requests.get(
f"{self.base_url}/{validation_type}",
params=params,
headers={"X-API-Key": self.api_key}
)
return response.json()
def collect_customer_info(self, email, phone, country="US"):
errors = []
validated = {}
# Validate email
email_result = self.validate("validate/email", email)
if not email_result["is_valid"]:
errors.append(f"Invalid email: {email}")
else:
validated["email"] = email
# Validate phone
phone_result = self.validate(
"validate/phone", phone, country=country
)
if not phone_result["is_valid"]:
errors.append(f"Invalid phone for {country}: {phone}")
else:
validated["phone"] = phone_result["formatted"]["e164"]
return {
"valid": len(errors) == 0,
"errors": errors,
"validated_data": validated
}
# Usage
agent = ValidationAgent("your-api-key")
result = agent.collect_customer_info(
email="john@example.com",
phone="212-555-1234"
)
if result["valid"]:
print("All inputs valid:", result["validated_data"])
else:
print("Errors found:", result["errors"])
Payment Processing Agent
class PaymentAgent {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.tinyfn.io/v1';
}
async validateCard(number, expiryMonth, expiryYear) {
// Validate card number
const cardResult = await this.callApi('validate/credit-card', {
number: number.replace(/\s/g, '')
});
if (!cardResult.is_valid) {
return {
valid: false,
error: 'Invalid card number. Please check and try again.',
details: cardResult
};
}
// Check expiry (basic check - could use datetime tools too)
const now = new Date();
const expiry = new Date(expiryYear, expiryMonth - 1);
if (expiry < now) {
return {
valid: false,
error: 'Card has expired.',
card_type: cardResult.card_type
};
}
return {
valid: true,
card_type: cardResult.card_type,
masked: cardResult.masked
};
}
async callApi(endpoint, params) {
const url = new URL(`${this.baseUrl}/${endpoint}`);
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
return response.json();
}
}
// Usage
const agent = new PaymentAgent('your-api-key');
const result = await agent.validateCard(
'4111 1111 1111 1111',
12,
2026
);
if (result.valid) {
console.log(`Valid ${result.card_type}: ${result.masked}`);
} else {
console.log(`Error: ${result.error}`);
}
Build Bulletproof AI Agent Workflows
Add reliable input validation to your AI agents with TinyFn MCP tools.
Get Free API Key