Skip to content

HTTP Service Overview

Introduction

The Crowd Control HTTP Service is an alternative to the PubSub WebSocket for environments where WebSockets are unavailable or impractical. It allows your game or application to receive viewer effect requests and report whether those effects were applied successfully.

Who is this for?

The HTTP Service is meant for integrations that cannot maintain a WebSocket connection because of engine limitations or platform constraints, such as Roblox servers, embedded systems, or tightly sandboxed runtimes.

However, if you are a game developer working in a popular engine, then there's a very high chance that you don't need to work with this service directly! We've worked with several talented developers to bring plugins to all your favorite game engines which do the hard work of managing logins and sessions and WebSocket listeners for you. Crowd Control plugins are available for:

Even if you aren't using one of the above engines, it's likely that your tech stack supports WebSockets in some form, and you may be better served by our WebSocket Service, which provides more timely communication without the need for polling.

This guide covers the full HTTP workflow, from user authorization to session management and effect responses. It is written primarily for game developers and plugin authors, but it is also useful for third-party apps and overlays.

Before you start

Before hooking your game up to Crowd Control's production servers, you should know that some parts of the process will require some manual approval and processing from our developers. We suggest first starting out by drafting some effect ideas, trying them out in your game, and writing up a pack file.

Examples

(JAYO TODO - provide working example of HTTP Service connectivity that demostrates all typical endpoints)

Connecting

To make requests to the HTTP service, you'll need an HTTP library with support for TLS 1.2 or greater. Be sure to send your requests with a custom User-Agent representing your game or plugin.

The HTTP Service address is https://openapi.crowdcontrol.live/. All paths listed in this documentation are relative to this address.

Some endpoints will require the authorization of either a User or the application itself, these endpoints require an Authorization header including either a User Token or Appication Token. This will be covered in more detail later

Request and Response Bodies

Information sent as part of a request to the HTTP service, and information received in reponse are simple JSON objects in the body of the HTTP message using the application/json encoding scheme. The shape and strucutre of the objects varies across different calls, so these will be broken down in more detail in the relevant sections of this document.

Authorizing

Most requests covered in this document are "User-Authorized" or "Application-Authorized", which means you'll need to provide an Auth Token obtained for a specific user or for the application itself.

Most operations will act on the behalf of or access resources for a specific user and will require a User Token. Other operations work on application-level or system-level resources and will require an Application Token.

Overview

Authorization Workflow

Here's a high-level breakdown of the typical user authorization workflow for an application to obtain a token for a user:

  1. The application requests an authorization code by identifying itself and the User Auth Scopes that it would like to be granted
  2. Crowd Control servers give the application an Authorization code, as well as an link they can provide to a user
  3. the application provides the user with the authorization link
  4. the user opens the link and follows the on-screen process to grant the application access to thier account
  5. when the user is finished, the application exchanges the authorization code along with thier application secret and gets a User Auth Token
  6. the Applicationb can now make User-Authorized requests on behalf of the user by provinig the token wit the request

User Auth Tokens

A User Auth Token is formatted as a JSON Web Token or JWT which represents some basic information about the user. JWTs consist of three Base64-encoded blocks separated by .; the second is the token payload, and can be decoded to the following list of items, knows as claims:

json
{
  "type": "user",
  "jti": "jti-01J7CNSK58ZXXCKP8AE93MBGXJ",
  "ccUID": "ccuid-01j7cnrvpbh5aw45pwpe1vqvdw",
  "originID": "106025167",
  "profileType": "twitch",
  "name": "lexikiq",
  "roles": ["dev"],
  "app": {
    "appID": "ccaid-01jp3av56v4m33njwgkh4zh1vd",
    "scopes": ["profile:read", "session:read", "session:write"],
    "packs": ["Minecraft"]
  },
  "exp": 1725928623,
  "ver": "1:2"
}

Token Claims

ClaimDescription
typethe type of token, will always be user
jtiUnique ID for this token. Used when extending the token
ccUIDCrowd Control ID for the relevant user
originIDID for the relevant user from their origin platform
profileTypethe identified for the user's platform of origin
namethe Crowd Control username for the user
rolesA list of any special roles the user may have
appcontains details about the app to which the token was issued
app : appIDthe ID of the application
app : scopesthe user scopes which have been granted to the application
app : packsthe game packs for which the token can perform operations
exptimestamp representing the expiry time of the token
verinternal value

