Mojang API

From wiki.vg
Revision as of 11:05, 30 May 2016 by Serializator (talk | contribs) (Updated the list of blocked servers.)
Jump to navigation Jump to search

Notes

  • All public APIs are rate limited so you are expected to cache the results. This is currently set at 600 requests per 10 minutes but this may change.
  • For some parts of the API, demo accounts are sometimes included, sometimes not. Mojang keeps changing this.

API Status

 GET https://status.mojang.com/check

Returns status of various Mojang services. Possible values are green (no issues), yellow (some issues), red (service unavailable).

Response

[
  {
    "minecraft.net": "yellow"
  },
  {
    "session.minecraft.net": "green"
  },
  {
    "account.mojang.com": "green"
  },
  {
    "auth.mojang.com": "green"
  },
  {
    "skins.minecraft.net": "green"
  },
  {
    "authserver.mojang.com": "green"
  },
  {
    "sessionserver.mojang.com": "yellow"
  },
  {
    "api.mojang.com": "green"
  },
  {
    "textures.minecraft.net": "red"
  }
]

Username -> UUID at time

 GET https://api.mojang.com/users/profiles/minecraft/<username>?at=<timestamp>

This will return the uuid of the name at the timestamp provided.

?at=0 can be used to get the UUID of the original user of that username, however it only works if the name was changed at least once, or if the account is legacy.

  • The timestamp is a UNIX timestamp (without milliseconds)
  • When the at parameter is not sent, the current time is used

Response

{
  "id": "7125ba8b1c864508b92bb5c042ccfe2b",
  "name": "KrisJelbring"
}
  • name is the current name of that uuid, it is not the name requested!
  • legacy only appears when true (not migrated to mojang account)
  • demo only appears when true (account unpaid)

If there is no player with the given username an HTTP status code 204 (No Content) is sent without any HTTP body.
If the timestamp is not a number, too big or too small the HTTP status code 400 (Bad Request) is sent with an error message looking like this:

{
  "error": "IllegalArgumentException",
  "errorMessage": "Invalid timestamp."
}

UUID -> Name history

  https://api.mojang.com/user/profiles/<uuid>/names

Returns all the usernames this user has used in the past and the one they are using currently. The UUID must be given without hyphens.

Response

[
  {
    "name": "Gold"
  },
  {
    "name": "Diamond",
    "changedToAt": 1414059749000
  }
]

The changedToAt field is a Java timestamp in milliseconds.

Playernames -> UUIDs

 POST https://api.mojang.com/profiles/minecraft

Where 'minecraft' - agent name

This will return player UUIDS and some extras.

Payload

[
    "maksimkurb",
    "nonExistingPlayer" //Test for non-existing player
]

Response

[
    {
        "id": "0d252b7218b648bfb86c2ae476954d32",
        "name": "maksimkurb",
        "legacy": true,
        "demo": true
    }
]
  • name is case-corrected
  • legacy only appears when true (profile not migrated to mojang.com)
  • demo only appears when true (account unpaid)
  • IllegalArgumentException is returned when any of the usernames is null or ""
  • The Content-Type HTTP header must be application/json
  • You cannot request more than 100 names per request

UUID -> Profile + Skin/Cape

 https://sessionserver.mojang.com/session/minecraft/profile/<uuid>

This will return the player's username plus any additional information about them (e.g. skins). Example: https://sessionserver.mojang.com/session/minecraft/profile/4566e69fc90748ee8d71d7ba5aa00d20

This has a much stricter rate limit: You can request the same profile once per minute, however you can send as many unique requests as you like.

Response

{
    "id": "<profile identifier>",
    "name": "<player name>",
    "properties": [ 
        {
            "name": "textures",
            "value": "<base64 string>",
            "signature": "<base64 string; signed data using Yggdrasil's private key>" // Only provided if ?unsigned=false is appended to url
        }
    ]
}

The "value" base64 string for the "textures" object decoded:

