From 77bf91f96d1a80f5cf5ba4dc57408d37f252b0a2 Mon Sep 17 00:00:00 2001 From: Deyner lopez Date: Thu, 14 May 2026 17:45:44 -0500 Subject: [PATCH] https://mobileaws.atlassian.net/browse/CLOUD-2744 --- README.md | 35 +++++ RELEASE-NOTES-v1.5.0.md | 10 ++ src/CCAI.NET/CCAI.NET.csproj | 4 +- src/CCAI.NET/CCAIClient.cs | 12 ++ .../ContactValidatorModels.cs | 139 ++++++++++++++++++ .../ContactValidatorService.cs | 104 +++++++++++++ 6 files changed, 302 insertions(+), 2 deletions(-) create mode 100644 RELEASE-NOTES-v1.5.0.md create mode 100644 src/CCAI.NET/ContactValidator/ContactValidatorModels.cs create mode 100644 src/CCAI.NET/ContactValidator/ContactValidatorService.cs diff --git a/README.md b/README.md index 941cb44..5836023 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ A C# client library for interacting with the [CloudContactAI](https://cloudconta - Brand registration and management for TCR verification - Campaign registration and management for TCR carrier vetting - Manage contact opt-out preferences (SetDoNotText) +- Validate email addresses (valid/invalid/risky) and phone numbers (valid/invalid/landline) - Webhook management: register, list, update, delete - Webhook signature verification - Template variable substitution (`${firstName}`, `${lastName}`) @@ -280,6 +281,40 @@ await ccai.Contact.SetDoNotTextAsync(false, phone: "+15551234567"); await ccai.Contact.SetDoNotTextAsync(true, contactId: "contact-abc-123"); ``` +### Contact Validator + +Validate email addresses and phone numbers. + +> Bulk endpoints accept up to 50 contacts per request and are processed server-side in chunks. + +```csharp +using CCAI.NET; +using CCAI.NET.ContactValidator; + +// Validate a single email +var emailResult = await ccai.ContactValidator.ValidateEmailAsync("user@example.com"); +Console.WriteLine(emailResult.Status); // "valid" | "invalid" | "risky" + +// Validate multiple emails (up to 50, processed server-side in chunks) +var bulkEmails = await ccai.ContactValidator.ValidateEmailsAsync(new[] { + "user@example.com", + "bad@invalid.xyz" +}); +Console.WriteLine(bulkEmails.Summary.Total); // 2 +Console.WriteLine(bulkEmails.Summary.Valid); // 1 + +// Validate a single phone number +var phoneResult = await ccai.ContactValidator.ValidatePhoneAsync("+15551234567", "US"); +Console.WriteLine(phoneResult.Status); // "valid" | "invalid" | "landline" + +// Validate multiple phone numbers (up to 50, processed server-side in chunks) +var bulkPhones = await ccai.ContactValidator.ValidatePhonesAsync(new[] { + new PhoneInput { Phone = "+15551234567" }, + new PhoneInput { Phone = "+15559876543", CountryCode = "US" } +}); +Console.WriteLine(bulkPhones.Summary.Landline); // 1 +``` + ### Webhook Management #### CloudContact Webhook Events (New Format) diff --git a/RELEASE-NOTES-v1.5.0.md b/RELEASE-NOTES-v1.5.0.md new file mode 100644 index 0000000..5daddd0 --- /dev/null +++ b/RELEASE-NOTES-v1.5.0.md @@ -0,0 +1,10 @@ +# Release Notes - Version 1.5.0 + +## New Features +- Added `ContactValidator` service for validating email addresses and phone numbers +- `ValidateEmailAsync` / `ValidateEmail` — validate a single email, returns `valid`, `invalid`, or `risky` status with `safe_to_send` and `ai_verdict` metadata +- `ValidateEmailsAsync` / `ValidateEmails` — bulk email validation (up to 50 addresses) with summary counts +- `ValidatePhoneAsync` / `ValidatePhone` — validate a single phone number, returns `valid`, `invalid`, or `landline` status with carrier metadata +- `ValidatePhonesAsync` / `ValidatePhones` — bulk phone validation (up to 50 numbers) with summary counts including landline count +- New models: `EmailValidationResult`, `PhoneValidationResult`, `ValidationSummary`, `BulkEmailValidationResult`, `BulkPhoneValidationResult`, `PhoneInput` +- `IContactValidatorService` interface for dependency injection and testing diff --git a/src/CCAI.NET/CCAI.NET.csproj b/src/CCAI.NET/CCAI.NET.csproj index 479c99f..1dc26a5 100644 --- a/src/CCAI.NET/CCAI.NET.csproj +++ b/src/CCAI.NET/CCAI.NET.csproj @@ -6,7 +6,7 @@ enable latest CloudContactAI.CCAI.NET - 1.4.5 + 1.5.0 CloudContactAI LLC CloudContactAI LLC C# client for CloudContactAI API with SMS, MMS, Email, and Webhook support. Enhanced webhook support with new CloudContact event format, contact.unsubscribed events, environment variable configuration, and comprehensive examples. @@ -15,7 +15,7 @@ true https://github.com/CloudContactAI/CCAI.NET true - $([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/../../RELEASE-NOTES-v1.4.5.md")) + $([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/../../RELEASE-NOTES-v1.5.0.md")) https://github.com/CloudContactAI/CCAI.NET git README.md diff --git a/src/CCAI.NET/CCAIClient.cs b/src/CCAI.NET/CCAIClient.cs index 986a7ad..aee1400 100644 --- a/src/CCAI.NET/CCAIClient.cs +++ b/src/CCAI.NET/CCAIClient.cs @@ -9,6 +9,7 @@ using CCAI.NET.Brands; using CCAI.NET.Campaigns; using CCAI.NET.Contact; +using CCAI.NET.ContactValidator; using CCAI.NET.Email; using CCAI.NET.SMS; using CCAI.NET.Webhook; @@ -60,6 +61,11 @@ public interface ICCAIClient : IDisposable /// CampaignService Campaigns { get; } + /// + /// Contact validator service for validating email and phone contacts + /// + IContactValidatorService ContactValidator { get; } + /// /// Get the client ID /// @@ -284,6 +290,11 @@ public class CCAIClient : ICCAIClient /// public CampaignService Campaigns { get; } + /// + /// Contact validator service for validating email and phone contacts + /// + public IContactValidatorService ContactValidator { get; } + /// /// Create a new CCAI client instance /// @@ -333,6 +344,7 @@ public CCAIClient(CCAIConfig config, HttpClient? httpClient = null) Contact = new ContactService(this); Brands = new BrandService(this); Campaigns = new CampaignService(this); + ContactValidator = new ContactValidatorService(this); } /// diff --git a/src/CCAI.NET/ContactValidator/ContactValidatorModels.cs b/src/CCAI.NET/ContactValidator/ContactValidatorModels.cs new file mode 100644 index 0000000..a4be04c --- /dev/null +++ b/src/CCAI.NET/ContactValidator/ContactValidatorModels.cs @@ -0,0 +1,139 @@ +// Copyright (c) 2025 CloudContactAI LLC +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CCAI.NET.ContactValidator; + +/// +/// Validation result for a single email address +/// +public class EmailValidationResult +{ + /// + /// The validated email address + /// + [JsonPropertyName("contactField")] + public string ContactField { get; set; } = string.Empty; + + /// + /// Contact type — always "email" + /// + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; + + /// + /// Validation status: "valid", "invalid", or "risky" + /// + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; + + /// + /// Additional metadata (e.g. safe_to_send, ai_verdict) + /// + [JsonPropertyName("metadata")] + public Dictionary? Metadata { get; set; } +} + +/// +/// Validation result for a single phone number +/// +public class PhoneValidationResult +{ + /// + /// The validated phone number + /// + [JsonPropertyName("contactField")] + public string ContactField { get; set; } = string.Empty; + + /// + /// Contact type — always "phone" + /// + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; + + /// + /// Validation status: "valid", "invalid", or "landline" + /// + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; + + /// + /// Additional metadata (e.g. country_code, national_number, carrier_type) + /// + [JsonPropertyName("metadata")] + public Dictionary? Metadata { get; set; } +} + +/// +/// Aggregate counts for a bulk validation response +/// +public class ValidationSummary +{ + /// Total contacts validated + [JsonPropertyName("total")] + public int Total { get; set; } + + /// Number of valid contacts + [JsonPropertyName("valid")] + public int Valid { get; set; } + + /// Number of invalid contacts + [JsonPropertyName("invalid")] + public int Invalid { get; set; } + + /// Number of risky contacts (emails only) + [JsonPropertyName("risky")] + public int Risky { get; set; } + + /// Number of landline numbers (phones only) + [JsonPropertyName("landline")] + public int Landline { get; set; } +} + +/// +/// Response for a bulk email validation request +/// +public class BulkEmailValidationResult +{ + /// Individual validation results + [JsonPropertyName("results")] + public List Results { get; set; } = new(); + + /// Aggregate summary + [JsonPropertyName("summary")] + public ValidationSummary Summary { get; set; } = new(); +} + +/// +/// Response for a bulk phone validation request +/// +public class BulkPhoneValidationResult +{ + /// Individual validation results + [JsonPropertyName("results")] + public List Results { get; set; } = new(); + + /// Aggregate summary + [JsonPropertyName("summary")] + public ValidationSummary Summary { get; set; } = new(); +} + +/// +/// Phone number input for bulk validation +/// +public class PhoneInput +{ + /// + /// Phone number in E.164 format (e.g. +15551234567) + /// + [JsonPropertyName("phone")] + public string Phone { get; set; } = string.Empty; + + /// + /// Optional ISO 3166-1 alpha-2 country code (e.g. "US") + /// + [JsonPropertyName("countryCode")] + public string? CountryCode { get; set; } +} diff --git a/src/CCAI.NET/ContactValidator/ContactValidatorService.cs b/src/CCAI.NET/ContactValidator/ContactValidatorService.cs new file mode 100644 index 0000000..793c016 --- /dev/null +++ b/src/CCAI.NET/ContactValidator/ContactValidatorService.cs @@ -0,0 +1,104 @@ +// Copyright (c) 2025 CloudContactAI LLC +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace CCAI.NET.ContactValidator; + +/// +/// Interface for the contact validator service +/// +public interface IContactValidatorService +{ + /// Validate a single email address (async) + Task ValidateEmailAsync(string email, CancellationToken cancellationToken = default); + + /// Validate multiple email addresses up to the configured bulk limit (async) + Task ValidateEmailsAsync(IEnumerable emails, CancellationToken cancellationToken = default); + + /// Validate a single phone number in E.164 format (async) + Task ValidatePhoneAsync(string phone, string? countryCode = null, CancellationToken cancellationToken = default); + + /// Validate multiple phone numbers up to the configured bulk limit (async) + Task ValidatePhonesAsync(IEnumerable phones, CancellationToken cancellationToken = default); + + /// Validate a single email address (synchronous) + EmailValidationResult ValidateEmail(string email); + + /// Validate multiple email addresses up to the configured bulk limit (synchronous) + BulkEmailValidationResult ValidateEmails(IEnumerable emails); + + /// Validate a single phone number in E.164 format (synchronous) + PhoneValidationResult ValidatePhone(string phone, string? countryCode = null); + + /// Validate multiple phone numbers up to the configured bulk limit (synchronous) + BulkPhoneValidationResult ValidatePhones(IEnumerable phones); +} + +/// +/// Service for validating email addresses and phone numbers through the CCAI API +/// +public class ContactValidatorService : IContactValidatorService +{ + private readonly ICCAIClient _client; + + /// + /// Create a new ContactValidatorService instance + /// + /// The parent CCAI client + public ContactValidatorService(ICCAIClient client) + { + _client = client; + } + + /// + /// Validate a single email address + /// + /// Email address to validate + /// Cancellation token + /// Validation result with status and metadata + public Task ValidateEmailAsync(string email, CancellationToken cancellationToken = default) => + _client.RequestAsync(HttpMethod.Post, "/v1/contact-validator/email", new { email }, cancellationToken); + + /// + /// Validate multiple email addresses (up to the configured bulk limit) + /// + /// List of email addresses to validate + /// Cancellation token + /// Bulk validation results with summary + public Task ValidateEmailsAsync(IEnumerable emails, CancellationToken cancellationToken = default) => + _client.RequestAsync(HttpMethod.Post, "/v1/contact-validator/emails", new { emails }, cancellationToken); + + /// + /// Validate a single phone number + /// + /// Phone number in E.164 format (e.g. +15551234567) + /// Optional ISO 3166-1 alpha-2 country code (e.g. "US") + /// Cancellation token + /// Validation result with status and metadata + public Task ValidatePhoneAsync(string phone, string? countryCode = null, CancellationToken cancellationToken = default) => + _client.RequestAsync(HttpMethod.Post, "/v1/contact-validator/phone", new { phone, countryCode }, cancellationToken); + + /// + /// Validate multiple phone numbers (up to the configured bulk limit) + /// + /// List of phone inputs with optional country codes + /// Cancellation token + /// Bulk validation results with summary + public Task ValidatePhonesAsync(IEnumerable phones, CancellationToken cancellationToken = default) => + _client.RequestAsync(HttpMethod.Post, "/v1/contact-validator/phones", new { phones }, cancellationToken); + + /// + public EmailValidationResult ValidateEmail(string email) => + ValidateEmailAsync(email).GetAwaiter().GetResult(); + + /// + public BulkEmailValidationResult ValidateEmails(IEnumerable emails) => + ValidateEmailsAsync(emails).GetAwaiter().GetResult(); + + /// + public PhoneValidationResult ValidatePhone(string phone, string? countryCode = null) => + ValidatePhoneAsync(phone, countryCode).GetAwaiter().GetResult(); + + /// + public BulkPhoneValidationResult ValidatePhones(IEnumerable phones) => + ValidatePhonesAsync(phones).GetAwaiter().GetResult(); +}