Data Models
Every Sent API v3 response uses the same JSON envelope. This page documents the shared structures: the response envelope, its error and metadata objects, and the pagination metadata returned by list endpoints. Request and response schemas for individual resources are generated from the OpenAPI specification and rendered on each endpoint page. See Resource schemas.
Naming Convention: The API v3 uses snake_case for all JSON property names (for example, phone_number, created_at).
Response Envelope
All v3 endpoints return the standard ApiResponse envelope:
| Field | Type | Description |
|---|---|---|
success | boolean | true when the request succeeded, false when it failed |
data | object | The response data. Omitted from error responses |
error | ApiError | Error details. Omitted from successful responses |
meta | ApiMeta | Metadata about the request and response |
Example Success Response
{
"success": true,
"data": {
"id": "0b9df168-9917-4b1e-bc5d-9cee5d2ce2d2",
"phone_number": "+15551234567",
"created_at": "2026-01-15T10:30:00Z"
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-01-15T10:30:00Z",
"version": "v3"
}
}Example Error Response
{
"success": false,
"status": 404,
"error": {
"code": "RESOURCE_001",
"message": "Contact not found",
"doc_url": "https://docs.sent.dm/reference/api/error-catalog"
},
"meta": {
"request_id": "req_def456",
"timestamp": "2026-01-15T10:30:00Z",
"version": "v3"
}
}Error Handling documents HTTP status codes and error response semantics; the Error Catalog enumerates every error code with causes and remediation.
ApiError
| Field | Type | Description |
|---|---|---|
code | string | Machine-readable error code (for example, RESOURCE_001) |
message | string | Human-readable error message |
details | object | Field-level validation errors: a map of field name to an array of error messages. Omitted when unset |
doc_url | string | URL to documentation about this error. Omitted when unset |
ApiMeta
| Field | Type | Description |
|---|---|---|
request_id | string | Unique identifier for this request, for tracing and support |
timestamp | string (date-time) | Server timestamp when the response was generated |
version | string | API version used for this request (v3) |
Paginated List Responses
Paginated list endpoints return the items array and a pagination object inside data. The array property is named after the resource:
| Endpoint | Array property |
|---|---|
GET /v3/contacts | contacts |
GET /v3/templates | templates |
GET /v3/webhooks | webhooks |
GET /v3/webhooks/{id}/events | events |
GET /v3/conversations | messages |
GET /v3/conversations/{id} | messages |
Paginated endpoints accept the page query parameter (1-indexed, default 1) and the page_size query parameter (default 20, range 1–100).
Example Paginated Response
{
"success": true,
"data": {
"contacts": [
{
"id": "0b9df168-9917-4b1e-bc5d-9cee5d2ce2d2",
"phone_number": "+15551234567"
}
],
"pagination": {
"page": 1,
"page_size": 20,
"total_count": 42,
"total_pages": 3,
"has_more": true,
"cursors": null
}
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-01-15T10:30:00Z",
"version": "v3"
}
}PaginationMeta
| Field | Type | Description |
|---|---|---|
page | integer | Current page number (1-indexed) |
page_size | integer | Number of items per page |
total_count | integer | Total number of items across all pages |
total_pages | integer | Total number of pages |
has_more | boolean | Whether there are more pages after this one |
cursors | PaginationCursors | null | Optional cursor pagination pointers. null when the response is paginated by page number only |
PaginationCursors
| Field | Type | Description |
|---|---|---|
after | string | null | Cursor to fetch the next page |
before | string | null | Cursor to fetch the previous page |
Resource Schemas
Request and response schemas for each resource are generated from the OpenAPI specification and rendered on the endpoint pages. Each mutation endpoint page documents its own request body; the pages below document the full response model for each resource:
| Resource | Response model | Documented on |
|---|---|---|
| Contacts | ContactResponse | Get contact by ID |
| Messages | MessageResponse | Get message status |
| Templates | TemplateResponse | Get template by ID |
| Profiles | ProfileDetailResponse | Get profile by ID |
| Webhooks | WebhookV3Response | Get a webhook |
| Brand campaigns | BrandCampaignV3Response | Get campaigns for a profile's brand |
| Users | UserResponse | Get user by ID |
| Account | AccountResponse | Get authenticated account |
| Number lookup | NumberLookupResultResponse | Get phone number details |
Message Status Values
The generated schema types the status field on MessageResponse as a plain string, so the endpoint page does not enumerate its values.
QUEUED, ROUTED, SENT, DELIVERED, READ, and FAILED cover the outbound lifecycle, and RECEIVED marks an inbound message from a contact. Three more statuses describe sends that Sent held back:
SCHEDULED: the send fell inside the recipient's quiet hours and was deferred rather than failed. Sent releases the message automatically once the window closes and it continues through the normal send path, soSCHEDULEDis not terminal.FILTERED: a policy gate suppressed the send before any provider call, either because the recipient opted out or is on your phone-channel suppression list, or because your routing rules denied it.BLOCKED: an account-level precondition stopped the send before policy evaluation, for example an insufficient balance, an unmet onboarding entitlement, or a template that is not approved for sending.
FILTERED and BLOCKED are policy outcomes rather than delivery failures, so both are excluded from your deliverability rate. Only FAILED counts against it.
Sent records why a message was filtered or blocked internally, but neither MessageResponse nor the webhook payload carries a field for it, and no field reports when a SCHEDULED message will be released.
Each of the preceding statuses has a matching webhook sub-type. PROCESSED, which a message reports for the short interval between acceptance and routing, is the one status without a sub-type, so status webhooks never carry it. See Event Types for the full status catalog and the payload shape of each event.