User Auth Scopes

Scopes

The Confidential field denotes that the scope is unavailable for Applications with poor security abilities, for example locally hosted game servers.

Additionally, requesting Confidential scopes will restrict your application to interfacing with only one Game Pack. Exceptions may be granted for applications with secure web servers that requests are sent through.

IDTitleDescriptionConf.
profile:readProfile ReadIdentify the user's profile (name, URL)
session:readSession ReadView information about your game sessions
session:writeSession WriteStart and stop game sessions
session:controlSession ControlControl effects for game sessions
custom-effects:readCustom Effects ReadRead custom effects
custom-effects:writeCustom Effects WriteCreate and edit custom effects
token:extendToken ExtendingExtend tokens for longer periods of time

Authorized Requests

When making a request that requires authorization (i.e. anything accessing user-specific resources or operations), this is done by passing a special Authorization header that includes the token in this strucutre:

Authorization: cc-auth-token eyJhbGciOiJIUzI1NiJ9.eyJ0eXBlIjoidXNlciIsImp0aSI…

Authorization Workflow

Starting a User Auth Request

In order to allow a user to authorize your application to access thier Crowd Control account, you first need to start an Auth Request with the Crowd Control servers. This allows you to define your intent to request User Access, identify your application, and specify the Scopes which determine which type of access is being requested. A successful auth request will provide a link to be given to the user to begin the auth process, as well as a code that your application can use to retrive the token once the user has authorized.

This is done using the following HTTP Request:

Address: /auth/application/code
Method: POST
Request Body:

json
{
  "appID": "ccaid-thisisafakeapplicationid",
  "scopes": [
    "profile:read",
    "session:read",
    "session:control",
    "session:write",
    "token:extend"
  ],
  "qrCode": false
}

Response Body:

json
{
  "code": "E2NBAAHC",
  "url": "http://auth.crowdcontrol.live/code/E2NBAAHC",
  "qrCode": "data:image/png;base64,…" // if qrCode was true in request
}

Obtaining a User Auth Token

After a user has followed the Authorization Request link and completed the process, your application will be able to obtain a User Auth Token that can be used to make authorized requests.

This is done by making an HTTP request which provides your application's secret as well as the auth code obtained during the previous request:

Address: /auth/application/token
Method: POST
Request Body:

json
{
  "appID": "ccaid-thisisafakeapplicationid",
  "code":"E2NBAAHC",
  "secret": "thisisafakeappliationsecret"
}

Response Body:

json
{
  "token": "eyJhbGciOiJIUzI1NiJ9.eyJ0eXBlIjoidXNlciIsImp0aSI6Imp0aS0wMUtD…"
}

This API call will provide an error message if the code provided is valid, but the user has not yet used it to provide authorization.

Extending a User Auth Token

User Auth Tokens expire about 24 hours after they are issued. If your app requests the token:extend scope, it will be able to use the jti value from the existing token to request a new one with a fresh expiry date, but only before the token has expired.

Address: /auth/application/token
Method: POST
Request Body:

json
{
  "jti": "jti-01KBR4VZ3ANKRCK2TCGFB5Q0HB",
}

Response Body:

json
{
  "token": "eyJhbGciOiJIUzI1NiJ9.eyJ0eXBlIjoidXNlciIsImp0aSI6Imp0aS0wMUtD…"
}

Invalidating a User Auth Token

Allows an authorized User Access Token to invalidate itself, preventing it from being extended or used in any subsequent requests. This gives users a way to revoke authorization if they so wish, or for the server to automatically remove its authorization for a user for any reason.

This is a User-Authorized Request that will require you to provide the Authorization header as specified above.

Address: /auth/token
Method: DELETE

The request does not have any body content, and the server will respond with a 200 OK status code if the request was successful

Obtaining an Application Auth Token

A small number of requests are not made on behalf of a specific user and don't access a specific user's resources, and instead act on behalf of the application itself.

Application Tokens do not automatically expire, unlike user Auth Tokens. There is also no back-and-forth process to authorize either, simply provide your application credentials in this HTTP Request:

Address: /auth/application/app-token
Method: POST
Request Body:

json
{
  "appID": "ccaid-thisisafakeapplicationid",
  "secret": "thisisafakeappliationsecret"
}

Response Body:

json
{
  "token": "eyJhbGciOiJIUzI1NiJ9.eyJ0eXBlIjoidXNlciIsImp0aSI6Imp0aS0wMUtD…"
}

