API reference
Everything the app does goes through a JSON API that you can use with your organization key. The full, interactive reference is at /api/docs, built from /openapi.json.
Authentication
curl -H "X-API-Key: dl_…" https://your-deepleaf-address/api/organizations/org-1
curl -H "Authorization: Bearer dl_…" https://your-deepleaf-address/api/organizations/org-1
Missing, unknown, or revoked keys get 401. A path under another organization gets 404. A member key gets 403 on key management and billing payments; see Organization and keys. Use the address you open the app on.
Path shorthand
Below, {cycle} stands for the full crop cycle path:
/api/organizations/{organization_id}/farms/{farm_id}/greenhouses/{greenhouse_id}/rows/{row_id}/cycles/{cycle_id}
Weeks are written 2026-W40 or as any date in that week, YYYY-MM-DD.
Scoring
| Method and path | What it does |
|---|---|
POST /api/observations | Upload a photo or video (multipart file, with optional mode, conf, sample_seconds, max_frames, mm_per_pixel). Returns a job id. |
GET /api/observations/{id} | Status, progress, and the result with frames, fruit, stems, plants, and quality. |
GET /api/observations/{id}/frames/{frame}/{name} | A frame image or overlay. |
POST /api/examples/{key} | Score one of the example photos. |
POST {cycle}/videos | Upload and save a walk to a cycle and a week. |
POST {cycle}/videos/batch | Up to 12 video clips as repeated files fields, in walking order, scored and counted as one walk. The job's clips field shows progress per clip. |
Registry
| Method and path | What it does |
|---|---|
GET /api/organizations/{org} | The organization's tree of farms, greenhouses, rows, and cycles. |
POST …/farms, …/greenhouses, …/rows, …/cycles | Create a level. |
PATCH a level's path | Change names and details. Ids stay. |
GET a level's path + /contents | Counts of everything under the level. |
DELETE a level's path | 409 with counts while it holds anything. ?cascade=true deletes it with its contents. |
Records
| Method and path | What it does |
|---|---|
POST / GET {cycle}/harvests | Log one harvest (week, kg, note), or list them. ?week= filters. |
POST {cycle}/harvests/csv | Upload a week,kg[,note] file. |
PATCH / DELETE {cycle}/harvests/{id} | Edit or delete one harvest. |
POST / GET {cycle}/irrigation | Log one entry, or list them newest first. |
PATCH / DELETE {cycle}/irrigation/{id} | Edit or delete one entry. |
POST / GET {cycle}/climate | Add readings as {"points": [...]}, or list them (metric, from, to, limit, offset). |
POST {cycle}/climate/csv/preview | Check a climate file without storing it: the detected layout, each column's metric, unit, conversion and confidence, the time zone and time range, the first rows, warnings and blocking problems, and a mapping to confirm. Takes the same form fields as the upload, including compartment and date_order (dmy or mdy). |
POST {cycle}/climate/csv | Upload a climate file. Send the mapping from the preview to import exactly what was previewed (columns left out of it are not imported), or columns to name them yourself; refused with 400 while the file has problems, and 413 above the size cap. |
POST {cycle}/climate/file/preview | Check a climate computer export (CSV, text or .xlsx) without storing it: the file, the clock it is read on (time_zone), each column with its metric and unit, setpoints, the first hours, what is already stored, warnings, blocking problems, and a mapping to confirm. |
POST {cycle}/climate/file | Store the export's hours with the confirmed mapping; remember saves the column choices for the greenhouse. Re-imported hours are updated, never doubled. |
POST {cycle}/climate/ingest | The same import for a script of your own: the file as the request body, a key in a header only, the greenhouse's saved column choices. See Import your climate computer data. |
GET / DELETE {greenhouse}/climate/file-mapping | The column choices saved for a greenhouse, or forget them. |
GET {cycle}/climate/imports | The cycle's recent climate imports, newest first. |
POST {cycle}/climate/imports/{id}/undo | Undo one import: removes the readings it added and puts back the values it changed. 409 when a later import changed the same readings, unless the body is {"confirm": true}. |
PATCH / DELETE {cycle}/climate/{id} | Edit or delete one reading. |
POST {cycle}/fruit-mass | Typed grams for green_g, turning_g, red_g. |
POST {cycle}/weather | Refresh outdoor weather for the greenhouse location now (past_days, forecast_days). |
Weeks and forecasts
| Method and path | What it does |
|---|---|
GET {cycle}/weeks/{week} | The week read: walk counts, harvest, irrigation, climate, water productivity, and forecast. |
GET {cycle}/forecast?week= | The forecast for the walk week and the seven after it (default: latest walk week). |
POST / GET {cycle}/forecasts | Issue and store the current forecast, or list stored ones with the harvest since. |
GET {cycle}/backtest | Replayed error per horizon against the harvests. |
GET {cycle}/export.csv | One row per week. |
Walk corrections
Below, {walk} stands for /api/organizations/{org}/walks/{walk_id}, where walk_id is the walk's job id. See Correct a walk.
| Method and path | What it does |
|---|---|
GET {walk}/corrections | The walk's corrections, its fruit after them, the crop-cycle weeks it is saved to, and the model and corrected counts. |
POST {walk}/corrections | Add one. kind is ripeness (track_id, ripeness), remove (track_id), add (ripeness, frame_id, box as [x1, y1, x2, y2] in pixels), or counts (counts with any of green, turning, red). Each takes an optional note. |
PATCH {walk}/corrections/{correction_id} | Change the ripeness, the box, the counts, or the note. The kind and the fruit stay. |
DELETE {walk}/corrections/{correction_id} | Undo one correction. |
Every answer carries the walk's model and corrected counts. Any key of the organization may correct, admin or member. A walk of another organization reads as 404, and a walk still scoring as 409. A second correction on the same fruit, a second set of counts, or more than 2,000 corrections on one walk get 409. Counts are whole numbers from 0 to 1,000,000, and a note is at most 500 characters.
Session and status
| Method and path | What it does |
|---|---|
GET /api/health | Whether scoring and the database are available. No key needed. |
GET / POST / DELETE /api/session | Read (with the key's role), sign in (sets the cookie), or sign out. |
GET / POST /api/organizations/{org}/keys | List or create keys. Admin keys only; a new key is shown once. |
PATCH …/keys/{id}, POST …/keys/{id}/revoke | Rename or revoke a key. The last admin key gets 409. |