Overview
Events are the activity log for your garden. Record watering, harvests, fertilizing, pruning, and other care activities for each plot. Events power XP calculations, achievement tracking, and care streak gamification.
Event Types
| Type | Description | XP |
|---|---|---|
watering | Watered the plot | 5 |
harvest | Harvested produce (includes weight data) | 15 |
fertilize | Applied fertilizer or amendments | 10 |
prune | Pruned or deadheaded plants | 10 |
sow | Sowed seeds directly in the plot | 10 |
transplant | Transplanted a seedling into the plot | 15 |
pest | Noted or treated pest/disease issue | 5 |
note | General observation or note | 5 |
mulch | Applied mulch | 10 |
weed | Weeded the plot | 10 |
train | Trained, staked, or trellised plants | 10 |
thin | Thinned seedlings | 5 |
Endpoints
| Method | Path | Description | Auth Required |
|---|---|---|---|
GET | /plots/:id/events | List events for a plot | Yes |
POST | /plots/:id/events | Create an event | Yes |
GET | /events/:id | Get event details | Yes |
PUT | /events/:id | Update an event | Yes |
DELETE | /events/:id | Delete an event | Yes |
List Events
Retrieve events for a specific plot, with optional filtering.
GET /plots/:plotId/events
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
per_page | integer | 20 | Items per page (max 100) |
event_type | string | — | Filter by event type |
start_date | string | — | Filter events after this date (RFC 3339) |
end_date | string | — | Filter events before this date (RFC 3339) |
Response 200 OK
{
"data": [
{
"id": "evt_a1b2c3d4",
"plot_id": "plt_m3n4o5p6",
"event_type": "harvest",
"title": "Tomato Harvest",
"notes": "First harvest of the season! Beautiful Cherokee Purples.",
"quantity_grams": 1250,
"quality_rating": 5,
"photos": [
{
"id": "pht_x1y2z3",
"url": "https://cdn.garden.gg/events/pht_x1y2z3.jpg",
"thumbnail_url": "https://cdn.garden.gg/events/pht_x1y2z3_thumb.jpg"
}
],
"xp_earned": 15,
"created_at": "2026-07-20T18:30:00Z",
"updated_at": "2026-07-20T18:30:00Z"
},
{
"id": "evt_e5f6g7h8",
"plot_id": "plt_m3n4o5p6",
"event_type": "watering",
"title": "Morning watering",
"notes": "Deep watering, soil was dry 2 inches down",
"quantity_grams": null,
"quality_rating": null,
"photos": [],
"xp_earned": 5,
"created_at": "2026-07-20T07:00:00Z",
"updated_at": "2026-07-20T07:00:00Z"
}
],
"total": 47,
"page": 1,
"per_page": 20
}
Examples
cURL
# List all harvest events for a plot
curl -X GET "https://garden.gg/api/v1/plots/plt_m3n4o5p6/events?event_type=harvest" \
-H "Authorization: Bearer gg_live_your_api_key_here"
# Filter events by date range
curl -X GET "https://garden.gg/api/v1/plots/plt_m3n4o5p6/events?start_date=2026-07-01T00:00:00Z&end_date=2026-07-31T23:59:59Z" \
-H "Authorization: Bearer gg_live_your_api_key_here"
Python
import requests
headers = {"Authorization": "Bearer gg_live_your_api_key_here"}
# Get all harvest events
response = requests.get(
"https://garden.gg/api/v1/plots/plt_m3n4o5p6/events",
headers=headers,
params={"event_type": "harvest"},
)
events = response.json()
total_grams = sum(e["quantity_grams"] for e in events["data"] if e["quantity_grams"])
print(f"Total harvested: {total_grams}g from {events['total']} harvests")
Node.js
const params = new URLSearchParams({
event_type: "harvest",
start_date: "2026-07-01T00:00:00Z",
end_date: "2026-07-31T23:59:59Z",
});
const response = await fetch(
`https://garden.gg/api/v1/plots/plt_m3n4o5p6/events?${params.toString()}`,
{ headers: { Authorization: "Bearer gg_live_your_api_key_here" } }
);
const { data: events, total } = await response.json();
console.log(`${total} harvest events in July`);
Create Event
Log a new garden activity event.
POST /plots/:plotId/events
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
event_type | string | Yes | One of the supported event types (see above) |
title | string | Yes | Short title for the event (1-200 characters) |
notes | string | No | Detailed notes |
quantity_grams | integer | No | Weight in grams (harvest events) |
quality_rating | integer | No | Quality rating 1-5 (harvest events) |
For harvest events, quantity_grams and quality_rating are strongly recommended.
Request
{
"event_type": "harvest",
"title": "Tomato Harvest",
"notes": "First harvest of the season! Beautiful Cherokee Purples.",
"quantity_grams": 1250,
"quality_rating": 5
}
Response 201 Created
{
"id": "evt_i9j0k1l2",
"plot_id": "plt_m3n4o5p6",
"event_type": "harvest",
"title": "Tomato Harvest",
"notes": "First harvest of the season! Beautiful Cherokee Purples.",
"quantity_grams": 1250,
"quality_rating": 5,
"photos": [],
"xp_earned": 15,
"created_at": "2026-07-20T18:30:00Z",
"updated_at": "2026-07-20T18:30:00Z"
}
Photo Upload
To attach photos to an event, use a multipart form data request:
curl -X POST "https://garden.gg/api/v1/plots/plt_m3n4o5p6/events" \
-H "Authorization: Bearer gg_live_your_api_key_here" \
-F "event_type=harvest" \
-F "title=Tomato Harvest" \
-F "quantity_grams=1250" \
-F "quality_rating=5" \
-F "photos[][email protected]" \
-F "photos[][email protected]"
Photos are automatically resized and thumbnails are generated. Supported formats: JPEG, PNG, WebP. Maximum file size: 10MB per photo, 5 photos per event.
Examples
cURL
# Log a watering event
curl -X POST "https://garden.gg/api/v1/plots/plt_m3n4o5p6/events" \
-H "Authorization: Bearer gg_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"event_type": "watering",
"title": "Evening watering",
"notes": "Deep watering before expected heat wave"
}'
Python
import requests
headers = {
"Authorization": "Bearer gg_live_your_api_key_here",
"Content-Type": "application/json",
}
# Log a fertilizing event
response = requests.post(
"https://garden.gg/api/v1/plots/plt_m3n4o5p6/events",
headers=headers,
json={
"event_type": "fertilize",
"title": "Fish emulsion feed",
"notes": "Applied 5-1-1 fish emulsion, diluted per label",
},
)
event = response.json()
print(f"Logged event: {event['title']} (+{event['xp_earned']} XP)")
Python (with photo upload)
import requests
headers = {"Authorization": "Bearer gg_live_your_api_key_here"}
with open("harvest.jpg", "rb") as photo:
response = requests.post(
"https://garden.gg/api/v1/plots/plt_m3n4o5p6/events",
headers=headers,
data={
"event_type": "harvest",
"title": "Basil harvest",
"quantity_grams": 200,
"quality_rating": 4,
},
files={"photos[]": ("harvest.jpg", photo, "image/jpeg")},
)
event = response.json()
print(f"Logged harvest with {len(event['photos'])} photo(s)")
Node.js
const response = await fetch(
"https://garden.gg/api/v1/plots/plt_m3n4o5p6/events",
{
method: "POST",
headers: {
Authorization: "Bearer gg_live_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
event_type: "pest",
title: "Aphid outbreak",
notes: "Found aphids on pepper plants. Applied neem oil spray.",
}),
}
);
const event = await response.json();
console.log(`Logged: ${event.title} (+${event.xp_earned} XP)`);
Get Event
Retrieve details for a single event.
GET /events/:id
Response 200 OK
Returns a full event object (same structure as in the list response).
Update Event
Update an existing event.
PUT /events/:id
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
title | string | No | Event title |
notes | string | No | Detailed notes |
quantity_grams | integer | No | Weight in grams |
quality_rating | integer | No | Quality rating 1-5 |
The event_type cannot be changed after creation.
Response 200 OK
Returns the full updated event object.
Delete Event
Delete an event. XP earned from this event will be deducted from your total.
DELETE /events/:id
Response 204 No Content
No response body.
Error Responses
| Scenario | HTTP Status | Error Code |
|---|---|---|
| Event not found | 404 | NOT_FOUND |
| Plot not found | 404 | NOT_FOUND |
| Invalid event type | 400 | VALIDATION_ERROR |
| Missing required fields | 400 | VALIDATION_ERROR |
| Invalid quality rating | 400 | VALIDATION_ERROR |
| Photo too large (>10MB) | 400 | VALIDATION_ERROR |
| Too many photos (>5) | 400 | VALIDATION_ERROR |
| Not your event | 403 | FORBIDDEN |
| Not authenticated | 401 | UNAUTHORIZED |