Session Control

Once your application has an Application Auth Token and a User Auth Token, it can (among other things) manage everything related to an Crowd Control session!

Session Management Workflow

Session management can be handled through various HTTP endpoints. Here's a breakdown of the general worlkflow that an application will follow when managing a user's Crowd Control session:

  1. When ready, start the Crowd Control session
  2. at a regular interval, poll Crowd Control to update the list of queued and ongoing effects
  3. process queued effects according to relevant conditions:
    • activate instant queued effects and send effect responses as they happen
    • begin, pause, resume, and end timed queued effects and send effect responses as they happen
    • control the viewer-side visibility state of effects to hide effects or make them unredeemable to viewers with effect reports when conditions require it or if something breaks
  4. When the user is finished, end the Crowd Control session

Start a User Session

Begins a Crowd Control session for the authorized user, for the specified Game Pack. This allows viewers to see the list of effects for a game pack and redeem coins to request the effects, and allows Crowd Control to communicate these requests to your application.

Fails if the game pack is invalid or if a session is already running for the user.

This is a User-Authorized Request that will require you to provide the Authorization header as specified above.

Address: /game-session/start
Method: POST
Request Body:

json
{
  "gamePackID": "ThisIsAFakeGamePackID",
}

Response Body:

json
{
  "gameSessionID": "thisisafakesessionid",
  "createdAt": "2025-12-05T08:06:37.215Z"
}

Stop a User Session

Finishes an ongoing Crowd Control session for the authorized user. This stops viewers from seeing any list of redeemable effects, cancels any queued effects, and prevents any new redemptions from happening

Fails if the user does not currently have a session running.

This is a User-Authorized Request that will require you to provide the Authorization header as specified above.

Address: /game-session/stop
Method: POST
Request Body:

json
None.

Response Body:

json
{
  "gameSessionID": "thisisafakesessionid",
}

Poll Effects Queue

Accepts a list of ccUIDs representing users which have authorized the application, and provides a list of queued effects (both timed and instant) and ongoing timed effects for any ongoing sessions for these users.

In most use-cases the application should only be requesting the queue for one user, but in certain situations (such as a server-side integration for a multiplayer game) it would make sense to retrive a list for multiple users.

