fivem.wtf ← shop

Castle API

Register Rockstar accounts programmatically. Pay per call, no subscription.

Authentication

Every request needs your API key in a header.

X-API-Key: ck_YOURAPIKEY

Get a key on account.fivem.wtf.

RegisterPOST /register

Runs Castle plus POST /api/registration/rsg and returns the mfaToken.

POSThttps://api.fivem.wtf/register
paramtyperequireddescription
emailstringyesOutlook/Hotmail address that receives the PIN
nicknamestringyes4-16 chars, no profanity
passwordstringyes1 upper + lowers + digits + special, 8+ chars
dobstringnoISO 8601, e.g. 2001-02-15T00:00:00.000Z
countrystringno2-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).

Create AccountPOST /create-account

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.

POSThttps://api.fivem.wtf/create-account
paramtyperequireddescription
emailstringyesThe Outlook/Hotmail address to register with
refresh_tokenstringyesMicrosoft Graph refresh_token for that inbox
client_idstringyesMicrosoft Graph app client_id paired with refresh_token
nicknamestringno4-16 chars, no profanity — generated if omitted
passwordstringnoRockstar account password — generated if omitted
dobstringnoISO 8601 — random 19-45y if omitted
countrystringno2-letter code, default FR
enable_2faboolnoAlso activate TOTP 2FA and return the secret. Default false, only charged on success.
codestringnoVoucher 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.

Claim CodePOST /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).

POSThttps://api.fivem.wtf/claim-code
paramtyperequireddescription
emailstringyesRockstar account email
passwordstringyesRockstar account password
codestringyesThe voucher code to redeem
totp_secretstringsee aboveAccount's TOTP secret, if it has authenticator 2FA
refresh_tokenstringsee aboveMicrosoft Graph refresh_token for the account's inbox
client_idstringsee aboveMicrosoft 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:

outcomechargedmeaning
SUCCESSyesCode redeemed on the account.
ALREADY_REDEEMEDyesWe logged in; the code had already been used.
INVALID_CODEyesWe logged in; the code doesn't exist.
ALREADY_OWNEDyesWe logged in; the account already owns what the code grants. The code was not consumed — use it on another account.
LOGIN_FAILEDnoWrong password, account locked, no matching verification method, or the verification code was rejected.
EMAIL_FAILnoBad refresh_token/client_id, or no verification code arrived in the inbox.
BLOCKEDnoOur side got blocked on the login. Retry.
ERRORnoSomething broke on our side. Retry.

Gen TokenPOST /gen-token

Cheap Castle token for the downstream endpoints (emailMfa, accountchallenge, accountverify). Won't pass /register.

POSThttps://api.fivem.wtf/gen-token

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>

BalanceGET /balance

GEThttps://api.fivem.wtf/balance
{
  "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).

Errors

HTTPDetailNotes
401missing / unknown X-API-KeyCheck the header
402insufficient balanceTop up
403API key disabledContact us
409email already used, or retried too soonOn /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.
422missing auth materialOn /claim-code only. Send either totp_secret, or both refresh_token and client_id. No charge.
429rate limited, too many blocked castles in a rowOn /register, /create-account and /claim-code. 20 blocked castles back to back locks the key for 15 min. Wait it out, no charge.
503server busy, retryPremium concurrency cap (/register, /create-account, /claim-code). Retry, no charge.
Questions? Discord
Get an API key · Shop