> ## Documentation Index
> Fetch the complete documentation index at: https://docs.revdesk.com/llms.txt
> Use this file to discover all available pages before exploring further.

# GET /v1/sms/stream

> Subscribe to real-time inbound SMS events via Server-Sent Events (SSE).

Opens a long-lived Server-Sent Events (SSE) connection that pushes inbound SMS messages to your client in real time. Messages are scoped to the phone numbers owned by the authenticated API key.

## Authentication

Requires a Bearer API key with the `sms:read` scope.

```bash theme={null}
curl -N "https://api.revdesk.com/v1/sms/stream" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

## Events

### `connected`

Sent immediately after the connection is established.

```
event: connected
data: {"clientId":"sms-42-1716000000000-abc1234","timestamp":1716000000000}
```

### `sms_received`

Sent when an inbound SMS arrives on one of your active phone numbers.

```
event: sms_received
data: {"message_id":"msg_abc123","from":"+14155551234","to":"+14155559999","body":"Hello!","received_at":"2026-05-22T18:30:00.000Z"}
```

| Field         | Type   | Description                                         |
| ------------- | ------ | --------------------------------------------------- |
| `message_id`  | string | Unique identifier for the message                   |
| `from`        | string | Sender phone number (E.164)                         |
| `to`          | string | Your phone number that received the message (E.164) |
| `body`        | string | Message text content                                |
| `received_at` | string | ISO 8601 timestamp of when the message was received |

### Heartbeat

A comment-only heartbeat is sent every 30 seconds to keep the connection alive:

```
: heartbeat
```

## Connection behavior

* **Max duration:** 300 seconds (5 minutes). Reconnect after the connection closes.
* **Reconnect:** Re-open the stream (with a short backoff) after it closes. Do **not** use native
  `EventSource` — it cannot send an `Authorization` header, and you must never put your API key in
  the URL (it leaks into logs and history). Use `fetch` with a streamed body reader instead.
* **Scope filtering:** Events are filtered to the user or team associated with the API key.

## Example

<CodeGroup>
  ```javascript Browser (fetch stream) theme={null}
  // Native EventSource can't set headers, so authenticate with fetch + a stream reader.
  const res = await fetch("https://api.revdesk.com/v1/sms/stream", {
    headers: { Authorization: "Bearer YOUR_API_KEY" },
  });

  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";

  for (;;) {
    const { value, done } = await reader.read();
    if (done) break; // connection closed — reconnect with a short backoff
    buffer += decoder.decode(value, { stream: true });

    // SSE frames are separated by a blank line.
    const frames = buffer.split("\n\n");
    buffer = frames.pop() ?? "";
    for (const frame of frames) {
      const event = frame.match(/^event: (.+)$/m)?.[1];
      const dataLine = frame.match(/^data: (.+)$/m)?.[1];
      if (!dataLine) continue; // e.g. `: heartbeat`
      const data = JSON.parse(dataLine);
      if (event === "sms_received") console.log(`New SMS from ${data.from}: ${data.body}`);
    }
  }
  ```

  ```python Python theme={null}
  import requests
  import json

  url = "https://api.revdesk.com/v1/sms/stream"
  headers = {"Authorization": "Bearer YOUR_API_KEY"}

  with requests.get(url, headers=headers, stream=True) as r:
      for line in r.iter_lines(decode_unicode=True):
          if line.startswith("data: "):
              data = json.loads(line[6:])
              print(f"Received: {data}")
  ```
</CodeGroup>