Use this call at a regular interval to keep track of incoming effect requests, the state of currently-running timed effects, and use the absense of previously-included entries as an indication of server-side dequeueing/cancellation:

  • If a queued effect is no longer present in subsequent responses (and your application had not yet responsed to that effect), it means it was unqueued from server-side. Your application should no longer send an effect response for it.

  • If a running Timed effect is not present in subsequent reponses (but your application hasn't sent an effect response to end the effect), that means it was cancelled from server-side. Your application should end any changes related to the effect immediately.

IMPORTANT: This is an Application-Authorized Request. Unlike the other endpoints, this one required you to provide the Application Auth Token in the Authorization header rather than a User Auth Token.

Address: /game-session/effect-queues
Method: GET
Request Body: This request passes CCUIDs as URL query parameters rather than a JSON body as it is a GET request:

?ccUIDs=ccuid-fakeccuid&ccUIDs=ccuid-anotherfakeid...

Response Body:

json
{
  "currentEffects": [
    {
      "ccUID": "ccuid-fakeccuid",
      "requestID": "1dbf056e-2a52-458f-accf-d94ad61129c5",
      "effectID": "infarrows1",
      "duration": 60,
      "status": "queued"
    },
    {
      "ccUID": "ccuid-fakeccuid",
      "requestID": "1dbf056e-2a52-458f-accf-d94ad61129c5",
      "effectID": "bombsup1",
      "status": "queued"
    },
    {
      "ccUID": "ccuid-anotherfakeid",
      "requestID": "e0956d0c-90e5-4f3b-8842-10d90abe3070",
      "effectID": "icephys1",
      "duration": 60,
      "status": "queued"
    }
  ],
  "activeTimed": [
    {
      "ccUID": "ccuid-fakeccuid",
      "requestID": "243c3ef7-520a-45ea-9f5a-d3ebf1f527cb",
      "status": "begin"
    },
    {
      "ccUID": "ccuid-anotherfakeid",
      "requestID": "bbd096a8-1bbf-46f8-9849-3c420346830f",
      "status": "pause"
    }
  ]
}

Send an Effect Response

Respond to a pending effect request to indicate success/failure, or update the running status of an active timed effect. Your application should do this in time with actually applying the effects to the user in your game/application to properly communicate these changes in state to Crowd Control and your viewers.

When responding to an instant effect, or when updating a timed effect with a status of timedEnd, it will be cleared from the queue and will not appear on subsequent effect-polling requests

Pending Effect Statuses

These statuses can be provided for queued effects to communicate thier success or failure:

  • success - effect is accepted by the game/app and will be executed shortly. The effect request will be removed from the queue.
    • For instant effects, the in-game execution is expected to happen immediately.
    • For timed effects, the in-game execution is expected to happen when the status is updated to timedBegin. Both the success and timedBegin updates can be batched into one call if the timed effect is starting immediately on acceptance, just ensure that the success update is the first one in the args array
  • failTemporary - effect couldn't be executed at this time because game/app conditions weren't met in a reasonable amount of time. The effect request will be removed from the queue and the viewer's coins will be refunded.
  • failPermanent - effect couldn't be executed due to some internal game/app error. The effect request will be removed from the queue and the viewer's coins will be refunded.
    • The effect is assumed to be broken and this also signals crowd control to disable viewers from seeing or requesting it for the rest of the session.
Timed Effect Statuses

These statuses can be provided with on an accepted request for a timed effect to indicate the request's current running state:

  • timedBegin - a timed effect has started executing. Can only be called once per effect request
  • timedPause - a timed effect has been paused due to temporary change in game/app conditions
  • timedResume - a timed effect has been resumed after being paused
  • timedEnd - a timed effect has finished running. can only be called once per effect request, and this will clear it from the Active Effects list
Effect Response HTTP Endpoint

This is a User-Authorized Request that will require you to provide the Authorization header as specified above.

Address: /game-session/rpc
Method: POST
Request Body:

json
{
  "method": "effectResponse",
  "args": [
    {
      // provide the request ID retrieved from the polling endpoint
      "request": "878946984761298237469823746",
      // provide the current standard epoch timestamp
      "stamp": 1765576603,
      // provide a message (can be an empty string for non-failure statuses)
      "message": "effect could not be completed due to some internal reason explained here",
      // status to set for the identified effect request
      "status": "timedBegin"
    }
  ]
}

Response Body:

json
None (200 HTTP Status Code on success)

Send an Effect Report

Report the state of an effect in terms of the ability for viewers to see and request the effects in the menu for the authorized user's current game session. Effects can be reported as Enabled or Disabled, as well as Visible or Hidden. Effects can be targeted by their individual IDs, their group, or their category.

Disabling or hiding an effect does not automatically cancel and queued or running effect requests.

Effect Report Statuses

These statuses can be provided with an effect report to indicate its availability to viewers:

  • menuAvailable - effect is available and enabled. Viewers can select and request this effect provided that it is also marked as visible
  • menuUnavailable - effect is disabled and unavailable for request. It will still be visible to viewers (provided that it is marked as such) but will appear faded/greyed out
  • menuVisible - effect is visible to viewers. Viewers can select and request this effect provided that it is also marked as enabled
  • menuHidden - effect is hidden from Viewers. It will be removed from the list of available effects shown to viewers, and they will be unable to request it.

Enabled/Disabled and Visible/Hidden states operate as two separate state “layers”. Enabled/Disabled determines if a menu entry is greyed out and non-selectable when the effect is visible; Visible/Hidden determines if a menu entry should be seen by viewers at all. This means that both layers impact how viewers see the effect in the menu. It is possible for an effect to be Enabled but also Hidden, so it is important to take care in managing these statuses.

Effect Report HTTP Endpoint

This is a User-Authorized Request that will require you to provide the Authorization header as specified above.

Address: /game-session/rpc
Method: POST
Request Body:

json
{
  "method": "effectReport",
  "args": [
    {
      // provide any random/unique string 
      "id": "878946984761298237469823746",
      // provide the current standard epoch timestamp
      "stamp": 1765576603,
      // provide an array of identifiers for target items
      "ids": ["myGroup"],
      // type of identifier can be 'effect', 'group', or 'category'
      "identifierType": "group",
      // status to set for identified items. can be 'menuAvailable', 'menuUnavailable', 'menuVisible', 'menuHidden'
      "status": "menuUnavailable"
    }
  ]
}

Response Body:

json
None (200 HTTP Status Code on success)

Last updated: