diff --git a/README.md b/README.md index 4f8433f..d1cb25c 100644 --- a/README.md +++ b/README.md @@ -331,6 +331,45 @@ await ccai.contact.setDoNotText(false, undefined, '+15551234567'); await ccai.contact.setDoNotText(true, '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. + +```typescript +import { CCAI } from 'ccai-node'; + +const ccai = new CCAI({ + clientId: 'YOUR-CLIENT-ID', + apiKey: 'YOUR-API-KEY' +}); + +// Validate a single email +const emailResult = await ccai.contactValidator.validateEmail('user@example.com'); +console.log(emailResult.status); // "valid" | "invalid" | "risky" +console.log(emailResult.metadata.safe_to_send); // true | false + +// Validate multiple emails (up to 50, processed server-side in chunks) +const bulkEmails = await ccai.contactValidator.validateEmails([ + 'user@example.com', + 'invalid@nonexistent.xyz' +]); +console.log(bulkEmails.summary); // { total: 2, valid: 1, invalid: 1, risky: 0 } + +// Validate a single phone number +const phoneResult = await ccai.contactValidator.validatePhone('+15551234567', 'US'); +console.log(phoneResult.status); // "valid" | "invalid" | "landline" +console.log(phoneResult.metadata.carrier_type); // "mobile" | "landline" | "voip" + +// Validate multiple phone numbers (up to 50, processed server-side in chunks) +const bulkPhones = await ccai.contactValidator.validatePhones([ + { phone: '+15551234567' }, + { phone: '+15559876543', countryCode: 'US' } +]); +console.log(bulkPhones.summary); // { total: 2, valid: 1, invalid: 0, risky: 0, landline: 1 } +``` + ### Webhooks CloudContactAI can send webhook notifications when certain events occur, such as when messages are sent or received. Use the Webhook service to register, manage, and verify webhooks programmatically. @@ -704,6 +743,7 @@ This project includes a `.gitignore` file that excludes: - 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 (HMAC-SHA256) - Next.js API route handlers for webhook events diff --git a/package.json b/package.json index 3ddc328..a4bf973 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ccai-node", - "version": "1.0.2", + "version": "1.1.0", "description": "TypeScript client for CloudContactAI API", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/ccai.ts b/src/ccai.ts index 792afb3..4f49e3e 100644 --- a/src/ccai.ts +++ b/src/ccai.ts @@ -10,6 +10,7 @@ import axios, { AxiosResponse } from 'axios'; import { Brands } from './brands/brands'; import { Campaigns } from './campaigns/campaigns'; +import { ContactValidator } from './contact-validator/contact-validator'; import { Contact } from './contact/contact'; import { Email } from './email/email'; import { MMS } from './sms/mms'; @@ -110,6 +111,9 @@ export class CCAI { /** Contact service for managing contact preferences */ public contact: Contact; + /** Contact validator service for validating emails and phone numbers */ + public contactValidator: ContactValidator; + /** * Create a new CCAI client instance * @param config - Configuration object @@ -159,6 +163,7 @@ export class CCAI { this.contact = new Contact(this); this.brands = new Brands(this); this.campaigns = new Campaigns(this); + this.contactValidator = new ContactValidator(this); } /** diff --git a/src/contact-validator/contact-validator.ts b/src/contact-validator/contact-validator.ts new file mode 100644 index 0000000..ee417e7 --- /dev/null +++ b/src/contact-validator/contact-validator.ts @@ -0,0 +1,117 @@ +/** + * contact-validator.ts - A TypeScript module for validating email and phone contacts via CloudContactAI + * + * @license MIT + * @copyright 2025 CloudContactAI LLC + */ + +import { CCAI } from '../ccai'; + +export type ValidationStatus = 'valid' | 'invalid' | 'risky' | 'landline'; + +export type EmailValidationMetadata = { + safe_to_send?: boolean; + ai_verdict?: string | null; + [key: string]: unknown; +}; + +export type PhoneValidationMetadata = { + country_code?: string | null; + national_number?: string | null; + carrier_type?: string | null; + [key: string]: unknown; +}; + +export type EmailValidationResult = { + contactField: string; + type: 'email'; + status: ValidationStatus; + metadata: EmailValidationMetadata; +}; + +export type PhoneValidationResult = { + contactField: string; + type: 'phone'; + status: ValidationStatus; + metadata: PhoneValidationMetadata; +}; + +export type ValidationSummary = { + total: number; + valid: number; + invalid: number; + risky: number; + landline?: number; +}; + +export type BulkEmailValidationResult = { + results: EmailValidationResult[]; + summary: ValidationSummary; +}; + +export type BulkPhoneValidationResult = { + results: PhoneValidationResult[]; + summary: ValidationSummary; +}; + +export type PhoneInput = { + phone: string; + countryCode?: string; +}; + +/** + * Service for validating email addresses and phone numbers + */ +export class ContactValidator { + private ccai: CCAI; + + constructor(ccai: CCAI) { + this.ccai = ccai; + } + + /** + * Validate a single email address + * @param email - Email address to validate + * @returns Promise resolving to the validation result + */ + validateEmail(email: string): Promise { + return this.ccai.request('POST', '/v1/contact-validator/email', { + email, + }); + } + + /** + * Validate multiple email addresses (up to 50) + * @param emails - List of email addresses to validate + * @returns Promise resolving to bulk validation results with summary + */ + validateEmails(emails: string[]): Promise { + return this.ccai.request('POST', '/v1/contact-validator/emails', { + emails, + }); + } + + /** + * Validate a single phone number + * @param phone - Phone number in E.164 format (e.g. +15551234567) + * @param countryCode - Optional ISO 3166-1 alpha-2 country code (e.g. "US") + * @returns Promise resolving to the validation result + */ + validatePhone(phone: string, countryCode?: string): Promise { + return this.ccai.request('POST', '/v1/contact-validator/phone', { + phone, + countryCode, + }); + } + + /** + * Validate multiple phone numbers (up to 50) + * @param phones - List of phone inputs with optional country codes + * @returns Promise resolving to bulk validation results with summary + */ + validatePhones(phones: PhoneInput[]): Promise { + return this.ccai.request('POST', '/v1/contact-validator/phones', { + phones, + }); + } +} diff --git a/src/index.ts b/src/index.ts index 9a68d8c..6388d1b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,18 @@ import { Campaigns } from './campaigns/campaigns'; import type { CampaignData, CampaignResponse } from './campaigns/campaigns'; import { CCAI } from './ccai'; import type { Account, CCAIConfig } from './ccai'; +import { ContactValidator } from './contact-validator/contact-validator'; +import type { + BulkEmailValidationResult, + BulkPhoneValidationResult, + EmailValidationMetadata, + EmailValidationResult, + PhoneInput, + PhoneValidationMetadata, + PhoneValidationResult, + ValidationStatus, + ValidationSummary, +} from './contact-validator/contact-validator'; import { Contact } from './contact/contact'; import type { SetDoNotTextResponse } from './contact/contact'; import { Email } from './email/email'; @@ -35,6 +47,7 @@ export { WebhookEventType, createWebhookHandler, Contact, + ContactValidator, Brands, Campaigns, }; @@ -59,4 +72,13 @@ export type { BrandResponse, CampaignData, CampaignResponse, + ValidationStatus, + ValidationSummary, + EmailValidationResult, + EmailValidationMetadata, + PhoneValidationResult, + PhoneValidationMetadata, + BulkEmailValidationResult, + BulkPhoneValidationResult, + PhoneInput, };