CloudContactAI.CCAI.NET 1.4.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package CloudContactAI.CCAI.NET --version 1.4.1
                    
NuGet\Install-Package CloudContactAI.CCAI.NET -Version 1.4.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CloudContactAI.CCAI.NET" Version="1.4.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CloudContactAI.CCAI.NET" Version="1.4.1" />
                    
Directory.Packages.props
<PackageReference Include="CloudContactAI.CCAI.NET" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CloudContactAI.CCAI.NET --version 1.4.1
                    
#r "nuget: CloudContactAI.CCAI.NET, 1.4.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CloudContactAI.CCAI.NET@1.4.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CloudContactAI.CCAI.NET&version=1.4.1
                    
Install as a Cake Addin
#tool nuget:?package=CloudContactAI.CCAI.NET&version=1.4.1
                    
Install as a Cake Tool

CCAI.NET

A C# client library for interacting with the CloudContactAI API.

Features

  • Send SMS messages to single or multiple recipients
  • Send MMS messages with images
  • Send Email campaigns to single or multiple recipients
  • Upload images to S3 with signed URLs
  • Variable substitution in messages
  • Manage webhooks for event notifications
  • Async/await support
  • Progress tracking
  • Comprehensive error handling
  • Full test coverage

Requirements

  • .NET 8.0 or higher

Installation

dotnet add package CloudContactAI.CCAI.NET
dotnet add package DotNetEnv

Configuration

Create a .env file in your project root:

CCAI_CLIENT_ID=1231
CCAI_API_KEY=your-api-key-here

Usage

SMS Basic Usage

using CCAI.NET;
using CCAI.NET.SMS;
using DotNetEnv;

// Load environment variables
Env.Load();

// Initialize the client
var config = new CCAIConfig
{
    ClientId = Environment.GetEnvironmentVariable("CCAI_CLIENT_ID") ?? throw new InvalidOperationException("CCAI_CLIENT_ID not found"),
    ApiKey = Environment.GetEnvironmentVariable("CCAI_API_KEY") ?? throw new InvalidOperationException("CCAI_API_KEY not found")
};

using var ccai = new CCAIClient(config);

// Send a single SMS
var response = await ccai.SMS.SendSingleAsync(
    firstName: "John",
    lastName: "Doe",
    phone: "+15551234567",
    message: "Hello ${FirstName}, this is a test message!",
    title: "Test Campaign"
);

Console.WriteLine($"Message sent with ID: {response.Id}");

// Send to multiple recipients
var accounts = new List<Account>
{
    new Account
    {
        FirstName = "John",
        LastName = "Doe",
        Phone = "+15551234567"
    },
    new Account
    {
        FirstName = "Jane",
        LastName = "Smith",
        Phone = "+15559876543"
    }
};

var campaignResponse = await ccai.SMS.SendAsync(
    accounts: accounts,
    message: "Hello ${FirstName} ${LastName}, this is a test message!",
    title: "Bulk Test Campaign"
);

Console.WriteLine($"Campaign sent with ID: {campaignResponse.CampaignId}");

MMS Usage

using CCAI.NET;
using CCAI.NET.SMS;
using DotNetEnv;

// Load environment variables
Env.Load();

// Initialize the client
var config = new CCAIConfig
{
    ClientId = Environment.GetEnvironmentVariable("CCAI_CLIENT_ID") ?? throw new InvalidOperationException("CCAI_CLIENT_ID not found"),
    ApiKey = Environment.GetEnvironmentVariable("CCAI_API_KEY") ?? throw new InvalidOperationException("CCAI_API_KEY not found")
};

using var ccai = new CCAIClient(config);

// Create options with progress tracking
var options = new SMSOptions
{
    Timeout = 60,
    OnProgress = status => Console.WriteLine($"Progress: {status}")
};

// Complete MMS workflow (get URL, upload image, send MMS)
var imagePath = "path/to/your/image.jpg";
var contentType = "image/jpeg";

