Smart Home AssistantNewsletter

Home Assistant REST API: A Practical Guide

SepehrBy Sepehr· 19/06/2026· 7 min read
Home Assistant REST API: A Practical Guide

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:

  1. Open your Home Assistant instance (typically http://homeassistant.local:8123) and sign in.
  2. Click your profile avatar in the bottom-left corner of the sidebar.
  3. Scroll down to the Long-Lived Access Tokens section and click Create Token.
  4. Give it a descriptive name — for example, rest-api-scripts — and click OK.
  5. 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_template if 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., .env files 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.

Frequently asked questions

How do I enable the Home Assistant REST API?
The REST API is enabled by default in all Home Assistant installations — no extra configuration is needed. Access it at http://<your-ha-ip>:8123/api/. You only need to generate a long-lived access token from your profile page to authenticate requests.
What is the difference between the Home Assistant REST API and the WebSocket API?
The REST API is best for simple request-response interactions: reading sensor states, calling services, and pushing data into HA from external scripts. The WebSocket API is better for real-time event subscriptions and streaming state changes as they happen. Most external integrations start with REST.
Can I use the Home Assistant REST API remotely?
Yes, but you should not expose port 8123 directly to the internet. Instead, use Home Assistant's Nabu Casa remote connection, your own WireGuard or Tailscale VPN, or a reverse proxy with HTTPS and firewall rules to restrict access. Always use HTTPS for remote connections.
Why does calling /api/services not trigger my automation?
Service calls via the REST API go directly to the domain service (e.g. light.turn_on) and do not trigger automations by default — they change device state directly. To trigger an automation via the REST API, call POST /api/services/automation/trigger with the automation's entity_id, or fire a custom event with POST /api/events/<event_type> and set your automation to trigger on that event.

Sources

Sources verified 2026-06-19

  1. Home Assistant Developer Docs — REST API
  2. Home Assistant — RESTful Integration
  3. Home Assistant — RESTful Command Integration
  4. Unsplash — Photo of code on screen by Chris Ried
Sepehr

Written by

Sepehr

Head of Engineering with 15+ years of software experience and a decade of hands-on smart home tinkering. I run everything I write about — Home Assistant, Zigbee2MQTT, Frigate, and a full self-hosted homelab. Independent coverage, no brand deals, UK-focused.

LinkedIn →

Related reading