What is it
The Plant Reminder API lets other tools read your plants and log care for them: read what is due, and act by logging waterings and fertilizations or undoing them. Home Assistant and Alexa use it, and so can any script of your own.
It is included with Premium, or you can get a 30-day pass for 30 tokens (tokens are bought in the app). The pass does not renew automatically.
The API can never delete plants, photos or history.
Create your token in the app
Every integration uses a personal token. To create one:
- Open the More tab and go to Home Assistant and Alexa.
- Tap Activate.
- Tap Create token.
- Tap Copy.
The token is shown only once, so copy it right away. You can revoke it at any time and create a new one.
The option Allow logging waterings and fertilizations is checked by default. If you uncheck it, the token becomes read-only and any write returns insufficient_scope.
Home Assistant
Everything below can be pasted into your configuration.yaml. Replace YOUR_TOKEN with the token you copied.
Sensor: plants to water
A rest sensor that asks every 300 seconds. Its state is the number of plants due for watering today or overdue. The plants attribute lists everything due, each item with its kind: watering, fertilization or transplant.
rest:
- resource: https://kerijldtrzlwaawlpdcw.supabase.co/functions/v1/public-api/v1/due?days=1
scan_interval: 300
headers:
Authorization: "Bearer YOUR_TOKEN"
sensor:
- name: "Plants to water"
value_template: "{{ value_json.plants | selectattr('kind', 'eq', 'watering') | list | count }}"
json_attributes:
- plants
- overdue_count
- today
- as_of
Commands: water, fertilize and undo
One rest_command per action. plant_reminder_water and plant_reminder_fertilize receive a plant_id; the ids come from GET /v1/plants or from the plants attribute of the sensor.
rest_command:
plant_reminder_water:
url: "https://kerijldtrzlwaawlpdcw.supabase.co/functions/v1/public-api/v1/plants/{{ plant_id }}/water"
method: POST
headers:
Authorization: "Bearer YOUR_TOKEN"
content_type: "application/json"
payload: "{}"
plant_reminder_fertilize:
url: "https://kerijldtrzlwaawlpdcw.supabase.co/functions/v1/public-api/v1/plants/{{ plant_id }}/fertilize"
method: POST
headers:
Authorization: "Bearer YOUR_TOKEN"
content_type: "application/json"
payload: "{}"
plant_reminder_water_all_due:
url: "https://kerijldtrzlwaawlpdcw.supabase.co/functions/v1/public-api/v1/due/water"
method: POST
headers:
Authorization: "Bearer YOUR_TOKEN"
content_type: "application/json"
payload: "{}"
plant_reminder_undo:
url: "https://kerijldtrzlwaawlpdcw.supabase.co/functions/v1/public-api/v1/actions/undo"
method: POST
headers:
Authorization: "Bearer YOUR_TOKEN"
content_type: "application/json"
payload: "{}"
Tip: instead of writing the token in the file, keep it in secrets.yaml and reference it with !secret.
Automation: notify when something is due
It sends a notification with the plant names whenever the sensor goes above zero. It uses the syntax of Home Assistant 2024.10 or later (triggers: and actions:); change notify.notify to your own notification service.
automation:
- alias: "Plant Reminder: plants to water"
triggers:
- trigger: numeric_state
entity_id: sensor.plants_to_water
above: 0
actions:
- action: notify.notify
data:
title: "Plants to water"
message: >-
{{ state_attr('sensor.plants_to_water', 'plants') | selectattr('kind', 'eq', 'watering') | map(attribute='name') | join(', ') }}
This example has not been verified yet on a specific Home Assistant release; the syntax follows the 2024.10+ documentation. If something does not work on your version, write to us and tell us which one you use. The entity id comes from the sensor name: check it in Developer tools if yours differs.
Endpoint reference
All routes live under the base URL below and need the header Authorization: Bearer YOUR_TOKEN. Bodies are JSON.
Base URL: https://kerijldtrzlwaawlpdcw.supabase.co/functions/v1/public-api
| Endpoint | What it does |
|---|---|
GET /v1/due?days=0..7 | Care due in the next N days (0 to 7, default 1), overdue included: watering, fertilization and repotting. Each item carries its kind. |
GET /v1/plants | Lists your plants. |
GET /v1/plants/{id} | Details of one plant. |
GET /v1/plants/{id}/waterings?since=&limit= | Watering history of a plant. since (ISO date) and limit (1 to 500, default 100) are optional. |
GET /v1/plants/{id}/fertilizations | Fertilization history of a plant. Same optional parameters. |
GET /v1/actions | Actions logged through your token. limit is optional (1 to 100, default 20). |
GET /v1/rooms | Lists your rooms with how many plants each one has (only those that get watered). |
POST /v1/plants/{id}/water{at?} | Logs a watering. at is an ISO date (default: now; it cannot be in the future). |
POST /v1/plants/{id}/fertilize{at?, fertilizer_form?, application_method?} | Logs a fertilization. at works as above. fertilizer_form accepts liquid or solid, and application_method accepts soil, foliar or root_drench; if you leave them out, those of the plant's last fertilization are used. |
POST /v1/due/water{dry_run?} | Waters every plant that is due. With dry_run: true it only previews and logs nothing. A batch counts as one write. |
POST /v1/rooms/{id}/water{at?, dry_run?} | Logs a watering for every plant in that room. at works as above; with dry_run: true it only returns the list. It counts as one write and is undone as a whole. |
POST /v1/actions/undo{action_id?} | Undoes an action. Without action_id, it undoes the latest one. |
- On writes you can send an optional
Idempotency-Keyheader: repeating a request with the same key returns the original result instead of logging it twice. - Dates are ISO 8601 in UTC.
- Every response carries
api_version(currently"1"). - Errors look like
{"error": "code", "message": "..."}.
Errors and limits
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_request | The request is malformed (for example, a parameter out of range). |
| 400 | invalid_date | The date is not valid: it is in the future, before the plant was adopted, or not ISO 8601. |
| 401 | invalid_token | The token is missing, wrong or has been revoked. |
| 401 | token_expired | The access token has expired and must be refreshed (Alexa does this by itself). |
| 402 | api_access_expired | API access has ended (Premium or the pass). Renew it in the app. |
| 403 | insufficient_scope | The token does not have the permission to log care. |
| 403 | write_disabled | Writes are temporarily disabled on our side. Reading keeps working. |
| 404 | not_found | The route, plant or action does not exist. |
| 404 | nothing_to_undo | There is nothing of your token to undo. |
| 409 | already_gone | What you tried to undo had already been removed. |
| 410 | expired | The action is older than 24 hours and can no longer be undone. |
| 429 | rate_limited | Too many requests. Wait the seconds given in the Retry-After header. |
| 503 | api_disabled | The API is temporarily disabled. |
Limits
- 10 requests per minute and 5,000 per day for each token.
- 60 writes per day for each token (a batch counts as one).
- Undo only removes what your own integration logged in the last 24 hours.
Alexa Coming soon
The Plant Reminder skill for Alexa is still in certification, so it is not available yet. This is how it will work:
You can say:
- Alexa, open my plants
- Alexa, ask my plants what needs watering today
- Alexa, ask my plants if the monstera needs water
- Alexa, tell my plants I watered the ficus
- Alexa, tell my plants I watered the ficus yesterday
- Alexa, tell my plants to water the plants in the living room
- Alexa, tell my plants to water everything due today
- Alexa, tell my plants to undo the last one
You will link your account from the Alexa app. The skill will be available in English and Spanish. After logging a plant, the skill asks if you want to log another: say its name, or «that's all». Long lists are read five at a time. Ask about a single plant («does the monstera need water?») and it tells you whether it is due today, how many days overdue it is or which day it is due; if it is due, it offers to log the watering.
Privacy
For each token we store the date it was last used and a daily count of requests, so we can apply the limits and show you whether it is in use.
The token itself is stored only as a hash, never in clear text: nobody, not even us, can read it back. That is why it is shown just once.
Support
For questions, bug reports or help with your account, write to [email protected].
Typical response time: 24–48 business hours.