CEEJAYDocs

Get the result

Read the status of a connect session. When it is approved, the response includes the member summary, a player session and a refresh token.

POST /v1/connect/result · for public key

The game gets the result by polling. Poll every 3 seconds while a session is open, and immediately when the player returns to the game.

Body parameters

Prop

Type

Returns

The response has one of four shapes, distinguished by status.

While the session is waiting for the member (pending, needs_confirmation):

Prop

Type

While the session is waiting for the game to confirm (needs_game_confirmation):

Prop

Type

When the session ended without a connection (declined, cancelled, expired, locked, refused):

Prop

Type

When both sides approved (approved):

Prop

Type

member is the member summary. A game receives only these fields about the member:

Prop

Type

connection holds:

Prop

Type

sharing holds agreed, the kinds of data the member has consented to share with the community's team (progress, activity, purchases, location), and needed, the kinds the game has added since. A kind in needed is not shared for this member until they give consent at manageUrl.

reward holds status and items. CEEJAY's bot grants the reward for connecting shortly after the member approves, so a new connection reads pending at first: poll again in a few seconds. items lists what was granted once status is paid. The other values say why nothing was granted: none (the game has no reward for connecting, or the session ended without a reward), already_paid (this member or this player was rewarded before), needs_verified_proof (the game rewards only verified connections), not_member (the member is not in the server) and waiting_screening (the member has not passed Discord's membership screening; CEEJAY checks again every 15 minutes for 7 days). See Game rewards.

reasonWhy the session ended
member_cancelledThe member pressed Cancel, or kept the player they had
game_declinedThe game declined
bannedThe Discord account is banned from the server
player_blockedThe community blocked the player
player_already_connectedThe player is connected to another Discord account, and could not be moved
expired10 minutes passed
too_many_triesThe code was entered incorrectly five times
under_ageThe player is under age
nullA newer session for the same player superseded it, or the member connected another player in the meantime

Example

Request
curl -X POST https://ceejay.communitystudios.xyz/api/v1/connect/result \
  -H "Authorization: Bearer $CEEJAY_PUBLIC_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionSecret": "ceejay_cs_4f8a2c1e9b7d3e41f8a6b0c1d25f0c2a9b7d3e41f8a6b0c1d24f8a2c1e9b7d3e"
  }'

The TypeScript tab calls connect.getResult of the Connect client in the TypeScript SDK. Leave the session out to read the one connect.start opened. To wait until it ends, call connect.waitForResult.

200 OK, waiting for the member
{
  "success": true,
  "data": {
    "status": "pending",
    "expiresAt": "2026-10-08T18:14:11.000Z"
  }
}
200 OK, waiting for the game to confirm
{
  "success": true,
  "data": {
    "status": "needs_game_confirmation",
    "expiresAt": "2026-10-08T18:14:11.000Z",
    "member": {
      "displayName": "Nova",
      "avatarUrl": "https://cdn.discordapp.com/avatars/409876543210987654/a1b2c3d4e5f60718293a4b5c6d7e8f90.png"
    },
    "alreadyConnected": false
  }
}
200 OK, ended
{
  "success": true,
  "data": {
    "status": "declined",
    "reason": "member_cancelled"
  }
}
200 OK, approved
{
  "success": true,
  "data": {
    "status": "approved",
    "connection": {
      "connectionId": "8841",
      "game": "rugby_manager",
      "playerId": "p_19",
      "proof": "verified",
      "connectedAt": "2026-10-08T18:06:40.000Z",
      "moved": false,
      "alreadyConnected": false,
      "spendHoldUntil": "2026-10-09T18:06:40.000Z"
    },
    "member": {
      "displayName": "Nova",
      "nickname": "Nova | EU",
      "avatarUrl": "https://cdn.discordapp.com/avatars/409876543210987654/a1b2c3d4e5f60718293a4b5c6d7e8f90.png",
      "level": 12,
      "xp": 5420,
      "coins": 1450,
      "roles": [
        {
          "id": "982371004827100394",
          "name": "Tournament winner"
        }
      ],
      "membership": "member",
      "joinUrl": null
    },
    "join": {
      "asked": false,
      "result": "not_asked",
      "failure": null
    },
    "sharing": {
      "agreed": [
        "progress",
        "activity"
      ],
      "needed": []
    },
    "reward": {
      "status": "pending",
      "items": []
    },
    "manageUrl": "https://ceejay.communitystudios.xyz/connect/mine",
    "playerSession": {
      "token": "cjps1.eyJ2IjoxLCJhdWQiOiJnYW1lIiwicyI6IjcyMTEwNDkzODI3MTAwMzg0MiIsImciOjEyfQ.pV3mQ0b6k1y8ZtL2c9XwR4s7Nf5aHj0uEoGdBiKq3M",
      "expiresAt": "2026-10-08T18:21:44.000Z"
    },
    "refreshToken": "ceejay_rt_5512.1.4f8a2c1e9b7d3e41f8a6b0c1d25f0c2a9b7d3e41f8a6b0c1d24f8a2c1e9b7d3e",
    "refreshExpiresAt": "2027-01-06T18:06:44.000Z"
  }
}

What to do at each status

statusThe game
pending, needs_confirmationShows that it is waiting, and polls again in 3 seconds
needs_game_confirmationShows "Connect to" and the Discord name with options to confirm or cancel, and sends Confirm connect. There is no default: the player decides
approvedStores the refresh token, keeps the player session, discards the session secret
declined, cancelled, expired, locked, refusedDiscards the session and returns to not connected

Reading an approved result again

The result of an approved session can be read for 10 minutes. Each read returns a new refresh token and invalidates the one returned before, so a lost response can be requested again and still leaves one device signed in: keep the last one.

After those 10 minutes the response is 410 with the code result_gone. The same response is returned when what the session approved has changed since: the member disconnected, moved to another player, or signed the device out. An old session secret never signs a device back in. Start a new session.

A member who is not in the server

The connection is still saved. member.membership is not_member or left, playerSession is null, and member.joinUrl is where to send the player. The refresh token still works for Disconnect, and Renew a player session returns a player session once the member has joined.

Limits

One read per session every 2 seconds. Reads are never limited per IP address beyond the 600 requests a minute that every request of a game shares, so several players can poll from behind one IP address. No call to Discord is made, and data is written only when the session is approved.

Errors

StatuscodeerrorWhen
400bad_requestThe request body must be a JSON objectThe body is null, text, a number or a list. A request with no Content-Type header is read as text, so it gets this response too
401invalid_session_secretInvalid session secretsessionSecret is missing, is not a session secret, or is not the secret of a session of this game. A secret of another game's session is unknown here
429rate_limitedAsk for the result of one session at most every 2 secondsThe result of this session was requested less than 2 seconds ago. The body adds retryAfter
410result_goneThe result of this request can no longer be read. Start againThe session was approved more than 10 minutes ago, or what it approved has changed since: the member disconnected, moved to another player, or signed the device out. Start again

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 of a game shares (the key, the state of the game, the origin, 405, 429, 500) are on the Errors page.

On this page

Community StudiosPrivacyTerms