• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Account AND char creating in client ADDED

I remember the topic where the guy was saying this should never be done because it's not safe hahahaha
it will be fun seeing the implementation part though
 
To be honest, this actually looks clean.
I recently thought about adding something like this to my client as well.
As I remember Medivia has something like this in their client either.
 
I grabbed the data between the client and server in case someone like @Znote wants to add support for it.

The client uses https://www.tibia.com/clientservices/accountcreationclientservices.php for communicating this data. When you click on Create New Account the client POSTs:
JSON:
{
    "type":"getaccountcreationstatus"
}
and the server responds with a list of worlds, a recommended world, and whether captcha is activated:
JSON:
{
    "Worlds":[
        {
            "Name":"Adra",
             "PlayersOnline":30,
             "CreationDate":1601539200,
             "Region":"Europe",
             "PvPType":"Open PvP",
             "PremiumOnly":0,
             "TransferType":"Blocked",
             "BattlEyeActivationTimestamp":1603267200,
             "BattlEyeInitiallyActive":1
        },
        ...
        {
            "Name":"Zenobra",
             "PlayersOnline":111,
            "CreationDate":1588320000,
            "Region":"South America",
            "PvPType":"Open PvP",
            "PremiumOnly":0,
            "TransferType":"Blocked",
            "BattlEyeActivationTimestamp":1585299600,
            "BattlEyeInitiallyActive":1
        }
    ],
    "RecommendedWorld":"Marbera",
    "IsCaptchaDeactivated":false
}
The client will also request a suggested character name (it POSTs the same when you click the Suggest Name button):
JSON:
{
    "Type":"GenerateCharacterName"
}
and the server will respond with a generated name:
JSON:
{
    "GeneratedName":"Ironian Inup"
}
After you put your email in, the client will request the server to check if it is a valid email address (probably just a format check):
JSON:
{
    "Email":"[email protected]",
    "type":"CheckEMail"
}
and the server will tell the client if it passes or not:
JSON:
{
    "IsValid":true,
    "EMail":"[email protected]"
}
Here's the response for an invalid email:
JSON:
{
    "errorCode":59,
    "errorMessage":"This email address has an invalid format. Please enter a correct email address!",
    "EMail":"test@test"
}
Note that even if you haven't finished typing in your email, the client will send whatever you have typed if there is a short delay between the last keystroke.

Passwords follow the same process; the client will send it to the server for validation after a delay in keystrokes. Here's an example of an invalid password and the response, and a valid password and the response:
JSON:
POST invalid password:
{
    "Password1":"testpassword",
    "Type":"checkpassword"
}

Response:
{
    "PasswordRequirements":{
        "PasswordLength":true,
        "InvalidCharacters":true,
        "HasLowerCase":true,
        "HasUpperCase":false,
        "HasNumber":false
    },
    "Password1":"testpassword",
    "PasswordStrength":1,
    "PasswordStrengthColor":"#EC644B",
    "PasswordValid":false
}

POST valid password:
{
    "Password1":"testpasswordQ!1",
    "Type":"checkpassword"
}

Response:
{
    "PasswordRequirements":{
        "PasswordLength":true,
        "InvalidCharacters":true,
        "HasLowerCase":true,
        "HasUpperCase":true,
        "HasNumber":true
    },
    "Password1":"testpasswordQ!1",
    "PasswordStrength":3,
    "PasswordStrengthColor":"#b0b300",
    "PasswordValid":true
}
For the Repeat Password field, the client sends the exact same information for whatever is in the first password field but the client checks whether or not the two passwords match.

The Character Name field works the same way in that after a delay in keystrokes the client sends it to the server to check its validity:
JSON:
{
    "CharacterName":"Bubbles",
    "Type":"CheckCharacterName"
}
{
    "errorCode":54,
    "errorMessage":"This character name is already used. Please select another one!",
    "CharacterName":"Bubbles",
    "IsAvailable":false
}
...
{
    "CharacterName":"Bubbles234",
    "Type":"CheckCharacterName"
}
{
    "errorCode":99,
    "errorMessage":"This name contains invalid letters. Please use only A-Z, a-z and space.",
    "CharacterName":"Bubbles234",
    "IsAvailable":false
}
...
{
    "CharacterName":"Bubblessss",
    "Type":"CheckCharacterName"
}
{
    "CharacterName":"Bubblessss",
    "IsAvailable":true
}

