from datetime import datetime from typing import Self from dateutil.parser import parse as parse_datetime from pydantic import ( AwareDatetime, BaseModel, ConfigDict, field_validator, model_validator, ) from .enums import TwilioMessageNumberType class ErrorResponse(BaseModel): code: int message: str more_info: str | None = None class Price(BaseModel): number_type: TwilioMessageNumberType base_price: float current_price: float class SmsPrice(BaseModel): mcc: str mnc: str carrier: str prices: list[Price] class MessageCountryPricing(BaseModel): iso_country: str price_unit: str outbound_sms_prices: list[SmsPrice] class SendMessageRequest(BaseModel): """ https://www.twilio.com/docs/messaging/api/message-resource#request-body-parameters """ to: str from_: str | None = None messaging_service_sid: str | None = None body: str media_url: str | list[str] | None = None status_callback: str | None = None account_sid: str | None = None model_config = ConfigDict(populate_by_name=True) @model_validator(mode="after") def check_from_or_messaging_service_sid(self) -> Self: if self.from_ is None and self.messaging_service_sid is None: raise ValueError( "Either 'from_' or 'messaging_service_sid' must be provided." ) return self class SendMessageResponse(BaseModel): """ https://www.twilio.com/docs/messaging/api/message-resource#message-properties """ sid: str account_sid: str | None = None messaging_service_sid: str | None = None num_segments: str | None = None num_media: str | None = None price: str | None = None price_unit: str | None = None status: str | None = None date_created: AwareDatetime | None = None error_code: int | None = None error_message: str | None = None @field_validator("date_created", mode="before") @classmethod def parse_date_created(cls, value: str | datetime | None) -> datetime | None: if isinstance(value, str): return parse_datetime(value) return value class AccountResponse(BaseModel): sid: str owner_account_sid: str | None = None class APIKeyResponse(BaseModel): sid: str secret: str friendly_name: str class Capabilities(BaseModel): mms: bool sms: bool voice: bool class PhoneNumber(BaseModel): sid: str phone_number: str capabilities: list[str] class MessagingPhoneNumberMeta(BaseModel): next_page_url: str | None class MessagingPhoneNumberResponse(BaseModel): phone_numbers: list[PhoneNumber] meta: MessagingPhoneNumberMeta | None = None class MessagingService(BaseModel): sid: str friendly_name: str account_sid: str