Home Assistant's REST API is one of its most powerful — and underused — features. It exposes virtually everything your smart home does over standard HTTP, meaning any script, dashboard widget, or external service can read sensor data, trigger automations, or change device states without installing a custom integration. If you've already got Home Assistant running, the API is already live; you just need to unlock it with a token.
What Is the Home Assistant REST API?
A local HTTP interface to your entire smart home. The REST API sits at http://<your-ha-ip>:8123/api/ and follows standard HTTP conventions: GET requests read data, POST requests write it. All responses are JSON. Because it runs entirely on your local network (or over your own VPN), there's no dependency on any third-party cloud — unlike IFTTT or similar services.
The API is distinct from Home Assistant's WebSocket API. REST suits simple request-response tasks — querying a sensor value, calling a service, updating a virtual entity. The WebSocket API is better for real-time event streams. For most automation and integration tasks, REST is the right starting point. You can also pair REST API calls with Home Assistant automations to trigger external webhooks or poll third-party services.
Generating a Long-Lived Access Token
Every API call requires a Bearer token. Home Assistant uses long-lived access tokens for API authentication — these are permanent tokens tied to a specific user account that you generate yourself.
To create one:
- Open your Home Assistant instance (typically
http://homeassistant.local:8123) and sign in. - Click your profile avatar in the bottom-left corner of the sidebar.
- Scroll down to the Long-Lived Access Tokens section and click Create Token.
- Give it a descriptive name — for example,
rest-api-scripts— and click OK. - Copy the token immediately. Home Assistant will never display it again.
Store the token in an environment variable or a secrets manager rather than hardcoding it into scripts. Every API request must include the header Authorization: Bearer <TOKEN>.
Key Endpoints and curl Examples
The API base URL is http://<ha-ip>:8123/api/ — note the trailing slash on the root endpoint. All examples below use a placeholder token; substitute your own.
Health Check
Confirm the API is reachable:
curl -H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
http://homeassistant.local:8123/api/
A successful response returns {"message": "API running."}.
Reading All Entity States
Retrieve the current state of every entity in Home Assistant:
curl -H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
http://homeassistant.local:8123/api/states
The response is a JSON array. Each object includes entity_id, state, attributes, and last_changed timestamps.
Reading a Specific Entity State
Query a single entity by its ID — for example, a temperature sensor:
curl -H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
http://homeassistant.local:8123/api/states/sensor.kitchen_temperature
The response includes the current state value and all attributes (unit of measurement, device class, etc.).
Calling a Service
Services are actions — turning lights on, running a script, locking a door. Call them via POST to /api/services/<domain>/<service>. To turn on a light:
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "light.living_room"}' \
http://homeassistant.local:8123/api/services/light/turn_on
To dim the same light to 50%:
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "light.living_room", "brightness_pct": 50}' \
http://homeassistant.local:8123/api/services/light/turn_on
Service calls return an array of the affected entity states after the call.
Writing (or Creating) an Entity State
POST to /api/states/<entity_id> to create a virtual sensor or update a state. This is useful for pushing data from external systems into Home Assistant:
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"state": "21.5", "attributes": {"unit_of_measurement": "°C", "friendly_name": "Office Temp"}}' \
http://homeassistant.local:8123/api/states/sensor.office_temp_external
Note: states written this way do not survive a Home Assistant restart unless you use a persistent virtual entity (such as an input_number or template sensor).
Python Example
Python's requests library makes REST API calls straightforward. Install it with pip install requests if needed.
import requests
import os
HA_URL = "http://homeassistant.local:8123"
TOKEN = os.environ["HA_TOKEN"] # set in your shell or .env file
headers = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json",
}
# Read a sensor state
response = requests.get(
f"{HA_URL}/api/states/sensor.kitchen_temperature",
headers=headers,
)
data = response.json()
print(f"Kitchen temperature: {data['state']} {data['attributes']['unit_of_measurement']}")
# Turn on the kitchen lights
requests.post(
f"{HA_URL}/api/services/light/turn_on",
headers=headers,
json={"entity_id": "light.kitchen"},
)
print("Kitchen lights turned on")
This pattern works equally well in Node.js (using node-fetch or axios), shell scripts, or any language with an HTTP client. The token is the only credential you need — no session cookies or OAuth flow required.
REST Sensor Integration: Pulling External Data into Home Assistant
The rest integration works in the opposite direction — it lets Home Assistant poll an external API and expose the result as a sensor entity. Add it to your configuration.yaml:
sensor:
- platform: rest
name: "Open-Meteo Temperature"
resource: "https://api.open-meteo.com/v1/forecast?latitude=51.5&longitude=-0.1¤t_weather=true"
value_template: "{{ value_json.current_weather.temperature }}"
unit_of_measurement: "°C"
scan_interval: 300
Key parameters:
- resource — the external URL to poll. Use
resource_templateif the URL needs to include entity states or secrets. - value_template — a Jinja2 template to extract the value from the JSON response. See the template guide for template syntax.
- scan_interval — polling frequency in seconds (default: 30). Be considerate of rate limits on public APIs.
- headers — pass API keys or content-type headers needed by the external service.
If the external API returns multiple values, use json_attributes to extract several fields at once into entity attributes, then reference them in template sensors.
REST Command Integration: Calling External APIs from Automations
The rest_command integration lets HA trigger outbound HTTP calls as automation actions. Define commands in configuration.yaml:
rest_command:
notify_slack:
url: "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
method: POST
content_type: "application/json"
payload: '{"text": "{{ message }}"}'
set_thermostat_mode:
url: "https://api.example.com/thermostat/mode"
method: PUT
headers:
Authorization: "Bearer {{ states('input_text.thermostat_token') }}"
payload: '{"mode": "{{ mode }}"}'
content_type: "application/json"
Call these commands from an automation's action block:
action:
- action: rest_command.notify_slack
data:
message: "Front door opened at {{ now().strftime('%H:%M') }}"
rest_command returns a response_variable containing status, content, and headers — useful for conditional logic based on the API response code. This is a cleaner alternative to webhooks when you need HA to push data outward rather than receive it.
Practical Use Cases
The REST API unlocks a wide range of integrations that don't have a native HA component. Common examples include:
- Custom dashboards — build a wall-mounted tablet UI using plain HTML/JavaScript that reads entity states and calls services via fetch() calls to the REST API.
- External scripts and cron jobs — a nightly Python script that reads energy sensors and writes a CSV report, or a Node.js script that checks motion sensors before sending a notification.
- Third-party service webhooks — receive a webhook from Stripe, GitHub, or a delivery service and translate it into a HA event or automation trigger.
- IFTTT replacement — replicate simple "if this then that" logic entirely locally: poll a public API (weather, tide times, pollen count) with a REST sensor, then use the value in an automation.
- Homelab monitoring — push Proxmox VM status, Grafana alert states, or UPS battery levels into HA as virtual sensors for unified dashboard monitoring.
Security Considerations
Treat your long-lived access token like a password. Anyone who holds it can control your entire Home Assistant instance. Key precautions:
- Never commit tokens to version control. Use environment variables or a secrets manager (e.g.,
.envfiles excluded from git, or HashiCorp Vault). - Create separate tokens for each integration or script so you can revoke individual access without disrupting others.
- Restrict API access to your local network. If you need remote access, use Home Assistant's built-in Nabu Casa remote connection or your own VPN — do not expose port 8123 directly to the internet.
- Review your active tokens periodically under your profile page and revoke any that are no longer needed.
- Use HTTPS (via a reverse proxy such as NGINX or Caddy) if you access HA over a network where traffic could be intercepted.
The REST API is unauthenticated if no token is provided — Home Assistant will return a 401 Unauthorized response, but only if the API is properly secured. Always verify your setup with a deliberate token-less request during testing to confirm the 401 is returned.