// Define recipient
var account = new Account
{
    FirstName = "John",
    LastName = "Doe",
    Phone = "+15551234567"  // Use E.164 format
};

// Send MMS with image in one step
var response = await ccai.MMS.SendWithImageAsync(
    imagePath: imagePath,
    contentType: contentType,
    accounts: new[] { account },
    message: "Hello ${FirstName}, check out this image!",
    title: "MMS Campaign Example",
    options: options
);

Console.WriteLine($"MMS sent! Campaign ID: {response.CampaignId}");

Email Usage

using CCAI.NET;
using CCAI.NET.Email;
using DotNetEnv;

// Load environment variables
Env.Load();

// Initialize the client
var config = new CCAIConfig
{
    ClientId = Environment.GetEnvironmentVariable("CCAI_CLIENT_ID") ?? throw new InvalidOperationException("CCAI_CLIENT_ID not found"),
    ApiKey = Environment.GetEnvironmentVariable("CCAI_API_KEY") ?? throw new InvalidOperationException("CCAI_API_KEY not found")
};

using var ccai = new CCAIClient(config);

// Send a single email
var response = await ccai.Email.SendSingleAsync(
    firstName: "John",
    lastName: "Doe",
    email: "john@example.com",
    subject: "Welcome to Our Service",
    message: "<p>Hello ${FirstName},</p><p>Thank you for signing up!</p>",
    senderEmail: "noreply@yourcompany.com",
    replyEmail: "support@yourcompany.com",
    senderName: "Your Company",
    title: "Welcome Email"
);

Console.WriteLine($"Email sent with ID: {response.Id}");

// Send to multiple recipients
var emailAccounts = new List<EmailAccount>
{
    new EmailAccount
    {
        FirstName = "John",
        LastName = "Doe",
        Email = "john@example.com"
    },
    new EmailAccount
    {
        FirstName = "Jane",
        LastName = "Smith",
        Email = "jane@example.com"
    }
};

var campaign = new EmailCampaign
{
    Subject = "Monthly Newsletter",
    Title = "July 2025 Newsletter",
    Message = @"
        <h1>Monthly Newsletter - July 2025</h1>
        <p>Hello ${FirstName},</p>
        <p>Here are our updates for this month...</p>
    ",
    SenderEmail = "newsletter@yourcompany.com",
    ReplyEmail = "support@yourcompany.com",
    SenderName = "Your Company Newsletter",
    Accounts = emailAccounts,
    CampaignType = "EMAIL",
    AddToList = "noList",
    ContactInput = "accounts",
    FromType = "single",
    Senders = new List<object>()
};

var campaignResponse = await ccai.Email.SendCampaignAsync(
    campaign: campaign,
    options: new EmailOptions
    {
        OnProgress = status => Console.WriteLine($"Progress: {status}")
    }
);

Console.WriteLine($"Email campaign sent with ID: {campaignResponse.Id}");

Scheduled Email Campaign

// Schedule for tomorrow at 10:00 AM
var tomorrow = DateTime.Now.AddDays(1).Date.AddHours(10);

var scheduledCampaign = new EmailCampaign
{
    Subject = "Upcoming Event Reminder",
    Title = "Event Reminder Campaign",
    Message = @"
        <h1>Reminder: Upcoming Event</h1>
        <p>Hello ${FirstName},</p>
        <p>This is a reminder about our upcoming event tomorrow.</p>
    ",
    SenderEmail = "events@yourcompany.com",
    ReplyEmail = "events@yourcompany.com",
    SenderName = "Your Company Events",
    Accounts = emailAccounts,
    ScheduledTimestamp = tomorrow.ToString("o"), // ISO 8601 format
    ScheduledTimezone = "America/New_York"
};

var scheduledResponse = await ccai.Email.SendCampaignAsync(scheduledCampaign);
Console.WriteLine($"Email campaign scheduled with ID: {scheduledResponse.Id}");

Webhook Management

CloudContact Webhook Events (New Format)

