Overview
The Users API covers public profiles, account management, password changes, and API key management. Public profiles are viewable by anyone; account endpoints require authentication and operate on the authenticated user’s own data.
Endpoints
| Method | Path | Description | Auth Required |
|---|---|---|---|
GET | /users/:username | Get a public profile | No |
GET | /account | Get your account details | Yes |
PUT | /account | Update your account | Yes |
PUT | /account/password | Change your password | Yes |
GET | /account/api-keys | List your API keys | Yes |
POST | /account/api-keys | Create an API key | Yes |
DELETE | /account/api-keys/:id | Revoke an API key | Yes |
Public Profile
Retrieve a user’s public profile. This endpoint does not require authentication.
GET /users/:username
Path Parameters
| Parameter | Type | Description |
|---|---|---|
username | string | The user’s username |
Response 200 OK
{
"username": "green_thumb",
"display_name": "Green Thumb",
"bio": "Urban gardener in Portland, OR. Zone 8b. Growing tomatoes, peppers, and herbs.",
"avatar_url": "https://cdn.garden.gg/avatars/green_thumb.jpg",
"zone": "8b",
"level": 12,
"xp": 2450,
"badge_count": 8,
"badges": [
{
"id": "bdg_seedling",
"name": "Seedling",
"icon_url": "https://cdn.garden.gg/badges/seedling.png",
"tier": "bronze"
},
{
"id": "bdg_streak_7",
"name": "Week Warrior",
"icon_url": "https://cdn.garden.gg/badges/streak_7.png",
"tier": "bronze"
}
],
"public_gardens": [
{
"id": "gdn_a1b2c3d4",
"name": "Backyard Paradise",
"location": "Portland, OR",
"zone": "8b",
"plot_count": 4
}
],
"joined_at": "2026-01-10T00:00:00Z"
}
Examples
cURL
curl -X GET "https://garden.gg/api/v1/users/green_thumb"
Python
import requests
response = requests.get("https://garden.gg/api/v1/users/green_thumb")
profile = response.json()
print(f"{profile['display_name']} — Level {profile['level']}")
print(f"Bio: {profile['bio']}")
print(f"Badges: {profile['badge_count']}")
for garden in profile["public_gardens"]:
print(f" Garden: {garden['name']} ({garden['plot_count']} plots)")
Node.js
const response = await fetch("https://garden.gg/api/v1/users/green_thumb");
const profile = await response.json();
console.log(`${profile.display_name} — Level ${profile.level}`);
console.log(`Bio: ${profile.bio}`);
profile.public_gardens.forEach((g) =>
console.log(` Garden: ${g.name} (${g.plot_count} plots)`)
);
Get Account
Retrieve your own account details. Includes private information not shown on the public profile.
GET /account
Response 200 OK
{
"id": "usr_a1b2c3d4",
"email": "[email protected]",
"username": "green_thumb",
"display_name": "Green Thumb",
"bio": "Urban gardener in Portland, OR. Zone 8b.",
"avatar_url": "https://cdn.garden.gg/avatars/green_thumb.jpg",
"zone": "8b",
"level": 12,
"xp": 2450,
"plan": "bloom",
"email_verified": true,
"created_at": "2026-01-10T00:00:00Z",
"updated_at": "2026-03-15T09:00:00Z"
}
Examples
cURL
curl -X GET "https://garden.gg/api/v1/account" \
-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/account", headers=headers)
account = response.json()
print(f"Email: {account['email']}")
print(f"Plan: {account['plan']}")
print(f"Level: {account['level']} ({account['xp']} XP)")
Node.js
const response = await fetch("https://garden.gg/api/v1/account", {
headers: { Authorization: "Bearer gg_live_your_api_key_here" },
});
const account = await response.json();
console.log(`Email: ${account.email}`);
console.log(`Plan: ${account.plan}`);
console.log(`Level: ${account.level} (${account.xp} XP)`);
Update Account
Update your account details. Only include the fields you want to change.
PUT /account
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
display_name | string | No | Display name (1-50 characters) |
bio | string | No | Profile bio (max 500 characters) |
avatar | file | No | Avatar image (multipart upload) |
zone | string | No | USDA hardiness zone (e.g., “8b”) |
Request
{
"display_name": "Green Thumb Pro",
"bio": "Urban gardener and composting enthusiast in Portland, OR.",
"zone": "8b"
}
Response 200 OK
Returns the full updated account object.
Examples
cURL
curl -X PUT "https://garden.gg/api/v1/account" \
-H "Authorization: Bearer gg_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"display_name": "Green Thumb Pro",
"bio": "Urban gardener and composting enthusiast in Portland, OR."
}'
cURL (with avatar upload)
curl -X PUT "https://garden.gg/api/v1/account" \
-H "Authorization: Bearer gg_live_your_api_key_here" \
-F "display_name=Green Thumb Pro" \
-F "[email protected]"
Python
import requests
response = requests.put(
"https://garden.gg/api/v1/account",
headers={
"Authorization": "Bearer gg_live_your_api_key_here",
"Content-Type": "application/json",
},
json={
"display_name": "Green Thumb Pro",
"bio": "Urban gardener and composting enthusiast.",
"zone": "8b",
},
)
account = response.json()
print(f"Updated: {account['display_name']}")
Node.js
const response = await fetch("https://garden.gg/api/v1/account", {
method: "PUT",
headers: {
Authorization: "Bearer gg_live_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
display_name: "Green Thumb Pro",
bio: "Urban gardener and composting enthusiast.",
zone: "8b",
}),
});
const account = await response.json();
console.log(`Updated: ${account.display_name}`);
Change Password
Change your account password. Requires your current password for verification.
PUT /account/password
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
current_password | string | Yes | Your current password |
new_password | string | Yes | New password (min 8 characters) |
Request
{
"current_password": "old_s3cur3p4ss",
"new_password": "new_s3cur3p4ss"
}
Response 200 OK
{
"message": "Password updated successfully."
}
Examples
cURL
curl -X PUT "https://garden.gg/api/v1/account/password" \
-H "Authorization: Bearer gg_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"current_password": "old_s3cur3p4ss",
"new_password": "new_s3cur3p4ss"
}'
Python
import requests
response = requests.put(
"https://garden.gg/api/v1/account/password",
headers={
"Authorization": "Bearer gg_live_your_api_key_here",
"Content-Type": "application/json",
},
json={
"current_password": "old_s3cur3p4ss",
"new_password": "new_s3cur3p4ss",
},
)
print(response.json()["message"])
Node.js
const response = await fetch("https://garden.gg/api/v1/account/password", {
method: "PUT",
headers: {
Authorization: "Bearer gg_live_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
current_password: "old_s3cur3p4ss",
new_password: "new_s3cur3p4ss",
}),
});
const result = await response.json();
console.log(result.message);
List API Keys
Retrieve all API keys associated with your account. The full key value is not returned; only the last 4 characters are shown.
GET /account/api-keys
Response 200 OK
{
"data": [
{
"id": "key_x9y8z7",
"name": "CI Pipeline",
"key_suffix": "o345",
"created_at": "2026-02-01T10:00:00Z",
"last_used_at": "2026-03-15T08:30:00Z"
},
{
"id": "key_w6v5u4",
"name": "Home Assistant",
"key_suffix": "p678",
"created_at": "2026-03-01T14:00:00Z",
"last_used_at": null
}
]
}
Create API Key
Generate a new API key. The full key is only returned once.
POST /account/api-keys
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | A label for this key (1-50 chars) |
Request
{
"name": "Greenhouse Monitor"
}
Response 201 Created
{
"id": "key_t3s2r1",
"name": "Greenhouse Monitor",
"key": "gg_live_abc123def456ghi789jkl012mno345",
"created_at": "2026-03-15T10:00:00Z"
}
Store the key value securely. It will not be shown again.
Examples
cURL
curl -X POST "https://garden.gg/api/v1/account/api-keys" \
-H "Authorization: Bearer gg_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "Greenhouse Monitor"}'
Python
import requests
response = requests.post(
"https://garden.gg/api/v1/account/api-keys",
headers={
"Authorization": "Bearer gg_live_your_api_key_here",
"Content-Type": "application/json",
},
json={"name": "Greenhouse Monitor"},
)
key_data = response.json()
print(f"API Key created: {key_data['key']}")
print("Store this key securely — it will not be shown again.")
Node.js
const response = await fetch("https://garden.gg/api/v1/account/api-keys", {
method: "POST",
headers: {
Authorization: "Bearer gg_live_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({ name: "Greenhouse Monitor" }),
});
const keyData = await response.json();
console.log(`API Key created: ${keyData.key}`);
console.log("Store this key securely — it will not be shown again.");
Revoke API Key
Permanently revoke an API key. Any requests using this key will immediately start returning 401 Unauthorized.
DELETE /account/api-keys/:id
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The API key’s ID |
Response 204 No Content
No response body.
Examples
cURL
curl -X DELETE "https://garden.gg/api/v1/account/api-keys/key_w6v5u4" \
-H "Authorization: Bearer gg_live_your_api_key_here"
Python
import requests
response = requests.delete(
"https://garden.gg/api/v1/account/api-keys/key_w6v5u4",
headers={"Authorization": "Bearer gg_live_your_api_key_here"},
)
if response.status_code == 204:
print("API key revoked successfully.")
Node.js
const response = await fetch(
"https://garden.gg/api/v1/account/api-keys/key_w6v5u4",
{
method: "DELETE",
headers: { Authorization: "Bearer gg_live_your_api_key_here" },
}
);
if (response.status === 204) {
console.log("API key revoked successfully.");
}
Error Responses
| Scenario | HTTP Status | Error Code |
|---|---|---|
| User not found | 404 | NOT_FOUND |
| API key not found | 404 | NOT_FOUND |
| Current password incorrect | 400 | VALIDATION_ERROR |
| New password too short | 400 | VALIDATION_ERROR |
| Missing required name field | 400 | VALIDATION_ERROR |
| Avatar file too large | 400 | VALIDATION_ERROR |
| Not authenticated | 401 | UNAUTHORIZED |