CEEJAYDocs

Set player fields

Send values about your players, up to 500 players in one call, to be stored on the members they are connected to.

POST /v1/games/{game}/player-fields · requires players:write

Call it from your server whenever values about players change: a league position, a club, the day a player last played. The values are stored on the member the player is connected to, shown on their profile, and usable in segments and filters. Player data explains how the values are checked and what a result means, and the field map how a name your game uses becomes a field.

Path parameters

Prop

Type

Body parameters

Prop

Type

Each entry of players holds:

Prop

Type

Returns

Prop

Type

A batch with problems still returns 200. Only a body that is not shaped right is refused as a whole.

status of a playerWhat happened
writtenAt least one value was new or changed. The previous value is retained in the history
unchangedEvery value was already the current one, or there was nothing to clear
heldThe player has not connected, and the game holds data for players who have not. The values are held until the player connects
held_limitThe held store is full for this game (50,000 players)
not_connectedNo active connection exists for this player
not_memberThe player is connected, but the member is not in the server. Values are stored for members only
erasedThe player was erased, and is never held
under_ageYou sent underAge: true. Nothing is stored
bad_itemThe entry could not be read: message says why. The rest of the batch was processed

This list may grow: handle unknown values. An entry that names the player by discordId gets discordId only in its result, and one that names the player by playerId gets playerId only.

Each item of problems has field, the name you sent, and a code:

code of a problemThe field
unknown_fieldThe name is new and the game already has 50 proposed fields, so it was not added
not_approvedThe field is proposed and waiting for approval by the community's team, or the name was new and is now proposed
unusedThe team marked the field unused, so nothing is written
bad_valueThe value does not fit the field's type, or is out of range
not_a_choiceThe value is not one of the choices of a dropdown field. It is offered to the team
not_consentedThe member has not consented to the field's category
needs_verified_proofThe player is connected at the basic level, and the field is in the purchases or location category: it is not stored for a connection whose player ID the game supplied and CEEJAY did not verify
managedThe field is filled from the connection itself (the player ID and name) and cannot be set

Example

Request
curl -X POST https://ceejay.communitystudios.xyz/api/v1/games/rugby_manager/player-fields \
  -H "Authorization: Bearer $CEEJAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "players": [
      {
        "playerId": "p_19",
        "fields": {
          "league_position": 3,
          "club": "Harbour Town",
          "last_played": "2026-10-07T21:10:00+02:00",
          "coach_notes": "Ready for the cup"
        }
      },
      {
        "playerId": "p_77",
        "fields": { "league_position": 9 }
      }
    ],
    "dryRun": false
  }'

The TypeScript tab calls ceejay.players.setFields from the TypeScript SDK. It returns the data of the response below.

200 OK
{
  "success": true,
  "data": {
    "results": [
      {
        "index": 0,
        "playerId": "p_19",
        "status": "written",
        "written": 2,
        "unchanged": 1,
        "cleared": 0,
        "problems": [{ "field": "coach_notes", "code": "not_approved" }]
      },
      {
        "index": 1,
        "playerId": "p_77",
        "status": "not_connected",
        "written": 0,
        "unchanged": 0,
        "cleared": 0,
        "problems": []
      }
    ],
    "summary": {
      "players": 2,
      "written": 2,
      "unchanged": 1,
      "cleared": 0,
      "held": 0,
      "refused": 1
    }
  }
}

How values are checked

  • Set, not added. A value equal to the current one is not a new history entry. null clears a field. A field that is not in the object is left as it is.
  • The name. It is matched to the name your game uses for the field first (the sourceKey of the field map), then to the field's key, case-insensitively. A name nothing matches is added to the field map as a proposal, up to 50 at a time, and returns not_approved. Seven standard fields that need no choices are approved by the first value. All other fields need approval from the community's team.
  • Numbers beyond 1e15 either way are refused. A number is multiplied by the field's scale and rounded to 6 places: a scale of 0.01 turns cents into dollars.
  • Dates are YYYY-MM-DD, or a full time with an offset, which becomes its UTC day. Anything else is bad_value.
  • Dropdowns pass your value through the field's value map, and it must then be one of the choices. A value that is not is offered to the team and returns not_a_choice.
  • Text is up to 500 characters. An object or a list is bad_value.
  • Sharing. A connection a member made through Connect stores the categories the member consented to, and a field of another category is not_consented. A connection your own server created stores none, and your server is responsible for the consent.
  • Verification. A player connected at the basic level, where the game supplied an unverified player ID, does not accept fields of the purchases or location category: each is a problem with the code needs_verified_proof, and the player's other fields are still written. progress fields, and players your own server linked, are not affected.
  • Under age. underAge: true on a player needs the key to hold players:connect as well. Without it the whole call returns 403 with the code insufficient_scope and required: ["players:connect"], and nothing is written. A call can carry at most 50 such players, or it returns 400 with the code bad_request.

Values are stored for members only. Nothing here creates a member profile.

Body size

The body is read before it is parsed, up to 512 KB. A larger one is refused with 413 and the code body_too_large, in the usual error shape, and nothing is processed. Send fewer players in one call.

Safe to repeat

Sending the same values again changes nothing, so the request takes no idempotencyKey. The SDK does not retry automatically; retrying it yourself is safe.

The scope

players:write is part of *, so a Full Access key can call this. A call that says underAge: true for a player also needs players:connect, which * does not include.

Limits

This request is counted against the key's own requests per minute: 60 unless a higher limit was set on it, and never more than 600. Rate limits has the numbers and the headers.

A batch of 500 players is one request, so 60 calls a minute is 30,000 players.

Errors

StatuscodeerrorWhen
400bad_requestThe request body must be a JSON objectThe body is null, text, a number or a list
400bad_requestThe request body must be JSONThe body is not valid JSON, or could not be read
400bad_requestplayers must be a list of 1 to 500 playersplayers is missing, is not a list, or is empty
400too_many_playersA call can carry up to 500 playersplayers contains more than 500 players
400bad_requestA call can carry up to 50 players with underAge: trueMore than 50 entries of players say underAge: true
400bad_requestdryRun must be true or falsedryRun was sent and is not true or false
403community_not_activeThis community is no longer active on CEEJAYThe community removed CEEJAY from its server
403game_not_allowedThis API key is limited to other gamesThe key is limited to other games of the community
403audience_not_allowedA game made for children cannot connect players or send player dataThe game is set up as made for children. Such a game connects nobody and takes no player data
404not_availableThis is not available on this instance yet.Connect is not enabled for this instance. It is enabled per instance. The body adds feature, which is players. Retrying will not change the response
404game_not_foundGame not foundThe community has no game with this slug, or the game was removed. A slug that is not 2 to 32 lower-case letters, digits and underscores, starting with a letter, gets this response too
409game_pausedThis game is pausedThe game is paused or suspended
413body_too_largeThe request body is larger than 512 KB. Send fewer players or events in one callThe body is larger than 512 KB. It is refused before it is parsed

Every error body also carries requestId, and a 400 with the code bad_request names the invalid field in field. Match on code, not on the message text, which can change.

The errors every request shares (401, 403 for a missing scope, 405, 429, 500) are on the Errors page.

On this page

Community StudiosPrivacyTerms