Every request needs your API key in a header.
X-API-Key: ck_YOURAPIKEY
Get a key on account.fivem.wtf.
Runs Castle plus POST /api/registration/rsg and returns the mfaToken.
| param | type | required | description |
|---|---|---|---|
email | string | yes | Outlook/Hotmail address that receives the PIN |
nickname | string | yes | 4-16 chars, no profanity |
password | string | yes | 1 upper + lowers + digits + special, 8+ chars |
dob | string | no | ISO 8601, e.g. 2001-02-15T00:00:00.000Z |
country | string | no | 2-letter code, default FR |
const res = await fetch('https://api.fivem.wtf/register', {
method: 'POST',
headers: {
'X-API-Key': 'ck_YOURAPIKEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'john.doe123@hotmail.com',
nickname: 'swiftFox1234',
password: 'Abc123!def',
}),
});
const { mfaToken } = await res.json();
console.log('mfaToken:', mfaToken);
import requests
resp = requests.post(
'https://api.fivem.wtf/register',
headers={'X-API-Key': 'ck_YOURAPIKEY'},
json={
'email': 'john.doe123@hotmail.com',
'nickname': 'swiftFox1234',
'password': 'Abc123!def',
},
timeout=180,
)
print(resp.json()['mfaToken'])
Success response:
{
"outcome": "SUCCESS",
"charged": true,
"charged_eur": 0.02,
"balance_eur": 12.457,
"mfaToken": "eyJhbGciOiJIUzI1NiIs...",
"elapsedMs": 4218
}
outcome can also be INPUT_ERROR (charged, see fieldErrors), BLOCKED or ERROR (both refunded, charged: false).
Does the whole thing server-side: register + email verification. Give it an Outlook combo, get back a fully activated Rockstar account. No need to call /register, /gen-token, or handle the email PIN yourself.
Billed only on full success — if the account gets created but the email verification step fails for any reason, you're refunded in full. You either get a working account or you don't pay.
Pass enable_2fa: true to also activate TOTP 2FA right after creation — the response includes the TOTP secret. Billed independently: if the account is created but 2FA fails, only the add-on is refunded, you still get the account.
Pass code to also redeem a voucher code on the account as soon as it's created. No need to call /claim-code afterwards — the fresh account is already a live session, so there's no second login and it's cheaper (€0.0025 instead of €0.0075). Billed like the 2FA add-on: only if the code is actually redeemed. A dead, invalid or already-owned code refunds just the add-on, and you still get the account.
Both add-ons are independent — one failing never affects the other or the account itself.
| param | type | required | description |
|---|---|---|---|
email | string | yes | The Outlook/Hotmail address to register with |
refresh_token | string | yes | Microsoft Graph refresh_token for that inbox |
client_id | string | yes | Microsoft Graph app client_id paired with refresh_token |
nickname | string | no | 4-16 chars, no profanity — generated if omitted |
password | string | no | Rockstar account password — generated if omitted |
dob | string | no | ISO 8601 — random 19-45y if omitted |
country | string | no | 2-letter code, default FR |
enable_2fa | bool | no | Also activate TOTP 2FA and return the secret. Default false, only charged on success. |
code | string | no | Voucher code to redeem on the new account. Only charged if it actually gets redeemed. |
const res = await fetch('https://api.fivem.wtf/create-account', {
method: 'POST',
headers: {
'X-API-Key': 'ck_YOURAPIKEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'john.doe123@hotmail.com',
refresh_token: 'M.C1234...',
client_id: '9e5f94bc-e8a4-4e73-b8be-63364c29d753',
enable_2fa: true,
code: 'ABCD-EFGH-IJKL-MNOP',
}),
});
const data = await res.json();
console.log(data.account, data.claimRedeemed);
import requests
resp = requests.post(
'https://api.fivem.wtf/create-account',
headers={'X-API-Key': 'ck_YOURAPIKEY'},
json={
'email': 'john.doe123@hotmail.com',
'refresh_token': 'M.C1234...',
'client_id': '9e5f94bc-e8a4-4e73-b8be-63364c29d753',
'enable_2fa': True,
'code': 'ABCD-EFGH-IJKL-MNOP',
},
timeout=180,
)
print(resp.json()['account'])
Success response:
{
"outcome": "SUCCESS",
"stage": "emailMfa",
"charged": true,
"charged_eur": 0.015,
"balance_eur": 12.447,
"twofaRequested": true,
"twofaEnabled": true,
"claimRequested": true,
"claimRedeemed": true,
"claimOutcome": "SUCCESS",
"claimDetail": "",
"code": "ABCD-EFGH-IJKL-MNOP",
"account": {
"email": "john.doe123@hotmail.com",
"password": "Bcd456!efg",
"nickname": "swiftFox1234",
"dob": "1998-04-11T00:00:00.000Z",
"country": "FR",
"mfaToken": "eyJhbGciOiJIUzI1NiIs...",
"castleToken": "AQA...long-castle-payload...AAA",
"totpSecret": "JBSWY3DPEHPK3PXP"
},
"elapsedMs": 28417
}
totpSecret only appears when twofaEnabled is true. Without enable_2fa, charged_eur is just the base price.
Failure response:
{
"outcome": "EMAIL_FAIL",
"stage": "graph",
"charged": false,
"charged_eur": 0.0,
"balance_eur": 12.457,
"detail": "invalid refresh_token or client_id",
"elapsedMs": 1636
}
outcome is SUCCESS (charged, account present) or one of the refunded outcomes: BLOCKED / INPUT_ERROR (the register step itself failed — stage: "register") or EMAIL_FAIL (register passed but email verification didn't — stage is graph, challenge, verify, or emailMfa). If enable_2fa was set but 2FA fails, outcome is still SUCCESS — just twofaEnabled: false, no TOTP fields, base price only.
Same for code: outcome stays SUCCESS and you still get the account. claimRedeemed tells you whether the code went through, and claimOutcome says why it didn't — ALREADY_REDEEMED, INVALID_CODE, ALREADY_OWNED (the account already owns what the code grants; the code was not consumed, use it elsewhere) or ERROR. Anything other than SUCCESS refunds the add-on. claimDetail carries the same plain-English explanation as /claim-code.
Redeems a voucher code on an existing Rockstar account. We log into the account for you — including the verification step — and consume the code. You just send the account and the code.
Creating the account with us anyway? Pass code to /create-account instead — no login needed there, so it's €0.0025 rather than €0.0075. This endpoint is for accounts you already have.
The login has to pass the account's verification step, so send one of: totp_secret (if the account has authenticator 2FA — fastest, no inbox needed), or refresh_token + client_id (Microsoft Graph creds for the account's inbox, so we can read the emailed code).
| param | type | required | description |
|---|---|---|---|
email | string | yes | Rockstar account email |
password | string | yes | Rockstar account password |
code | string | yes | The voucher code to redeem |
totp_secret | string | see above | Account's TOTP secret, if it has authenticator 2FA |
refresh_token | string | see above | Microsoft Graph refresh_token for the account's inbox |
client_id | string | see above | Microsoft Graph app client_id paired with refresh_token |
const res = await fetch('https://api.fivem.wtf/claim-code', {
method: 'POST',
headers: {
'X-API-Key': 'ck_YOURAPIKEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'john.doe123@hotmail.com',
password: 'Abc123!def',
code: 'ABCD-EFGH-IJKL-MNOP',
totp_secret: 'JBSWY3DPEHPK3PXP',
}),
});
const data = await res.json();
console.log(data.outcome);
import requests
resp = requests.post(
'https://api.fivem.wtf/claim-code',
headers={'X-API-Key': 'ck_YOURAPIKEY'},
json={
'email': 'john.doe123@hotmail.com',
'password': 'Abc123!def',
'code': 'ABCD-EFGH-IJKL-MNOP',
# or: 'refresh_token': 'M.C1234...', 'client_id': '9e5f94bc-...'
'totp_secret': 'JBSWY3DPEHPK3PXP',
},
timeout=180,
)
print(resp.json()['outcome'])
Success response:
{
"outcome": "SUCCESS",
"charged": true,
"charged_eur": 0.0075,
"balance_eur": 12.44,
"email": "john.doe123@hotmail.com",
"code": "ABCD-EFGH-IJKL-MNOP",
"detail": "",
"elapsedMs": 24118
}
Failure response:
{
"outcome": "ALREADY_REDEEMED",
"charged": true,
"charged_eur": 0.0075,
"balance_eur": 12.44,
"email": "john.doe123@hotmail.com",
"code": "ABCD-EFGH-IJKL-MNOP",
"detail": "this code has already been redeemed",
"elapsedMs": 21903
}
detail is a short plain-English explanation of the outcome. It's empty on SUCCESS (nothing to explain) and filled on every other outcome — read it first when something didn't go the way you expected.
Outcomes:
| outcome | charged | meaning |
|---|---|---|
SUCCESS | yes | Code redeemed on the account. |
ALREADY_REDEEMED | yes | We logged in; the code had already been used. |
INVALID_CODE | yes | We logged in; the code doesn't exist. |
ALREADY_OWNED | yes | We logged in; the account already owns what the code grants. The code was not consumed — use it on another account. |
LOGIN_FAILED | no | Wrong password, account locked, no matching verification method, or the verification code was rejected. |
EMAIL_FAIL | no | Bad refresh_token/client_id, or no verification code arrived in the inbox. |
BLOCKED | no | Our side got blocked on the login. Retry. |
ERROR | no | Something broke on our side. Retry. |
Cheap Castle token for the downstream endpoints (emailMfa, accountchallenge, accountverify). Won't pass /register.
No body.
const res = await fetch('https://api.fivem.wtf/gen-token', {
method: 'POST',
headers: { 'X-API-Key': 'ck_YOURAPIKEY' },
});
const { token, ua } = await res.json();
console.log('token:', token, 'ua:', ua);
import requests
resp = requests.post(
'https://api.fivem.wtf/gen-token',
headers={'X-API-Key': 'ck_YOURAPIKEY'},
timeout=60,
)
data = resp.json()
print(data['token'], data['ua'])
Success response:
{
"outcome": "SUCCESS",
"charged": true,
"charged_eur": 0.003,
"balance_eur": 12.454,
"token": "AQA...long-castle-payload...AAA",
"ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/146.0.0.0 ...",
"elapsedMs": 87
}
Pair token with ua on the downstream request:
User-Agent: <ua>
x-castle-request-token: <token>
{
"key": "ck_...",
"balance_eur": 12.477,
"total_requests": 428,
"premium_requests": 63
}
total_requests counts every call (register + gen-token, any outcome). premium_requests only counts /register calls that actually went through (blocked ones get refunded and don't count).
| HTTP | Detail | Notes |
|---|---|---|
| 401 | missing / unknown X-API-Key | Check the header |
| 402 | insufficient balance | Top up |
| 403 | API key disabled | Contact us |
| 409 | email already used, or retried too soon | On /create-account only. Either this email already has a successfully created account (permanent — try a different email), or it failed recently and is still in its retry cooldown (retry in Xs in the detail). No charge, no real attempt sent to Rockstar either way. |
| 422 | missing auth material | On /claim-code only. Send either totp_secret, or both refresh_token and client_id. No charge. |
| 429 | rate limited, too many blocked castles in a row | On /register, /create-account and /claim-code. 20 blocked castles back to back locks the key for 15 min. Wait it out, no charge. |
| 503 | server busy, retry | Premium concurrency cap (/register, /create-account, /claim-code). Retry, no charge. |