The Change World window uses the information that was sent to the client when you click on Create New Account, so no additional information is exchanged if you select a different world.

When you click on Start Playing, the client will POST:
JSON:
{
    "CharacterName":"Sith Therwak",
    "CharacterSex":"male",
    "EMail":"[email protected]",
    "Password":"testpasswordQ!1",
    "ReCaptcha2Token":"03AAYGu2Ty9KLP0jM2TUqTigEmCRX7Nn07Kgh7u5ZF18I8lhDkHz8J32l2yiTCR87SGBM_uSrVCWl7b_dClGegTqhvrjbuOptk1DZ9Yydeq4Asn6Mrq2nXE5r6SjG7jx5-VZ3lElps5iCARWqXf7fnBHZFhu7D35ueihYCdf9ZbMtEHJ4pgT8Kqr_MPAmCfgEtjniDAfHgSpIK0PEoxkI07x_6F71gZoQfktp2X0vO04WCciWHB7Df3qmUeMkEig7RLvFBXN7je7yvAXwgzWJz1G7XN30UF3lJST_TKFY7VI5VdVoMBqu-tGS1LKv9ZFKHX24yplQ4UBIa_q_daNoPZQm81g4ubq64rxTnQj6_U-MnyOSyx2oUHx6mvR_7Uc6-sBNSC5N7_ISWt-w0yODSqjqx1BFxNZksRl6H45AupreKoW3BDKotIiYr57kgT5EG69ZRA67syoKbko58CIXtO6tOVIoOJV-xNqlqDTzSipeLqqaYzlf9g4ARqTe9JBY8IqATlGwZlORKlGUv72E8_r1mkYvEeXn6mI3RDpM90sDQzriaLinbZ8c",
    "ReCaptcha3Token":"",
    "SelectedWorld":"Marbera",
    "Type":"CreateAccountAndCharacter"
}
Presumably, if IsCaptchaDeactivated is true in the initial data sent to the client when creating a new account, a captcha token won't be generated by the client.

If the email is already being used then the server will let the client know:
JSON:
{
    "errorCode":2,
    "errorMessage":"This email address is already used. Please enter another email address!",
    "Success":false
}

For me there was an issue with ReCaptcha3, so the server requested ReCaptcha2:
JSON:
{
    "errorCode":101,
    "errorMessage":"An internal error has occurred. Please try again later!",
    "Success":false,
    "IsRecaptcha2Requested":true
}
The client then responded with the same information as above but with a ReCaptcha2Token instead of a ReCaptcha3Token.

If the information is valid and an account is created, the server responds with the account ID:
JSON:
{
    "Success":true,
    "AccountID":26679853
}

Once this is done the client will wait for the server to send the character list over of the loginWebService that is used to log in to an account.
 
I grabbed the data between the client and server in case someone like @Znote wants to add support for it.