{
    "timestamp": "<java time in ms>",
    "profileId": "<profile uuid>",
    "profileName": "<player name>",
    "isPublic": "<true or false>",
    "textures": {
        "SKIN": {
            "url": "<player skin URL>"
        },
        "CAPE": {
            "url": "<player cape URL>"
        }
    }
}
  • The timestamp is sometimes in the past (probably due to cached results?)
  • The "SKIN" object will have "metadata": {"model": "slim"} if the player model has slim arms (“Alex?” style). For square arms (“Steve?” style), "metadata" will be missing.
  • If no custom skin has been set, "SKIN" will be missing.
    Whether the player has the “Alex?” or “Steve?” skin depends on the Java hashCode of their UUID. Steve is used for even hashes. Example implementations:
  • Likewise "CAPE" will be missing if the account has no cape.

Change Skin

  POST https://api.mojang.com/user/profile/<uuid>/skin

This will set the skin for the selected profile, but Mojang's servers will fetch the skin from a URL. This will also work for legacy accounts.

Response

Upon error the server will send back a JSON with the error. (Success is a blank payload)

Headers

Authorization: Bearer <access token>

Payload

The payload for this API consists of two url-encoded form fields (conjoined by '&').

model=<alex/steve>&url=<skin url>

Example

curl -H "Authorization: Bearer <access token>" --data-urlencode "model=steve" --data-urlencode "url=http://assets.mojang.com/SkinTemplates/steve.png" https://api.mojang.com/user/profile/<uuid>/skin
POST /user/profile/<uuid>/skin HTTP/1.1
Host: api.mojang.com
User-Agent: curl/7.49.0
Accept: */*
Authorization: Bearer <access token>
Content-Length: <74>
Content-Type: application/x-www-form-urlencoded
model=steve&url=http%3A%2F%2Fassets.mojang.com%2FSkinTemplate%2Fsteve.png

Upload Skin

  PUT https://api.mojang.com/user/profile/<uuid>/skin

This uploads a skin to Mojang's servers. It also sets the users skin. This works on legacy counts as well.

Response

No response unless error

Headers

Authorization: Bearer <access token>

Payload

The payload for this API consists of multipart form data. There are two parts (order does not matter b/c of boundary):

model=<steve/alex>
file=<raw file>

Example

curl -X PUT -H "Authorization: Bearer <access token>" -F model=steve -F file=@steve.png https://api.mojang.com/user/profile/<uuid>/skin
PUT /user/profile/<uuid>/skin HTTP/1.1
Host: api.mojang.com
User-Agent: curl/7.49.0
Accept: */*
Authorization: Bearer <access token>
Content-Length: <length>
Content-Type: multipart/form-data; boundary=<boundary>
<boundary>


Content-Disposition: form-data; name="model"

steve
<boundary>
Content-Disposition: form-data; name="file"; filename="steve.png"
Content-Type=application/octet-stream

<image data>
<boundary>

User Info

  GET https://api.mojang.com/user

Returns information on the logged in Mojang account.

Response

{
    "id": "<Account Identifier?>",
    "email": "<Email attached to account>",
    "username": "<Username of account, with migrated accounts this is the same as email>",
    "registerIp": "<IP used to register account>",
    "registeredAt": <Epoch timestamp in ms of date the Mojang account was registered>,
    "passwordChangedAt": <Epoch timestamp of time password was last changed>,
    "dateOfBirth":  <Epoch timestamp of date of birth for this Mojang Account>,
    "deleted": <Unknown, probably whether account has been deleted or not>,
    "blocked": <Unknown, probably whether account has been blocked or not>,
    "secured": <Whether security questions are enabled on this Mojang Account>,
    "migrated": <Whether the account has been migrated, if the account was made after Mojang Accounts were mandatory for new accounts this is set to false>,
    "emailVerified": <Whether the email attached to the account is verified>,
    "legacyUser": <Whether the account is a legacy user?>,
    "verifiedByParent": <Whether the account has been verified by parent, is set to false if no parent verification was needed>,
    "fullName": "<Full name attached to Mojang account, can be an empty string>",
    "fromMigratedUser": <Not sure, probably related to migrated?>,
    "hashed": <Unsure, seems to be set to false?>
}

Headers

Authorization: Bearer <access token>

Blocked Servers

  GET https://sessionserver.mojang.com/blockedservers

Returns a list of SHA1 hashes used to check server addresses against when the client tries to connect.

Clients check the lowercase name, using the ISO-8859-1 charset, against this list. They will also attempt to check subdomains, replacing each level with a *. Specifically, it splits based off of the . in the domain, goes through each section removing one at a time. For instance, for mc.example.com, it would try mc.example.com, *.example.com, and *.com. With IP addresses (verified by having 4 split sections, with each section being a valid integer between 0 and 255, inclusive) substitution starts from the end, so for 192.168.0.1, it would try 192.168.0.1, 192.168.0.*, 192.168.*, and 192.*.

This check is done by the bootstrap class in netty. The default netty class is overridden by one in the com.mojang:netty dependency loaded by the launcher. This allows it to affect any version that used netty (1.7+)

Response

6f2520f8bd70a718c568ab5274c56bdbbfc14ef4
b13009db1e2fbe05465716f67c8d58b9c0503520
3e560742576af9413fca72e70f75d7ddc9416020
e3985eb936d66c9b07aa72c15358f92965b1194e
b140bec2347bfbe6dcae44aa876b9ba5fe66505b
c005ad34245a8f2105658da2d6d6e8545ef0f0de
11a2c115510bfa6cb56bbd18a7259a4420498fd5
c78697e385bfa58d6bd2a013f543cdfbdc297c4f
c645d6c6430db3069abd291ec13afebdb320714b
073ca448ef3d311218d7bd32d6307243ce22e7d0
33839f4006d6044a3a6675c593fada6a690bb64d
4d303ec6c914007f3214ce9184e1891e97af71de
266723d98e2cccb7b45c9364c7716efe4da00dfa

All of the current hashes have been cracked. They are as follows:

6f2520f8bd70a718c568ab5274c56bdbbfc14ef4 : *.minetime.com
b13009db1e2fbe05465716f67c8d58b9c0503520 : *.endercraft.com
3e560742576af9413fca72e70f75d7ddc9416020 : *.insanefactions.org
e3985eb936d66c9b07aa72c15358f92965b1194e : *.insanenetwork.org
b140bec2347bfbe6dcae44aa876b9ba5fe66505b : *.phoenixnexus.net
c005ad34245a8f2105658da2d6d6e8545ef0f0de : *.skygod.us
11a2c115510bfa6cb56bbd18a7259a4420498fd5 : *.slaughterhousepvp.com
c78697e385bfa58d6bd2a013f543cdfbdc297c4f : *.mineaqua.net
c645d6c6430db3069abd291ec13afebdb320714b : *.mineaqua.es
073ca448ef3d311218d7bd32d6307243ce22e7d0 : *.diacraft.org
33839f4006d6044a3a6675c593fada6a690bb64d : *.diacraft.de
4d303ec6c914007f3214ce9184e1891e97af71de : *.menoxia.com
266723d98e2cccb7b45c9364c7716efe4da00dfa : *.styxnetwork.net

Statistics

  POST https://api.mojang.com/orders/statistics

Get statistics on the sales of Minecraft.

Payload

The payload is a json list of options under the metricKeys key. Below is the default list used by https://minecraft.net/en/stats/

{
    "metricKeys": [
        "item_sold_minecraft",
        "prepaid_card_redeemed_minecraft"
    ]
}

Valid options (Sales > 0) are:

   item_sold_minecraft
   prepaid_card_redeemed_minecraft
   item_sold_cobalt
   item_sold_scrolls

Response

A json object is returned with the total amount of copies sold, the amount of copies sold in the last 24h and how many sales there are per second.

{
    "total": integer total amount sold,
    "last24h": integer total sold in last 24 hours,
    "saleVelocityPerSeconds": integer average sales per second
}

Examples

Go | uuids or names to profiles with skins, capes and name histories

Python | uuids or names to profiles

Python | names file to uuids+names file

PHP | uuids or names to profiles with skins, heads and name histories

PHP | uuids to names

PHP | uuids to names, names to uuids

JavaScript | uuids or names to profiles with skins, capes and name histories