Developer docs

Integrate retroshelf into your emulator, launcher, or frontend.

Add play tracking to your app

retroshelf's API lets your emulator, launcher, or app record what a player plays to their retroshelf activity. When a play session ends, send the game, play time, and timestamp, and retroshelf logs it automatically.

Begin by applying for a client ID. Once approved, link players with the device-code flow and send completed play sessions in the background.

Device flow overview

  1. 1Request a device code with your approved client ID.
  2. 2Show the user code and verification URL to the user.
  3. 3Poll the token endpoint until the user approves access.
  4. 4Send the bearer token with completeLink and syncSessions.
POST/api/auth/device/code

Request a device code

Creates a short user code and verification URL for the OAuth device flow.

Fields

FieldTypeRequiredDescription
client_idstringYesThe client ID issued after your integration application is approved.
  • client_idstring · required

    The client ID issued after your integration application is approved.

Request

{
  "client_id": "rs_your_client_id"
}

Response

{
  "device_code": "internal-device-code",
  "user_code": "483921",
  "verification_uri": "https://retroshelf.org/link",
  "verification_uri_complete": "https://retroshelf.org/link?user_code=483921",
  "expires_in": 86400,
  "interval": 5
}
POST/api/auth/device/token

Poll for an access token

Poll at the returned interval until the user approves the code.

Fields

FieldTypeRequiredDescription
grant_typestringYesUse urn:ietf:params:oauth:grant-type:device_code.
device_codestringYesThe internal device code returned by the device-code endpoint.
client_idstringYesThe same approved client ID used to request the device code.
  • grant_typestring · required

    Use urn:ietf:params:oauth:grant-type:device_code.

  • device_codestring · required

    The internal device code returned by the device-code endpoint.

  • client_idstring · required

    The same approved client ID used to request the device code.

Request

{
  "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
  "device_code": "internal-device-code",
  "client_id": "rs_your_client_id"
}

Response

{
  "access_token": "bearer_access_token",
  "token_type": "Bearer"
}
POST/api/syncClient/syncSessions

Upload play sessions

Sends completed play sessions. Offline clients should queue sessions locally and retry with the same values.

Authorization: Bearer access_token

Fields

FieldTypeRequiredDescription
syncClientIdstringYesThe sync client ID returned by completeLink.
sessions[].romPathstringYesThe path or filename available to the emulator or launcher.
sessions[].durationnumberYesSession length in seconds.
sessions[].devicePlayedAtnumberYesUnix timestamp, in seconds, for when the session started on the device. RetroShelf derives the end by adding duration.
sessions[].romNamestringNoClean game name when available. Used before falling back to romPath matching.
sessions[].romHashstringNoMD5 ROM hash when available.
sessions[].steamAppIdstringNoNumeric Steam app ID for exact native Steam game matching.
sessions[].platformHintstringNoConsole or platform hint, such as snes, gba, psx, or arcade.
  • syncClientIdstring · required

    The sync client ID returned by completeLink.

  • sessions[].romPathstring · required

    The path or filename available to the emulator or launcher.

  • sessions[].durationnumber · required

    Session length in seconds.

  • sessions[].devicePlayedAtnumber · required

    Unix timestamp, in seconds, for when the session started on the device. RetroShelf derives the end by adding duration.

  • sessions[].romNamestring · optional

    Clean game name when available. Used before falling back to romPath matching.

  • sessions[].romHashstring · optional

    MD5 ROM hash when available.

  • sessions[].steamAppIdstring · optional

    Numeric Steam app ID for exact native Steam game matching.

  • sessions[].platformHintstring · optional

    Console or platform hint, such as snes, gba, psx, or arcade.

Request

{
  "syncClientId": "sync_client_id_from_completeLink",
  "sessions": [
    {
      "romPath": "steam/367520",
      "romName": "Hollow Knight",
      "steamAppId": "367520",
      "duration": 5400,
      "devicePlayedAt": 1781229600,
      "platformHint": "steam"
    }
  ]
}

Response

{
  "submitted": 1,
  "created": 1,
  "synced": 1,
  "matched": 1,
  "unmatched": 0,
  "results": [
    {
      "romPath": "steam/367520",
      "status": "matched",
      "syncSessionIds": ["sync_session_id"],
      "matched": true,
      "gameId": "game_id",
      "gameName": "Hollow Knight",
      "gameSlug": "hollow-knight",
      "coverImageUrl": "https://cdn.retroshelf.org/covers/hollow-knight.webp"
    }
  ]
}
retroshelf deduplicates by sync client, ROM path, played-at timestamp, and duration. Retrying the same queued session is safe. created counts newly stored rows; synced counts rows accepted for matching in this request, including an idempotent retry that was already stored but still pending.