Overview
Provisional accounts let players use Social SDK features in your game without linking a Discord account so all players can have a consistent gameplay experience.
With provisional accounts, players can:
- Add friends and communicate with other players
- Join voice chats in game lobbies
- Send direct messages to other players
- Appear in friends lists and game lobbies
All of this works seamlessly whether your players have Discord accounts or not.
This guide will show you how to:
- Set up provisional accounts for your game
- Create and manage provisional accounts
- Handle account merging when users want to upgrade to full Discord
Prerequisites
Before you begin, make sure you have:
- A basic understanding of how the SDK works from the Getting Started Guide
- An external authentication provider set up for your game
What Are Provisional Accounts?
Think of provisional accounts as temporary Discord accounts that:
- Work only with your game
- Can be upgraded to full Discord accounts later
- Persist between game sessions
- Use your game’s authentication system
With provisional accounts, players can use Discord features like chat and voice and interact with game friends without creating a full Discord account. They are “placeholder” Discord accounts for the user that your game owns and manages.
For existing Discord users who have added a provisional account as a game friend, the provisional account will appear in their friend list, allowing you to send direct messages and interact with them for text and voice in lobbies.
How It Works
- Your game authenticates players using your existing system (Steam, Epic, etc.)
- Discord creates temporary accounts linked to those identities
- Players can use Discord features immediately
- Players can optionally upgrade to full Discord accounts later
- All friends and chat history transfer when upgrading
Benefits
- Instant Access: Players can use social features immediately
- Seamless Experience: Works the same for all players
- Easy Upgrade Path: Simple conversion to full Discord accounts
- Data Persistence: Friends and history are preserved
- Cross-Platform: Works on all supported platforms
Getting Set Up
Choosing an Authentication Method
Discord offers a number of authentication methods, the one you use depends on how you game and account system is set up:
- Use the Bot Token Endpoint if your game has an account system which uniquely identifies users. This is the recommended approach when possible.
- Use the Server Authentication with External Credentials Exchange if you have an existing OIDC provider, or do not have an account system.
- Use the Client Side Token Exchange Method if you are using a Public Client.
If you are using (2) or (3), you must configure you identity provider before being able to create provisional accounts.
Configuring Your Identity Provider
If you are using the bot token endpoint, no Identity Provider configuration is required.
Open the Discord app for your game in the Developer Portal. Find the External Auth page under the Discord Social SDK section in the sidebar.
Click on Add Auth Provider and choose the type of provider you’re using (Steam, OIDC, etc.). Fill in the required details for your provider.
We currently support the following provider types:
- OpenID Connect (OIDC)
- Steam Session Tickets
- Epic Online Services (EOS)
- Unity
- Apple
- PlayStation Network (PSN)
If you are configuring OIDC, see OIDC Integration Requirements for the full list of requirements your issuer URL, discovery document, and ID tokens must meet.
Providers are represented in Discord’s systems by the following types:
External Auth Types
| Type | Description |
|---|
| OIDC | OpenID Connect ID token |
| STEAM_SESSION_TICKET | A Steam auth ticket for web generated with discord as the identity |
| EPIC_ONLINE_SERVICES_ACCESS_TOKEN | Access token for Epic Online Services. Supports EOS Auth access tokens |
| EPIC_ONLINE_SERVICES_ID_TOKEN | ID token for Epic Online Services. Supports both EOS Auth + Connect ID tokens |
| UNITY_SERVICES_ID_TOKEN | Unity Services authentication ID token |
| APPLE_ID_TOKEN | Apple sign-in authentication ID token |
| PLAYSTATION_NETWORK_ID_TOKEN | PlayStation Network account authentication ID token |
| DISCORD_BOT_ISSUED_ACCESS_TOKEN | An access token for a user authenticated via the Bot Token Endpoint |
Implementing Provisional Accounts
Creating a Provisional Account and requesting an Access Token for the account always happens in a single step.
You provide external authentication and uniquely identifies the user, and Discord finds a user associated with that identifier.
- If there is no account associated with the identity, a new provisional account is created along with a new access token for the user.
- If there is a provisional account associated with the identity, an access token is returned.
- If there is an existing full Discord account associated with the identity, the request is aborted (See Error Handling).
Once authentication is complete, you can use the access token as you would a full Discord user’s access token.
Server Authentication with Bot Token Endpoint
This is the preferred method of authentication. It ends up being the simplest choice for most provisional account integrations.
# filepath: your_game/server/auth.py
import requests
from models import GameAccount
def get_provisional_token(game_account: GameAccount):
response = requests.post(
'https://dc.mintsclubs.xyz/api/v10/partner-sdk/token/bot',
headers={
'Content-Type': 'application/json',
'Authorization': 'Bot <BOT_TOKEN>' # your application's bot token
},
json={
'external_user_id': game_account.id, # your account system's unique id
'preferred_global_name': game_account.display_name, # your account system's display name for the user
}
)
return response.json()
Bot Token Endpoint Response
{
"access_token": "<access token>",
"id_token": "<id token>",
"token_type": "Bearer",
"expires_in": 604800,
"scope": "sdk.social_layer"
}
Server Authentication with External Credentials Exchange
# filepath: your_game/server/auth.py
import requests
def get_provisional_token(external_token: str):
response = requests.post(
'https://dc.mintsclubs.xyz/api/v10/partner-sdk/token',
json={
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'external_auth_type': EXTERNAL_AUTH_TYPE, # See External Auth Types above
'external_auth_token': external_token
}
)
return response.json()
External Credentials Exchange Response
{
"access_token": "<access token>",
"id_token": "<id token>",
"token_type": "Bearer",
"expires_in": 604800,
"scope": "sdk.social_layer"
}
If you are using OIDC, you may see a refresh_token in this response. Using it via the OAuth2 refresh_token grant is deprecated — re-authenticate using a fresh provider token instead. See Refreshing Provisional Account Tokens for details.
Authentication for Public Clients
This method requires enabling Public Client for your app. Most games will not want to ship with this enabled. Learn more
If you have Public Client enabled on your Discord app, you can use the following code to authenticate your players with the external provider.
// filepath: your_game/auth_manager.cpp
void AuthenticateUser(std::shared_ptr<discordpp::Client> client) {
// Get your external auth token (Steam, OIDC, etc.)
std::string externalToken = GetExternalAuthToken();
// Get provisional token from Discord
client->GetProvisionalToken(DISCORD_APPLICATION_ID,
discordpp::AuthenticationExternalAuthType::OIDC,
externalToken,
[client](discordpp::ClientResult result, std::string accessToken, std::string refreshToken, discordpp::AuthorizationTokenType tokenType, int32_t expiresIn, std::string scope) {
if (result.Successful()) {
std::cout << "🔓 Provisional token received! Establishing connection...\n";
client->UpdateToken(discordpp::AuthorizationTokenType::Bearer, accessToken, [client](discordpp::ClientResult result) {
client->Connect();
});
} else {
std::cerr << "❌ Provisional token request failed: " << result.Error() << std::endl;
}
});
}
OIDC Integration Requirements
If you are using OpenID Connect (OIDC) as your identity provider, Discord validates your configuration and tokens against the requirements below. Meeting these requirements is necessary both when saving your OIDC configuration in the Developer Portal and at runtime when tokens are exchanged.
Issuer URL Requirements
The issuer URL you configure in the Developer Portal must meet all of the following:
| Requirement | Details |
|---|
| HTTPS scheme | Must use https:// — HTTP is not permitted |
| No query parameters | The URL must not contain a ? character |
| No fragment | The URL must not contain a # character |
| No embedded credentials | The URL must not contain a username or password |
| Public hostname | The hostname must have at least two segments (e.g. example.com). Bare hostnames such as localhost are not permitted |
| No private or reserved TLDs | The hostname must not end in .local, .arpa, .internal, or .localhost |
| No IP addresses | The hostname must not be a bare IP address (e.g. 192.168.1.1) |
Non-standard ports (e.g. :8080) are permitted.
OIDC Discovery Document Requirements
Discord fetches your OIDC configuration from {issuer_url}/.well-known/openid-configuration per RFC 8414. This endpoint must:
- Be accessible over HTTPS
- Not require HTTP redirects — Discord does not follow redirects when fetching this document or your JWKS endpoint
- Return a valid JSON object (not an array)
The discovery document must include these fields:
| Field | Type | Requirement |
|---|
issuer | HTTPS URL | Must exactly match the issuer URL used to fetch the document |
jwks_uri | HTTPS URL | URI to your JWKS signing key endpoint |
id_token_signing_alg_values_supported | Array of strings | Must contain at least one supported algorithm |
authorization_endpoint and token_endpoint are accepted but not used by Discord.
Supported Signing Algorithms
Your ID tokens must be signed using an asymmetric algorithm. Discord supports:
| Algorithm family | Algorithms |
|---|
| RSA | RS256, RS384, RS512 |
| ECDSA | ES256, ES384, ES512 |
| RSA-PSS | PS256, PS384, PS512 |
Symmetric (HMAC) algorithms such as HS256 are not supported. Any unsupported algorithms listed in id_token_signing_alg_values_supported are silently ignored.
ID Token Requirements
The OIDC ID token passed as external_auth_token must meet all of the following:
| Requirement | Details |
|---|
kid header | The JWT header must include a kid (Key ID) field that matches a key in your JWKS |
| Signing algorithm | Must use one of the supported algorithms listed in your discovery document |
iss claim | Must exactly match the configured issuer URL |
sub claim | Required — the unique user identifier from your identity provider |
aud claim | Must include the client ID configured for this application in the Developer Portal |
exp claim | Required — token must not be expired |
iat claim | Required — token must have been issued within the past 7 days |
The optional preferred_username claim (1–32 characters) sets the provisional account’s display name if present.
Provisional Account Access Tokens
These methods generate a Discord access token. You pass in the user’s identity, and it generates a new Discord account tied to that identity. There are multiple ways of specifying that identity, including using Steam/Epic services or your own identity system.
All these methods will return with an access token that expires in 7 days.
Refreshing Provisional Account Tokens
Use Client::SetTokenExpirationCallback to receive a callback when the current token is about to expire or has expired, so you can refresh it without interrupting the user’s experience.
When the token expires, re-call the same method you used originally to obtain a new access token, then pass it to Client::UpdateToken.
When the token expires, the SDK will still receive updates, such as new messages sent in a lobby, and any voice calls will continue to be active. However, any new actions, such as sending a message or adding a friend, will fail. You can get a new token and pass it to Client::UpdateToken without interrupting the user’s experience.
// Register a callback to handle token expiration
client->SetTokenExpirationCallback([client](discordpp::AuthorizationTokenType tokenType) {
// Re-acquire a new token using the same method you used originally.
// For example, if you used GetProvisionalToken:
std::string externalToken = GetExternalAuthToken(); // get a fresh token from your identity provider
client->GetProvisionalToken(DISCORD_APPLICATION_ID,
discordpp::AuthenticationExternalAuthType::OIDC,
externalToken,
[client](discordpp::ClientResult result, std::string accessToken, std::string refreshToken,
discordpp::AuthorizationTokenType tokenType, int32_t expiresIn, std::string scope) {
if (result.Successful()) {
// Pass the new access token to UpdateToken — no reconnect needed
client->UpdateToken(discordpp::AuthorizationTokenType::Bearer, accessToken, [](discordpp::ClientResult result) {
if (result.Successful()) {
std::cout << "✅ Token refreshed successfully\n";
}
});
} else {
std::cerr << "❌ Failed to refresh provisional token: " << result.Error() << std::endl;
}
});
});
If you are using Server Authentication with OIDC, a refresh_token is returned but using it via the OAuth2 refresh_token grant is deprecated. Re-authenticate using a fresh provider token instead.
Provisional Account Access Token Storage
It is suggested that these provisional tokens are not stored and instead invoke this function each time the game is launched and when these tokens are about to expire. However, should you choose to store it, it is recommended that these provisional account tokens be differentiated from “full” Discord account tokens.
Error Handling
Common error codes and solutions for the server token exchange methods:
| Code | Meaning | Solution |
|---|
| 530000 | Application not configured | Contact Discord support to enable provisional accounts for your application |
| 530001 | Expired ID token | Request a new token from your identity provider |
| 530004 | Token too old | Request a new token (tokens over 1 week old are rejected) |
| 530006 | Username generation failed | Retry the operation (temporary error) |
| 530007 | Invalid client secret | Verify or regenerate your client secret in the Developer Portal |
| 530010 | User account non-provisional | User already linked to Discord account - use standard OAuth2 flow |
If you are using OIDC, you may encounter more specific errors:
| Code | Meaning | Solution |
|---|
| 530002 | Invalid issuer | Verify the iss claim in your ID token exactly matches the issuer URL in your OIDC configuration |
| 530003 | Invalid audience | Verify the aud claim in your ID token includes the client ID in your OIDC configuration |
| 530008 | OIDC configuration not found | Verify your issuer URL is correct, accessible over HTTPS, and serves a valid discovery document without HTTP redirects |
| 530009 | OIDC JWKS not found | Verify your JWKS endpoint is accessible over HTTPS without HTTP redirects |
| 530020 | Invalid OIDC JWT token | Verify your ID token is properly signed and uses a supported algorithm |
| 530027 | Missing kid header | Ensure your ID token includes a kid (Key ID) header in the JWT header identifying the signing key |
Setting Display Names
Using these credentials, we’ll create a limited Discord account just for your game and try to set the username for you according to the following:
- For Bot issued tokens, the
preferred_global_name you specified will be used.
- For OIDC, a provisional account’s display name will be the value of the
preferred_username claim, if specified in
the ID token. This field is optional and should be between 1 and 32 characters. If not specified, the user’s display
name will default to the user’s unique username, which Discord generates on creation.
- For Steam session tickets, the display name of the user’s Steam
account is used as the provisional account’s display name.
- For EOS Auth Access Tokens or ID Tokens,
the name of the user’s Epic account is used as the provisional account’s display name. EOS Connect ID Tokens do
not expose any username, and thus the game will need to configure the display name with
Client::UpdateProvisionalAccountDisplayName.
- For Unity Services ID Tokens,
the display name of the user’s Unity Player Account is used as the provisional account’s display name.
If you’d like to set the display name for a provisional account, you can use the Client::UpdateProvisionalAccountDisplayName method.
client->UpdateProvisionalAccountDisplayName("CoolPlayer123", [](discordpp::ClientResult result) {
if (result.Successful()) {
std::cout << "✅ Display name updated\n";
}
}
);
Merging Provisional Accounts
When a player wants to convert their provisional account to a full Discord account, we start a special version of the access token request flow where the provisional users external identity is included.
Unlike other API rate limits, the merge operation has a strict per-user limit since account merging is not something we expect to happen frequently. Under normal circumstances, a player will only ever link their account once.If you are testing your merge integration, make sure to add your QA users to your application’s App Testers list to avoid hitting rate limits during testing.
Merging Provisional Accounts for Servers
To merge a provisional account, extend the standard OAuth2 token exchange by posting to /oauth2/token with two additional parameters — external_auth_type and external_auth_token. Discord uses these to identify the provisional account and merge it into the full Discord account associated with the provided authorization code or device code.
See the External Auth Types table above for the full list of supported external_auth_type values.
The external_auth_token is the same credential you provided when creating the provisional account — for example, your OIDC identity token, Steam session ticket, or EOS access token. If you created the provisional account using the Bot Token Endpoint, use DISCORD_BOT_ISSUED_ACCESS_TOKEN as the external_auth_type and the external_user_id (your game account ID) as the external_auth_token.
Desktop & Mobile
Request Body Parameters
| Parameter | Description |
|---|
grant_type | Must be authorization_code. This is the standard OAuth2 authorization code grant — the authorization code from the Client::Authorize flow is exchanged for an access token. |
code | The authorization code returned to your server after the user completes the Client::Authorize flow. |
redirect_uri | The redirect URI used in the original authorization request. Must match exactly. |
external_auth_type | The type of external identity provider. See External Auth Types. |
external_auth_token | The external identity token. For example, for OIDC, this is the OIDC identity token. For DISCORD_BOT_ISSUED_ACCESS_TOKEN, this is the external_user_id (game account ID) used when creating the provisional account. |
import requests
API_ENDPOINT = 'https://dc.mintsclubs.xyz/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
# See External Auth Types above for all supported values
EXTERNAL_AUTH_TYPE = 'DISCORD_BOT_ISSUED_ACCESS_TOKEN'
def exchange_code_with_merge(code, redirect_uri, external_auth_token):
data = {
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': redirect_uri,
'external_auth_type': EXTERNAL_AUTH_TYPE,
'external_auth_token': external_auth_token
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET))
r.raise_for_status()
return r.json()
Console
Request Body Parameters
| Parameter | Description |
|---|
grant_type | Must be urn:ietf:params:oauth:grant-type:device_code. This is the RFC 8628 device authorization grant, used for consoles and devices without a browser. |
device_code | The device code from the device authorization flow. See Account Linking on Consoles. |
external_auth_type | The type of external identity provider. See External Auth Types. |
external_auth_token | The external identity token. For example, for OIDC, this is the OIDC identity token. For DISCORD_BOT_ISSUED_ACCESS_TOKEN, this is the external_user_id (game account ID) used when creating the provisional account. |
import requests
API_ENDPOINT = 'https://dc.mintsclubs.xyz/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
# See External Auth Types above for all supported values
EXTERNAL_AUTH_TYPE = 'DISCORD_BOT_ISSUED_ACCESS_TOKEN'
def exchange_device_code_with_merge(device_code, external_auth_token):
data = {
'grant_type': 'urn:ietf:params:oauth:grant-type:device_code',
'device_code': device_code,
'external_auth_type': EXTERNAL_AUTH_TYPE,
'external_auth_token': external_auth_token
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET))
r.raise_for_status()
return r.json()
Merge Request Response
{
"access_token": "<access token>",
"token_type": "Bearer",
"expires_in": 604800,
"refresh_token": "<refresh token>",
"scope": "sdk.social_layer"
}
Merging Provisional Accounts for Public Clients
This method requires enabling Public Client for your app. Most games will not want to ship with this enabled. Learn more
If you do not have a backend, leverage the Client::GetTokenFromProvisionalMerge (Desktop & Mobile) or Client::GetTokenFromDeviceProvisionalMerge (Console) method, which will handle the entire process for you. You’ll want to first enable Public Client on your Discord application’s OAuth2 tab on the Discord developer portal. You can then leverage the Client::GetTokenFromProvisionalMerge or Client::GetTokenFromDeviceProvisionalMerge method using just the client.
This function should be used with the Client::Authorize function whenever a user with a provisional account wants to link to an existing Discord account or “upgrade” their provisional account into a “full” Discord account.
In this case, data from the provisional account should be “migrated” to the Discord account, a process we call “account merging”. Specifically, relationships, DMs, and lobby memberships are transferred to the Discord account.
The provisional account will be deleted once this merging process is completed. If the user unlinks later, a new provisional account with a new unique ID is created.
The account merging process starts like the normal login flow, invoking the Client::Authorize method to get an authorization code back. Instead of calling GetToken, call this function and pass on the provisional user’s identity.
Discord can then find the provisional account with that identity and the new Discord account and merge any data as necessary.
See the documentation for Client::GetToken for more details on the callback. Note that the callback will be invoked when the token exchange is complete, but merging accounts happens asynchronously and will not be complete yet.
// Create a code verifier and challenge if using GetToken
auto codeVerifier = client->CreateAuthorizationCodeVerifier();
discordpp::AuthorizationArgs args{};
args.SetClientId(YOUR_DISCORD_APPLICATION_ID);
args.SetScopes(discordpp::Client::GetDefaultPresenceScopes());
args.SetCodeChallenge(codeVerifier.Challenge());
client->Authorize(args, [client, codeVerifier](discordpp::ClientResult result, std::string code, std::string redirectUri) {
if (!result.Successful()) {
std::cerr << "❌ Authorization Error: " << result.Error() << std::endl;
} else {
std::cout << "✅ Authorization successful! Next step: GetTokenFromProvisionalMerge \n";
// Retrieve your external auth token
std::string externalAuthToken = GetExternalAuthToken();
client->GetTokenFromProvisionalMerge(YOUR_DISCORD_APPLICATION_ID, code, codeVerifier, redirectUri, discordpp::AuthenticationExternalAuthType::OIDC, externalAuthToken,[client](
discordpp::ClientResult result,
std::string accessToken,
std::string refreshToken,
discordpp::AuthorizationTokenType tokenType,
int32_t expiresIn,
std::string scope) {
if (result.Successful()) {
std::cout << "🔓 Token received! Establishing connection...\n";
client->UpdateToken(discordpp::AuthorizationTokenType::Bearer, accessToken, [client](discordpp::ClientResult result) {
client->Connect();
});
} else {
std::cerr << "❌ Token request failed: " << result.Error() << std::endl;
}
});
}
});
Data Migration During Merging
When a user merges their provisional account with a Discord account, the following data is automatically transferred:
- ✅ Friends: All In-game and Discord friendships made through the provisional account
- ✅ Lobby Memberships: Active and historical lobby participation
- ✅ DM Messages: Direct messages and history
This migration ensures users don’t lose their social connections built while using the provisional account.
Merge Request Failures
You may receive a merge specific error code while attempting this operation:
| Code | HTTP Status | Meaning | Solution |
|---|
| 530014 | 400 | Invalid merge source | The source account is not provisional |
| 530016 | 400 | Invalid merge destination | The destination account is provisional |
| 530017 | 400 | Merge source user banned | The provisional account being merged is banned from platform |
| 530023 | 400 | Too many application identities | User already has an associated external identity for this application |
| - | 423 | Resource locked | Transient error, wait and retry |
Unmerging Provisional Accounts
When a player wants to unlink their Discord account from their provisional account, there are three options:
- The user can unmerge their account from the Discord client
- A developer can unmerge the account using the unmerge endpoint on the Discord API
- A developer can use the SDK helper method for public clients
Unmerging invalidates all access/refresh tokens for the user. They cannot be used again after the unmerge operation completes. Any connected game sessions will be disconnected.
The external_auth_token from your original provisional account setup is not affected by an unmerge. After the
unmerge completes, you can use the same token to retrieve the new provisional token for the newly created provisional
account.
Discord Users
Users can unmerge their account by removing access to your application on their Discord User Settings -> Authorized Apps page.
This method doesn’t require any code changes from developers, but we recommend providing unmerging functionality through
one of the options below for a better user experience.
If you would like to be notified when a user unlinks this way, you can configure you application to listen for the APPLICATION_DEAUTHORIZED webhook event.
Otherwise, you will know that the user has unlinked because their access token and refresh token (if you have one) will be invalidated.
Unmerging Provisional Accounts for Servers
A developer can unmerge a user’s account by sending a request to the unmerge endpoint on the Discord API.
import requests
API_ENDPOINT = 'https://dc.mintsclubs.xyz/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
EXTERNAL_AUTH_TYPE = 'OIDC'
def unmerge_provisional_account(external_auth_token):
data = {
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'external_auth_type': EXTERNAL_AUTH_TYPE,
'external_auth_token': external_auth_token
}
r = requests.post('%s/partner-sdk/provisional-accounts/unmerge' % API_ENDPOINT, json=data, headers=headers)
r.raise_for_status()
If you have a server backend, you’ll want to use the server-to-server unmerge endpoint rather than the SDK helper method to maintain better security and control over the unmerge process.
Unmerging with Bot Token Endpoint
If you’re using the Bot Token Endpoint for authentication, you can unmerge accounts without an external auth token.
import requests
API_ENDPOINT = 'https://dc.mintsclubs.xyz/api/v10'
BOT_TOKEN = 'YOUR_BOT_TOKEN'
def unmerge_provisional_account(external_user_id):
data = {
'external_user_id': external_user_id # identifier used in the /token/bot endpoint
}
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bot {BOT_TOKEN}'
}
r = requests.post('%s/partner-sdk/provisional-accounts/unmerge/bot' % API_ENDPOINT, json=data, headers=headers)
r.raise_for_status()
This endpoint can also be useful in cases where the Discord Auth token has been lost to error or data loss, and an unmerge operation is required to migrate to a provisional account before re-linking a Discord account.
Unmerging Provisional Accounts for Public Clients
This method requires enabling Public Client for your app. Most games will not want to ship with this enabled. Learn more
The quickest way to unmerge accounts is to leverage the Client::UnmergeIntoProvisionalAccount method,
which will handle the entire process for you. This method is designed for public clients that don’t have a backend server.
Important Notes:
- This function only works for public clients (applications without backend servers)
- You’ll need to enable “Public Client” on your Discord application’s OAuth2 tab in the Discord developer portal
- After unmerging, you should use
Client::GetProvisionalToken to get a new provisional token for the newly created provisional account
// unmerge a user account
void UnmergeUserAccount(const std::shared_ptr<discordpp::Client>& client) {
// Get your external auth token (Steam, OIDC, etc.)
std::string externalToken = GetExternalAuthToken();
// Unmerge the Discord account from the external identity
client->UnmergeIntoProvisionalAccount(
YOUR_DISCORD_APPLICATION_ID,
discordpp::AuthenticationExternalAuthType::OIDC, // or STEAM, EOS, etc.
externalToken,
[client, externalToken](const discordpp::ClientResult &result) {
if (result.Successful()) {
std::cout << "✅ Account unmerged successfully! Creating new provisional account...\n";
// Now get a new provisional token for the unlinked identity
client->GetProvisionalToken(
YOUR_DISCORD_APPLICATION_ID,
discordpp::AuthenticationExternalAuthType::OIDC,
externalToken,
[client](const discordpp::ClientResult &result,
const std::string &accessToken,
const std::string& refreshToken,
discordpp::AuthorizationTokenType tokenType,
int32_t expiresIn,
const std::string& scopes) {
if (result.Successful()) {
std::cout << "🔓 New provisional account created! Establishing connection...\n";
client->UpdateToken(discordpp::AuthorizationTokenType::Bearer, accessToken,
[client](const discordpp::ClientResult &updateResult) {
if (updateResult.Successful()) {
client->Connect();
} else {
std::cerr << "❌ Failed to update token: " << updateResult.Error() << std::endl;
}
}
);
} else {
std::cerr << "❌ Failed to create new provisional account: " << result.Error() << std::endl;
}
}
);
} else {
std::cerr << "❌ Unmerge failed: " << result.Error() << std::endl;
}
}
);
}
Data Migration During Unmerging
When a user unmerges their account, a new provisional account is created with a new user ID. The following data is transferred to the new provisional account:
- ✅ Username: Global name is copied to the new provisional account
- ✅ In-game friends: All copied to the new provisional account
- ✅ Discord friends who use this application: Copied to the provisional account
- ✅ Blockers: Accounts that blocked the original Discord account are preserved
- ✅ Lobbies: Active lobby memberships for the application are transferred
The following data is not transferred:
- ❌ Discord friends who don’t use this application: Not transferred
- ❌ DM message history: Not moved to provisional accounts
Provisional accounts can have Discord friends, but can only message these friends when actively playing the game.
Unmerge Request Failures
You may receive an unmerge specific error code while attempting this operation:
| Code | HTTP Status | Meaning | Solution |
|---|
| 50229 | 400 | Invalid user type | User account is provisional and cannot be unmerged |
| - | 404 | Unknown user | No user identity found for the provided external identity |
Next Steps
Now that you’ve set up provisional accounts for your game, you can explore more features of the Discord Social SDK:
Design: Provisional Accounts
Design guidelines for implementing provisional accounts in your game.
Creating a Unified Friends List
Combine Discord and game friends into a single list for easy management.
Setting Rich Presence
Display game status and information to Discord friends.
Need help? Join the Discord Developers Server and share questions in the #social-sdk-dev-help channel for support from the community.
If you encounter a bug while working with the Social SDK, please report it here: https://dis.gd/social-sdk-bug-report
Change Log
| Date | Changes |
|---|
| April 21, 2026 | Document OIDC integration requirements |
| April 14, 2026 | Clarify provisional account token refresh flow |
| April 13, 2026 | Clarify Merging Provisional Accounts for Servers |
| February 25, 2026 | Clarify unmerge behavior and data migration |
| March 17, 2025 | Initial release |