Overview
POST /nest/transport is the heart of the Nest Cloud Protocol. The thermostat maintains a persistent HTTP connection here and receives server-pushed state updates via chunked transfer encoding.
This endpoint is part of the Device Protocol API on port 8000. It is called exclusively by thermostat firmware — you do not call it directly.
Endpoint
How It Works
The subscribe endpoint implements a long-poll pattern:- Device connects — sends its current bucket revisions/timestamps
- Server responds with headers immediately —
Transfer-Encoding: chunkedis sent right away, allowing the device to offload the open connection to WiFi hardware and sleep - Server holds the connection — either sends a JSON chunk immediately (if server has newer data) or waits silently
- Server sends a chunk — when state changes, the server serializes the updated buckets and sends them as a chunked response body, waking the device via WoWLAN
- Server closes after a batch window — waits up to 3 seconds after the first chunk for additional data, then closes the connection
- Device resubscribes — on connection close (or after
suspend_time_maxseconds as a safety net), the device reconnects
Request
Headers
Body
The device sends anobjects array with its current bucket revisions:
value field with object_revision: 0 and object_timestamp: 0:
Request Body Fields
| Field | Type | Description |
|---|---|---|
chunked | boolean | Always true — device expects chunked response |
session | string | Persistent session identifier (reused across reconnects) |
objects | array | Bucket descriptors with device’s current state |
objects[].object_key | string | Bucket key, e.g., device.09AA01AB12345678 |
objects[].object_revision | integer | Device’s current revision for this bucket |
objects[].object_timestamp | integer | Device’s current timestamp for this bucket (ms) |
objects[].value | object | (Inline update only) New field values; only used when rev=0 and ts=0 |
Response Headers
| Header | Description |
|---|---|
Transfer-Encoding: chunked | Required — enables server push and WoWLAN sleep |
X-nl-suspend-time-max | Device’s safety-net wake timer in seconds (default: 300) |
X-nl-service-timestamp | Server timestamp in ms — device uses for sync decisions |
X-nl-defer-device-window | Seconds to delay device PUT after local changes (batches dial jitter) |
X-nl-disable-defer-window | Seconds to temporarily disable defer delay after a server push |
Response Body (Chunked)
When the server has data to push, it sends a JSON object in a chunked body:objects array:
When No Data Is Available
If the server has no updates to send immediately, it holds the connection open silently (no body, no empty JSON). It does NOT send an empty{} or an empty objects array. The connection is held until:
- Data arrives to push (then a chunk is sent)
connection_hold_timeoutseconds elapse (default:suspend_time_max - 10 = 290s), at which point the connection closes with no body
Synchronization Logic
The server compares timestamps (not revisions) to decide what to push:- If
server_timestamp > device_timestampfor a bucket → include it in the response - If
device_timestamp > server_timestamp→ merge the inline value into server state (if it’s an inline update) - Timestamp = 0 is a sentinel meaning “no data for this bucket yet”
Security Considerations
The server accepts all credentials. The device serial is extracted from the Basic Auth user ID (d.{SERIAL}.{suffix}) and used for state lookup.
Related
POST /nest/transport/put
Device-to-server state updates
Nest Protocol: Transport
Deep dive on the subscribe/push mechanism