The client uses https://www.tibia.com/clientservices/accountcreationclientservices.php for communicating this data. When you click on Create New Account the client POSTs:
JSON:
{
    "type":"getaccountcreationstatus"
}
and the server responds with a list of worlds, a recommended world, and whether captcha is activated:
JSON:
{
    "Worlds":[
        {
            "Name":"Adra",
             "PlayersOnline":30,
             "CreationDate":1601539200,
             "Region":"Europe",
             "PvPType":"Open PvP",
             "PremiumOnly":0,
             "TransferType":"Blocked",
             "BattlEyeActivationTimestamp":1603267200,
             "BattlEyeInitiallyActive":1
        },
        ...
        {
            "Name":"Zenobra",
             "PlayersOnline":111,
            "CreationDate":1588320000,
            "Region":"South America",
            "PvPType":"Open PvP",
            "PremiumOnly":0,
            "TransferType":"Blocked",
            "BattlEyeActivationTimestamp":1585299600,
            "BattlEyeInitiallyActive":1
        }
    ],
    "RecommendedWorld":"Marbera",
    "IsCaptchaDeactivated":false
}
The client will also request a suggested character name (it POSTs the same when you click the Suggest Name button):
JSON:
{
    "Type":"GenerateCharacterName"
}
and the server will respond with a generated name:
JSON:
{
    "GeneratedName":"Ironian Inup"
}
After you put your email in, the client will request the server to check if it is a valid email address (probably just a format check):
JSON:
{
    "Email":"[email protected]",
    "type":"CheckEMail"
}
and the server will tell the client if it passes or not:
JSON:
{
    "IsValid":true,
    "EMail":"[email protected]"
}
Here's the response for an invalid email:
JSON:
{
    "errorCode":59,
    "errorMessage":"This email address has an invalid format. Please enter a correct email address!",
    "EMail":"test@test"
}
Note that even if you haven't finished typing in your email, the client will send whatever you have typed if there is a short delay between the last keystroke.

Passwords follow the same process; the client will send it to the server for validation after a delay in keystrokes. Here's an example of an invalid password and the response, and a valid password and the response:
JSON:
POST invalid password:
{
    "Password1":"testpassword",
    "Type":"checkpassword"
}

Response:
{
    "PasswordRequirements":{
        "PasswordLength":true,
        "InvalidCharacters":true,
        "HasLowerCase":true,
        "HasUpperCase":false,
        "HasNumber":false
    },
    "Password1":"testpassword",
    "PasswordStrength":1,
    "PasswordStrengthColor":"#EC644B",
    "PasswordValid":false
}

POST valid password:
{
    "Password1":"testpasswordQ!1",
    "Type":"checkpassword"
}

Response:
{
    "PasswordRequirements":{
        "PasswordLength":true,
        "InvalidCharacters":true,
        "HasLowerCase":true,
        "HasUpperCase":true,
        "HasNumber":true
    },
    "Password1":"testpasswordQ!1",
    "PasswordStrength":3,
    "PasswordStrengthColor":"#b0b300",
    "PasswordValid":true
}
For the Repeat Password field, the client sends the exact same information for whatever is in the first password field but the client checks whether or not the two passwords match.

The Character Name field works the same way in that after a delay in keystrokes the client sends it to the server to check its validity:
JSON:
{
    "CharacterName":"Bubbles",
    "Type":"CheckCharacterName"
}
{
    "errorCode":54,
    "errorMessage":"This character name is already used. Please select another one!",
    "CharacterName":"Bubbles",
    "IsAvailable":false
}
...
{
    "CharacterName":"Bubbles234",
    "Type":"CheckCharacterName"
}
{
    "errorCode":99,
    "errorMessage":"This name contains invalid letters. Please use only A-Z, a-z and space.",
    "CharacterName":"Bubbles234",
    "IsAvailable":false
}
...
{
    "CharacterName":"Bubblessss",
    "Type":"CheckCharacterName"
}
{
    "CharacterName":"Bubblessss",
    "IsAvailable":true
}

The Change World window uses the information that was sent to the client when you click on Create New Account, so no additional information is exchanged if you select a different world.

