🌾 Farming Valley Admin

Farming Valley admin console & API

Change anything happening in the game: time, weather, live events, festivals, crop growth, passes, products and player data. Use the 🛠 Admin window in game, or this web API from anywhere.

🕒 World

Move the clock, skip to a dawn or season, force weather, start or stop events and festivals, boost growth, ripen crops.

👥 Players

Coins, XP, items, energy, in-game pass grants, developer product rewards, any save value, save, kick.

🔒 Server authoritative

Every command is checked and run by the game server and written to an audit log. Clients only send intent.

Who can use it

Admin access is decided on the game server only, from a hard-coded list in src/shared/Config/Admin.luau:

  • User id 1496883649 (Moe).
  • Rank 255 (owner) or higher in the Cedar Tech Games group 853754178. Lower minGroupRank to admit trusted ranks.

Nothing a client sends can make it an admin. The admin remote is never answered for anyone else, and refused requests are logged. The web API has its own token, and the game checks a second token inside every message.

In-game panel

Admins get a 🛠 Admin tile in the ☰ menu. It has three tabs:

  • World: one-press time, weather, events, festivals, growth boosts and ripening.
  • Players: pick a player in the server, then coins, XP, energy, ripen, save, go to, kick, and grant or revoke passes.
  • Console: type any command, e.g. weather.set rain 2 scope=global or item.give Moe carrot 10. New API token lives here too.

Red buttons are dangerous and need a second press. Results show in the box at the bottom.

Command line syntax

command arg1 arg2 key=value
weather.set storm 3 scope=global     # positional args in order, key=value for any arg
announce Market day at the plaza!    # a final text arg takes the rest of the line
player.kick SomeName "spamming the trade board"   # quotes keep spaces
data.get Moe tools                   # read part of a save
data.set Moe tools.hoe 3             # change one value (same type only)

Server vs global

World commands take scope:

scopeApplies toSavedDefault from
serverOnly the server you're inNo, it ends with the serverIn-game panel
globalEvery server, and new ones as they startYes, in DataStore FVAdminWorld_v1Web API

For everything except time, a server value wins over the global one.

Time is always global and forward only. Saves are stamped with the farm day, so the clock moves for every server at once and is saved. Skipping dawns grows watered crops, starts new days for energy and the shipping bin, and can start a festival. time.set to an earlier hour rolls into tomorrow. Skipped farm days are permanent: time.reset puts the hour back on real time but keeps the days already skipped.

Web API

Base URL: https://fvdashboard.cedartechsolutions.ca. Every call except /api/health needs:

Authorization: Bearer <DASHBOARD_TOKEN>

The dashboard turns your request into a signed message and publishes it to every live server through Roblox Open Cloud MessagingService. Servers check it and run it within a second or two. MessagingService is one-way, so the reply only says the message was sent; read the outcome from the audit log.

The Roblox Open Cloud key and the in-game token stay inside the dashboard as encrypted Cloudflare secrets. Browsers and API callers only ever hold the dashboard token.

Endpoints

MethodPathWhat it does
POST/api/commandBody { "cmd": "weather.set", "args": { "kind": "rain" }, "job"?: "<JobId>", "by"?: "name" }. Returns 202 { ok, id, sentAt }.
GET/api/log?day=YYYYMMDD&limit=100That UTC day's admin actions, newest first (default today).
GET/api/stateThe saved global overrides (clock shift, weather, event, festival, growth).
GET/api/healthWhich secrets are configured (never their values). No token needed.
GET/commands.jsonThe full command catalog with every argument, range and option.

job limits a command to one server. Player commands run on whichever server that player is in; the others ignore them. Errors come back as { "ok": false, "error": "..." } with 400 (bad request), 401 (token), 413 (over 1 kB), 502 (Open Cloud refused) or 503 (dashboard not set up).

Examples

curl

TOKEN="your-dashboard-token"
curl -X POST https://fvdashboard.cedartechsolutions.ca/api/command \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"cmd":"weather.set","args":{"kind":"storm","days":2}}'