CloudContact now sends webhook notifications with a consistent structure for all event types:

using CCAI.NET;
using CCAI.NET.Webhook;

// Parse CloudContact webhook event
var cloudContactEvent = ccai.Webhook.ParseCloudContactEvent(json);

switch (cloudContactEvent.EventType)
{
    case "message.sent":
        Console.WriteLine($"✅ Message delivered to {cloudContactEvent.Data.To}");
        Console.WriteLine($"   Cost: ${cloudContactEvent.Data.TotalPrice}");
        Console.WriteLine($"   Segments: {cloudContactEvent.Data.Segments}");
        break;
        
    case "message.incoming":
        Console.WriteLine($"📨 Reply from {cloudContactEvent.Data.From}: {cloudContactEvent.Data.Message}");
        break;
        
    case "message.excluded":
        Console.WriteLine($"⚠️ Message excluded: {cloudContactEvent.Data.ExcludedReason}");
        break;
        
    case "message.error.carrier":
        Console.WriteLine($"❌ Carrier error {cloudContactEvent.Data.ErrorCode}: {cloudContactEvent.Data.ErrorMessage}");
        break;
        
    case "message.error.cloudcontact":
        Console.WriteLine($"🚨 System error {cloudContactEvent.Data.ErrorCode}: {cloudContactEvent.Data.ErrorMessage}");
        break;
}
Supported Event Types
  • message.sent - Message successfully delivered to recipient
  • message.incoming - Reply received from recipient
  • message.excluded - Message excluded during campaign (duplicates, invalid numbers, etc.)
  • message.error.carrier - Carrier-level delivery failure
  • message.error.cloudcontact - CloudContact system error
ASP.NET Core Webhook Endpoint
[ApiController]
[Route("api/[controller]")]
public class WebhookController : ControllerBase
{
    [HttpPost("cloudcontact")]
    public async Task<IActionResult> HandleCloudContactWebhook()
    {
        using var reader = new StreamReader(Request.Body, Encoding.UTF8);
        var body = await reader.ReadToEndAsync();
        
        var webhookService = new WebhookService(null!);
        var cloudContactEvent = webhookService.ParseCloudContactEvent(body);
        
        // Process the event
        await ProcessWebhookEvent(cloudContactEvent);
        
        return Ok(new { status = "success" });
    }
}
Legacy Webhook Format (Backward Compatibility)

The library still supports the original webhook format:

using CCAI.NET;
using CCAI.NET.Webhook;
using DotNetEnv;

// Load environment variables
Env.Load();

// Initialize the client
var config = new CCAIConfig
{
    ClientId = Environment.GetEnvironmentVariable("CCAI_CLIENT_ID") ?? throw new InvalidOperationException("CCAI_CLIENT_ID not found"),
    ApiKey = Environment.GetEnvironmentVariable("CCAI_API_KEY") ?? throw new InvalidOperationException("CCAI_API_KEY not found")
};

using var ccai = new CCAIClient(config);

// Register a webhook
var webhookConfig = new WebhookConfig
{
    Url = "https://your-webhook-endpoint.com/webhook",
    Events = new List<WebhookEventType>
    {
        WebhookEventType.MessageSent,
        WebhookEventType.MessageIncoming,
        WebhookEventType.MessageExcluded,
        WebhookEventType.MessageErrorCarrier,
        WebhookEventType.MessageErrorCloudContact
    },
    Secret = "your-webhook-secret"
};

var registration = await ccai.Webhook.RegisterAsync(webhookConfig);
Console.WriteLine($"Webhook registered with ID: {registration.Id}");

// List all webhooks
var webhooks = await ccai.Webhook.ListAsync();
foreach (var webhook in webhooks)
{
    Console.WriteLine($"Webhook ID: {webhook.Id}, URL: {webhook.Url}");
}

// Update a webhook
var updatedConfig = new WebhookConfig
{
    Url = "https://your-updated-endpoint.com/webhook",
    Events = new List<WebhookEventType> { WebhookEventType.MessageSent },
    Secret = "your-updated-secret"
};

