"""Pydantic models for voip.ms SMS/MMS request and response payloads.""" from __future__ import annotations from typing import Literal from pydantic import BaseModel, Field class SendResult(BaseModel): """Result of a successful sendSMS / sendMMS call.""" id: int = Field(..., description="The new SMS/MMS id assigned by voip.ms.") class SmsRecord(BaseModel): """A single SMS row as returned by getSMS. voip.ms returns a flat object per message; only the commonly-used fields are typed. Extra fields are ignored so the model stays forward-compatible. """ id: str | int date: str | None = None type: str | None = Field(None, description="e.g. '1' received / '0' sent") did: str | None = None contact: str | None = None message: str | None = None model_config = {"extra": "ignore"} class MmsRecord(BaseModel): """A single MMS row as returned by getMMS.""" id: str | int date: str | None = None type: str | None = None did: str | None = None contact: str | None = None message: str | None = None media: str | None = Field(None, description="Comma-separated media file list, if present.") model_config = {"extra": "ignore"} class MediaResult(BaseModel): """Media attachments for one MMS, from getMediaMMS.""" id: str | int date: str | None = None media: list[str] = Field(default_factory=list, description="Up to 3 media URLs/slots.") class DeleteResult(BaseModel): """Result of deleteSMS / deleteMMS.""" status: Literal["success"] = "success" # --- Request bodies for the FastAPI routes --------------------------------- class SendSmsRequest(BaseModel): did: str = Field(..., description="Sender DID (10 digits, or +1... for e164).") dst: str = Field(..., description="Destination number.") message: str = Field(..., max_length=160) class SendMmsRequest(BaseModel): did: str dst: str message: str = Field(..., max_length=2048) media1: str | None = Field(None, description="URL to a media file.") media2: str | None = Field(None, description="Base64-encoded image (data:image/...;base64,...).") media3: str | None = Field(None, description="Reserved; usually empty.")