Last changed

Sending feedback from inside a game

The contract for a game that lets its players report a bug, send an idea, or complain. Both of this site's games use it: TGSC (Touching Grass Simulator Coop, on PC) and Touch Grass (on Android). They are separate games with similar names, and each has its own address and its own queue.

One call, one form, and the site sorts it. There is no account and no token - a game cannot ask a player to sign in to a website before telling you the game crashed.

Base address: https://dasmaffin.com.


Send one

POST /TouchGrass/api/report        (Touch Grass, Android)
POST /Tgsc/api/report              (TGSC, PC)
Content-Type: multipart/form-data

The address decides the queue. Nothing in the body says which game this is; the site stamps it from the endpoint you posted to. A client cannot file into the other game's queue, by accident or otherwise.

Both addresses are the same endpoint under a different name: a module on this site declares that it takes feedback, and the site answers POST /{module}/api/report for it. A third game would appear here without a line of new intake code, and would behave exactly as these two do.

The fields

Field Touch Grass TGSC Meaning
playerId required - Who is sending. The Unity Gaming Services player id, the same one the save is filed under
steamId - required Who is sending. A SteamID64, digits only
summary required required One line. Up to 300 characters
description required required What happened, in their words. Up to 8,000
kind optional optional Bug, Idea or Other. Anything else becomes Other
playerName optional optional What they call themselves in game. A label, not identity
build optional optional Your version string
scene optional optional Where they were - the screen or level
facts optional optional Device, OS, settings, anything else worth knowing. Up to 8,000
edition, role, world - optional PC game concepts; leave them out

Anything longer than its limit is cut, not refused - a report is worth having with a truncated log.

summary and description are both required. An empty report costs nothing to send, arrives looking like feedback, and can only be answered by guessing.

Attachments

One field per kind, and each takes as many files as you like. The field name says what a file is; the file name is only a label for whoever reads the report afterwards. A part sent as logs carrying whatever.json is a log. A part sent as notes carrying screenshot.png is not a picture.

Send it as What it is Where it appears on the report
images Pictures Shown, full size on click
logs Log files The first is shown as text on the page; every one is downloadable
charts Measurements over time Plotted - see charts. Also downloadable
saves A save or world file Under Files, as a download
benchmarks A finished benchmark run Shown as text
files Anything else Under Files, as a download

Repeat a field to send several: two parts both named logs are two logs, and there is no numbering scheme to follow. Multipart allows a repeated field name, so nothing has to be invented per file.

curl -X POST https://dasmaffin.com/TouchGrass/api/report \
  -F "playerId=..." -F "summary=..." -F "description=..." \
  -F "logs=@session.json;type=application/json" \
  -F "logs=@previous-session.json;type=application/json" \
  -F "images=@shot1.png;type=image/png" \
  -F "images=@shot2.png;type=image/png" \
  -F "charts=@metrics.json;type=application/json"

A field name that is not on that list lands under Files, as a plain download. Nothing is guessed from the file's name or its content: a file the site was not told the kind of is one it will not describe. It used to guess "picture", which put a game's second log in the Pictures section as a broken image.

The older names still work, because both of this site's games send them and neither should break before it ships a new build: shot, log, metrics, save, benchmark. That is the whole list - exactly what those two emit, not a set of spellings that might be accepted. Anything new should use the fields in the table, which are the kinds themselves.

Set Content-Encoding: gzip on a part and it is unpacked before it is stored, so what somebody opens is the plain thing. Compress for the upload's sake, not for the reader's.

Charts

A file part named metrics is plotted on the report's page. Its shape is its own document: charts.

What comes back

{ "id": 412 }
Code Meaning
200 Stored. The id is the report's
400 No sender id, or a missing summary or description
403 That player is barred from sending. Body: {"banned":true,"reason":"..."} - show the reason
413 Everything together came to more than 16 MB
429 More than 12 reports from that player in the last hour

A 403 is worth handling properly: the reason is written for the player and is the only explanation they will get. Touch Grass has no ban list today, so it will not see one - the code is documented because the endpoint can answer it the moment there is one, and a client that treats an unknown status as "it worked" is a client that silently loses reports.


An example

curl -f -X POST \
  -F "playerId=Ax7Bq2Kd9Lm4Np6Rs8Tv0Wx2Yz4A" \
  -F "summary=Garden resets after closing the app" \
  -F "description=Planted three plots, closed the app from recents, came back and the garden was empty." \
  -F "kind=Bug" \
  -F "playerName=Someone" \
  -F "build=1.0.4" \
  -F "scene=Garden" \
  -F "facts=Pixel 7a, Android 15, English" \
  -F "log=@player.log;type=text/plain" \
  https://dasmaffin.com/TouchGrass/api/report

Reading them back

There is a private read API for programs on the project's side - not for game clients. It needs a private API key, and so does its documentation: reading.


What happens to it

It lands in that game's queue on this site, where somebody reads it, can answer it, and can close it. Reports are deleted after 120 days.

The player id is what the game claimed, not something this site proved, and it is treated that way: it is good for grouping one person's reports together and for answering them, and for nothing else. Send the id you already have rather than inventing one per report, or two reports from the same person cannot be recognised as such.

Nothing here needs an account, on either side. What a player types is what arrives.

The plain file: /docs/reports/sending.md