Treegens API
This is the backend for the Treegens Game (GROWalition): a cross-player leaderboard and counter, a cloud-save service for player progress, and a small read-only proxy onto public Treegens platform stats. It is a purpose-built API for that game client, published here for transparency rather than as a general third-party platform: there is no signup flow or issued API key.
https://treegens-api.netlify.app
Environment: Production only
No API key required
What this API is for
/api/grow: the in-game tree counter and leaderboard (read and write, no account needed)./api/tg: a cached, read-only mirror of a few public Treegens platform statistics./api/save: cloud save and restore for a player's game progress, protected by a recovery secret.
There is currently no staging or sandbox environment. Netlify creates a temporary deploy-preview URL for every branch push, but those are not a stable target for integration, so build against the production base URL above.
Authentication
Two of the three endpoint groups need no credential at all; the third uses a bearer secret that is shown to the caller exactly once. There is no OAuth flow, no API key issuance, and no account system.
/api/grow and /api/tg
No authentication. These are public, anonymous endpoints. Abuse is controlled with IP-based rate limiting and server-side caching rather than a credential.
/api/save
Every action except create requires either:
Authorization: Bearer <recoverySecret>: a 256-bit secret returned once when a save is created, or once on rotation. It is never re-shown or recoverable.X-Grow-Session: <token>: a short-lived signed token (30 minutes) issued from a valid secret, so autosave doesn't have to keep resending it.
Credentials are header-only. A request that carries a secret, token,
key, or password in the query string is rejected outright (400 credential-in-url),
because query strings end up in logs and browser history.
Browser origin policy (CORS)
CORS is enforced as a browser-only policy, not as authentication. Requests with no
Origin header (curl, server-to-server calls, most native/backend clients) are not
blocked by it. They are gated purely by the credential above. Browser writes and all
/api/save calls are only accepted from:
https://treegens-game.netlify.app(production)- Netlify deploy-preview subdomains of that site
http://localhost:5700(local development)
GET /api/grow from this documentation origin is allowed so the live demo
below can run. POST and DELETE from this origin are rejected.
Browser requests to /api/tg from this documentation origin are rejected.
Use curl (no Origin header) or the game origin.
Health & status
Not published: there is no dedicated
/health or status endpoint, and no uptime/SLA figure is published for this API.
Do not treat any number on this page as an uptime guarantee.
Closest available liveness signal
There is still no /health route. There is no Try-it button for
/api/tg on this page. From curl (no
Origin header) or the game origin,
GET /api/tg?r=stats doubles as a liveness check
for this service: if it responds, the function and its cache are up. Browser requests to
/api/tg from this documentation origin are rejected. The JSON body also tells you
whether that data is fresh:
"_cached": false: served live from the upstream Treegens backend."_cached": true, "_age": <seconds>: served from cache (stats cache for 300s, leaderboards for 600s) instead of calling upstream again."_cached": true, "_stale": true: the upstream backend didn't answer in time, so a stale cached copy was served rather than an error.503 {"error":"upstream-unavailable"}: upstream failed and there was no cached copy to fall back to.
Quick start
The fastest way to see a real response is the public leaderboard endpoint. It needs no credential and no request body:
curl https://treegens-api.netlify.app/api/grow
Not run yet. This calls the real, public /api/grow endpoint relative to this page.
Nothing is faked. It does not call /api/tg: browser GET from this origin is rejected.
Example response shape
This mirrors the fields /api/grow actually returns on GET. Numbers
below are illustrative placeholders, not a live snapshot. Use "Try it live" above for real
current values.
{
"you": null,
"weekly": { "week": 3021, "goal": 5000, "planted": 812 },
"counter": 48210,
"growers": 137,
"realTrees": 0,
"board": [
{ "name": "Treegen", "exp": 9120, "trees": 340, "real": 0, "id": "a1b2c3" }
],
"daily": {
"day": 20323,
"players": 22,
"top": [ { "name": "Treegen", "score": 14200, "id": "a1b2c3" } ]
}
}
Pass ?id=<yourPlayerId> on the request to also receive a you
object with your leaderboard rank; player ids in board and daily.top
are always truncated to 6 characters for privacy.
Endpoints
| Endpoint | Auth | Purpose |
|---|---|---|
GET POST DEL /api/grow |
None | Read the leaderboard/counter (GET), submit a score (POST), or remove your own entry by id (DELETE). No PII is stored; writes only ever move stats upward. |
GET /api/tg?r=stats|leaderboard-trees|leaderboard-points |
None | Cached, read-only proxy onto the public Treegens platform backend. Only these three routes are relayed; any other r value returns 400 unknown-route. Browser GET from this documentation origin is rejected; use curl or the game origin. There is no live Try-it for /api/tg here. |
GET POST DEL /api/save |
Bearer secret or session token (see Authentication) | Create, read, update, or delete a cloud save. POST actions are create, save, session, rotate, revoke, and share. See save, resume, return. |
Not published: there is no OpenAPI/Swagger document and no official client SDK for this API yet. The table above is the complete, current route list.
Save, resume, return
Cloud save is how a player comes back. Create a save once, keep the recovery secret on the
device, then GET to resume. This API never re-shows a lost secret.
Browser calls to /api/save from this page are rejected (CORS). Allowed
browser origins are the Treegens Game production site, its deploy previews, and
http://localhost:5700. Curl and other no-Origin clients are not blocked by
CORS; after create they still need the recovery secret. There is no live create-save
button here: it would fail CORS and would write a real record.
Create (secret shown once)
exp and grove are required. The 201 body includes id,
recoverySecret (this once only), expiresAt, session,
version, and savedAt. Copy recoverySecret off the
response immediately.
curl -sS -X POST https://treegens-api.netlify.app/api/save \
-H "content-type: application/json" \
-d '{"action":"create","save":{"exp":0,"grove":[]}}'
Resume
Replace the placeholders with values from the create response. Do not put the secret in the
query string: that is rejected as 400 credential-in-url.
curl -sS "https://treegens-api.netlify.app/api/save?id=YOUR_SAVE_ID" \
-H "Authorization: Bearer YOUR_RECOVERY_SECRET"
The 200 body is { id, version, savedAt, save }. Autosave for 30 minutes:
POST action: "session", then send X-Grow-Session
instead of the secret. To write progress after resume, POST
action: "save" with the version you just read as baseVersion.
A mismatch returns 409 conflict with the server version, so re-GET and retry.
- Lost secret and expired session: the save stays stored, but this API will not recover it. Create a new save.
action: "claim-legacy"is off. It returns403 migration-unavailableunless an operator setsGROW_LEGACY_CLAIM=on.- There is no staging environment and no account reset email. Rotation only works while you still hold a valid secret or session.
Rate limits
Limits are enforced server-side per caller (fixed one-hour windows) with an additional
shared cap across all callers. There is no Retry-After header on a
429 today, so back off and retry after roughly the window shown.
| Route / action | Per-caller limit | Shared cap |
|---|---|---|
POST /api/grow | 40 / hour / IP | N/A |
GET /api/save | 300 / hour | 20,000 / hour |
DELETE /api/save, and POST save/session/rotate/revoke/share | 60 / hour | 5,000 / hour |
POST /api/save (action: "create") | 10 / hour | 2,000 / hour |
POST /api/save (action: "claim-legacy") | 5 / hour | 500 / hour |
GET /api/tg | No per-caller limit; shielded by a 5 to 10 minute server-side cache instead | N/A |
action: "claim-legacy" is disabled by default and returns
403 migration-unavailable unless an operator explicitly turns it on; it exists only
to migrate pre-v2 saves.
Security notes
- Every response carries a strict
Content-Security-Policy, HSTS,X-Content-Type-Options: nosniff,X-Frame-Options: DENY, and a same-siteCross-Origin-Resource-Policy. /api/save,/api/grow, and/api/tgecho back a single allowed origin and never respond with a wildcardAccess-Control-Allow-Origin.- Recovery secrets are stored only as a salted HMAC-SHA256 hash server-side; the plaintext secret is shown to a caller exactly once and cannot be re-displayed, only rotated.
Support
This API doesn't have a dedicated status page or ticketing system. For questions, integration issues, or to report a problem, email jimi@wemakeimpact.org (the same contact used for Treegens Game support).