use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum MessageStatus {
Queued,
Sent,
Delivered,
Failed,
Bounced,
Retrying,
}
impl std::fmt::Display for MessageStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MessageStatus::Queued => write!(f, "queued"),
MessageStatus::Sent => write!(f, "sent"),
MessageStatus::Delivered => write!(f, "delivered"),
MessageStatus::Failed => write!(f, "failed"),
MessageStatus::Bounced => write!(f, "bounced"),
MessageStatus::Retrying => write!(f, "retrying"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum MessageDirection {
Outbound,
Inbound,
}
impl Default for MessageDirection {
fn default() -> Self {
MessageDirection::Outbound
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SenderType {
User,
Api,
System,
Campaign,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
pub id: String,
pub to: String,
#[serde(default)]
pub from: Option<String>,
pub text: String,
pub status: MessageStatus,
#[serde(default)]
pub direction: MessageDirection,
#[serde(default = "default_segments")]
pub segments: i32,
#[serde(default, alias = "creditsUsed")]
pub credits_used: i32,
#[serde(default, alias = "isSandbox")]
pub is_sandbox: bool,
#[serde(default, alias = "senderType")]
pub sender_type: Option<SenderType>,
#[serde(default, alias = "telnyxMessageId")]
pub telnyx_message_id: Option<String>,
#[serde(default)]
pub warning: Option<String>,
#[serde(default, alias = "senderNote")]
pub sender_note: Option<String>,
#[serde(default)]
pub error: Option<String>,
#[serde(default, alias = "errorCode")]
pub error_code: Option<String>,
#[serde(default, alias = "errorMessage")]
pub error_message: Option<String>,
#[serde(default, alias = "retryCount")]
pub retry_count: i32,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
#[serde(default, alias = "updatedAt")]
pub updated_at: Option<String>,
#[serde(default, alias = "deliveredAt")]
pub delivered_at: Option<String>,
#[serde(default)]
pub metadata: Option<std::collections::HashMap<String, serde_json::Value>>,
#[serde(default, rename = "aiMetadata")]
pub ai_metadata: Option<AiMetadata>,
}
fn default_segments() -> i32 {
1
}
impl Message {
pub fn is_delivered(&self) -> bool {
self.status == MessageStatus::Delivered
}
pub fn is_failed(&self) -> bool {
self.status == MessageStatus::Failed
}
pub fn is_pending(&self) -> bool {
matches!(self.status, MessageStatus::Queued | MessageStatus::Sent)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AiMetadata {
pub intent: String,
#[serde(rename = "intentConfidence")]
pub intent_confidence: f64,
pub sentiment: String,
#[serde(rename = "sentimentConfidence")]
pub sentiment_confidence: f64,
#[serde(rename = "classifiedAt")]
pub classified_at: String,
pub model: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum MessageType {
Marketing,
Transactional,
}
impl std::fmt::Display for MessageType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MessageType::Marketing => write!(f, "marketing"),
MessageType::Transactional => write!(f, "transactional"),
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct SendMessageRequest {
pub to: String,
pub text: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "messageType")]
pub message_type: Option<MessageType>,
#[serde(skip_serializing_if = "Option::is_none", rename = "mediaUrls")]
pub media_urls: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<std::collections::HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MediaFile {
pub id: String,
pub url: String,
#[serde(rename = "contentType")]
pub content_type: String,
#[serde(rename = "sizeBytes")]
pub size_bytes: i64,
}
#[derive(Debug, Clone, Default)]
pub struct ListMessagesOptions {
pub limit: Option<u32>,
pub offset: Option<u32>,
pub status: Option<MessageStatus>,
pub to: Option<String>,
}
impl ListMessagesOptions {
pub fn new() -> Self {
Self::default()
}
pub fn limit(mut self, limit: u32) -> Self {
self.limit = Some(limit.min(100));
self
}
pub fn offset(mut self, offset: u32) -> Self {
self.offset = Some(offset);
self
}
pub fn status(mut self, status: MessageStatus) -> Self {
self.status = Some(status);
self
}
pub fn to(mut self, to: impl Into<String>) -> Self {
self.to = Some(to.into());
self
}
pub(crate) fn to_query_params(&self) -> Vec<(String, String)> {
let mut params = Vec::new();
if let Some(limit) = self.limit {
params.push(("limit".to_string(), limit.to_string()));
}
if let Some(offset) = self.offset {
params.push(("offset".to_string(), offset.to_string()));
}
if let Some(ref status) = self.status {
params.push(("status".to_string(), status.to_string()));
}
if let Some(ref to) = self.to {
params.push(("to".to_string(), to.clone()));
}
params
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct MessageList {
pub data: Vec<Message>,
#[serde(default)]
pub count: i32,
}
impl MessageList {
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn total(&self) -> i32 {
self.count
}
pub fn first(&self) -> Option<&Message> {
self.data.first()
}
pub fn last(&self) -> Option<&Message> {
self.data.last()
}
pub fn iter(&self) -> impl Iterator<Item = &Message> {
self.data.iter()
}
}
impl IntoIterator for MessageList {
type Item = Message;
type IntoIter = std::vec::IntoIter<Message>;
fn into_iter(self) -> Self::IntoIter {
self.data.into_iter()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ScheduledMessageStatus {
Scheduled,
Sent,
Cancelled,
Failed,
}
impl std::fmt::Display for ScheduledMessageStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ScheduledMessageStatus::Scheduled => write!(f, "scheduled"),
ScheduledMessageStatus::Sent => write!(f, "sent"),
ScheduledMessageStatus::Cancelled => write!(f, "cancelled"),
ScheduledMessageStatus::Failed => write!(f, "failed"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScheduledMessage {
pub id: String,
pub to: String,
#[serde(default)]
pub from: Option<String>,
pub text: String,
#[serde(alias = "scheduledAt")]
pub scheduled_at: String,
pub status: ScheduledMessageStatus,
#[serde(default, alias = "creditsReserved")]
pub credits_reserved: i32,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
#[serde(default, alias = "sentAt")]
pub sent_at: Option<String>,
#[serde(default, alias = "cancelledAt")]
pub cancelled_at: Option<String>,
#[serde(default, alias = "messageId")]
pub message_id: Option<String>,
}
impl ScheduledMessage {
pub fn is_scheduled(&self) -> bool {
self.status == ScheduledMessageStatus::Scheduled
}
pub fn is_sent(&self) -> bool {
self.status == ScheduledMessageStatus::Sent
}
pub fn is_cancelled(&self) -> bool {
self.status == ScheduledMessageStatus::Cancelled
}
}
#[derive(Debug, Clone, Serialize)]
pub struct ScheduleMessageRequest {
pub to: String,
pub text: String,
#[serde(rename = "scheduledAt")]
pub scheduled_at: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub from: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "messageType")]
pub message_type: Option<MessageType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<std::collections::HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Default)]
pub struct ListScheduledMessagesOptions {
pub limit: Option<u32>,
pub offset: Option<u32>,
pub status: Option<ScheduledMessageStatus>,
}
impl ListScheduledMessagesOptions {
pub fn new() -> Self {
Self::default()
}
pub fn limit(mut self, limit: u32) -> Self {
self.limit = Some(limit.min(100));
self
}
pub fn offset(mut self, offset: u32) -> Self {
self.offset = Some(offset);
self
}
pub fn status(mut self, status: ScheduledMessageStatus) -> Self {
self.status = Some(status);
self
}
pub(crate) fn to_query_params(&self) -> Vec<(String, String)> {
let mut params = Vec::new();
if let Some(limit) = self.limit {
params.push(("limit".to_string(), limit.to_string()));
}
if let Some(offset) = self.offset {
params.push(("offset".to_string(), offset.to_string()));
}
if let Some(ref status) = self.status {
params.push(("status".to_string(), status.to_string()));
}
params
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct ScheduledMessageList {
pub data: Vec<ScheduledMessage>,
#[serde(default)]
pub count: i32,
}
impl ScheduledMessageList {
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn total(&self) -> i32 {
self.count
}
}
impl IntoIterator for ScheduledMessageList {
type Item = ScheduledMessage;
type IntoIter = std::vec::IntoIter<ScheduledMessage>;
fn into_iter(self) -> Self::IntoIter {
self.data.into_iter()
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct CancelScheduledMessageResponse {
pub id: String,
pub status: ScheduledMessageStatus,
#[serde(default, alias = "creditsRefunded")]
pub credits_refunded: i32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BatchStatus {
Processing,
Completed,
PartialFailure,
Failed,
}
impl std::fmt::Display for BatchStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BatchStatus::Processing => write!(f, "processing"),
BatchStatus::Completed => write!(f, "completed"),
BatchStatus::PartialFailure => write!(f, "partial_failure"),
BatchStatus::Failed => write!(f, "failed"),
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct BatchMessageItem {
pub to: String,
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<std::collections::HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Serialize)]
pub struct SendBatchRequest {
pub messages: Vec<BatchMessageItem>,
#[serde(skip_serializing_if = "Option::is_none")]
pub from: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "messageType")]
pub message_type: Option<MessageType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<std::collections::HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BatchMessageResult {
#[serde(default)]
pub id: Option<String>,
pub to: String,
pub status: String,
#[serde(default)]
pub error: Option<String>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
#[serde(default, alias = "deliveredAt")]
pub delivered_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BatchMessageResponse {
#[serde(alias = "batchId")]
pub batch_id: String,
pub status: BatchStatus,
pub total: i32,
pub queued: i32,
pub sent: i32,
pub failed: i32,
#[serde(default, alias = "creditsUsed")]
pub credits_used: i32,
#[serde(default)]
pub messages: Vec<BatchMessageResult>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
#[serde(default, alias = "completedAt")]
pub completed_at: Option<String>,
}
impl BatchMessageResponse {
pub fn is_processing(&self) -> bool {
self.status == BatchStatus::Processing
}
pub fn is_completed(&self) -> bool {
self.status == BatchStatus::Completed
}
pub fn is_failed(&self) -> bool {
self.status == BatchStatus::Failed
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchPreviewItem {
pub to: String,
pub text: String,
#[serde(default = "default_segments")]
pub segments: i32,
#[serde(default)]
pub credits: i32,
#[serde(default, alias = "canSend")]
pub can_send: bool,
#[serde(default, alias = "blockReason")]
pub block_reason: Option<String>,
#[serde(default)]
pub country: Option<String>,
#[serde(default, alias = "pricingTier")]
pub pricing_tier: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchPreviewResponse {
#[serde(alias = "canSend")]
pub can_send: bool,
#[serde(default, alias = "totalMessages")]
pub total_messages: i32,
#[serde(default, alias = "willSend")]
pub will_send: i32,
#[serde(default)]
pub blocked: i32,
#[serde(default, alias = "creditsNeeded")]
pub credits_needed: i32,
#[serde(default, alias = "currentBalance")]
pub current_balance: i32,
#[serde(default, alias = "hasEnoughCredits")]
pub has_enough_credits: bool,
#[serde(default)]
pub messages: Vec<BatchPreviewItem>,
#[serde(default, alias = "blockReasons")]
pub block_reasons: Option<std::collections::HashMap<String, i32>>,
}
#[derive(Debug, Clone, Default)]
pub struct ListBatchesOptions {
pub limit: Option<u32>,
pub offset: Option<u32>,
pub status: Option<BatchStatus>,
}
impl ListBatchesOptions {
pub fn new() -> Self {
Self::default()
}
pub fn limit(mut self, limit: u32) -> Self {
self.limit = Some(limit.min(100));
self
}
pub fn offset(mut self, offset: u32) -> Self {
self.offset = Some(offset);
self
}
pub fn status(mut self, status: BatchStatus) -> Self {
self.status = Some(status);
self
}
pub(crate) fn to_query_params(&self) -> Vec<(String, String)> {
let mut params = Vec::new();
if let Some(limit) = self.limit {
params.push(("limit".to_string(), limit.to_string()));
}
if let Some(offset) = self.offset {
params.push(("offset".to_string(), offset.to_string()));
}
if let Some(ref status) = self.status {
params.push(("status".to_string(), status.to_string()));
}
params
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct BatchList {
pub data: Vec<BatchMessageResponse>,
#[serde(default)]
pub count: i32,
}
impl BatchList {
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn total(&self) -> i32 {
self.count
}
}
impl IntoIterator for BatchList {
type Item = BatchMessageResponse;
type IntoIter = std::vec::IntoIter<BatchMessageResponse>;
fn into_iter(self) -> Self::IntoIter {
self.data.into_iter()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CircuitState {
Closed,
Open,
HalfOpen,
}
impl Default for CircuitState {
fn default() -> Self {
CircuitState::Closed
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum WebhookMode {
All,
Test,
Live,
}
impl Default for WebhookMode {
fn default() -> Self {
WebhookMode::All
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Webhook {
pub id: String,
pub url: String,
#[serde(default)]
pub events: Vec<String>,
#[serde(default)]
pub mode: WebhookMode,
#[serde(default = "default_true", alias = "isActive")]
pub is_active: bool,
#[serde(default, alias = "failureCount")]
pub failure_count: i32,
#[serde(default, alias = "circuitState")]
pub circuit_state: CircuitState,
#[serde(default, alias = "apiVersion")]
pub api_version: Option<String>,
#[serde(default, alias = "totalDeliveries")]
pub total_deliveries: i32,
#[serde(default, alias = "successfulDeliveries")]
pub successful_deliveries: i32,
#[serde(default, alias = "successRate")]
pub success_rate: f64,
#[serde(default, alias = "lastDeliveryAt")]
pub last_delivery_at: Option<String>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
#[serde(default, alias = "updatedAt")]
pub updated_at: Option<String>,
}
fn default_true() -> bool {
true
}
impl Webhook {
pub fn is_healthy(&self) -> bool {
self.is_active && self.circuit_state == CircuitState::Closed
}
pub fn is_circuit_open(&self) -> bool {
self.circuit_state == CircuitState::Open
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct WebhookCreatedResponse {
#[serde(default)]
pub webhook: Option<Webhook>,
#[serde(default)]
pub secret: String,
#[serde(flatten)]
pub data: Option<Webhook>,
}
impl WebhookCreatedResponse {
pub fn get_webhook(&self) -> Option<&Webhook> {
self.webhook.as_ref().or(self.data.as_ref())
}
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateWebhookRequest {
pub url: String,
pub events: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<WebhookMode>,
#[serde(skip_serializing_if = "Option::is_none", rename = "apiVersion")]
pub api_version: Option<String>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct UpdateWebhookRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub events: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none", rename = "is_active")]
pub is_active: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<WebhookMode>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebhookDelivery {
pub id: String,
#[serde(alias = "webhookId")]
pub webhook_id: String,
#[serde(alias = "eventType")]
pub event_type: String,
#[serde(default, alias = "httpStatus")]
pub http_status: i32,
#[serde(default)]
pub success: bool,
#[serde(default = "default_one", alias = "attemptNumber")]
pub attempt_number: i32,
#[serde(default, alias = "errorMessage")]
pub error_message: Option<String>,
#[serde(default, alias = "responseTimeMs")]
pub response_time_ms: i32,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
}
fn default_one() -> i32 {
1
}
#[derive(Debug, Clone, Deserialize)]
pub struct WebhookDeliveryList {
#[serde(default, alias = "deliveries")]
pub data: Vec<WebhookDelivery>,
#[serde(default)]
pub total: i32,
#[serde(default, alias = "hasMore")]
pub has_more: bool,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WebhookTestResult {
#[serde(default)]
pub success: bool,
#[serde(default, alias = "statusCode")]
pub status_code: i32,
#[serde(default, alias = "responseTimeMs")]
pub response_time_ms: i32,
#[serde(default)]
pub error: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WebhookSecretRotation {
#[serde(default)]
pub secret: String,
#[serde(default, alias = "rotatedAt")]
pub rotated_at: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub struct ListDeliveriesOptions {
pub limit: Option<u32>,
pub offset: Option<u32>,
}
impl ListDeliveriesOptions {
pub fn new() -> Self {
Self::default()
}
pub fn limit(mut self, limit: u32) -> Self {
self.limit = Some(limit.min(100));
self
}
pub fn offset(mut self, offset: u32) -> Self {
self.offset = Some(offset);
self
}
pub(crate) fn to_query_params(&self) -> Vec<(String, String)> {
let mut params = Vec::new();
if let Some(limit) = self.limit {
params.push(("limit".to_string(), limit.to_string()));
}
if let Some(offset) = self.offset {
params.push(("offset".to_string(), offset.to_string()));
}
params
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct Credits {
#[serde(default)]
pub balance: i32,
#[serde(default, alias = "availableBalance")]
pub available_balance: i32,
#[serde(default, alias = "pendingCredits")]
pub pending_credits: i32,
#[serde(default, alias = "reservedCredits")]
pub reserved_credits: i32,
#[serde(default = "default_currency")]
pub currency: String,
}
fn default_currency() -> String {
"USD".to_string()
}
impl Credits {
pub fn has_credits(&self) -> bool {
self.available_balance > 0
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TransactionType {
Purchase,
Usage,
Refund,
Bonus,
Adjustment,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreditTransaction {
pub id: String,
#[serde(rename = "type")]
pub transaction_type: TransactionType,
#[serde(default)]
pub amount: i32,
#[serde(default, alias = "balanceAfter")]
pub balance_after: i32,
#[serde(default)]
pub description: Option<String>,
#[serde(default, alias = "referenceId")]
pub reference_id: Option<String>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
}
impl CreditTransaction {
pub fn is_credit(&self) -> bool {
self.amount > 0
}
pub fn is_debit(&self) -> bool {
self.amount < 0
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreditTransactionList {
#[serde(default, alias = "transactions")]
pub data: Vec<CreditTransaction>,
#[serde(default)]
pub total: i32,
#[serde(default, alias = "hasMore")]
pub has_more: bool,
}
#[derive(Debug, Clone, Default)]
pub struct ListTransactionsOptions {
pub limit: Option<u32>,
pub offset: Option<u32>,
pub transaction_type: Option<TransactionType>,
}
impl ListTransactionsOptions {
pub fn new() -> Self {
Self::default()
}
pub fn limit(mut self, limit: u32) -> Self {
self.limit = Some(limit.min(100));
self
}
pub fn offset(mut self, offset: u32) -> Self {
self.offset = Some(offset);
self
}
pub fn transaction_type(mut self, t: TransactionType) -> Self {
self.transaction_type = Some(t);
self
}
pub(crate) fn to_query_params(&self) -> Vec<(String, String)> {
let mut params = Vec::new();
if let Some(limit) = self.limit {
params.push(("limit".to_string(), limit.to_string()));
}
if let Some(offset) = self.offset {
params.push(("offset".to_string(), offset.to_string()));
}
if let Some(ref t) = self.transaction_type {
let type_str = match t {
TransactionType::Purchase => "purchase",
TransactionType::Usage => "usage",
TransactionType::Refund => "refund",
TransactionType::Bonus => "bonus",
TransactionType::Adjustment => "adjustment",
};
params.push(("type".to_string(), type_str.to_string()));
}
params
}
}
#[derive(Debug, Clone, Serialize)]
pub struct TransferCreditsRequest {
#[serde(rename = "targetOrganizationId")]
pub target_organization_id: String,
pub amount: i32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct TransferCreditsResponse {
pub success: bool,
pub amount: i32,
#[serde(alias = "sourceBalance")]
pub source_balance: i32,
#[serde(alias = "targetBalance")]
pub target_balance: i32,
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct ApiKey {
pub id: String,
#[serde(default)]
pub name: String,
#[serde(default)]
pub prefix: String,
#[serde(default, alias = "lastUsedAt")]
pub last_used_at: Option<String>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
#[serde(default, alias = "expiresAt")]
pub expires_at: Option<String>,
#[serde(default = "default_true", alias = "isActive")]
pub is_active: bool,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreateApiKeyResponse {
#[serde(default, alias = "apiKey")]
pub api_key: Option<ApiKey>,
#[serde(default)]
pub key: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateApiKeyRequest {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "expires_at")]
pub expires_at: Option<String>,
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct AccountVerification {
#[serde(default, alias = "emailVerified")]
pub email_verified: bool,
#[serde(default, alias = "phoneVerified")]
pub phone_verified: bool,
#[serde(default, alias = "identityVerified")]
pub identity_verified: bool,
}
impl AccountVerification {
pub fn is_fully_verified(&self) -> bool {
self.email_verified && self.phone_verified && self.identity_verified
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct AccountLimits {
#[serde(default = "default_mps", alias = "messagesPerSecond")]
pub messages_per_second: i32,
#[serde(default = "default_mpd", alias = "messagesPerDay")]
pub messages_per_day: i32,
#[serde(default = "default_batch", alias = "maxBatchSize")]
pub max_batch_size: i32,
}
fn default_mps() -> i32 {
10
}
fn default_mpd() -> i32 {
10000
}
fn default_batch() -> i32 {
1000
}
impl Default for AccountLimits {
fn default() -> Self {
Self {
messages_per_second: 10,
messages_per_day: 10000,
max_batch_size: 1000,
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct Account {
pub id: String,
#[serde(default)]
pub email: String,
#[serde(default)]
pub name: Option<String>,
#[serde(default, alias = "companyName")]
pub company_name: Option<String>,
#[serde(default)]
pub verification: AccountVerification,
#[serde(default)]
pub limits: AccountLimits,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct EnterpriseWorkspaceSummary {
pub id: String,
#[serde(default)]
pub name: String,
#[serde(default)]
pub slug: String,
#[serde(default, alias = "verificationStatus")]
pub verification_status: Option<String>,
#[serde(default, alias = "verificationType")]
pub verification_type: Option<String>,
#[serde(default, alias = "tollFreeNumber")]
pub toll_free_number: Option<String>,
#[serde(default, alias = "creditBalance")]
pub credit_balance: i64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct EnterpriseAccount {
pub id: String,
#[serde(default, alias = "maxWorkspaces")]
pub max_workspaces: i32,
#[serde(default, alias = "workspaceCount")]
pub workspace_count: i32,
#[serde(default)]
pub workspaces: Vec<EnterpriseWorkspaceSummary>,
#[serde(default)]
pub metadata: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateWorkspaceRequest {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
impl CreateWorkspaceRequest {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
description: None,
}
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct EnterpriseWorkspace {
pub id: String,
#[serde(default)]
pub name: String,
#[serde(default)]
pub slug: String,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct EnterpriseWorkspaceVerification {
#[serde(default)]
pub status: String,
#[serde(default, rename = "type")]
pub verification_type: Option<String>,
#[serde(default, alias = "tollFreeNumber")]
pub toll_free_number: Option<String>,
#[serde(default, alias = "businessName")]
pub business_name: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct EnterpriseWorkspaceDetail {
pub id: String,
#[serde(default)]
pub name: String,
#[serde(default)]
pub slug: String,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
#[serde(default)]
pub verification: Option<EnterpriseWorkspaceVerification>,
#[serde(default)]
pub credits: i64,
#[serde(default, alias = "keyCount")]
pub key_count: i32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DeleteWorkspaceResponse {
#[serde(default)]
pub success: bool,
#[serde(default, alias = "deletedId")]
pub deleted_id: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct SubmitVerificationRequest {
#[serde(rename = "businessName")]
pub business_name: String,
pub website: String,
pub address: VerificationAddress,
pub contact: VerificationContact,
#[serde(rename = "useCase")]
pub use_case: String,
#[serde(rename = "useCaseSummary")]
pub use_case_summary: String,
#[serde(rename = "sampleMessages")]
pub sample_messages: String,
#[serde(rename = "optInWorkflow")]
pub opt_in_workflow: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "doingBusinessAs")]
pub doing_business_as: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub brn: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "brnType")]
pub brn_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "brnCountry")]
pub brn_country: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "optInImageUrls")]
pub opt_in_image_urls: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none", rename = "monthlyVolume")]
pub monthly_volume: Option<String>,
#[serde(
skip_serializing_if = "Option::is_none",
rename = "additionalInformation"
)]
pub additional_information: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "ageGatedContent")]
pub age_gated_content: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "isvReseller")]
pub isv_reseller: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "privacyUrl")]
pub privacy_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "termsUrl")]
pub terms_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "entityType")]
pub entity_type: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct VerificationAddress {
pub street: String,
pub city: String,
pub state: String,
pub zip: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub country: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub address2: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct VerificationContact {
#[serde(rename = "firstName")]
pub first_name: String,
#[serde(rename = "lastName")]
pub last_name: String,
pub email: String,
pub phone: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SubmitVerificationResponse {
#[serde(default, alias = "verificationId")]
pub verification_id: Option<String>,
#[serde(default)]
pub status: String,
#[serde(default, alias = "tollFreeNumber")]
pub toll_free_number: Option<String>,
#[serde(default, alias = "businessName")]
pub business_name: Option<String>,
#[serde(default, alias = "telnyxProfileId")]
pub telnyx_profile_id: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct InheritVerificationRequest {
#[serde(rename = "sourceWorkspaceId")]
pub source_workspace_id: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct InheritVerificationResponse {
#[serde(default, alias = "verificationId")]
pub verification_id: Option<String>,
#[serde(default)]
pub status: String,
#[serde(default, rename = "type")]
pub verification_type: Option<String>,
#[serde(default, alias = "tollFreeNumber")]
pub toll_free_number: Option<String>,
#[serde(default, alias = "inheritedFrom")]
pub inherited_from: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WorkspaceVerificationStatus {
#[serde(default)]
pub status: String,
#[serde(default, alias = "verificationId")]
pub verification_id: Option<String>,
#[serde(default, rename = "type")]
pub verification_type: Option<String>,
#[serde(default, alias = "tollFreeNumber")]
pub toll_free_number: Option<String>,
#[serde(default, alias = "businessName")]
pub business_name: Option<String>,
#[serde(default, alias = "submittedAt")]
pub submitted_at: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct WorkspaceTransferCreditsRequest {
#[serde(rename = "sourceWorkspaceId")]
pub source_workspace_id: String,
pub amount: i32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WorkspaceTransferCreditsResponse {
#[serde(default)]
pub success: bool,
#[serde(default)]
pub amount: i32,
#[serde(default, alias = "sourceBalance")]
pub source_balance: i64,
#[serde(default, alias = "targetBalance")]
pub target_balance: i64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WorkspaceCredits {
#[serde(default)]
pub balance: i64,
#[serde(default, alias = "lifetimeCredits")]
pub lifetime_credits: i64,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateWorkspaceKeyRequest {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "type")]
pub key_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scopes: Option<Vec<String>>,
}
impl CreateWorkspaceKeyRequest {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
key_type: None,
scopes: None,
}
}
pub fn key_type(mut self, key_type: impl Into<String>) -> Self {
self.key_type = Some(key_type.into());
self
}
pub fn scopes(mut self, scopes: Vec<impl Into<String>>) -> Self {
self.scopes = Some(scopes.into_iter().map(|s| s.into()).collect());
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct WorkspaceKeyResponse {
pub id: String,
#[serde(default)]
pub name: String,
#[serde(default)]
pub key: String,
#[serde(default, alias = "keyPrefix")]
pub key_prefix: String,
#[serde(default, rename = "type")]
pub key_type: String,
#[serde(default)]
pub scopes: Vec<String>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WorkspaceKey {
pub id: String,
#[serde(default)]
pub name: String,
#[serde(default, alias = "keyPrefix")]
pub key_prefix: String,
#[serde(default, rename = "type")]
pub key_type: String,
#[serde(default)]
pub scopes: Vec<String>,
#[serde(default, alias = "lastUsedAt")]
pub last_used_at: Option<String>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct RevokeKeyResponse {
#[serde(default)]
pub success: bool,
#[serde(default, alias = "revokedId")]
pub revoked_id: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct ProvisionWorkspaceRequest {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "sourceWorkspaceId")]
pub source_workspace_id: Option<String>,
#[serde(
skip_serializing_if = "Option::is_none",
rename = "inheritWithNewNumber"
)]
pub inherit_with_new_number: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub verification: Option<SubmitVerificationRequest>,
#[serde(skip_serializing_if = "Option::is_none", rename = "creditAmount")]
pub credit_amount: Option<i32>,
#[serde(
skip_serializing_if = "Option::is_none",
rename = "creditSourceWorkspaceId"
)]
pub credit_source_workspace_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "keyName")]
pub key_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "keyType")]
pub key_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "webhookUrl")]
pub webhook_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "generateOptInPage")]
pub generate_opt_in_page: Option<bool>,
}
impl ProvisionWorkspaceRequest {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
source_workspace_id: None,
inherit_with_new_number: None,
verification: None,
credit_amount: None,
credit_source_workspace_id: None,
key_name: None,
key_type: None,
webhook_url: None,
generate_opt_in_page: None,
}
}
pub fn source_workspace_id(mut self, id: impl Into<String>) -> Self {
self.source_workspace_id = Some(id.into());
self
}
pub fn key_name(mut self, name: impl Into<String>) -> Self {
self.key_name = Some(name.into());
self
}
pub fn key_type(mut self, key_type: impl Into<String>) -> Self {
self.key_type = Some(key_type.into());
self
}
pub fn webhook_url(mut self, url: impl Into<String>) -> Self {
self.webhook_url = Some(url.into());
self
}
pub fn credit_amount(mut self, amount: i32) -> Self {
self.credit_amount = Some(amount);
self
}
pub fn credit_source_workspace_id(mut self, id: impl Into<String>) -> Self {
self.credit_source_workspace_id = Some(id.into());
self
}
pub fn inherit_with_new_number(mut self, value: bool) -> Self {
self.inherit_with_new_number = Some(value);
self
}
pub fn generate_opt_in_page(mut self, value: bool) -> Self {
self.generate_opt_in_page = Some(value);
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct ProvisionWorkspaceResponse {
#[serde(default)]
pub workspace: Option<EnterpriseWorkspace>,
#[serde(default)]
pub verification: Option<serde_json::Value>,
#[serde(default)]
pub credits: Option<serde_json::Value>,
#[serde(default)]
pub key: Option<serde_json::Value>,
#[serde(default)]
pub webhook: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize)]
pub struct GenerateBusinessPageRequest {
#[serde(rename = "businessName")]
pub business_name: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "useCase")]
pub use_case: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "useCaseSummary")]
pub use_case_summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "contactEmail")]
pub contact_email: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "contactPhone")]
pub contact_phone: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "businessAddress")]
pub business_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "socialUrl")]
pub social_url: Option<String>,
}
impl GenerateBusinessPageRequest {
pub fn new(business_name: impl Into<String>) -> Self {
Self {
business_name: business_name.into(),
use_case: None,
use_case_summary: None,
contact_email: None,
contact_phone: None,
business_address: None,
social_url: None,
}
}
pub fn use_case(mut self, use_case: impl Into<String>) -> Self {
self.use_case = Some(use_case.into());
self
}
pub fn use_case_summary(mut self, summary: impl Into<String>) -> Self {
self.use_case_summary = Some(summary.into());
self
}
pub fn contact_email(mut self, email: impl Into<String>) -> Self {
self.contact_email = Some(email.into());
self
}
pub fn contact_phone(mut self, phone: impl Into<String>) -> Self {
self.contact_phone = Some(phone.into());
self
}
pub fn business_address(mut self, address: impl Into<String>) -> Self {
self.business_address = Some(address.into());
self
}
pub fn social_url(mut self, url: impl Into<String>) -> Self {
self.social_url = Some(url.into());
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct GenerateBusinessPageResponse {
pub slug: String,
pub url: String,
#[serde(alias = "pageId")]
pub page_id: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct VerificationDocumentUploadResponse {
pub url: String,
pub id: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct SetEnterpriseWebhookRequest {
pub url: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct EnterpriseWebhook {
#[serde(default)]
pub url: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct EnterpriseWebhookTestResult {
#[serde(default)]
pub success: bool,
#[serde(default)]
pub message: Option<String>,
#[serde(default, alias = "statusCode")]
pub status_code: Option<i32>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct AnalyticsOverview {
#[serde(default, alias = "totalMessages")]
pub total_messages: i64,
#[serde(default, alias = "deliveredMessages")]
pub delivered_messages: i64,
#[serde(default, alias = "failedMessages")]
pub failed_messages: i64,
#[serde(default, alias = "deliveryRate")]
pub delivery_rate: f64,
#[serde(default, alias = "totalCreditsUsed")]
pub total_credits_used: i64,
#[serde(default, alias = "activeWorkspaces")]
pub active_workspaces: i32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MessageDataPoint {
#[serde(default)]
pub date: String,
#[serde(default)]
pub sent: i64,
#[serde(default)]
pub delivered: i64,
#[serde(default)]
pub failed: i64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MessagesAnalytics {
#[serde(default)]
pub period: String,
#[serde(default)]
pub data: Vec<MessageDataPoint>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DeliveryByWorkspace {
#[serde(default, alias = "workspaceId")]
pub workspace_id: String,
#[serde(default)]
pub name: String,
#[serde(default)]
pub sent: i64,
#[serde(default)]
pub delivered: i64,
#[serde(default)]
pub failed: i64,
#[serde(default)]
pub rate: f64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreditDataPoint {
#[serde(default)]
pub date: String,
#[serde(default)]
pub used: i64,
#[serde(default)]
pub transferred: i64,
#[serde(default)]
pub purchased: i64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreditsAnalytics {
#[serde(default)]
pub period: String,
#[serde(default)]
pub data: Vec<CreditDataPoint>,
}
#[derive(Debug, Clone, Default)]
pub struct AnalyticsPeriod {
pub period: Option<String>,
pub workspace_id: Option<String>,
}
impl AnalyticsPeriod {
pub fn new() -> Self {
Self::default()
}
pub fn period(mut self, period: impl Into<String>) -> Self {
self.period = Some(period.into());
self
}
pub fn workspace_id(mut self, id: impl Into<String>) -> Self {
self.workspace_id = Some(id.into());
self
}
pub(crate) fn to_query_params(&self) -> Vec<(String, String)> {
let mut params = Vec::new();
if let Some(ref period) = self.period {
params.push(("period".to_string(), period.clone()));
}
if let Some(ref id) = self.workspace_id {
params.push(("workspaceId".to_string(), id.clone()));
}
params
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct OptInPage {
pub id: String,
#[serde(default)]
pub slug: String,
#[serde(default)]
pub url: String,
#[serde(default, alias = "businessName")]
pub business_name: String,
#[serde(default, alias = "useCase")]
pub use_case: Option<String>,
#[serde(default = "default_true", alias = "isActive")]
pub is_active: bool,
#[serde(default, alias = "viewCount")]
pub view_count: i32,
#[serde(default, alias = "logoUrl")]
pub logo_url: Option<String>,
#[serde(default, alias = "headerColor")]
pub header_color: Option<String>,
#[serde(default, alias = "buttonColor")]
pub button_color: Option<String>,
#[serde(default, alias = "customHeadline")]
pub custom_headline: Option<String>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateOptInPageRequest {
#[serde(rename = "businessName")]
pub business_name: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "useCase")]
pub use_case: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "useCaseSummary")]
pub use_case_summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "sampleMessages")]
pub sample_messages: Option<String>,
}
impl CreateOptInPageRequest {
pub fn new(business_name: impl Into<String>) -> Self {
Self {
business_name: business_name.into(),
use_case: None,
use_case_summary: None,
sample_messages: None,
}
}
pub fn use_case(mut self, use_case: impl Into<String>) -> Self {
self.use_case = Some(use_case.into());
self
}
pub fn use_case_summary(mut self, summary: impl Into<String>) -> Self {
self.use_case_summary = Some(summary.into());
self
}
pub fn sample_messages(mut self, messages: impl Into<String>) -> Self {
self.sample_messages = Some(messages.into());
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreateOptInPageResponse {
pub id: String,
#[serde(default)]
pub slug: String,
#[serde(default)]
pub url: String,
#[serde(default, alias = "businessName")]
pub business_name: String,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct UpdateOptInPageRequest {
#[serde(skip_serializing_if = "Option::is_none", rename = "logoUrl")]
pub logo_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "headerColor")]
pub header_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "buttonColor")]
pub button_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "customHeadline")]
pub custom_headline: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "customBenefits")]
pub custom_benefits: Option<Vec<String>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DeleteOptInPageResponse {
#[serde(default)]
pub success: bool,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WorkspaceWebhookConfig {
pub id: String,
#[serde(default)]
pub url: String,
#[serde(default)]
pub events: Vec<String>,
#[serde(default = "default_true", alias = "isActive")]
pub is_active: bool,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct SetWorkspaceWebhookRequest {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub events: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
impl SetWorkspaceWebhookRequest {
pub fn new(url: impl Into<String>) -> Self {
Self {
url: url.into(),
events: None,
description: None,
}
}
pub fn events(mut self, events: Vec<impl Into<String>>) -> Self {
self.events = Some(events.into_iter().map(|e| e.into()).collect());
self
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct SetWorkspaceWebhookResponse {
pub id: String,
#[serde(default)]
pub url: String,
#[serde(default)]
pub events: Vec<String>,
#[serde(default)]
pub secret: Option<String>,
#[serde(default)]
pub created: Option<bool>,
#[serde(default)]
pub updated: Option<bool>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WorkspaceWebhookTestResult {
#[serde(default)]
pub success: bool,
#[serde(default)]
pub message: Option<String>,
#[serde(default, alias = "statusCode")]
pub status_code: Option<i32>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct SuspendWorkspaceRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SuspendWorkspaceResponse {
pub id: String,
#[serde(default)]
pub status: String,
#[serde(default, alias = "suspendedAt")]
pub suspended_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ResumeWorkspaceResponse {
pub id: String,
#[serde(default)]
pub status: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct PoolCredits {
#[serde(default)]
pub balance: i64,
#[serde(default, alias = "lifetimeCredits")]
pub lifetime_credits: i64,
#[serde(default, alias = "reservedBalance")]
pub reserved_balance: i64,
}
#[derive(Debug, Clone, Serialize)]
pub struct DepositCreditsRequest {
pub amount: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AutoTopUpSettings {
#[serde(default)]
pub enabled: bool,
#[serde(default)]
pub threshold: i32,
#[serde(default)]
pub amount: i32,
#[serde(default, alias = "sourceWorkspaceId")]
pub source_workspace_id: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdateAutoTopUpRequest {
pub enabled: bool,
pub threshold: i32,
pub amount: i32,
#[serde(skip_serializing_if = "Option::is_none", rename = "sourceWorkspaceId")]
pub source_workspace_id: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub struct BillingBreakdownOptions {
pub period: Option<String>,
pub page: Option<u32>,
pub limit: Option<u32>,
}
impl BillingBreakdownOptions {
pub fn new() -> Self {
Self::default()
}
pub fn period(mut self, period: impl Into<String>) -> Self {
self.period = Some(period.into());
self
}
pub fn page(mut self, page: u32) -> Self {
self.page = Some(page);
self
}
pub fn limit(mut self, limit: u32) -> Self {
self.limit = Some(limit);
self
}
pub(crate) fn to_query_params(&self) -> Vec<(String, String)> {
let mut params = Vec::new();
if let Some(ref period) = self.period {
params.push(("period".to_string(), period.clone()));
}
if let Some(page) = self.page {
params.push(("page".to_string(), page.to_string()));
}
if let Some(limit) = self.limit {
params.push(("limit".to_string(), limit.to_string()));
}
params
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct WorkspaceBillingItem {
pub id: String,
#[serde(default)]
pub name: String,
#[serde(default, alias = "creditsUsed")]
pub credits_used: i64,
#[serde(default, alias = "creditsPurchased")]
pub credits_purchased: i64,
#[serde(default, alias = "creditsTransferredIn")]
pub credits_transferred_in: i64,
#[serde(default, alias = "creditsTransferredOut")]
pub credits_transferred_out: i64,
#[serde(default, alias = "messagesSent")]
pub messages_sent: i64,
#[serde(default, alias = "messagesDelivered")]
pub messages_delivered: i64,
#[serde(default, alias = "workspaceFee")]
pub workspace_fee: f64,
#[serde(default, alias = "allocatedPlatformFee")]
pub allocated_platform_fee: f64,
#[serde(default, alias = "totalCost")]
pub total_cost: f64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BillingBreakdownSummary {
#[serde(default, alias = "platformFee")]
pub platform_fee: f64,
#[serde(default, alias = "totalWorkspaceFees")]
pub total_workspace_fees: f64,
#[serde(default, alias = "totalCreditsUsed")]
pub total_credits_used: i64,
#[serde(default, alias = "totalCost")]
pub total_cost: f64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BillingBreakdown {
#[serde(default)]
pub period: String,
#[serde(default)]
pub summary: Option<BillingBreakdownSummary>,
#[serde(default)]
pub workspaces: Vec<WorkspaceBillingItem>,
}
#[derive(Debug, Clone, Serialize)]
pub struct BulkProvisionWorkspace {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "sourceWorkspaceId")]
pub source_workspace_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "creditAmount")]
pub credit_amount: Option<i32>,
#[serde(
skip_serializing_if = "Option::is_none",
rename = "creditSourceWorkspaceId"
)]
pub credit_source_workspace_id: Option<String>,
}
impl BulkProvisionWorkspace {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
source_workspace_id: None,
credit_amount: None,
credit_source_workspace_id: None,
}
}
pub fn source_workspace_id(mut self, id: impl Into<String>) -> Self {
self.source_workspace_id = Some(id.into());
self
}
pub fn credit_amount(mut self, amount: i32) -> Self {
self.credit_amount = Some(amount);
self
}
pub fn credit_source_workspace_id(mut self, id: impl Into<String>) -> Self {
self.credit_source_workspace_id = Some(id.into());
self
}
}
#[derive(Debug, Clone, Serialize)]
pub struct BulkProvisionRequest {
pub workspaces: Vec<BulkProvisionWorkspace>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BulkProvisionResultItem {
#[serde(default)]
pub name: String,
#[serde(default)]
pub status: String,
#[serde(default, alias = "workspaceId")]
pub workspace_id: Option<String>,
#[serde(default)]
pub slug: Option<String>,
#[serde(default)]
pub warning: Option<String>,
#[serde(default)]
pub error: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BulkProvisionSummary {
#[serde(default)]
pub total: i32,
#[serde(default)]
pub succeeded: i32,
#[serde(default)]
pub failed: i32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BulkProvisionResult {
#[serde(default)]
pub results: Vec<BulkProvisionResultItem>,
#[serde(default)]
pub summary: Option<BulkProvisionSummary>,
}
#[derive(Debug, Clone, Serialize)]
pub struct SetCustomDomainRequest {
pub domain: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DnsRecord {
#[serde(default, rename = "type")]
pub record_type: String,
#[serde(default)]
pub name: String,
#[serde(default)]
pub value: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DnsInstructions {
#[serde(default)]
pub cname: Option<DnsRecord>,
#[serde(default)]
pub txt: Option<DnsRecord>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SetCustomDomainResponse {
#[serde(default)]
pub domain: String,
#[serde(default)]
pub verified: bool,
#[serde(default, alias = "dnsInstructions")]
pub dns_instructions: Option<DnsInstructions>,
}
#[derive(Debug, Clone, Serialize)]
pub struct SendInvitationRequest {
pub email: String,
pub role: String,
}
impl SendInvitationRequest {
pub fn new(email: impl Into<String>, role: impl Into<String>) -> Self {
Self {
email: email.into(),
role: role.into(),
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct Invitation {
pub id: String,
#[serde(default)]
pub email: String,
#[serde(default)]
pub role: String,
#[serde(default)]
pub status: String,
#[serde(default, alias = "expiresAt")]
pub expires_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CancelInvitationResponse {
#[serde(default)]
pub success: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QuotaSettings {
#[serde(default, alias = "monthlyMessageQuota")]
pub monthly_message_quota: Option<i64>,
#[serde(default, alias = "messagesThisMonth")]
pub messages_this_month: i64,
#[serde(default, alias = "quotaResetAt")]
pub quota_reset_at: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdateQuotaRequest {
#[serde(rename = "monthlyMessageQuota")]
pub monthly_message_quota: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ConversationStatus {
Active,
Closed,
}
impl std::fmt::Display for ConversationStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ConversationStatus::Active => write!(f, "active"),
ConversationStatus::Closed => write!(f, "closed"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Conversation {
pub id: String,
#[serde(alias = "phoneNumber")]
pub phone_number: String,
pub status: ConversationStatus,
#[serde(default, alias = "unreadCount")]
pub unread_count: i32,
#[serde(default, alias = "messageCount")]
pub message_count: i32,
#[serde(default, alias = "lastMessageText")]
pub last_message_text: Option<String>,
#[serde(default, alias = "lastMessageAt")]
pub last_message_at: Option<String>,
#[serde(default, alias = "lastMessageDirection")]
pub last_message_direction: Option<String>,
#[serde(default)]
pub metadata: std::collections::HashMap<String, serde_json::Value>,
#[serde(default)]
pub tags: Vec<String>,
#[serde(default, alias = "contactId")]
pub contact_id: Option<String>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
#[serde(default, alias = "updatedAt")]
pub updated_at: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConversationPagination {
#[serde(default)]
pub total: i64,
#[serde(default)]
pub limit: i32,
#[serde(default)]
pub offset: i32,
#[serde(default, alias = "hasMore")]
pub has_more: bool,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ConversationListResponse {
#[serde(default)]
pub data: Vec<Conversation>,
pub pagination: ConversationPagination,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ConversationMessages {
#[serde(default)]
pub data: Vec<Message>,
pub pagination: ConversationPagination,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ConversationWithMessages {
pub id: String,
#[serde(alias = "phoneNumber")]
pub phone_number: String,
pub status: ConversationStatus,
#[serde(default, alias = "unreadCount")]
pub unread_count: i32,
#[serde(default, alias = "messageCount")]
pub message_count: i32,
#[serde(default, alias = "lastMessageText")]
pub last_message_text: Option<String>,
#[serde(default, alias = "lastMessageAt")]
pub last_message_at: Option<String>,
#[serde(default, alias = "lastMessageDirection")]
pub last_message_direction: Option<String>,
#[serde(default)]
pub metadata: std::collections::HashMap<String, serde_json::Value>,
#[serde(default)]
pub tags: Vec<String>,
#[serde(default, alias = "contactId")]
pub contact_id: Option<String>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
#[serde(default, alias = "updatedAt")]
pub updated_at: Option<String>,
#[serde(default)]
pub messages: Option<ConversationMessages>,
}
#[derive(Debug, Clone, Default)]
pub struct ListConversationsOptions {
pub limit: Option<i32>,
pub offset: Option<i32>,
pub status: Option<ConversationStatus>,
}
impl ListConversationsOptions {
pub fn new() -> Self {
Self::default()
}
pub fn limit(mut self, limit: i32) -> Self {
self.limit = Some(limit);
self
}
pub fn offset(mut self, offset: i32) -> Self {
self.offset = Some(offset);
self
}
pub fn status(mut self, status: ConversationStatus) -> Self {
self.status = Some(status);
self
}
pub(crate) fn to_query_params(&self) -> Vec<(String, String)> {
let mut params = Vec::new();
if let Some(limit) = self.limit {
params.push(("limit".to_string(), limit.to_string()));
}
if let Some(offset) = self.offset {
params.push(("offset".to_string(), offset.to_string()));
}
if let Some(ref status) = self.status {
params.push(("status".to_string(), status.to_string()));
}
params
}
}
#[derive(Debug, Clone, Default)]
pub struct GetConversationOptions {
pub include_messages: Option<bool>,
pub message_limit: Option<i32>,
pub message_offset: Option<i32>,
}
impl GetConversationOptions {
pub fn new() -> Self {
Self::default()
}
pub fn include_messages(mut self, include: bool) -> Self {
self.include_messages = Some(include);
self
}
pub fn message_limit(mut self, limit: i32) -> Self {
self.message_limit = Some(limit);
self
}
pub fn message_offset(mut self, offset: i32) -> Self {
self.message_offset = Some(offset);
self
}
pub(crate) fn to_query_params(&self) -> Vec<(String, String)> {
let mut params = Vec::new();
if let Some(true) = self.include_messages {
params.push(("include_messages".to_string(), "true".to_string()));
}
if let Some(limit) = self.message_limit {
params.push(("message_limit".to_string(), limit.to_string()));
}
if let Some(offset) = self.message_offset {
params.push(("message_offset".to_string(), offset.to_string()));
}
params
}
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct UpdateConversationRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<std::collections::HashMap<String, serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize)]
pub struct ReplyToConversationRequest {
pub text: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "messageType")]
pub message_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<std::collections::HashMap<String, serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none", rename = "mediaUrls")]
pub media_urls: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddLabelsRequest {
#[serde(rename = "labelIds")]
pub label_ids: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Label {
pub id: String,
pub name: String,
pub color: String,
#[serde(default)]
pub description: Option<String>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct LabelListResponse {
#[serde(default)]
pub data: Vec<Label>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateLabelRequest {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
impl CreateLabelRequest {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
color: None,
description: None,
}
}
pub fn color(mut self, color: impl Into<String>) -> Self {
self.color = Some(color.into());
self
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct ConversationContextResponse {
pub context: String,
pub conversation: ConversationContextInfo,
#[serde(default, alias = "tokenEstimate")]
pub token_estimate: i64,
#[serde(default)]
pub business: Option<ConversationContextBusiness>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ConversationContextInfo {
pub id: String,
#[serde(alias = "phoneNumber")]
pub phone_number: String,
pub status: String,
#[serde(default, alias = "messageCount")]
pub message_count: i32,
#[serde(default, alias = "unreadCount")]
pub unread_count: i32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ConversationContextBusiness {
#[serde(default)]
pub name: Option<String>,
#[serde(default, alias = "useCase")]
pub use_case: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Rule {
pub id: String,
pub name: String,
pub conditions: Vec<std::collections::HashMap<String, serde_json::Value>>,
pub actions: Vec<std::collections::HashMap<String, serde_json::Value>>,
#[serde(default)]
pub priority: i32,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
#[serde(default, alias = "updatedAt")]
pub updated_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct RuleListResponse {
#[serde(default)]
pub data: Vec<Rule>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateRuleRequest {
pub name: String,
pub conditions: Vec<std::collections::HashMap<String, serde_json::Value>>,
pub actions: Vec<std::collections::HashMap<String, serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<i32>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct UpdateRuleRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub conditions: Option<Vec<std::collections::HashMap<String, serde_json::Value>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub actions: Option<Vec<std::collections::HashMap<String, serde_json::Value>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<i32>,
}
#[derive(Debug, Clone, Serialize)]
pub struct GenerateTemplateRequest {
pub description: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct GeneratedTemplate {
pub name: String,
pub text: String,
#[serde(default)]
pub variables: Vec<String>,
pub category: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum DraftStatus {
Pending,
Approved,
Rejected,
Sent,
Failed,
}
impl std::fmt::Display for DraftStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DraftStatus::Pending => write!(f, "pending"),
DraftStatus::Approved => write!(f, "approved"),
DraftStatus::Rejected => write!(f, "rejected"),
DraftStatus::Sent => write!(f, "sent"),
DraftStatus::Failed => write!(f, "failed"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageDraft {
pub id: String,
#[serde(alias = "conversationId")]
pub conversation_id: String,
pub text: String,
#[serde(default, alias = "mediaUrls")]
pub media_urls: Option<Vec<String>>,
#[serde(default)]
pub metadata: Option<std::collections::HashMap<String, serde_json::Value>>,
pub status: DraftStatus,
#[serde(default)]
pub source: Option<String>,
#[serde(default, alias = "createdBy")]
pub created_by: Option<String>,
#[serde(default, alias = "reviewedBy")]
pub reviewed_by: Option<String>,
#[serde(default, alias = "reviewedAt")]
pub reviewed_at: Option<String>,
#[serde(default, alias = "rejectionReason")]
pub rejection_reason: Option<String>,
#[serde(default, alias = "messageId")]
pub message_id: Option<String>,
#[serde(default, alias = "createdAt")]
pub created_at: Option<String>,
#[serde(default, alias = "updatedAt")]
pub updated_at: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DraftPagination {
#[serde(default)]
pub total: i64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DraftListResponse {
#[serde(default)]
pub data: Vec<MessageDraft>,
pub pagination: DraftPagination,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateDraftRequest {
#[serde(rename = "conversationId")]
pub conversation_id: String,
pub text: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "mediaUrls")]
pub media_urls: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<std::collections::HashMap<String, serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<String>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct UpdateDraftRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "mediaUrls")]
pub media_urls: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<std::collections::HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Serialize)]
pub struct RejectDraftRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub struct ListDraftsOptions {
pub conversation_id: Option<String>,
pub status: Option<DraftStatus>,
pub limit: Option<i32>,
pub offset: Option<i32>,
}
impl ListDraftsOptions {
pub fn new() -> Self {
Self::default()
}
pub fn conversation_id(mut self, id: impl Into<String>) -> Self {
self.conversation_id = Some(id.into());
self
}
pub fn status(mut self, status: DraftStatus) -> Self {
self.status = Some(status);
self
}
pub fn limit(mut self, limit: i32) -> Self {
self.limit = Some(limit);
self
}
pub fn offset(mut self, offset: i32) -> Self {
self.offset = Some(offset);
self
}
pub(crate) fn to_query_params(&self) -> Vec<(String, String)> {
let mut params = Vec::new();
if let Some(ref id) = self.conversation_id {
params.push(("conversation_id".to_string(), id.clone()));
}
if let Some(ref status) = self.status {
params.push(("status".to_string(), status.to_string()));
}
if let Some(limit) = self.limit {
params.push(("limit".to_string(), limit.to_string()));
}
if let Some(offset) = self.offset {
params.push(("offset".to_string(), offset.to_string()));
}
params
}
}