Skip to content


One of the common issues that can occur is that Loot/Items were misconfigured, or players were given items that they should not have. This can be fixed by running a fix-up script for all players.

This script is only meant to run at a relatively small scale (probably less than 5k players). The iteration batches are quite fast, however calling other APIs from it on a per-player basis will likely take a long time. It could be improved with multi-threading, but that is left as an exercise for the reader.


In order to run the following python script, you’ll need to have the following:

  • Your RallyHere environment URL
  • A Client ID and secret for a client that has at least the user:player:iterate permission from its policy.
    • If you need to do other operations, you may need other permissions. Such as inv:* to do any operation on inventory

By default this script simply iterates all players and logs the number found. You can add your own logic to the process_batch function to call other RallyHere Environment APIs. The RallyHereAccessToken class will handle getting and refreshing the access token for you.

import requests
from datetime import datetime, timedelta
from requests.auth import HTTPBasicAuth
rally_here_environment_url: str = "YOUR ENVIRONMENT URL HERE"
rally_here_client_id: str = "YOUR CLIENT ID HERE"
rally_here_client_secret: str = "YOUR CLIENT SECRET HERE"
def process_batch(players: list, sess: requests.Session, access_token, base_url: str):
This function is responsible for processing a batch of players. You can add your own logic here.
# for player in players:
# print(f"Player: {player.get('player_uuid')} (player_id: {player.get('player_id')})")
class RallyHereAccessToken:
This class is responsible for managing the access token for RallyHere.
def __init__(self, sess: requests.Session, base_url: str, client_id: str, client_secret: str):
:param sess: The requests session to use for all requests.
:param base_url: The base URL of the RallyHere Environment API.
:param client_id: The client ID for the RallyHere Environment API.
:param client_secret: The client secret for the RallyHere Environment API.
self.sess: requests.Session = sess
self.base_url: str = base_url
self.client_id: str = client_id
self.client_secret: str = client_secret
self.access_token: str = None
self.access_token_type: str = None
self.access_token_expiration: datetime = None
def get_authorization_header(self):
This function is responsible for getting the authorization header for the RallyHere Environment API.
:return: The authorization header.
return f"{self.access_token_type} {self.get_token()}"
def get_token(self, force_refresh: bool = False):
This function is responsible for getting the access token. It will refresh the token if it is expired or if
force_refresh is True.
:param force_refresh: If True, the token will be refreshed even if it is not expired.
:return: The access token.
if self.access_token is None or force_refresh or datetime.utcnow() > self.access_token_expiration:
self.access_token, self.access_token_type, expiration_seconds = self.authenticate()
self.access_token_expiration = datetime.utcnow() + timedelta(seconds=expiration_seconds - 60)
return self.access_token
def authenticate(self):
This function is responsible for authenticating to the RallyHere Environment API.
:return: The access token, the access token type, and the expiration in seconds.
response ="{self.base_url}/users/v1/login",
auth=HTTPBasicAuth(self.client_id, self.client_secret),
"grant_type": "client_credentials",
if response.status_code != 200:
raise Exception(f"authenticate - Got status code {response.status_code} from auth request: {response.content}")
result = response.json()
return result["access_token"], result['token_type'], result["expires_in"]
def get_iteration_batch(sess: requests.Session, access_token: RallyHereAccessToken, base_url: str, cursor: str, page_size: int = 1000):
This function is responsible for getting a batch of players from a RallyHere Environment API.
:param sess: The requests session to use for all requests.
:param access_token: The access token to use for the request.
:param base_url: The base URL of the RallyHere Environment API.
:param cursor: The cursor to use for the request.
params = {"page_size": page_size}
if cursor is not None:
params["cursor"] = cursor
response = sess.get(f"{base_url}/users/v2/player:iterate",
"Authorization": access_token.get_authorization_header(),
if response.status_code != 200:
raise Exception(f"do_iteration - Got status code {response.status_code} from server")
result = response.json()
return result["players"], result["cursor"]
def iterate_all(base_url: str, client_id: str, client_secret: str):
with requests.Session() as sess:
access_token = RallyHereAccessToken(sess, base_url, client_id, client_secret)
last_player_count: int = 1
cursor: str = None
iteration_number: int = 0
while last_player_count > 0:
players, cursor = get_iteration_batch(sess, access_token, base_url, cursor)
process_batch(players, sess, access_token, base_url)
last_player_count = len(players)
print(f"Found {last_player_count} players in iteration {iteration_number}")
iteration_number += 1
iterate_all(rally_here_environment_url, rally_here_client_id, rally_here_client_secret)