var updatedWebhook = await ccai.Webhook.UpdateAsync(registration.Id, updatedConfig);

// Delete a webhook
var deleteResponse = await ccai.Webhook.DeleteAsync(registration.Id);
Console.WriteLine($"Webhook deleted: {deleteResponse.Success}");

// Parse a webhook event (in your webhook handler)
public void ProcessWebhookEvent(string json, string signature, string secret)
{
    // Verify the signature
    if (ccai.Webhook.VerifySignature(signature, json, secret))
    {
        // Parse the event (supports both new and legacy formats)
        var webhookEvent = ccai.Webhook.ParseEvent(json);
        
        if (webhookEvent is MessageSentEvent sentEvent)
        {
            Console.WriteLine($"Message sent to: {sentEvent.To}");
        }
        else if (webhookEvent is MessageIncomingEvent incomingEvent)
        {
            Console.WriteLine($"Message received from: {incomingEvent.From}");
        }
    }
    else
    {
        Console.WriteLine("Invalid signature");
    }
}

Step-by-Step MMS Workflow

// Step 1: Get a signed URL for uploading
var uploadResponse = await ccai.MMS.GetSignedUploadUrlAsync(
    fileName: "image.jpg",
    fileType: "image/jpeg"
);

var signedUrl = uploadResponse.SignedS3Url;
var fileKey = uploadResponse.FileKey;

// Step 2: Upload the image to the signed URL
var uploadSuccess = await ccai.MMS.UploadImageToSignedUrlAsync(
    signedUrl: signedUrl,
    filePath: "path/to/your/image.jpg",
    contentType: "image/jpeg"
);

if (uploadSuccess)
{
    // Step 3: Send the MMS with the uploaded image
    var response = await ccai.MMS.SendAsync(
        pictureFileKey: fileKey,
        accounts: accounts,
        message: "Hello ${FirstName}, check out this image!",
        title: "MMS Campaign Example"
    );
    
    Console.WriteLine($"MMS sent! Campaign ID: {response.CampaignId}");
}

With Progress Tracking

// Create options with progress tracking
var options = new SMSOptions
{
    Timeout = 60,
    Retries = 3,
    OnProgress = status => Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {status}")
};

// Send SMS with progress tracking
var response = await ccai.SMS.SendAsync(
    accounts: accounts,
    message: message,
    title: title,
    options: options
);

Synchronous API

// Send a single SMS synchronously
var response = ccai.SMS.SendSingle(
    firstName: "John",
    lastName: "Doe",
    phone: "+15551234567",
    message: "Hello ${FirstName}, this is a test message!",
    title: "Test Campaign"
);

// Send a single MMS synchronously
var mmsResponse = ccai.MMS.SendSingle(
    pictureFileKey: "your-client-id/campaign/image.jpg",
    firstName: "John",
    lastName: "Doe",
    phone: "+15551234567",
    message: "Hello ${FirstName}, check out this image!",
    title: "MMS Campaign"
);

// Send a single email synchronously
var emailResponse = ccai.Email.SendSingle(
    firstName: "John",
    lastName: "Doe",
    email: "john@example.com",
    subject: "Welcome to Our Service",
    message: "<p>Hello ${FirstName},</p><p>Thank you for signing up!</p>",
    senderEmail: "noreply@yourcompany.com",
    replyEmail: "support@yourcompany.com",
    senderName: "Your Company",
    title: "Welcome Email"
);

License

This project is licensed under the MIT License - see the LICENSE file for details.

Testing Webhook Installation

Step 1: Install Ngrok

brew install ngrok

Step 2: Verify Ngrok

ngrok version

Step 3: Start the standalone webhook server

Open a new terminal window and run:

cd /Users/../CCAI.NET/examples/webhook-server
dotnet run

This will start a webhook server on http://localhost:3000

Step 4: In another terminal, start ngrok

Open another terminal window and run:

ngrok http 3000