When you click on Start Playing, the client will POST:
JSON:
{
    "CharacterName":"Sith Therwak",
    "CharacterSex":"male",
    "EMail":"[email protected]",
    "Password":"testpasswordQ!1",
    "ReCaptcha2Token":"03AAYGu2Ty9KLP0jM2TUqTigEmCRX7Nn07Kgh7u5ZF18I8lhDkHz8J32l2yiTCR87SGBM_uSrVCWl7b_dClGegTqhvrjbuOptk1DZ9Yydeq4Asn6Mrq2nXE5r6SjG7jx5-VZ3lElps5iCARWqXf7fnBHZFhu7D35ueihYCdf9ZbMtEHJ4pgT8Kqr_MPAmCfgEtjniDAfHgSpIK0PEoxkI07x_6F71gZoQfktp2X0vO04WCciWHB7Df3qmUeMkEig7RLvFBXN7je7yvAXwgzWJz1G7XN30UF3lJST_TKFY7VI5VdVoMBqu-tGS1LKv9ZFKHX24yplQ4UBIa_q_daNoPZQm81g4ubq64rxTnQj6_U-MnyOSyx2oUHx6mvR_7Uc6-sBNSC5N7_ISWt-w0yODSqjqx1BFxNZksRl6H45AupreKoW3BDKotIiYr57kgT5EG69ZRA67syoKbko58CIXtO6tOVIoOJV-xNqlqDTzSipeLqqaYzlf9g4ARqTe9JBY8IqATlGwZlORKlGUv72E8_r1mkYvEeXn6mI3RDpM90sDQzriaLinbZ8c",
    "ReCaptcha3Token":"",
    "SelectedWorld":"Marbera",
    "Type":"CreateAccountAndCharacter"
}
Presumably, if IsCaptchaDeactivated is true in the initial data sent to the client when creating a new account, a captcha token won't be generated by the client.

If the email is already being used then the server will let the client know:
JSON:
{
    "errorCode":2,
    "errorMessage":"This email address is already used. Please enter another email address!",
    "Success":false
}

For me there was an issue with ReCaptcha3, so the server requested ReCaptcha2:
JSON:
{
    "errorCode":101,
    "errorMessage":"An internal error has occurred. Please try again later!",
    "Success":false,
    "IsRecaptcha2Requested":true
}
The client then responded with the same information as above but with a ReCaptcha2Token instead of a ReCaptcha3Token.

If the information is valid and an account is created, the server responds with the account ID:
JSON:
{
    "Success":true,
    "AccountID":26679853
}

Once this is done the client will wait for the server to send the character list over of the loginWebService that is used to log in to an account.
Very useful, thank you <3
 
nowdays almost everygame includes character or account creating included ingame itself
See, that's the thing, almost no game has account creation in the client. Its simply impractical and waste of development time. In 99% of cases players create their account while downloading the client. Also often lots of functions on the web are blocked and require being logged in. How do you do that if you don't have the account yet and have to wait for the client to download first? But if you have the account creation on the website then what's the point of having one in the client? Character creation in the client makes 1000x more sense and should be a thing from the beginning. Not sure how it works here but can you create new char without the need to create new account at the same time? Looking at the screenshot it seems like you can't?
 
See, that's the thing, almost no game has account creation in the client. It’s simply impractical and waste of development time. In 99% of cases players create their account while downloading the client. Also often lots of functions on the web are blocked and require being logged in. How do you do that if you don't have the account yet and have to wait for the client to download first? But if you have the account creation on the website then what's the point of having one in the client? Character creation in the client makes 1000x more sense and should be a thing from the beginning. Not sure how it works here but can you create new char without the need to create new account at the same time? Looking at the screenshot it seems like you can't?
Correct. You can only create a new account and character at the same time; you can’t create a new character on an existing account.
 
If the information is valid and an account is created, the server responds with the account ID:
JSON:
{
    "Success":true,
    "AccountID":26679853
}

Once this is done the client will wait for the server to send the character list over of the loginWebService that is used to log in to an account.
Woah, it sends an AccountID to the client?

That is potentially very unsafe. monkaS

Why would the client ever need to know the AccountID? I'm so baffled.

The only thing the client should need is a sessionID, which is created by the server and sent back to the client on the first request from client to server.
The AccountID reference can be tied to the sessionID, but that should never be accessible / would never leave the server.

At least that's how it works in my game. lol
 
Woah, it sends an AccountID to the client?

That is potentially very unsafe. monkaS

Why would the client ever need to know the AccountID? I'm so baffled.

The only thing the client should need is a sessionID, which is created by the server and sent back to the client on the first request from client to server.
The AccountID reference can be tied to the sessionID, but that should never be accessible / would never leave the server.

