Data Models
Complete reference for all data structures used in the Sent API v3. All API responses follow a consistent JSON envelope format with standardized property naming conventions.
Naming Convention: The API v3 uses snake_case for all JSON property names (e.g., phone_number, created_at).
Response Envelope
All API responses follow a consistent envelope structure:
ApiResponse<T>
| Field | Type | Description |
|---|---|---|
success | boolean | Indicates whether the request was successful |
data | T | null | The response data (null if error) |
error | ApiError | null | Error details (null if successful) |
meta | ApiMeta | Metadata about the request and response |
Example Success Response
{
"success": true,
"data": {
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"phone_number": "+1234567890",
"created_at": "2024-01-15T10:30:00Z"
},
"error": null,
"meta": {
"request_id": "req_abc123",
"timestamp": "2024-01-15T10:30:00Z",
"version": "v3",
"response_time_ms": 45
}
}Example Error Response
{
"success": false,
"data": null,
"error": {
"code": "RESOURCE_001",
"message": "Contact not found",
"details": null,
"doc_url": "https://docs.sent.dm/errors/RESOURCE_001"
},
"meta": {
"request_id": "req_def456",
"timestamp": "2024-01-15T10:30:00Z",
"version": "v3"
}
}Type Definitions
export interface ApiResponse<T> {
success: boolean;
data: T | null;
error: ApiError | null;
meta: ApiMeta;
}
export interface ApiError {
code: string;
message: string;
details: Record<string, string[]> | null;
doc_url: string | null;
}
export interface ApiMeta {
request_id: string;
timestamp: string;
version: string;
response_time_ms?: number;
}
export interface PaginationMeta {
has_next_page: boolean;
has_previous_page: boolean;
next_cursor: string | null;
previous_cursor: string | null;
total_count?: number;
}from typing import Generic, TypeVar, Optional, Dict, List, Any
from dataclasses import dataclass
T = TypeVar('T')
@dataclass
class ApiResponse(Generic[T]):
success: bool
data: Optional[T]
error: Optional['ApiError']
meta: 'ApiMeta'
@dataclass
class ApiError:
code: str
message: str
details: Optional[Dict[str, List[str]]]
doc_url: Optional[str]
@dataclass
class ApiMeta:
request_id: str
timestamp: str
version: str
response_time_ms: Optional[int] = None
@dataclass
class PaginationMeta:
has_next_page: bool
has_previous_page: bool
next_cursor: Optional[str]
previous_cursor: Optional[str]
total_count: Optional[int] = Nonepackage sent
// ApiResponse represents the standard API response envelope
type ApiResponse[T any] struct {
Success bool `json:"success"`
Data T `json:"data"`
Error *ApiError `json:"error"`
Meta ApiMeta `json:"meta"`
}
// ApiError represents error details in API responses
type ApiError struct {
Code string `json:"code"`
Message string `json:"message"`
Details map[string][]string `json:"details"`
DocURL string `json:"doc_url"`
}
// ApiMeta contains metadata about the API request/response
type ApiMeta struct {
RequestID string `json:"request_id"`
Timestamp string `json:"timestamp"`
Version string `json:"version"`
ResponseTimeMs int `json:"response_time_ms,omitempty"`
}
// PaginationMeta contains pagination information for list responses
type PaginationMeta struct {
HasNextPage bool `json:"has_next_page"`
HasPreviousPage bool `json:"has_previous_page"`
NextCursor string `json:"next_cursor"`
PreviousCursor string `json:"previous_cursor"`
TotalCount int `json:"total_count,omitempty"`
}Contact Models
ContactResponse
A contact represents a phone number with validated formats and available messaging channels.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique identifier for the contact |
phone_number | string | Phone number in original format |
format_e164 | string | Phone number in E.164 format (e.g., +1234567890) |
format_international | string | International format (e.g., +1 234-567-890) |
format_national | string | National format (e.g., (234) 567-890) |
format_rfc | string | RFC 3966 format (e.g., tel:+1-234-567-890) |
country_code | string | Country calling code (e.g., 1 for US/Canada) |
region_code | string | ISO 3166-1 alpha-2 country code (e.g., US, CA) |
available_channels | string | Comma-separated list (e.g., sms,whatsapp) |
default_channel | string | Default messaging channel (sms or whatsapp) |
opt_out | boolean | Whether the contact has opted out of messaging |
created_at | string (date-time) | When the contact was created |
updated_at | string (date-time) | When the contact was last updated |
Type Definitions
export interface Contact {
id: string;
phone_number: string;
format_e164: string;
format_international: string;
format_national: string;
format_rfc: string;
country_code: string;
region_code: string;
available_channels: string;
default_channel: string;
opt_out: boolean;
created_at: string;
updated_at: string;
}
export interface CreateContactRequest {
phone_number: string;
test_mode?: boolean;
}
export interface UpdateContactRequest {
phone_number?: string;
test_mode?: boolean;
}from dataclasses import dataclass
from typing import Optional
@dataclass
class Contact:
id: str
phone_number: str
format_e164: str
format_international: str
format_national: str
format_rfc: str
country_code: str
region_code: str
available_channels: str
default_channel: str
opt_out: bool
created_at: str
updated_at: str
@dataclass
class CreateContactRequest:
phone_number: str
test_mode: Optional[bool] = None
@dataclass
class UpdateContactRequest:
phone_number: Optional[str] = None
test_mode: Optional[bool] = None// Contact represents a phone number with validated formats and available messaging channels
type Contact struct {
ID string `json:"id"`
PhoneNumber string `json:"phone_number"`
FormatE164 string `json:"format_e164"`
FormatInternational string `json:"format_international"`
FormatNational string `json:"format_national"`
FormatRFC string `json:"format_rfc"`
CountryCode string `json:"country_code"`
RegionCode string `json:"region_code"`
AvailableChannels string `json:"available_channels"`
DefaultChannel string `json:"default_channel"`
OptOut bool `json:"opt_out"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
// CreateContactRequest represents the request body for creating a contact
type CreateContactRequest struct {
PhoneNumber string `json:"phone_number"`
TestMode bool `json:"test_mode,omitempty"`
}
// UpdateContactRequest represents the request body for updating a contact
type UpdateContactRequest struct {
PhoneNumber string `json:"phone_number,omitempty"`
TestMode bool `json:"test_mode,omitempty"`
}Message Models
MessageResponse
A message represents an outbound message sent to a contact.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique message identifier |
customer_id | string (uuid) | Customer who sent the message |
contact_id | string (uuid) | Contact who received the message |
phone | string | Recipient phone number |
phone_international | string | International format phone number |
region_code | string | Country code (e.g., US) |
template_id | string (uuid) | null | Template used (if any) |
template_name | string | Name of the template used |
template_category | string | Category of the template |
channel | string | Channel used (sms, whatsapp) |
message_body | MessageBody | null | Rendered message content |
status | string | Message status (e.g., pending, sent, delivered, failed) |
created_at | string (date-time) | When the message was created |
price | number | null | Price charged for the message |
events | MessageEvent[] | null | Delivery events |
Type Definitions
export interface Message {
id: string;
customer_id: string;
contact_id: string;
phone: string;
phone_international: string;
region_code: string;
template_id: string | null;
template_name: string;
template_category: string;
channel: string;
message_body: MessageBody | null;
status: MessageStatus;
created_at: string;
price: number | null;
events: MessageEvent[] | null;
}
export interface MessageBody {
body: string;
header?: MessageHeader;
footer?: MessageFooter;
buttons?: MessageButton[];
}
export interface MessageHeader {
type: 'TEXT' | 'IMAGE' | 'VIDEO' | 'DOCUMENT';
content: string;
}
export interface MessageFooter {
content: string;
}
export interface MessageButton {
type: 'QUICK_REPLY' | 'URL' | 'PHONE_NUMBER';
text: string;
url?: string;
phone_number?: string;
}
export interface MessageEvent {
status: string;
timestamp: string;
provider: string;
error_code?: string;
error_message?: string;
}
export interface SendMessageRequest {
phone_number: string;
template_id: string;
variables?: Record<string, string>;
channel?: 'sms' | 'whatsapp';
webhook_url?: string;
callback_url?: string;
test_mode?: boolean;
}
export type MessageStatus =
| 'pending'
| 'sent'
| 'delivered'
| 'read'
| 'failed';from dataclasses import dataclass
from typing import Optional, List, Dict, Literal
@dataclass
class Message:
id: str
customer_id: str
contact_id: str
phone: str
phone_international: str
region_code: str
template_id: Optional[str]
template_name: str
template_category: str
channel: str
message_body: Optional['MessageBody']
status: str
created_at: str
price: Optional[float]
events: Optional[List['MessageEvent']]
@dataclass
class MessageBody:
body: str
header: Optional['MessageHeader'] = None
footer: Optional['MessageFooter'] = None
buttons: Optional[List['MessageButton']] = None
@dataclass
class MessageHeader:
type: Literal['TEXT', 'IMAGE', 'VIDEO', 'DOCUMENT']
content: str
@dataclass
class MessageFooter:
content: str
@dataclass
class MessageButton:
type: Literal['QUICK_REPLY', 'URL', 'PHONE_NUMBER']
text: str
url: Optional[str] = None
phone_number: Optional[str] = None
@dataclass
class MessageEvent:
status: str
timestamp: str
provider: str
error_code: Optional[str] = None
error_message: Optional[str] = None
@dataclass
class SendMessageRequest:
phone_number: str
template_id: str
variables: Optional[Dict[str, str]] = None
channel: Optional[Literal['sms', 'whatsapp']] = None
webhook_url: Optional[str] = None
callback_url: Optional[str] = None
test_mode: Optional[bool] = None// Message represents an outbound message sent to a contact
type Message struct {
ID string `json:"id"`
CustomerID string `json:"customer_id"`
ContactID string `json:"contact_id"`
Phone string `json:"phone"`
PhoneInternational string `json:"phone_international"`
RegionCode string `json:"region_code"`
TemplateID string `json:"template_id"`
TemplateName string `json:"template_name"`
TemplateCategory string `json:"template_category"`
Channel string `json:"channel"`
MessageBody *MessageBody `json:"message_body"`
Status MessageStatus `json:"status"`
CreatedAt string `json:"created_at"`
Price float64 `json:"price"`
Events []MessageEvent `json:"events"`
}
// MessageStatus represents the status of a message
type MessageStatus string
const (
MessageStatusPending MessageStatus = "pending"
MessageStatusSent MessageStatus = "sent"
MessageStatusDelivered MessageStatus = "delivered"
MessageStatusRead MessageStatus = "read"
MessageStatusFailed MessageStatus = "failed"
)
// MessageBody represents the rendered message content
type MessageBody struct {
Body string `json:"body"`
Header *MessageHeader `json:"header,omitempty"`
Footer *MessageFooter `json:"footer,omitempty"`
Buttons []MessageButton `json:"buttons,omitempty"`
}
// MessageHeader represents the header of a message
type MessageHeader struct {
Type string `json:"type"` // TEXT, IMAGE, VIDEO, DOCUMENT
Content string `json:"content"`
}
// MessageFooter represents the footer of a message
type MessageFooter struct {
Content string `json:"content"`
}
// MessageButton represents a button in a message
type MessageButton struct {
Type string `json:"type"` // QUICK_REPLY, URL, PHONE_NUMBER
Text string `json:"text"`
URL string `json:"url,omitempty"`
PhoneNumber string `json:"phone_number,omitempty"`
}
// MessageEvent represents a delivery event for a message
type MessageEvent struct {
Status string `json:"status"`
Timestamp string `json:"timestamp"`
Provider string `json:"provider"`
ErrorCode string `json:"error_code,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
}
// SendMessageRequest represents the request body for sending a message
type SendMessageRequest struct {
PhoneNumber string `json:"phone_number"`
TemplateID string `json:"template_id"`
Variables map[string]string `json:"variables,omitempty"`
Channel string `json:"channel,omitempty"` // sms, whatsapp
WebhookURL string `json:"webhook_url,omitempty"`
CallbackURL string `json:"callback_url,omitempty"`
TestMode bool `json:"test_mode,omitempty"`
}Template Models
TemplateResponse
A template is a reusable message format with variables for personalization.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique template identifier |
name | string | Template display name |
category | string | Template category: MARKETING, UTILITY, AUTHENTICATION |
language | string | Language code (e.g., en_US) |
status | string | Approval status: APPROVED, PENDING, REJECTED |
channels | string[] | Supported channels (sms, whatsapp) |
variables | string[] | Template variable names |
created_at | string (date-time) | When the template was created |
updated_at | string (date-time) | null | When the template was last updated |
is_published | boolean | Whether the template is published and active |
Type Definitions
export interface Template {
id: string;
name: string;
category: TemplateCategory;
language: string;
status: TemplateStatus;
channels: string[];
variables: string[];
created_at: string;
updated_at: string | null;
is_published: boolean;
}
export interface TemplateBody {
content: string;
variables?: TemplateVariable[];
}
export interface TemplateHeader {
type: 'TEXT' | 'IMAGE' | 'VIDEO' | 'DOCUMENT';
content: string;
}
export interface TemplateFooter {
content: string;
}
export interface TemplateButton {
type: 'QUICK_REPLY' | 'URL' | 'PHONE_NUMBER';
text: string;
url?: string;
phone_number?: string;
}
export interface TemplateVariable {
name: string;
type: 'text' | 'number' | 'date';
example?: string;
}
export interface CreateTemplateRequest {
name: string;
category: TemplateCategory;
language: string;
body: TemplateBody;
header?: TemplateHeader;
footer?: TemplateFooter;
buttons?: TemplateButton[];
channels?: string[];
test_mode?: boolean;
}
export interface UpdateTemplateRequest {
name?: string;
category?: TemplateCategory;
body?: TemplateBody;
test_mode?: boolean;
}
export type TemplateCategory = 'MARKETING' | 'UTILITY' | 'AUTHENTICATION';
export type TemplateStatus = 'APPROVED' | 'PENDING' | 'REJECTED';from dataclasses import dataclass
from typing import Optional, List, Literal
@dataclass
class Template:
id: str
name: str
category: str
language: str
status: str
channels: List[str]
variables: List[str]
created_at: str
updated_at: Optional[str]
is_published: bool
@dataclass
class TemplateBody:
content: str
variables: Optional[List['TemplateVariable']] = None
@dataclass
class TemplateHeader:
type: Literal['TEXT', 'IMAGE', 'VIDEO', 'DOCUMENT']
content: str
@dataclass
class TemplateFooter:
content: str
@dataclass
class TemplateButton:
type: Literal['QUICK_REPLY', 'URL', 'PHONE_NUMBER']
text: str
url: Optional[str] = None
phone_number: Optional[str] = None
@dataclass
class TemplateVariable:
name: str
type: Literal['text', 'number', 'date']
example: Optional[str] = None
@dataclass
class CreateTemplateRequest:
name: str
category: str
language: str
body: TemplateBody
header: Optional[TemplateHeader] = None
footer: Optional[TemplateFooter] = None
buttons: Optional[List[TemplateButton]] = None
channels: Optional[List[str]] = None
test_mode: Optional[bool] = None
@dataclass
class UpdateTemplateRequest:
name: Optional[str] = None
category: Optional[str] = None
body: Optional[TemplateBody] = None
test_mode: Optional[bool] = None// Template represents a reusable message format with variables for personalization
type Template struct {
ID string `json:"id"`
Name string `json:"name"`
Category TemplateCategory `json:"category"`
Language string `json:"language"`
Status TemplateStatus `json:"status"`
Channels []string `json:"channels"`
Variables []string `json:"variables"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
IsPublished bool `json:"is_published"`
}
// TemplateCategory represents the category of a template
type TemplateCategory string
const (
TemplateCategoryMarketing TemplateCategory = "MARKETING"
TemplateCategoryUtility TemplateCategory = "UTILITY"
TemplateCategoryAuthentication TemplateCategory = "AUTHENTICATION"
)
// TemplateStatus represents the approval status of a template
type TemplateStatus string
const (
TemplateStatusApproved TemplateStatus = "APPROVED"
TemplateStatusPending TemplateStatus = "PENDING"
TemplateStatusRejected TemplateStatus = "REJECTED"
)
// TemplateBody represents the body of a template
type TemplateBody struct {
Content string `json:"content"`
Variables []TemplateVariable `json:"variables,omitempty"`
}
// TemplateHeader represents the header of a template
type TemplateHeader struct {
Type string `json:"type"` // TEXT, IMAGE, VIDEO, DOCUMENT
Content string `json:"content"`
}
// TemplateFooter represents the footer of a template
type TemplateFooter struct {
Content string `json:"content"`
}
// TemplateButton represents a button in a template
type TemplateButton struct {
Type string `json:"type"` // QUICK_REPLY, URL, PHONE_NUMBER
Text string `json:"text"`
URL string `json:"url,omitempty"`
PhoneNumber string `json:"phone_number,omitempty"`
}
// TemplateVariable represents a variable in a template
type TemplateVariable struct {
Name string `json:"name"`
Type string `json:"type"` // text, number, date
Example string `json:"example,omitempty"`
}
// CreateTemplateRequest represents the request body for creating a template
type CreateTemplateRequest struct {
Name string `json:"name"`
Category TemplateCategory `json:"category"`
Language string `json:"language"`
Body TemplateBody `json:"body"`
Header *TemplateHeader `json:"header,omitempty"`
Footer *TemplateFooter `json:"footer,omitempty"`
Buttons []TemplateButton `json:"buttons,omitempty"`
Channels []string `json:"channels,omitempty"`
TestMode bool `json:"test_mode,omitempty"`
}
// UpdateTemplateRequest represents the request body for updating a template
type UpdateTemplateRequest struct {
Name string `json:"name,omitempty"`
Category TemplateCategory `json:"category,omitempty"`
Body *TemplateBody `json:"body,omitempty"`
TestMode bool `json:"test_mode,omitempty"`
}Profile Models
ProfileResponse
A profile (sender profile) represents an organization or sub-account for sending messages.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique profile identifier |
name | string | Profile name |
icon | string | null | Profile icon URL |
description | string | null | Profile description |
short_name | string | null | Short name/abbreviation |
role | string | null | User's role: admin, billing, developer |
status | string | null | Setup status: incomplete, pending_review, approved, rejected |
created_at | string (date-time) | When the profile was created |
settings | ProfileSettings | Profile configuration |
Type Definitions
export interface Profile {
id: string;
name: string;
icon: string | null;
description: string | null;
short_name: string | null;
role: 'admin' | 'billing' | 'developer' | null;
status: 'incomplete' | 'pending_review' | 'approved' | 'rejected' | null;
created_at: string;
settings: ProfileSettings;
}
export interface ProfileSettings {
default_channel: string | null;
webhook_url: string | null;
timezone: string | null;
language: string | null;
}
export interface CreateProfileRequest {
name: string;
description?: string;
short_name?: string;
test_mode?: boolean;
}from dataclasses import dataclass
from typing import Optional, Literal
@dataclass
class Profile:
id: str
name: str
icon: Optional[str]
description: Optional[str]
short_name: Optional[str]
role: Optional[Literal['admin', 'billing', 'developer']]
status: Optional[Literal['incomplete', 'pending_review', 'approved', 'rejected']]
created_at: str
settings: 'ProfileSettings'
@dataclass
class ProfileSettings:
default_channel: Optional[str]
webhook_url: Optional[str]
timezone: Optional[str]
language: Optional[str]
@dataclass
class CreateProfileRequest:
name: str
description: Optional[str] = None
short_name: Optional[str] = None
test_mode: Optional[bool] = None// Profile represents a sender profile for sending messages
type Profile struct {
ID string `json:"id"`
Name string `json:"name"`
Icon string `json:"icon"`
Description string `json:"description"`
ShortName string `json:"short_name"`
Role ProfileRole `json:"role"`
Status ProfileStatus `json:"status"`
CreatedAt string `json:"created_at"`
Settings ProfileSettings `json:"settings"`
}
// ProfileRole represents the user's role in a profile
type ProfileRole string
const (
ProfileRoleAdmin ProfileRole = "admin"
ProfileRoleBilling ProfileRole = "billing"
ProfileRoleDeveloper ProfileRole = "developer"
)
// ProfileStatus represents the setup status of a profile
type ProfileStatus string
const (
ProfileStatusIncomplete ProfileStatus = "incomplete"
ProfileStatusPendingReview ProfileStatus = "pending_review"
ProfileStatusApproved ProfileStatus = "approved"
ProfileStatusRejected ProfileStatus = "rejected"
)
// ProfileSettings represents the configuration for a profile
type ProfileSettings struct {
DefaultChannel string `json:"default_channel"`
WebhookURL string `json:"webhook_url"`
Timezone string `json:"timezone"`
Language string `json:"language"`
}
// CreateProfileRequest represents the request body for creating a profile
type CreateProfileRequest struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
ShortName string `json:"short_name,omitempty"`
TestMode bool `json:"test_mode,omitempty"`
}Webhook Models
WebhookV3Response
A webhook endpoint receives event notifications for message delivery and other events.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique webhook identifier |
url | string | Webhook endpoint URL |
description | string | null | Webhook description |
event_types | string[] | Subscribed event types |
is_active | boolean | Whether the webhook is active |
signing_secret | string | null | Secret for verifying webhook signatures |
created_at | string (date-time) | When the webhook was created |
updated_at | string (date-time) | null | When the webhook was last updated |
Type Definitions
export interface Webhook {
id: string;
url: string;
description: string | null;
event_types: string[];
is_active: boolean;
signing_secret: string | null;
created_at: string;
updated_at: string | null;
}
export interface WebhookEvent {
id: string;
webhook_id: string;
event_type: string;
payload: Record<string, unknown>;
status: string;
response_status_code?: number;
created_at: string;
}
export interface WebhookEventType {
name: string;
description: string;
category: string;
}
export interface CreateWebhookRequest {
url: string;
event_types: string[];
description?: string;
test_mode?: boolean;
}from dataclasses import dataclass
from typing import Optional, List, Dict, Any
@dataclass
class Webhook:
id: str
url: str
description: Optional[str]
event_types: List[str]
is_active: bool
signing_secret: Optional[str]
created_at: str
updated_at: Optional[str]
@dataclass
class WebhookEvent:
id: str
webhook_id: str
event_type: str
payload: Dict[str, Any]
status: str
response_status_code: Optional[int] = None
created_at: str
@dataclass
class WebhookEventType:
name: str
description: str
category: str
@dataclass
class CreateWebhookRequest:
url: str
event_types: List[str]
description: Optional[str] = None
test_mode: Optional[bool] = None// Webhook represents a webhook endpoint for receiving event notifications
type Webhook struct {
ID string `json:"id"`
URL string `json:"url"`
Description string `json:"description"`
EventTypes []string `json:"event_types"`
IsActive bool `json:"is_active"`
SigningSecret string `json:"signing_secret"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
// WebhookEvent represents a single webhook delivery attempt
type WebhookEvent struct {
ID string `json:"id"`
WebhookID string `json:"webhook_id"`
EventType string `json:"event_type"`
Payload map[string]interface{} `json:"payload"`
Status string `json:"status"`
ResponseStatusCode int `json:"response_status_code,omitempty"`
CreatedAt string `json:"created_at"`
}
// WebhookEventType represents an available webhook event type
type WebhookEventType struct {
Name string `json:"name"`
Description string `json:"description"`
Category string `json:"category"`
}
// CreateWebhookRequest represents the request body for creating a webhook
type CreateWebhookRequest struct {
URL string `json:"url"`
EventTypes []string `json:"event_types"`
Description string `json:"description,omitempty"`
TestMode bool `json:"test_mode,omitempty"`
}