ChatStyle External API
The External API lets third-party tools — chatbots, Twitch extensions, stream management apps — interact with your ChatStyle overlay programmatically. L'accès à l'API externe nécessite un abonnement ChatStyle Premium actif.
Authentication
All requests require a Bearer token in the Authorization header and must include Accept: application/json — without it, error responses will redirect instead of returning JSON:
Production traffic is filtered by Cloudflare. Some default bot/client user agents are blocked before the request reaches the app, so send a descriptive custom User-Agent header.
Authorization: Bearer YOUR_API_KEY
Accept: application/json
User-Agent: YourApp/1.0
Generating an API Key
- Go to Dashboard → Settings
- Open the API tab and click Create Key
- Copy the token immediately — it will not be shown again
Votre clé API donne un accès complet à tous les endpoints tant que Premium est actif. You can have one active key at a time — revoke the existing key to create a new one.
Revoking Keys
Go to Dashboard → Settings → API and click Revoke on any key. Revoked keys stop working immediately.
Rate Limiting
- 30 requests per minute per API key
- Write request bodies are limited to 64 KiB; larger requests return
413 Payload Too Large - Exceeding the limit returns
429 Too Many Requests - The response includes
Retry-AfterandX-RateLimit-*headers
Error Responses
All errors follow a consistent format:
{
"message": "Human-readable error description."
}
Validation errors (422) include field-level details:
{
"message": "The values field is required.",
"errors": {
"values": ["The values field is required."]
}
}
Common Status Codes
| Code | Meaning |
|---|---|
200 | Success |
201 | Created |
401 | Unauthenticated — invalid or missing token |
403 | Forbidden — access denied |
404 | Resource not found |
422 | Validation error |
429 | Rate limit exceeded |
Endpoints
Style Settings
Read the active template settings for an overlay.
Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
preset_id | integer | No | Overlay ID. Pass as preset_id for API compatibility. Defaults to your default overlay. |
Example:
curl -A "YourApp/1.0" \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
"https://chatstyle.gg/api/ext/template"
Response:
{
"data": {
"template_id": 1,
"template_name": "Twitch Basic",
"template_slug": "twitch-basic",
"settings_values": {
"bubble.background-color": "#1a1a2e",
"bubble.padding": 12,
"message.font-color": "#ffffff"
},
"source_values": {
"bubble.background-color": "#1a1a2e"
},
"override_values": {
"bubble.padding": 12
},
"overridden_keys": ["bubble.padding"],
"sync_source_preset_id": 1,
"preset_id": 1,
"preset_name": "Default"
}
}
Update template settings with an explicit overlay sync scope. Values are merged with the chosen scope (partial updates are supported).
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
scope | string | Yes | source updates the selected overlay's sync source, override updates overlay overrides, independent updates an overlay with no sync source. |
values | object | Yes | Key-value pairs of settings to update |
preset_id | integer | No | Overlay ID. Pass as preset_id for API compatibility. Defaults to your default overlay. |
Example:
curl -X PUT \
-A "YourApp/1.0" \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"scope":"override","values":{"bubble.background-color":"#ff0000"}}' \
"https://chatstyle.gg/api/ext/template"
Response:
{
"message": "Style settings updated.",
"data": {
"settings_values": {
"bubble.background-color": "#ff0000",
"message.font-color": "#ffffff"
},
"source_values": {
"message.font-color": "#ffffff"
},
"override_values": {
"bubble.background-color": "#ff0000"
},
"scope": "override",
"preset_id": 1
}
}
Skins
List your custom skins for the active template.
Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
preset_id | integer | No | Overlay ID to filter skins by that overlay's template. Pass as preset_id for API compatibility. Defaults to default overlay. |
Example:
curl -A "YourApp/1.0" \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
"https://chatstyle.gg/api/ext/skins"
Response:
{
"data": [
{
"id": 42,
"name": "Neon Purple",
"slug": "neon-purple",
"description": "A vibrant purple skin",
"availability": "free",
"settings_values": {
"bubble.background-color": "#6b21a8",
"message.font-color": "#e9d5ff"
},
"is_active": true
}
]
}
Update a skin's settings. Only skins owned by your streamer profile can be updated. Values are merged with existing settings; values matching the template or preset base are removed from the stored skin overrides.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
values | object | Yes | Key-value pairs of settings to update |
Example:
curl -X PUT \
-A "YourApp/1.0" \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"values": {"bubble.background-color": "#00ff00"}}' \
"https://chatstyle.gg/api/ext/skins/42"
Response:
{
"message": "Skin updated.",
"data": {
"id": 42,
"name": "Neon Purple",
"settings_values": {
"bubble.background-color": "#00ff00",
"message.font-color": "#e9d5ff"
}
}
}
Viewer Skin Access
Grant a viewer access to a specific skin. This creates an entitlement — the viewer can then select the skin via the overlay or streamer shop page.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
twitch_username | string | One of username/user_id required | Viewer's Twitch login name |
twitch_user_id | string | One of username/user_id required | Viewer's Twitch user ID |
skin_id | integer | Yes | The skin to unlock |
Example:
curl -X POST \
-A "YourApp/1.0" \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"twitch_username": "someviewer", "skin_id": 42}' \
"https://chatstyle.gg/api/ext/viewers/unlock-skin"
Response:
{
"message": "Skin unlocked for viewer.",
"data": {
"twitch_username": "someviewer",
"skin": {
"id": 42,
"name": "Neon Purple"
}
}
}
- The viewer must have a ChatStyle account (they need to have logged in at least once). Returns
404if the viewer doesn't exist. - The skin must belong to your channel (your own custom skin or a global platform skin).
- Unlocking is idempotent — calling it twice for the same viewer+skin does not create duplicates.
- Unlocking grants access but does not auto-select the skin. The viewer still needs to select it.
Revoke a viewer's API-granted skin access. Only revokes access that was granted via this API — real purchases are never affected.
Request body: Same as unlock (provide twitch_username or twitch_user_id, plus skin_id).
Example:
curl -X DELETE \
-A "YourApp/1.0" \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"twitch_username": "someviewer", "skin_id": 42}' \
"https://chatstyle.gg/api/ext/viewers/unlock-skin"
Response:
{
"message": "Skin access revoked for viewer."
}
404 if no API-granted access exists for that viewer+skin combination.
List all skins a viewer has been granted access to via this API.
The {identifier} can be either a Twitch username or Twitch user ID.
Example:
curl -A "YourApp/1.0" \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
"https://chatstyle.gg/api/ext/viewers/someviewer/skins"
Response:
{
"data": [
{
"id": 42,
"name": "Neon Purple",
"slug": "neon-purple"
}
]
}
Settings Keys Reference
Style and skin settings use dotted keys in the format element.property. The available keys depend on the active style's settings schema — not every style uses every key. Use GET /api/ext/template to see the current settings_values and discover which keys are in use.
#fff, #fffc, or #1a1a2e. Short hex values are expanded in responses. Fully transparent colors are represented by the literal transparent in both requests and responses. Numeric values must be JSON numbers inside the documented range. Most numeric settings accept 0 through 10000; box shadow offset and spread settings accept -10000 through 10000. Select values must be one of the listed options. Toggle values must be JSON true or false.
*-advanced toggle is true, the matching per-side or per-corner keys control rendering. The uniform key is still stored, but it does not affect output until the advanced toggle is turned off again.
Chat
Spacing
| Key | Type | Default | Description |
|---|---|---|---|
chat.padding | integer | 0 | Uniform inner spacing around the whole chat container in px (0–10000). Designer label: Space Inside Chat Area |
chat.padding-advanced | toggle | false | Enable per-side chat inner spacing controls |
chat.padding-top | integer | 0 | Top inner spacing for the chat container in px (0–10000) |
chat.padding-right | integer | 0 | Right inner spacing for the chat container in px (0–10000) |
chat.padding-bottom | integer | 0 | Bottom inner spacing for the chat container in px (0–10000) |
chat.padding-left | integer | 0 | Left inner spacing for the chat container in px (0–10000) |
Bubble
bubble.message-direction, bubble.alignment, and bubble.direction.
Structural
| Key | Type | Default | Description |
|---|---|---|---|
bubble.direction | select | ltr | Text direction. Options: ltr, rtl |
bubble.message-direction | select | bottom-up | Message flow direction. Options: bottom-up, top-down, left-to-right, right-to-left |
bubble.full-width | toggle | false | Whether bubbles stretch to full container width |
bubble.alignment | select | left | Bubble alignment. Options: left, center, right |
Background
| Key | Type | Default | Description |
|---|---|---|---|
bubble.background-color | color | transparent | Background color |
bubble.background-gradient | gradient | "" | Complete normalized CSS gradient string |
Border
| Key | Type | Default | Description |
|---|---|---|---|
bubble.border-width | integer | 0 | Border width in px (0–10000) |
bubble.border-color | color | transparent | Border color |
bubble.border-style | select | solid | Options: none, solid, dashed, dotted, double |
bubble.border-radius | integer | 0 | Uniform border radius in px (0–10000) |
bubble.border-radius-advanced | toggle | false | Enable per-corner radius |
bubble.border-radius-top-left | integer | 0 | Top-left corner radius (0–10000) |
bubble.border-radius-top-right | integer | 0 | Top-right corner radius (0–10000) |
bubble.border-radius-bottom-right | integer | 0 | Bottom-right corner radius (0–10000) |
bubble.border-radius-bottom-left | integer | 0 | Bottom-left corner radius (0–10000) |
Shadow
| Key | Type | Default | Description |
|---|---|---|---|
bubble.box-shadow-offset-x | integer | 0 | Horizontal shadow offset (-10000 to 10000) |
bubble.box-shadow-offset-y | integer | 0 | Vertical shadow offset (-10000 to 10000) |
bubble.box-shadow-blur-radius | integer | 0 | Shadow blur radius (0–10000) |
bubble.box-shadow-spread-radius | integer | 0 | Shadow spread radius (-10000 to 10000) |
bubble.box-shadow-color | color | #000000 | Shadow color |
bubble.box-shadow-inset | toggle | false | Use inset shadow |
Animation
| Key | Type | Default | Description |
|---|---|---|---|
bubble.animation-entrance | select | slide-in-up | Entrance animation. Options: none, fade-in, fade-in-up, fade-in-down, fade-in-left, fade-in-right, slide-in-up, slide-in-down, slide-in-left, slide-in-right, bounce-in, bounce-in-up, bounce-in-down, zoom-in, zoom-in-up, flip-in-x, flip-in-y, rotate-in, jack-in-the-box, roll-in, light-speed-in-right |
bubble.animation-duration | integer | 750 | Animation duration in ms (0–10000) |
bubble.animation-delay | integer | 0 | Animation delay in ms (0–10000) |
bubble.animation-easing | select | ease-out | Options: ease-out, ease-in, ease-in-out, linear, ease |
Spacing
| Key | Type | Default | Description |
|---|---|---|---|
bubble.padding | integer | 0 | Inner padding in px (0–10000) |
bubble.gap | integer | 10 | Gap between bubbles on the .cs-chat container in px (0–10000) |
bubble.width | integer | 400 | Bubble width in px (0–10000) |
Avatar
Structural
| Key | Type | Default | Description |
|---|---|---|---|
avatar.show | toggle | true | Show/hide avatar |
avatar.position | select | right | Options: left, center, right |
avatar.size | integer | 60 | Avatar size in px (0–10000) |
Background
| Key | Type | Default | Description |
|---|---|---|---|
avatar.background-color | color | transparent | Background color |
avatar.background-gradient | gradient | "" | Complete normalized CSS gradient string |
Border
| Key | Type | Default | Description |
|---|---|---|---|
avatar.border-width | integer | 0 | Border width in px (0–10000) |
avatar.border-color | color | transparent | Border color |
avatar.border-style | select | solid | Options: none, solid, dashed, dotted, double |
avatar.border-radius | integer | 0 | Uniform border radius in px (0–10000) |
avatar.border-radius-advanced | toggle | false | Enable per-corner radius |
avatar.border-radius-top-left | integer | 0 | Top-left corner radius (0–10000) |
avatar.border-radius-top-right | integer | 0 | Top-right corner radius (0–10000) |
avatar.border-radius-bottom-right | integer | 0 | Bottom-right corner radius (0–10000) |
avatar.border-radius-bottom-left | integer | 0 | Bottom-left corner radius (0–10000) |
Shadow
| Key | Type | Default | Description |
|---|---|---|---|
avatar.box-shadow-offset-x | integer | 0 | Horizontal shadow offset (-10000 to 10000) |
avatar.box-shadow-offset-y | integer | 0 | Vertical shadow offset (-10000 to 10000) |
avatar.box-shadow-blur-radius | integer | 0 | Shadow blur radius (0–10000) |
avatar.box-shadow-spread-radius | integer | 0 | Shadow spread radius (-10000 to 10000) |
avatar.box-shadow-color | color | #000000 | Shadow color |
avatar.box-shadow-inset | toggle | false | Use inset shadow |
Animation
| Key | Type | Default | Description |
|---|---|---|---|
avatar.animation-entrance | select | none | Entrance animation (same options as bubble) |
avatar.animation-duration | integer | 750 | Animation duration in ms (0–10000) |
avatar.animation-delay | integer | 0 | Animation delay in ms (0–10000) |
avatar.animation-easing | select | ease-out | Options: ease-out, ease-in, ease-in-out, linear, ease |
Spacing
| Key | Type | Default | Description |
|---|---|---|---|
avatar.padding | integer | 0 | Inner padding in px (0–10000) |
Username
Structural
| Key | Type | Default | Description |
|---|---|---|---|
username.position | select | above-message | Options: above-message, inline |
username.font-style | select | normal | Options: normal, italic |
username.text-decoration | select | none | Options: none, underline |
username.text-transform | select | none | Options: none, uppercase, lowercase, capitalize |
Typography
| Key | Type | Default | Description |
|---|---|---|---|
username.font-size | integer | 14 | Font size in px (0–10000) |
username.font-color | color | #ffffff | Text color |
username.font-family | string | Inter | Font family (from font catalog) |
username.font-weight | select | 400 | Options: 300, 400, 500, 600, 700, 800, 900 |
username.text-shadow-offset-x | integer | 0 | Horizontal text shadow offset (0–10000) |
username.text-shadow-offset-y | integer | 0 | Vertical text shadow offset (0–10000) |
username.text-shadow-blur-radius | integer | 0 | Text shadow blur (0–10000) |
username.text-shadow-color | color | #000000 | Text shadow color |
username.text-stroke-width | integer | 0 | Text stroke width in px (0–10000) |
username.text-stroke-color | color | #000000 | Text stroke color |
Background
| Key | Type | Default | Description |
|---|---|---|---|
username.background-color | color | transparent | Background color |
username.background-gradient | gradient | "" | Complete normalized CSS gradient string |
Border
| Key | Type | Default | Description |
|---|---|---|---|
username.border-width | integer | 0 | Border width in px (0–10000) |
username.border-color | color | transparent | Border color |
username.border-style | select | solid | Options: none, solid, dashed, dotted, double |
username.border-radius | integer | 0 | Uniform border radius in px (0–10000) |
username.border-radius-advanced | toggle | false | Enable per-corner radius |
username.border-radius-top-left | integer | 0 | Top-left corner radius (0–10000) |
username.border-radius-top-right | integer | 0 | Top-right corner radius (0–10000) |
username.border-radius-bottom-right | integer | 0 | Bottom-right corner radius (0–10000) |
username.border-radius-bottom-left | integer | 0 | Bottom-left corner radius (0–10000) |
Shadow
| Key | Type | Default | Description |
|---|---|---|---|
username.box-shadow-offset-x | integer | 0 | Horizontal shadow offset (-10000 to 10000) |
username.box-shadow-offset-y | integer | 0 | Vertical shadow offset (-10000 to 10000) |
username.box-shadow-blur-radius | integer | 0 | Shadow blur radius (0–10000) |
username.box-shadow-spread-radius | integer | 0 | Shadow spread radius (-10000 to 10000) |
username.box-shadow-color | color | #000000 | Shadow color |
username.box-shadow-inset | toggle | false | Use inset shadow |
Animation
| Key | Type | Default | Description |
|---|---|---|---|
username.animation-entrance | select | none | Entrance animation (same options as bubble) |
username.animation-duration | integer | 750 | Animation duration in ms (0–10000) |
username.animation-delay | integer | 0 | Animation delay in ms (0–10000) |
username.animation-easing | select | ease-out | Options: ease-out, ease-in, ease-in-out, linear, ease |
Spacing
| Key | Type | Default | Description |
|---|---|---|---|
username.padding | integer | 0 | Inner padding in px (0–10000) |
Message
Structural
| Key | Type | Default | Description |
|---|---|---|---|
message.font-style | select | normal | Options: normal, italic |
message.text-decoration | select | none | Options: none, underline |
message.text-transform | select | none | Options: none, uppercase, lowercase, capitalize |
Typography
| Key | Type | Default | Description |
|---|---|---|---|
message.font-size | integer | 14 | Font size in px (0–10000) |
message.font-color | color | #ffffff | Text color |
message.font-family | string | Inter | Font family (from font catalog) |
message.font-weight | select | 400 | Options: 300, 400, 500, 600, 700, 800, 900 |
message.text-shadow-offset-x | integer | 0 | Horizontal text shadow offset (0–10000) |
message.text-shadow-offset-y | integer | 0 | Vertical text shadow offset (0–10000) |
message.text-shadow-blur-radius | integer | 0 | Text shadow blur (0–10000) |
message.text-shadow-color | color | #000000 | Text shadow color |
message.text-stroke-width | integer | 0 | Text stroke width in px (0–10000) |
message.text-stroke-color | color | #000000 | Text stroke color |
Background
| Key | Type | Default | Description |
|---|---|---|---|
message.background-color | color | transparent | Background color |
message.background-gradient | gradient | "" | Complete normalized CSS gradient string |
Border
| Key | Type | Default | Description |
|---|---|---|---|
message.border-width | integer | 0 | Border width in px (0–10000) |
message.border-color | color | transparent | Border color |
message.border-style | select | solid | Options: none, solid, dashed, dotted, double |
message.border-radius | integer | 0 | Uniform border radius in px (0–10000) |
message.border-radius-advanced | toggle | false | Enable per-corner radius |
message.border-radius-top-left | integer | 0 | Top-left corner radius (0–10000) |
message.border-radius-top-right | integer | 0 | Top-right corner radius (0–10000) |
message.border-radius-bottom-right | integer | 0 | Bottom-right corner radius (0–10000) |
message.border-radius-bottom-left | integer | 0 | Bottom-left corner radius (0–10000) |
Shadow
| Key | Type | Default | Description |
|---|---|---|---|
message.box-shadow-offset-x | integer | 0 | Horizontal shadow offset (-10000 to 10000) |
message.box-shadow-offset-y | integer | 0 | Vertical shadow offset (-10000 to 10000) |
message.box-shadow-blur-radius | integer | 0 | Shadow blur radius (0–10000) |
message.box-shadow-spread-radius | integer | 0 | Shadow spread radius (-10000 to 10000) |
message.box-shadow-color | color | #000000 | Shadow color |
message.box-shadow-inset | toggle | false | Use inset shadow |
Animation
| Key | Type | Default | Description |
|---|---|---|---|
message.animation-entrance | select | none | Entrance animation (same options as bubble) |
message.animation-duration | integer | 750 | Animation duration in ms (0–10000) |
message.animation-delay | integer | 0 | Animation delay in ms (0–10000) |
message.animation-easing | select | ease-out | Options: ease-out, ease-in, ease-in-out, linear, ease |
Spacing
| Key | Type | Default | Description |
|---|---|---|---|
message.padding | integer | 0 | Inner padding in px (0–10000) |
Badges
| Key | Type | Default | Description |
|---|---|---|---|
badges.show | toggle | true | Show/hide chat badges |
badges.position | select | before-name | Options: before-name, after-name |