This will create a public tunnel to your local webhook server.

If you have not signed up for ngrok, you will need to:

ERROR: Sign up for an account: https://dashboard.ngrok.com/signup
ERROR: Install your authtoken: https://dashboard.ngrok.com/get-started/your-authtoken

Step 5: Get your ngrok URL

ngrok will display something like:

Forwarding    https://abc123.ngrok.io -> http://localhost:3000

Copy that https://abc123.ngrok.io URL - this is your public webhook URL.

Example: https://81dbae920588.ngrok-free.app

Step 6: Configure CCAI with your Ngrok URL

  1. Log in to your CCAI account
  2. Navigate to the Settings\Integration tab
  3. Specify your ngrok url + '/webhook'

SMS Callbacks:

  • Call this URL when an inbound message is received: https://81dbae920588.ngrok-free.app/webhook
  • Call this URL after an outbound message has been delivered: https://81dbae920588.ngrok-free.app/webhook

Step 7: Send a test SMS to trigger webhook

cd /Users/../CCAI.NET/examples
dotnet run

Step 8: The Web server should receive the delivery notification

Press Ctrl+C to stop the server

info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:3000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/j../CCAI.NET/examples/webhook-server
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 POST http://81dbae920588.ngrok-free.app/webhook - application/json 175
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'HTTP: POST /webhook'
Received webhook event at /webhook path!
Headers:
  Accept: application/json, application/*+json
  Host: 81dbae920588.ngrok-free.app
  User-Agent: Java/14-ea
  Accept-Encoding: gzip
  Content-Type: application/json
  Content-Length: 175
  X-Forwarded-For: 157.245.236.180
  X-Forwarded-Host: 81dbae920588.ngrok-free.app
  X-Forwarded-Proto: https
Body:
{"message":"Hello John! We are testing the CCAI SMS functionality with the webhooks","segments":1,"smsSid":141321,"messageStatus":"SENT","totalPrice":0.03,"to":"+1XXXYYYZZZZ"}
info: Microsoft.AspNetCore.Http.Result.OkObjectResult[1]
      Setting HTTP status code 200.
info: Microsoft.AspNetCore.Http.Result.OkObjectResult[3]
      Writing value of type 'String' as Json.
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'HTTP: POST /webhook'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 POST http://81dbae920588.ngrok-free.app/webhook - 200 - application/json;+charset=utf-8 137.6141ms

Step 9: From your phone, respond to the message

On your mobile phone, respond to the message that was sent to you by CCAI

Step 10: Web Server should receive the response notification

Received webhook event at /webhook path!
Headers:
  Accept: text/plain, application/json, application/*+json, */*
  Host: 81dbae920588.ngrok-free.app
  User-Agent: Java/14-ea
  Accept-Encoding: gzip
  Content-Type: application/json
  Content-Length: 204
  X-Forwarded-For: 157.245.236.180
  X-Forwarded-Host: 81dbae920588.ngrok-free.app
  X-Forwarded-Proto: https
Body:
{"campaign":{"id":141293,"title":"Default Campaign","message":"","senderPhone":null,"createdAt":"2025-08-13T21:20:50.212623Z","runAt":"null"},"from":"+1XXXYYYZZZZ","to":"+14158735045","message":"Rockin "}
info: Microsoft.AspNetCore.Http.Result.OkObjectResult[1]
      Setting HTTP status code 200.
info: Microsoft.AspNetCore.Http.Result.OkObjectResult[3]
      Writing value of type 'String' as Json.
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'HTTP: POST /webhook'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 POST http://81dbae920588.ngrok-free.app/webhook - 200 - application/json;+charset=utf-8 3.7664ms

This demonstrates a complete webhook testing workflow where:

  1. Outbound SMS messages trigger delivery notifications
  2. Inbound SMS responses trigger message received notifications
  3. All webhook events are captured and logged by your local webhook server
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.4.3 93 9/5/2025
1.4.2 156 9/4/2025
1.4.1 130 9/3/2025
1.4.0 122 9/3/2025
1.3.0 181 8/27/2025
1.2.0 140 8/14/2025
1.1.0 136 8/14/2025
1.0.0 274 6/9/2025

