use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
pub type JsonObject = HashMap<String, Value>;
pub type NullablePrimitive = Value;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ListResponse<T> {
pub object: String,
pub data: Vec<T>,
pub pagination: Option<Pagination>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ResourceResponse<T> {
pub object: String,
pub data: T,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DeletionResponse {
pub object: String,
pub id: String,
pub deleted: bool,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Pagination {
pub page: u32,
pub limit: u32,
pub total: u32,
pub total_pages: u32,
pub has_next: bool,
pub has_prev: bool,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ContactStatus {
Active,
Unsubscribed,
Bounced,
SpamComplaint,
Inactive,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Contact {
pub object: String,
pub id: String,
pub email: String,
pub first_name: Option<String>,
pub last_name: Option<String>,
pub full_name: Option<String>,
pub attributes: HashMap<String, Value>,
pub status: ContactStatus,
pub source: Option<String>,
pub external_id: Option<String>,
pub metadata: JsonObject,
pub created_at: String,
pub updated_at: String,
pub subscribed_at: Option<String>,
pub unsubscribed_at: Option<String>,
}
#[derive(Clone, Debug, Default, Serialize)]
pub struct ContactCreateRequest {
pub email: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub first_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attributes: Option<HashMap<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<ContactStatus>,
#[serde(skip_serializing_if = "Option::is_none")]
pub external_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<JsonObject>,
}
impl ContactCreateRequest {
pub fn new(email: impl Into<String>) -> Self {
Self {
email: email.into(),
..Default::default()
}
}
pub fn first_name(mut self, value: impl Into<String>) -> Self {
self.first_name = Some(value.into());
self
}
pub fn last_name(mut self, value: impl Into<String>) -> Self {
self.last_name = Some(value.into());
self
}
pub fn external_id(mut self, value: impl Into<String>) -> Self {
self.external_id = Some(value.into());
self
}
pub fn status(mut self, value: ContactStatus) -> Self {
self.status = Some(value);
self
}
}
#[derive(Clone, Debug, Default, Serialize)]
pub struct ContactUpdateRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub first_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attributes: Option<HashMap<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<ContactStatus>,
#[serde(skip_serializing_if = "Option::is_none")]
pub external_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<JsonObject>,
}
impl ContactUpdateRequest {
pub fn new() -> Self {
Self::default()
}
pub fn email(mut self, value: impl Into<String>) -> Self {
self.email = Some(value.into());
self
}
pub fn first_name(mut self, value: impl Into<String>) -> Self {
self.first_name = Some(value.into());
self
}
pub fn last_name(mut self, value: impl Into<String>) -> Self {
self.last_name = Some(value.into());
self
}
pub fn external_id(mut self, value: impl Into<String>) -> Self {
self.external_id = Some(value.into());
self
}
pub fn status(mut self, value: ContactStatus) -> Self {
self.status = Some(value);
self
}
}
#[derive(Clone, Debug, Default)]
pub struct ContactListParams {
pub page: Option<u32>,
pub limit: Option<u32>,
pub status: Option<ContactStatus>,
pub search: Option<String>,
pub external_id: Option<String>,
pub sort_by: Option<ContactSortBy>,
pub sort_order: Option<SortOrder>,
}
#[derive(Clone, Debug)]
pub enum ContactSortBy {
CreatedAt,
UpdatedAt,
Email,
FirstName,
LastName,
}
#[derive(Clone, Debug)]
pub enum SortOrder {
Asc,
Desc,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct BatchCreateContactsResult {
pub object: String,
pub data: BatchCreateContactsData,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct BatchCreateContactsData {
pub created: Vec<Contact>,
pub failed: Vec<BatchCreateContactFailure>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct BatchCreateContactFailure {
pub email: String,
pub error: String,
pub code: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SegmentFilterField {
Email,
FirstName,
LastName,
FullName,
Status,
Source,
ExternalId,
CreatedAt,
UpdatedAt,
SubscribedAt,
UnsubscribedAt,
Attribute,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SegmentFilterOperator {
Equals,
NotEquals,
Contains,
NotContains,
StartsWith,
EndsWith,
IsEmpty,
IsNotEmpty,
Before,
After,
OnOrBefore,
OnOrAfter,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SegmentFilterCondition {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
pub field: SegmentFilterField,
pub operator: SegmentFilterOperator,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attribute_key: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SegmentFilterCriteria {
pub version: u8,
pub r#match: SegmentFilterMatch,
pub conditions: Vec<SegmentFilterCondition>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SegmentFilterMatch {
All,
Any,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Segment {
pub object: String,
pub id: String,
pub name: String,
pub description: Option<String>,
pub filter_criteria: SegmentFilterCriteria,
pub r#type: Option<String>,
pub contact_count: u32,
pub is_active: bool,
pub metadata: Option<JsonObject>,
pub created_at: String,
pub updated_at: String,
}
#[derive(Clone, Debug, Default, Serialize)]
pub struct SegmentCreateRequest {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub filter_criteria: Option<SegmentFilterCriteria>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_active: Option<bool>,
}
impl SegmentCreateRequest {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
..Default::default()
}
}
pub fn description(mut self, value: impl Into<String>) -> Self {
self.description = Some(value.into());
self
}
pub fn active(mut self, value: bool) -> Self {
self.is_active = Some(value);
self
}
}
#[derive(Clone, Debug, Default, Serialize)]
pub struct SegmentUpdateRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub filter_criteria: Option<SegmentFilterCriteria>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_active: Option<bool>,
}
impl SegmentUpdateRequest {
pub fn new() -> Self {
Self::default()
}
pub fn name(mut self, value: impl Into<String>) -> Self {
self.name = Some(value.into());
self
}
pub fn description(mut self, value: impl Into<String>) -> Self {
self.description = Some(value.into());
self
}
pub fn active(mut self, value: bool) -> Self {
self.is_active = Some(value);
self
}
}
#[derive(Clone, Debug, Default)]
pub struct SegmentListParams {
pub page: Option<u32>,
pub limit: Option<u32>,
pub search: Option<String>,
pub active: Option<bool>,
pub include_counts: Option<bool>,
pub sort_by: Option<SegmentSortBy>,
pub sort_order: Option<SortOrder>,
}
#[derive(Clone, Debug)]
pub enum SegmentSortBy {
CreatedAt,
UpdatedAt,
Name,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum TopicDefaultSubscription {
OptIn,
OptOut,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum TopicVisibility {
Public,
Private,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Topic {
pub object: String,
pub id: String,
pub name: String,
pub description: Option<String>,
pub default_subscription: TopicDefaultSubscription,
pub visibility: TopicVisibility,
pub is_active: bool,
pub subscriber_count: u32,
pub explicit_subscriber_count: u32,
pub explicit_unsubscriber_count: u32,
pub created_at: String,
pub updated_at: String,
}
#[derive(Clone, Debug, Default, Serialize)]
pub struct TopicCreateRequest {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_subscription: Option<TopicDefaultSubscription>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visibility: Option<TopicVisibility>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_active: Option<bool>,
}
impl TopicCreateRequest {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
..Default::default()
}
}
pub fn description(mut self, value: impl Into<String>) -> Self {
self.description = Some(value.into());
self
}
pub fn default_subscription(mut self, value: TopicDefaultSubscription) -> Self {
self.default_subscription = Some(value);
self
}
pub fn visibility(mut self, value: TopicVisibility) -> Self {
self.visibility = Some(value);
self
}
pub fn active(mut self, value: bool) -> Self {
self.is_active = Some(value);
self
}
}
#[derive(Clone, Debug, Default, Serialize)]
pub struct TopicUpdateRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visibility: Option<TopicVisibility>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_active: Option<bool>,
}
impl TopicUpdateRequest {
pub fn new() -> Self {
Self::default()
}
pub fn name(mut self, value: impl Into<String>) -> Self {
self.name = Some(value.into());
self
}
pub fn description(mut self, value: impl Into<String>) -> Self {
self.description = Some(value.into());
self
}
pub fn visibility(mut self, value: TopicVisibility) -> Self {
self.visibility = Some(value);
self
}
pub fn active(mut self, value: bool) -> Self {
self.is_active = Some(value);
self
}
}
#[derive(Clone, Debug, Default)]
pub struct TopicListParams {
pub page: Option<u32>,
pub limit: Option<u32>,
pub search: Option<String>,
pub active: Option<bool>,
pub visibility: Option<TopicVisibility>,
pub sort_by: Option<TopicSortBy>,
pub sort_order: Option<SortOrder>,
}
#[derive(Clone, Debug)]
pub enum TopicSortBy {
CreatedAt,
UpdatedAt,
Name,
}
#[derive(Clone, Debug, Serialize)]
pub struct EmailSendRequest {
pub from: String,
pub to: EmailRecipients,
#[serde(skip_serializing_if = "Option::is_none")]
pub subject: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub html: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reply_to: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub template_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub template_alias: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub template_params: Option<HashMap<String, Value>>,
}
impl EmailSendRequest {
pub fn new(from: impl Into<String>, to: impl Into<EmailRecipients>) -> Self {
Self {
from: from.into(),
to: to.into(),
subject: None,
text: None,
html: None,
reply_to: None,
tags: None,
template_id: None,
template_alias: None,
template_params: None,
}
}
pub fn subject(mut self, value: impl Into<String>) -> Self {
self.subject = Some(value.into());
self
}
pub fn text(mut self, value: impl Into<String>) -> Self {
self.text = Some(value.into());
self
}
pub fn html(mut self, value: impl Into<String>) -> Self {
self.html = Some(value.into());
self
}
pub fn reply_to(mut self, value: impl Into<String>) -> Self {
self.reply_to = Some(value.into());
self
}
pub fn tag(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.tags
.get_or_insert_with(HashMap::new)
.insert(key.into(), value.into());
self
}
pub fn template_id(mut self, value: impl Into<String>) -> Self {
self.template_id = Some(value.into());
self
}
pub fn template_alias(mut self, value: impl Into<String>) -> Self {
self.template_alias = Some(value.into());
self
}
pub fn template_param(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
self.template_params
.get_or_insert_with(HashMap::new)
.insert(key.into(), value.into());
self
}
}
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
pub enum EmailRecipients {
Single(String),
Multiple(Vec<String>),
}
impl From<String> for EmailRecipients {
fn from(value: String) -> Self {
Self::Single(value)
}
}
impl From<&str> for EmailRecipients {
fn from(value: &str) -> Self {
Self::Single(value.to_string())
}
}
impl From<Vec<String>> for EmailRecipients {
fn from(value: Vec<String>) -> Self {
Self::Multiple(value)
}
}
impl From<Vec<&str>> for EmailRecipients {
fn from(value: Vec<&str>) -> Self {
Self::Multiple(value.into_iter().map(str::to_string).collect())
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct QueuedEmail {
pub object: String,
pub id: String,
pub to: String,
pub status: String,
}
#[derive(Clone, Debug, Serialize)]
pub struct AutomationTrackRequest {
pub event_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub contact_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub payload: Option<JsonObject>,
#[serde(skip_serializing_if = "Option::is_none")]
pub event_id: Option<String>,
}
impl AutomationTrackRequest {
pub fn new(event_name: impl Into<String>) -> Self {
Self {
event_name: event_name.into(),
contact_id: None,
payload: None,
event_id: None,
}
}
pub fn contact_id(mut self, value: impl Into<String>) -> Self {
self.contact_id = Some(value.into());
self
}
pub fn event_id(mut self, value: impl Into<String>) -> Self {
self.event_id = Some(value.into());
self
}
pub fn payload(mut self, value: JsonObject) -> Self {
self.payload = Some(value);
self
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AutomationEvent {
pub object: String,
pub event_id: String,
pub event_name: String,
pub contact_id: Option<String>,
pub queued_runs: u32,
}
pub(crate) fn sort_order_to_string(value: &SortOrder) -> &'static str {
match value {
SortOrder::Asc => "asc",
SortOrder::Desc => "desc",
}
}
pub(crate) fn contact_sort_by_to_string(value: &ContactSortBy) -> &'static str {
match value {
ContactSortBy::CreatedAt => "created_at",
ContactSortBy::UpdatedAt => "updated_at",
ContactSortBy::Email => "email",
ContactSortBy::FirstName => "first_name",
ContactSortBy::LastName => "last_name",
}
}
pub(crate) fn segment_sort_by_to_string(value: &SegmentSortBy) -> &'static str {
match value {
SegmentSortBy::CreatedAt => "created_at",
SegmentSortBy::UpdatedAt => "updated_at",
SegmentSortBy::Name => "name",
}
}
pub(crate) fn topic_sort_by_to_string(value: &TopicSortBy) -> &'static str {
match value {
TopicSortBy::CreatedAt => "created_at",
TopicSortBy::UpdatedAt => "updated_at",
TopicSortBy::Name => "name",
}
}