curl -X POST https://fvdashboard.cedartechsolutions.ca/api/command \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"cmd":"pass.grant","args":{"player":1496883649,"pass":"travel_pass"}}'

curl -H "Authorization: Bearer $TOKEN" "https://fvdashboard.cedartechsolutions.ca/api/log?limit=20"

PowerShell

$h = @{ Authorization = "Bearer $env:FV_DASHBOARD_TOKEN" }
$body = @{ cmd = "event.start"; args = @{ event = "starfall"; hours = 24 } } | ConvertTo-Json
Invoke-RestMethod -Method Post -Uri https://fvdashboard.cedartechsolutions.ca/api/command `
  -Headers $h -ContentType 'application/json' -Body $body

JavaScript

const res = await fetch("https://fvdashboard.cedartechsolutions.ca/api/command", {
  method: "POST",
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
  body: JSON.stringify({ cmd: "time.season", args: { season: "Winter" } }),
});
console.log(await res.json()); // { ok: true, id: "…", sentAt: 1793… }

Direct Open Cloud (advanced)

Anything holding an Open Cloud key with universe-messaging-service:publish on universe 10773432892 and the in-game token can skip the dashboard and publish to topic FVAdmin itself:

POST https://apis.roblox.com/cloud/v2/universes/10773432892:publishMessage
x-api-key: <open cloud key>
{ "topic": "FVAdmin", "message": "<envelope as a JSON string>" }

envelope = {
  "v": 1,                       // version
  "id": "8-64 chars [A-Za-z0-9_-]",  // unique; replays are dropped
  "ts": 1793225000,             // unix seconds, within 5 minutes of the server clock
  "token": "<in-game API token>",
  "by": "my-script",            // shown in the log
  "cmd": "growth.boost",
  "args": { "multiplier": 3, "minutes": 20 },
  "job": "<optional JobId>"
}

The whole message must fit in 1 kB. Each server runs at most 30 remote commands a minute.

Audit log

Every admin action, from the panel or the web, accepted or refused, is printed to the server Output and saved to DataStore FVAdminAudit_v1 under day_YYYYMMDD (UTC, up to 1,000 a day). Each entry has the time, source, admin, command, arguments, outcome and server JobId. Tokens are never logged.

{ "t": 1793225012, "src": "remote", "by": "web:dashboard", "byId": 0,
  "cmd": "weather.set", "args": "kind=storm days=2 scope=global",
  "ok": true, "msg": "⛈ Storm for 2 day(s).", "job": "6b1f…" }

Command reference

Generated from the game's own catalog (/commands.json). panel only commands can't run from the web. danger commands ask for a second press in game.

CommandWhat it doesArguments
Loading the catalog…

Setup

  1. In game: open 🛠 Admin → Console → New API token (or api.rotate). Copy the token shown; it isn't shown again, and the old one stops working on every server.
  2. Open Cloud key: in Creator Hub → Open Cloud → API Keys, give a key universe-messaging-service:publish and universe-datastores.objects:read for the Farming Valley experience.
  3. Dashboard secrets: from site/fvdashboard run npx wrangler secret put GAME_TOKEN, ROBLOX_API_KEY and DASHBOARD_TOKEN (any long random string), then npx wrangler deploy.
  4. Check /api/health shows everything configured, then open the web console.

To switch the web API off, run api.disable in game: servers then refuse every remote message.

Troubleshooting

  • 202 but nothing happened: check /api/log. "refused: wrong API token" means GAME_TOKEN doesn't match the latest api.rotate. No entry at all usually means no server is running, or the player is in no server.
  • 502 from /api/command: the Open Cloud key lacks the messaging scope or the universe.
  • Events and festivals appear within 30 s and 10 s; weather, time and growth apply at once.
  • No 🛠 tile in game: you aren't on the allowlist, or the group rank check failed; the server Output says [Admin] OK system:<you> join for admins.