At least that's how it works in my game. lol
No idea why they would send the account ID to the client, but apparently they don’t think knowing someone’s account ID is a big deal. When the friend system was introduced, I noticed that the server included the account ID for friends I had added (characters on other accounts I own that I knew the account number for): TibiaAPI/TibiaAPI/Network/ServerPackets/FriendSystemData.cs at master · jo3bingham/TibiaAPI (https://github.com/jo3bingham/TibiaAPI/blob/master/TibiaAPI/Network/ServerPackets/FriendSystemData.cs)

No clue if that’s still the case, though.
 
Woah, it sends an AccountID to the client?

That is potentially very unsafe. monkaS

Why would the client ever need to know the AccountID? I'm so baffled.

The only thing the client should need is a sessionID, which is created by the server and sent back to the client on the first request from client to server.
The AccountID reference can be tied to the sessionID, but that should never be accessible / would never leave the server.

At least that's how it works in my game. lol
What you gonna do with account id? You have no access to anything that would let you use that account id in any attack-ish way. You don't authenticate with it, nor use it anywhere, its purely internal value. All we know is that they auto increment the id probably xD
Anyway I don't know what they need that id for, cant find a reason too
 
Woah, it sends an AccountID to the client?
Why would the client ever need to know the AccountID? I'm so baffled.
Probably will be used on the future by external softwares, for now there is no reason for it
 
Woah, it sends an AccountID to the client?

That is potentially very unsafe. monkaS

Why would the client ever need to know the AccountID? I'm so baffled.

The only thing the client should need is a sessionID, which is created by the server and sent back to the client on the first request from client to server.
The AccountID reference can be tied to the sessionID, but that should never be accessible / would never leave the server.

At least that's how it works in my game. lol
What are you talking about? That's a very standard behaviour in any API, creation endpoints to return the entity id. You cannot do anything with the account id itself, login is email + password, and most of the in game actions are based on your email. This is super common for integrations for instance, where you use the returned entity id to perform other actions via the API. Not the case here, but I guess they chose to keep the standard.

Considering all the bad design choices they made in this new feature, returning the account id is almost nice. The fact that they do a different post request for every single validation and that they chose to use type field instead of using dedicated endpoints for different actions, same kind of shit they do in the login, those are freaking aberrations if you ask me.

In any case, I think it's a nice new feature.
 
Last edited:
I grabbed the data between the client and server in case someone like @Znote wants to add support for it.

The client uses https://www.tibia.com/clientservices/accountcreationclientservices.php for communicating this data. When you click on Create New Account the client POSTs:
JSON:
{
    "type":"getaccountcreationstatus"
}
and the server responds with a list of worlds, a recommended world, and whether captcha is activated:
JSON:
{
    "Worlds":[
        {
            "Name":"Adra",
             "PlayersOnline":30,
             "CreationDate":1601539200,
             "Region":"Europe",
             "PvPType":"Open PvP",
             "PremiumOnly":0,
             "TransferType":"Blocked",
             "BattlEyeActivationTimestamp":1603267200,
             "BattlEyeInitiallyActive":1
        },
        ...
        {
            "Name":"Zenobra",
             "PlayersOnline":111,
            "CreationDate":1588320000,
            "Region":"South America",
            "PvPType":"Open PvP",
            "PremiumOnly":0,
            "TransferType":"Blocked",
            "BattlEyeActivationTimestamp":1585299600,
            "BattlEyeInitiallyActive":1
        }
    ],
    "RecommendedWorld":"Marbera",
    "IsCaptchaDeactivated":false
}
The client will also request a suggested character name (it POSTs the same when you click the Suggest Name button):
JSON:
{
    "Type":"GenerateCharacterName"
}
and the server will respond with a generated name:
JSON:
{
    "GeneratedName":"Ironian Inup"
}
After you put your email in, the client will request the server to check if it is a valid email address (probably just a format check):
JSON:
{
    "Email":"[email protected]",
    "type":"CheckEMail"
}
and the server will tell the client if it passes or not:
JSON:
{
    "IsValid":true,
    "EMail":"[email protected]"
}
Here's the response for an invalid email:
JSON:
{
    "errorCode":59,
    "errorMessage":"This email address has an invalid format. Please enter a correct email address!",
    "EMail":"test@test"
}
Note that even if you haven't finished typing in your email, the client will send whatever you have typed if there is a short delay between the last keystroke.

Passwords follow the same process; the client will send it to the server for validation after a delay in keystrokes. Here's an example of an invalid password and the response, and a valid password and the response:
JSON:
POST invalid password:
{
    "Password1":"testpassword",
    "Type":"checkpassword"
}

Response:
{
    "PasswordRequirements":{
        "PasswordLength":true,
        "InvalidCharacters":true,
        "HasLowerCase":true,
        "HasUpperCase":false,
        "HasNumber":false
    },
    "Password1":"testpassword",
    "PasswordStrength":1,
    "PasswordStrengthColor":"#EC644B",
    "PasswordValid":false
}

POST valid password:
{
    "Password1":"testpasswordQ!1",
    "Type":"checkpassword"
}

Response:
{
    "PasswordRequirements":{
        "PasswordLength":true,
        "InvalidCharacters":true,
        "HasLowerCase":true,
        "HasUpperCase":true,
        "HasNumber":true
    },
    "Password1":"testpasswordQ!1",
    "PasswordStrength":3,
    "PasswordStrengthColor":"#b0b300",
    "PasswordValid":true
}
For the Repeat Password field, the client sends the exact same information for whatever is in the first password field but the client checks whether or not the two passwords match.

The Character Name field works the same way in that after a delay in keystrokes the client sends it to the server to check its validity:
JSON:
{
    "CharacterName":"Bubbles",
    "Type":"CheckCharacterName"
}
{
    "errorCode":54,
    "errorMessage":"This character name is already used. Please select another one!",
    "CharacterName":"Bubbles",
    "IsAvailable":false
}
...
{
    "CharacterName":"Bubbles234",
    "Type":"CheckCharacterName"
}
{
    "errorCode":99,
    "errorMessage":"This name contains invalid letters. Please use only A-Z, a-z and space.",
    "CharacterName":"Bubbles234",
    "IsAvailable":false
}
...
{
    "CharacterName":"Bubblessss",
    "Type":"CheckCharacterName"
}
{
    "CharacterName":"Bubblessss",
    "IsAvailable":true
}

The Change World window uses the information that was sent to the client when you click on Create New Account, so no additional information is exchanged if you select a different world.

When you click on Start Playing, the client will POST:
JSON:
{
    "CharacterName":"Sith Therwak",
    "CharacterSex":"male",
    "EMail":"[email protected]",
    "Password":"testpasswordQ!1",
    "ReCaptcha2Token":"03AAYGu2Ty9KLP0jM2TUqTigEmCRX7Nn07Kgh7u5ZF18I8lhDkHz8J32l2yiTCR87SGBM_uSrVCWl7b_dClGegTqhvrjbuOptk1DZ9Yydeq4Asn6Mrq2nXE5r6SjG7jx5-VZ3lElps5iCARWqXf7fnBHZFhu7D35ueihYCdf9ZbMtEHJ4pgT8Kqr_MPAmCfgEtjniDAfHgSpIK0PEoxkI07x_6F71gZoQfktp2X0vO04WCciWHB7Df3qmUeMkEig7RLvFBXN7je7yvAXwgzWJz1G7XN30UF3lJST_TKFY7VI5VdVoMBqu-tGS1LKv9ZFKHX24yplQ4UBIa_q_daNoPZQm81g4ubq64rxTnQj6_U-MnyOSyx2oUHx6mvR_7Uc6-sBNSC5N7_ISWt-w0yODSqjqx1BFxNZksRl6H45AupreKoW3BDKotIiYr57kgT5EG69ZRA67syoKbko58CIXtO6tOVIoOJV-xNqlqDTzSipeLqqaYzlf9g4ARqTe9JBY8IqATlGwZlORKlGUv72E8_r1mkYvEeXn6mI3RDpM90sDQzriaLinbZ8c",
    "ReCaptcha3Token":"",
    "SelectedWorld":"Marbera",
    "Type":"CreateAccountAndCharacter"
}
Presumably, if IsCaptchaDeactivated is true in the initial data sent to the client when creating a new account, a captcha token won't be generated by the client.

If the email is already being used then the server will let the client know:
JSON:
{
    "errorCode":2,
    "errorMessage":"This email address is already used. Please enter another email address!",
    "Success":false
}

For me there was an issue with ReCaptcha3, so the server requested ReCaptcha2:
JSON:
{
    "errorCode":101,
    "errorMessage":"An internal error has occurred. Please try again later!",
    "Success":false,
    "IsRecaptcha2Requested":true
}
The client then responded with the same information as above but with a ReCaptcha2Token instead of a ReCaptcha3Token.

If the information is valid and an account is created, the server responds with the account ID:
JSON:
{
    "Success":true,
    "AccountID":26679853
}

Once this is done the client will wait for the server to send the character list over of the loginWebService that is used to log in to an account.
Absolutely amazing! Thank you for that!!
 
Hello guys, could you post how the PHP file of the json call to the web server for the creation of accounts would look? Because I don't know how it works, if it is an external database or another parameter, but I don't see how it works. connection to the database where the accounts are.
 
Woah, it sends an AccountID to the client?

That is potentially very unsafe.
you don't even have to include this
once you send success = true, the client acts as if you were inputting email and password manually to fetch character list

also it supports both v2 and v3 captcha
 
I grabbed the data between the client and server in case someone like @Znote wants to add support for it.

The client uses https://www.tibia.com/clientservices/accountcreationclientservices.php for communicating this data. When you click on Create New Account the client POSTs:
JSON:
{
    "type":"getaccountcreationstatus"
}
and the server responds with a list of worlds, a recommended world, and whether captcha is activated:
JSON:
{
    "Worlds":[
        {
            "Name":"Adra",
             "PlayersOnline":30,
             "CreationDate":1601539200,
             "Region":"Europe",
             "PvPType":"Open PvP",
             "PremiumOnly":0,
             "TransferType":"Blocked",
             "BattlEyeActivationTimestamp":1603267200,
             "BattlEyeInitiallyActive":1
        },
        ...
        {
            "Name":"Zenobra",
             "PlayersOnline":111,
            "CreationDate":1588320000,
            "Region":"South America",
            "PvPType":"Open PvP",
            "PremiumOnly":0,
            "TransferType":"Blocked",
            "BattlEyeActivationTimestamp":1585299600,
            "BattlEyeInitiallyActive":1
        }
    ],
    "RecommendedWorld":"Marbera",
    "IsCaptchaDeactivated":false
}
The client will also request a suggested character name (it POSTs the same when you click the Suggest Name button):
JSON:
{
    "Type":"GenerateCharacterName"
}
and the server will respond with a generated name:
JSON:
{
    "GeneratedName":"Ironian Inup"
}
After you put your email in, the client will request the server to check if it is a valid email address (probably just a format check):
JSON:
{
    "Email":"[email protected]",
    "type":"CheckEMail"
}
and the server will tell the client if it passes or not:
JSON:
{
    "IsValid":true,
    "EMail":"[email protected]"
}
Here's the response for an invalid email:
JSON:
{
    "errorCode":59,
    "errorMessage":"This email address has an invalid format. Please enter a correct email address!",
    "EMail":"test@test"
}
Note that even if you haven't finished typing in your email, the client will send whatever you have typed if there is a short delay between the last keystroke.

Passwords follow the same process; the client will send it to the server for validation after a delay in keystrokes. Here's an example of an invalid password and the response, and a valid password and the response:
JSON:
POST invalid password:
{
    "Password1":"testpassword",
    "Type":"checkpassword"
}

Response:
{
    "PasswordRequirements":{
        "PasswordLength":true,
        "InvalidCharacters":true,
        "HasLowerCase":true,
        "HasUpperCase":false,
        "HasNumber":false
    },
    "Password1":"testpassword",
    "PasswordStrength":1,
    "PasswordStrengthColor":"#EC644B",
    "PasswordValid":false
}

POST valid password:
{
    "Password1":"testpasswordQ!1",
    "Type":"checkpassword"
}

Response:
{
    "PasswordRequirements":{
        "PasswordLength":true,
        "InvalidCharacters":true,
        "HasLowerCase":true,
        "HasUpperCase":true,
        "HasNumber":true
    },
    "Password1":"testpasswordQ!1",
    "PasswordStrength":3,
    "PasswordStrengthColor":"#b0b300",
    "PasswordValid":true
}
For the Repeat Password field, the client sends the exact same information for whatever is in the first password field but the client checks whether or not the two passwords match.

The Character Name field works the same way in that after a delay in keystrokes the client sends it to the server to check its validity:
JSON:
{
    "CharacterName":"Bubbles",
    "Type":"CheckCharacterName"
}
{
    "errorCode":54,
    "errorMessage":"This character name is already used. Please select another one!",
    "CharacterName":"Bubbles",
    "IsAvailable":false
}
...
{
    "CharacterName":"Bubbles234",
    "Type":"CheckCharacterName"
}
{
    "errorCode":99,
    "errorMessage":"This name contains invalid letters. Please use only A-Z, a-z and space.",
    "CharacterName":"Bubbles234",
    "IsAvailable":false
}
...
{
    "CharacterName":"Bubblessss",
    "Type":"CheckCharacterName"
}
{
    "CharacterName":"Bubblessss",
    "IsAvailable":true
}

The Change World window uses the information that was sent to the client when you click on Create New Account, so no additional information is exchanged if you select a different world.

When you click on Start Playing, the client will POST:
JSON:
{
    "CharacterName":"Sith Therwak",
    "CharacterSex":"male",
    "EMail":"[email protected]",
    "Password":"testpasswordQ!1",
    "ReCaptcha2Token":"03AAYGu2Ty9KLP0jM2TUqTigEmCRX7Nn07Kgh7u5ZF18I8lhDkHz8J32l2yiTCR87SGBM_uSrVCWl7b_dClGegTqhvrjbuOptk1DZ9Yydeq4Asn6Mrq2nXE5r6SjG7jx5-VZ3lElps5iCARWqXf7fnBHZFhu7D35ueihYCdf9ZbMtEHJ4pgT8Kqr_MPAmCfgEtjniDAfHgSpIK0PEoxkI07x_6F71gZoQfktp2X0vO04WCciWHB7Df3qmUeMkEig7RLvFBXN7je7yvAXwgzWJz1G7XN30UF3lJST_TKFY7VI5VdVoMBqu-tGS1LKv9ZFKHX24yplQ4UBIa_q_daNoPZQm81g4ubq64rxTnQj6_U-MnyOSyx2oUHx6mvR_7Uc6-sBNSC5N7_ISWt-w0yODSqjqx1BFxNZksRl6H45AupreKoW3BDKotIiYr57kgT5EG69ZRA67syoKbko58CIXtO6tOVIoOJV-xNqlqDTzSipeLqqaYzlf9g4ARqTe9JBY8IqATlGwZlORKlGUv72E8_r1mkYvEeXn6mI3RDpM90sDQzriaLinbZ8c",
    "ReCaptcha3Token":"",
    "SelectedWorld":"Marbera",
    "Type":"CreateAccountAndCharacter"
}
Presumably, if IsCaptchaDeactivated is true in the initial data sent to the client when creating a new account, a captcha token won't be generated by the client.

If the email is already being used then the server will let the client know:
JSON:
{
    "errorCode":2,
    "errorMessage":"This email address is already used. Please enter another email address!",
    "Success":false
}

For me there was an issue with ReCaptcha3, so the server requested ReCaptcha2:
JSON:
{
    "errorCode":101,
    "errorMessage":"An internal error has occurred. Please try again later!",
    "Success":false,
    "IsRecaptcha2Requested":true
}
The client then responded with the same information as above but with a ReCaptcha2Token instead of a ReCaptcha3Token.

If the information is valid and an account is created, the server responds with the account ID:
JSON:
{
    "Success":true,
    "AccountID":26679853
}

Once this is done the client will wait for the server to send the character list over of the loginWebService that is used to log in to an account.
What is the PHP file that needs to be put in so that this account creation thing can work? or how does this thing you mentioned work?
 
Back
Top