# CCAI.NET v1.4.0 Release Notes - [CloudContactAI](https://cloudcontactai.com/)

## 🚀 New Features

### Enhanced Webhook Support
- **New CloudContact Webhook Format**: Added support for the new CloudContact webhook event structure with 5 event types:
 - `message.sent` - Message successfully sent to recipient
 - `message.incoming` - Incoming message from recipient
 - `message.excluded` - Message excluded during campaign creation
 - `message.error.carrier` - Carrier-level delivery errors
 - `message.error.cloudcontact` - CloudContact system errors

- **New Webhook Classes**:
 - `CloudContactWebhookEvent` - Main webhook event wrapper
 - `WebhookEventData` - Comprehensive event data with pricing, segments, and error details
 - Enhanced `WebhookService` with `ParseCloudContactEvent()` method

### Updated Event Types
- **Breaking Change**: Renamed `MessageReceived` to `MessageIncoming` for consistency
- **Legacy Support**: Maintained backward compatibility with existing webhook implementations
- **New Event Classes**: Added `MessageIncomingEvent` to replace deprecated `MessageReceivedEvent`

## 🔧 Improvements

### Environment Variable Support
- **BasicExample**: Now loads `ClientId`, `ApiKey`, `FirstName`, `LastName`, and `Phone` from environment variables
- **Flexible Configuration**: Falls back to sensible defaults when environment variables are not set

### Code Quality
- **Cleaned Examples**: Removed 18+ redundant example files for better maintainability
- **Fixed Build Warnings**: Resolved all unreachable code and entry point conflicts
- **Improved Structure**: Streamlined examples directory with 10 core, comprehensive examples

## 📝 Enhanced Examples

### New Webhook Examples
- **webhook_cloudcontact_example.cs**: Demonstrates parsing new CloudContact webhook format
- **webhook_endpoint_example.cs**: Production-ready ASP.NET Core webhook controller
- **Enhanced webhook server**: Updated with emoji indicators and event-specific processing

### Updated Examples
- **BasicExample.cs**: Environment variable integration for account data
- **WebhookExample.cs**: Updated to use new `MessageIncoming` event type
- All webhook registration examples updated with new event types

## 🛠️ Technical Changes

### Webhook Service Enhancements
```csharp
// New method for parsing CloudContact webhooks
public CloudContactWebhookEvent? ParseCloudContactEvent(string json)

// Enhanced event data with new properties
public record WebhookEventData
{
   public decimal? TotalPrice { get; init; }
   public int? Segments { get; init; }
   public string? ExcludedReason { get; init; }
   public string? ErrorCode { get; init; }
   public string? ErrorMessage { get; init; }
   // ... and more
}
```

### Environment Variables
- `CCAI_CLIENT_ID` - Your CloudContact client ID
- `CCAI_API_KEY` - Your CloudContact API key
- `CCAI_FIRST_NAME` - Test recipient first name (optional)
- `CCAI_LAST_NAME` - Test recipient last name (optional)
- `CCAI_PHONE` - Test recipient phone number (optional)

## 🔄 Migration Guide

### Webhook Event Types
```csharp
// Old (deprecated)
WebhookEventType.MessageReceived

// New
WebhookEventType.MessageIncoming
```

### Webhook Event Classes
```csharp
// Old (deprecated)
MessageReceivedEvent receivedEvent

// New
MessageIncomingEvent incomingEvent
```

## 📦 Dependencies
- No new dependencies added
- Maintained compatibility with .NET 8.0
- DotNetEnv package already included for environment variable support

## 🐛 Bug Fixes
- Fixed build warnings related to unreachable code
- Resolved entry point conflicts in examples project
- Fixed webhook event type references in all examples

---

**Full Changelog**: Compare changes from v1.3.0 to v1.4.0 for complete details.