Overview
Garden.gg uses gamification to make gardening more engaging. Earn XP for garden activities, unlock badges for milestones, maintain care streaks, and compete on leaderboards. The Achievements API lets you query all gamification data.
XP Values
Every garden activity earns experience points:
| Activity | XP Earned |
|---|---|
| Watering | 5 |
| Note / Observation | 5 |
| Pest treatment | 5 |
| Thinning | 5 |
| Fertilizing | 10 |
| Pruning | 10 |
| Mulching | 10 |
| Weeding | 10 |
| Training/Staking | 10 |
| Sowing | 10 |
| Harvesting | 15 |
| Transplanting | 15 |
| Photo upload | 20 |
Achievement Categories
| Category | Description |
|---|---|
| Planting | Milestones for number of plants grown |
| Harvesting | Milestones for total harvest weight and variety |
| Streaks | Consecutive days of garden care activity |
| Community | Sharing gardens, helping others, public profiles |
| Discovery | Growing new plant types, trying new techniques |
Endpoints
| Method | Path | Description | Auth Required |
|---|---|---|---|
GET | /achievements | List all achievements with status | Yes |
GET | /achievements/badges | List available badges | Yes |
GET | /gamification/stats | Get your gamification stats | Yes |
GET | /leaderboard | Get the leaderboard | Yes |
GET | /leaderboard/friends | Get friends-only leaderboard | Yes |
List Achievements
Retrieve all achievements and your unlock status for each.
GET /achievements
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
per_page | integer | 20 | Items per page (max 100) |
category | string | — | Filter by category |
unlocked | boolean | — | Filter by unlock status (true/false) |
Response 200 OK
{
"data": [
{
"id": "ach_first_seed",
"name": "First Seed",
"description": "Sow your first seed",
"category": "Planting",
"icon_url": "https://cdn.garden.gg/badges/first_seed.png",
"xp_reward": 50,
"unlocked": true,
"unlocked_at": "2026-02-15T09:30:00Z"
},
{
"id": "ach_green_thumb",
"name": "Green Thumb",
"description": "Grow 10 different plant types",
"category": "Discovery",
"icon_url": "https://cdn.garden.gg/badges/green_thumb.png",
"xp_reward": 200,
"unlocked": false,
"unlocked_at": null,
"progress": {
"current": 7,
"target": 10
}
},
{
"id": "ach_harvest_king",
"name": "Harvest Royalty",
"description": "Harvest over 10kg total",
"category": "Harvesting",
"icon_url": "https://cdn.garden.gg/badges/harvest_king.png",
"xp_reward": 500,
"unlocked": false,
"unlocked_at": null,
"progress": {
"current": 4250,
"target": 10000,
"unit": "grams"
}
}
],
"total": 42,
"page": 1,
"per_page": 20
}
Examples
cURL
# List unlocked achievements
curl -X GET "https://garden.gg/api/v1/achievements?unlocked=true" \
-H "Authorization: Bearer gg_live_your_api_key_here"
# List planting achievements
curl -X GET "https://garden.gg/api/v1/achievements?category=Planting" \
-H "Authorization: Bearer gg_live_your_api_key_here"
Python
import requests
headers = {"Authorization": "Bearer gg_live_your_api_key_here"}
# Get all achievements and show progress
response = requests.get(
"https://garden.gg/api/v1/achievements",
headers=headers,
params={"per_page": 100},
)
achievements = response.json()
for ach in achievements["data"]:
status = "Unlocked" if ach["unlocked"] else "Locked"
progress = ""
if not ach["unlocked"] and "progress" in ach:
p = ach["progress"]
progress = f" ({p['current']}/{p['target']})"
print(f"[{status}] {ach['name']}: {ach['description']}{progress}")
Node.js
const response = await fetch(
"https://garden.gg/api/v1/achievements?per_page=100",
{ headers: { Authorization: "Bearer gg_live_your_api_key_here" } }
);
const { data: achievements } = await response.json();
const unlocked = achievements.filter((a) => a.unlocked);
const locked = achievements.filter((a) => !a.unlocked);
console.log(`Unlocked: ${unlocked.length} / ${achievements.length}`);
locked.forEach((a) => {
const progress = a.progress
? ` (${a.progress.current}/${a.progress.target})`
: "";
console.log(` - ${a.name}${progress}`);
});
List Badges
Retrieve all available badges. Badges are visual representations of achievements displayed on your profile.
GET /achievements/badges
Response 200 OK
{
"data": [
{
"id": "bdg_seedling",
"name": "Seedling",
"description": "Reach level 5",
"icon_url": "https://cdn.garden.gg/badges/seedling.png",
"tier": "bronze",
"unlocked": true
},
{
"id": "bdg_grower",
"name": "Grower",
"description": "Reach level 15",
"icon_url": "https://cdn.garden.gg/badges/grower.png",
"tier": "silver",
"unlocked": false
},
{
"id": "bdg_master_gardener",
"name": "Master Gardener",
"description": "Reach level 30",
"icon_url": "https://cdn.garden.gg/badges/master_gardener.png",
"tier": "gold",
"unlocked": false
}
]
}
Gamification Stats
Get your current gamification summary.
GET /gamification/stats
Response 200 OK
{
"user_id": "usr_a1b2c3d4",
"xp": 2450,
"level": 12,
"xp_to_next_level": 550,
"xp_for_next_level": 3000,
"streak_days": 14,
"longest_streak": 31,
"badge_count": 8,
"total_badges": 24,
"achievements_unlocked": 15,
"total_achievements": 42,
"total_harvests": 23,
"total_harvest_grams": 4250,
"plants_grown": 7,
"gardens_count": 2
}
Examples
cURL
curl -X GET "https://garden.gg/api/v1/gamification/stats" \
-H "Authorization: Bearer gg_live_your_api_key_here"
Python
import requests
headers = {"Authorization": "Bearer gg_live_your_api_key_here"}
response = requests.get(
"https://garden.gg/api/v1/gamification/stats",
headers=headers,
)
stats = response.json()
print(f"Level {stats['level']} — {stats['xp']} XP")
print(f"Streak: {stats['streak_days']} days (best: {stats['longest_streak']})")
print(f"Badges: {stats['badge_count']}/{stats['total_badges']}")
print(f"Harvested: {stats['total_harvest_grams']}g from {stats['total_harvests']} harvests")
Node.js
const response = await fetch("https://garden.gg/api/v1/gamification/stats", {
headers: { Authorization: "Bearer gg_live_your_api_key_here" },
});
const stats = await response.json();
console.log(`Level ${stats.level} — ${stats.xp} XP`);
console.log(`Streak: ${stats.streak_days} days (best: ${stats.longest_streak})`);
console.log(`Badges: ${stats.badge_count}/${stats.total_badges}`);
Leaderboard
Retrieve the global leaderboard, ranked by XP.
GET /leaderboard
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
period | string | weekly | One of: weekly, monthly, all_time |
page | integer | 1 | Page number |
per_page | integer | 20 | Items per page (max 100) |
Response 200 OK
{
"period": "weekly",
"data": [
{
"rank": 1,
"user": {
"username": "plant_master",
"display_name": "Plant Master",
"level": 28,
"avatar_url": "https://cdn.garden.gg/avatars/plant_master.jpg"
},
"xp": 890,
"activities": 47
},
{
"rank": 2,
"user": {
"username": "green_thumb",
"display_name": "Green Thumb",
"level": 12,
"avatar_url": "https://cdn.garden.gg/avatars/green_thumb.jpg"
},
"xp": 735,
"activities": 38
}
],
"your_rank": 15,
"total": 1234,
"page": 1,
"per_page": 20
}
Examples
cURL
# Get monthly leaderboard
curl -X GET "https://garden.gg/api/v1/leaderboard?period=monthly" \
-H "Authorization: Bearer gg_live_your_api_key_here"
Python
import requests
headers = {"Authorization": "Bearer gg_live_your_api_key_here"}
response = requests.get(
"https://garden.gg/api/v1/leaderboard",
headers=headers,
params={"period": "weekly"},
)
board = response.json()
print(f"Your rank: #{board['your_rank']} (out of {board['total']})")
for entry in board["data"][:5]:
print(f" #{entry['rank']} {entry['user']['display_name']} — {entry['xp']} XP")
Node.js
const response = await fetch(
"https://garden.gg/api/v1/leaderboard?period=all_time",
{ headers: { Authorization: "Bearer gg_live_your_api_key_here" } }
);
const board = await response.json();
console.log(`Your rank: #${board.your_rank}`);
board.data.forEach((e) =>
console.log(` #${e.rank} ${e.user.display_name} — ${e.xp} XP`)
);
Friends Leaderboard
Retrieve a leaderboard limited to users you follow.
GET /leaderboard/friends
Same query parameters and response format as the global leaderboard. Returns only users you follow, plus your own entry.
Error Responses
| Scenario | HTTP Status | Error Code |
|---|---|---|
| Invalid period value | 400 | VALIDATION_ERROR |
| Invalid category filter | 400 | VALIDATION_ERROR |
| Not authenticated | 401 | UNAUTHORIZED |