> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.getdial.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getdial.ai/_mcp/server.

# List messages

GET https://api.getdial.ai/api/v1/messages

Returns up to 100 of the most recent messages on the account's numbers.

Reference: https://docs.getdial.ai/api-reference/rest-api/messages/list-messages

## Authentication

- `Authorization` header (bearer token, required) — Your Dial API key, sent as `Authorization: Bearer sk_live_...`

## Request

### Query parameters

- `numberId` (string, optional) — Filter to a single phone number.
- `groupId` (string, optional) — Filter to a single group conversation (see List groups). Combines with the other filters. A group ID that isn't on your account returns an empty list rather than an error.
- `direction` (enum, optional)
  - Allowed values: `inbound`, `outbound`
- `since` (datetime, optional) — Only messages created after this timestamp.

## Response

### 200

Messages, newest first.

- `messages` (list of object, optional)
  - `id` (string, optional)
  - `phoneNumberId` (string, optional)
  - `from` (string, optional) — Sender in E.164 format. On an inbound group message this is the participant who sent it — not the group, and not your own line.
  - `to` (string, optional, nullable) — Recipient in E.164 format, and **null exactly when `groupId` is set** — in both directions. A group message is addressed to the group, and a group is not a phone number. Which of your numbers the conversation is on is `phoneNumberId`, which is set on every message. Code that reads `to` as "my number" must read `phoneNumberId` instead.
  - `groupId` (string, optional, nullable) — The group conversation this message belongs to, or null for a one-to-one conversation. A Dial ID (see List groups) — never the channel's own group identifier.
  - `body` (string, optional)
  - `direction` (enum, optional)
    - Allowed values: `inbound`, `outbound`
  - `channel` (enum, optional) — The channel the message was delivered on. `sms` for SMS/call numbers. For iMessage numbers, inbound messages report the channel actually used — `imessage`, `rcs`, or `sms`. Outbound iMessage sends report `unknown`, because the iMessage channel does not confirm which channel was ultimately used. `whatsapp` is a channel in its own right — a WhatsApp registration on an iMessage line — and is reported in both directions. Every group message is `whatsapp` today.
    - Allowed values: `sms`, `imessage`, `rcs`, `whatsapp`, `unknown`
  - `service` (enum, optional) — For iMessage numbers, the confirmed delivery channel. Null for SMS/call numbers (where `channel` already says `sms`). Deprecated — prefer `channel`, which is authoritative.
    - Allowed values: `imessage`, `rcs`, `sms`
  - `status` (enum, optional) — Delivery status. Outbound SMS/call messages start at `sent` and reach a terminal `delivered`, `undelivered`, or `failed`. Outbound iMessage messages are `unknown` (the iMessage channel does not report delivery). Inbound messages are `received`.
    - Allowed values: `sent`, `delivered`, `undelivered`, `failed`, `unknown`, `received`
  - `statusError` (string, optional, nullable) — A human-readable reason, present only when `status` is `undelivered` or `failed` (for example, when a carrier rejects the message). Null otherwise.
  - `deliveryState` (enum, optional) — The delivery axis — the same information as `status`, in the vocabulary that says what to do about it. `pending` means wait for a disposition (`status: "sent"`); `unconfirmed` means never expect one (`status: "unknown"`, an iMessage send, or a WhatsApp send before its first receipt). Inbound messages are `delivered`.
    - Allowed values: `pending`, `delivered`, `undelivered`, `failed`, `unconfirmed`
  - `readState` (enum, optional) — The read axis, independent of delivery — a message can be both delivered and read, which `status` alone could never express. `unsupported` on channels that report no reads (SMS) and on every inbound message, since Dial does not track whether you read one. iMessage and WhatsApp report reads, so an outbound message there is `unread` until it is `read`. In a group, `read` means every recipient has read it — never just somebody.
    - Allowed values: `unread`, `read`, `unsupported`
  - `readAt` (datetime, optional, nullable) — When the message was read, or null. Always null on inbound messages and on channels that report no reads.
  - `deliveryError` (string, optional, nullable) — The current name for `statusError`; identical value. A vendor-neutral reason, present only on an `undelivered` or `failed` message.
  - `media` (list of object, optional) — Media attachments on the message, in send order. Empty for plain text messages.
    - `id` (string, optional) — Public media ID — an unguessable 32-character token.
    - `url` (string, optional) — Stable public URL serving the media (see Get public media). Safe to use directly as an image source; requires no authentication.
    - `contentType` (string, optional) — MIME type of the media.
    - `originalUrl` (string, optional, nullable) — The caller-supplied source URL on outbound messages. Null on inbound messages and when the media was uploaded directly as bytes — inbound media is always served from `url`.
  - `replyToId` (string, optional, nullable) — ID of the message this one replies or reacts to. Set on messages created via Reply to a message, and on inbound threaded replies and reactions received on iMessage numbers. Null for ordinary messages, or when the target of an inbound reply isn't a message on your account.
  - `reaction` (string, optional, nullable) — The reaction this message carries — a reaction name (`love`, `like`, `dislike`, `laugh`, `emphasize`, `question`) or an emoji — when the message is a reaction, sent or received. Null otherwise. A reaction delivered natively has an empty `body`; a reaction delivered as a regular message over SMS carries the emoji in `body` too.
  - `createdAt` (datetime, optional)

## Examples

**Response**

```json
{
  "messages": [
    {
      "id": "string",
      "phoneNumberId": "string",
      "from": "+14155550123",
      "to": "+14155559876",
      "groupId": null,
      "body": "string",
      "direction": "inbound",
      "channel": "sms",
      "service": "imessage",
      "status": "delivered",
      "statusError": null,
      "deliveryState": "delivered",
      "readState": "unread",
      "readAt": null,
      "deliveryError": null,
      "media": [
        {
          "id": "a3f9c2d41e8b4f0a9c6d2e7b5a1f8c30",
          "url": "https://getdial.ai/public-media/a3f9c2d41e8b4f0a9c6d2e7b5a1f8c30.jpg",
          "contentType": "image/jpeg",
          "originalUrl": "https://your-cdn.example.com/summary.png"
        }
      ],
      "replyToId": null,
      "reaction": null,
      "createdAt": "2024-01-15T09:30:00Z"
    }
  ]
}
```

**SDK Code**

```python
import requests

url = "https://api.getdial.ai/api/v1/messages"

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.getdial.ai/api/v1/messages';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.getdial.ai/api/v1/messages"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.getdial.ai/api/v1/messages")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.getdial.ai/api/v1/messages")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.getdial.ai/api/v1/messages', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.getdial.ai/api/v1/messages");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.getdial.ai/api/v1/messages")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```