Introduction
Welcome to the documentation for osu!api v2. You can use this API to get information on various circles and those who click them.
Note that while we endeavour to keep this documentation up to date, consider it a work-in-progress and note that it will likely contain errors.
If you notice any errors in the documentation or encounter problems using the API, please check for (or create if necessary) issues on GitHub. Alternatively, you can ask in #osu-web
on the development discord.
Code examples are provided in the dark area to the right, you can use the tabs at the top of the page to switch between bash and javascript samples.
Terms of Use
Use the API for good. Don't overdo it. If in doubt, ask before (ab)using :). this section may expand as necessary.
Current rate limit is set at an insanely high 1200 requests per minute, with burst capability of up to 200 beyond that. If you require more, you probably fall into the above category of abuse. If you are doing more than 60 requests a minute, you should probably give peppy a yell.
Wrappers
Below is a list of some language-specific wrappers maintained by the community. Your mileage may vary when using them – please report any issues to the wrapper first before reporting back to us.
Changelog
For a full list of changes, see the Changelog on the site.
Breaking Changes
2024-07-30
key
parameter for Get User endpoint has been deprecated. Prefix username with@
to lookup by username instead.
2024-01-23
active_tournament_banner
in User has been deprecated, useactive_tournament_banners
instead.
2023-10-17
- GameMode has been renamed to Ruleset; existing property names remain unchanged.
number
has been removed from documentation and replaced withinteger
orfloat
to better reflect the type of number.
2023-09-11
- object structures with two main variants (Beatmap, Beatmapset, and User) have their naming changed. The base object which previously has
Compact
suffix has their suffix removed and the previously extended object with no suffix now hasExtended
suffix instead. This matches existing TypeScript interface.
2023-02-17
content_html
in ChatMessage has been deprecated; pre-rendered markdown will be removed.
2023-01-05
new_channel_id
in Create New PM response has been deprecated, usechannel.channel_id
instead.
2022-11-21
messages
has been removed from Chat Get Updates.
2022-11-11
recent_messages
in ChatChannel has been deprecated, it will be removed from Create Channel response in the near future.
2022-09-27
user
include in Get User Scores response has been deprecated, it will be removed in the near future.
2022-07-06
chat/presence
endpoint has been deprecated, it will be removed in the near future.
2022-06-08
discussion_enabled
in Beatmapset is deprecated. All beatmapsets now have it enabled.
2021-10-28
beatmap
in Get Beatmap scoresscores
array item is removed (it's never been documented in the first place).
2021-09-01
last_read_id
in ChatChannel is deprecated, usecurrent_user_attributes.last_read_id
instead.
2021-08-11
bot
scope removed in favour fordelegate
scope Client Credentials Delegation.
2021-06-14
- Removed
description
from UserGroup. It has been moved to an optional attribute with a different type on Group.
2021-06-09
ranked_and_approved_beatmapset_count
andunranked_beatmapset_count
attributes in UserCompact object have been deprecated and replaced withranked_beatmapset_count
andpending_beatmapset_count
respectively.ranked_and_approved
andunranked
types in Get User Beatmaps have been deprecated and replaced withranked
andpending
respectively.
2021-04-20
cover_url
in User is deprecated, usecover.url
instead.
2021-02-25
current_mode_rank
has been removed from UserCompact- attributes in UserStatistics have been moved around
rank.country
is deprecated, replaced bycountry_rank
rank.global
andpp_rank
are removed, replaced byglobal_rank
2020-09-08
presence
removed fromchat/new
response.
2020-08-28
/rooms/{room_id}/leaderboard
no longer returns an array at the top level; an object with keys is now returned.
2020-05-01
users.read
scope removed, replaced with more generalpublic
scope.
2020-02-18
- Beatmap
max_combo
and build update streamuser_count
now return the values as primitives instead of numbers wrapped in an array.
2019-10-09
- Ranking API response no longer returns an array at the top level; an object with keys is now returned.
2019-07-18
- User now returns counts directly as primitives instead of numbers wrapped in an array.
Endpoint
Base URL
The base URL is: https://osu.ppy.sh/api/[version]/
API Versions
This is combined with the base endpoint to determine where requests should be sent.
Version | Status |
---|---|
v2 | current |
v1 | legacy api provided by the old site, will be deprecated soon |
API Response Version
Sometimes, an API response need to be updated in non-backward compatible ways. In such cases, the x-api-version
header is used to determine which version of the response will be returned.
Version 0 is assumed when the header is omitted.
Version | Change |
---|---|
20220705 | Score object with different set of fields. |
20240529 | GET /rooms will not return rooms with category daily_challenge prior to this version. Temporary, will not be supported after 2024-11-29. |
Language
Language for the response is determined by Accept-Language
header when specified. Specifying *
or not setting the header will set the language to user configured language when accessing API as a user.
Authentication
Routes marked with the OAuth label require a valid OAuth2 token for access.
More information about applications you have registered and granted permissions to can be found here.
The API supports the following grant types:
Before you can use the osu!api, you will need to
- have registered an OAuth Application.
-
acquire an access token by either:
- authorizing users for your application;
- requesting Client Credentials token.
Registering an OAuth application
Before you can get an OAuth token, you will need to register an OAuth application on your account settings page.
To register an OAuth application you will need to provide the:
Name | Description |
---|---|
Application Name | This is the name that will be visible to users of your application. The name of your application cannot be changed. |
Application Callback URL | The URL in your application where users will be sent after authorization. |
The Application Callback URL
is required when for using Authorization Codes.
This may be left blank if you are only using Client Credentials Grants.
Your new OAuth application will have a Client ID
and Client Secret
; the Client Secret
is like a password for your OAuth application, it should be kept private and do not share it with anyone else.
Authorization Code Grant
The flow to authorize users for your application is:
- Requesting authorization from users
- Users are redirected back to your site
- Your application accesses the API with the user's access token
Request authorization from a user
To obtain an access token, you must first get an authorization code that is created when a user grants permissions to your application. To request permission from the user, they should be redirected to:
GET
https://osu.ppy.sh/oauth/authorize
User is redirected back to your site
If the user accepts your request, they will be redirected back to your site with a temporary single-use code
contained in the URL parameter.
If a state
value was provided in the previous request, it will be returned here.
Exchange this code
for an access token:
Example request:
curl --request POST \
"https://osu.ppy.sh/oauth/token" \
--header "Accept: application/json" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data "client_id=1&client_secret=clientsecret&code=receivedcode&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A4000"
const url = new URL(
"https://osu.ppy.sh/oauth/token"
);
const headers = {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
};
let body = "client_id=1&client_secret=clientsecret&code=receivedcode&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A4000";
fetch(url, {
method: "POST",
headers,
body: body,
}).then(response => response.json());
Example response (200):
{
"access_token": "verylongstring",
"expires_in": 86400,
"refresh_token": "anotherlongstring",
"token_type": "Bearer"
}
Received response:
Request failed with error:
POST
https://osu.ppy.sh/oauth/token
Response Format
Successful requests will be issued an access token:
Name | Type | Description |
---|---|---|
token_type | string | The type of token, this should always be Bearer . |
expires_in | integer | The number of seconds the token will be valid for. |
access_token | string | The access token. |
refresh_token | string | The refresh token. |
Refresh access token
Access token expires after some time as per expires_in
field. Refresh the token to get new access token without going through authorization process again.
Use refresh_token
received during previous access token request:
Example request:
curl --request POST \
"https://osu.ppy.sh/oauth/token" \
--header "Accept: application/json" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data "client_id=1&client_secret=clientsecret&grant_type=refresh_token&refresh_token=longstring&scope=public+identify"
const url = new URL(
"https://osu.ppy.sh/oauth/token"
);
const headers = {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
};
let body = "client_id=1&client_secret=clientsecret&grant_type=refresh_token&refresh_token=longstring&scope=public+identify";
fetch(url, {
method: "POST",
headers,
body: body,
}).then(response => response.json());
Example response (200):
{
"access_token": "verylongstring",
"expires_in": 86400,
"refresh_token": "anotherlongstring",
"token_type": "Bearer"
}
Received response:
Request failed with error:
POST
https://osu.ppy.sh/oauth/token
Response Format
Successful requests will be issued an access token and a new refresh token:
Name | Type | Description |
---|---|---|
token_type | string | The type of token, this should always be Bearer . |
expires_in | integer | The number of seconds the token will be valid for. |
access_token | string | The access token. |
refresh_token | string | The refresh token. |
Client Credentials Grant
The client credential flow provides a way for developers to get access tokens that do not have associated user permissions; as such, these tokens are considered as guest users.
Example for requesting Client Credentials token:
Example request:
curl --request POST \
"https://osu.ppy.sh/oauth/token" \
--header "Accept: application/json" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data "client_id=1&client_secret=clientsecret&grant_type=client_credentials&scope=public"
const url = new URL(
"https://osu.ppy.sh/oauth/token"
);
const headers = {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
};
let body = "client_id=1&client_secret=clientsecret&grant_type=client_credentials&scope=public";
fetch(url, {
method: "POST",
headers,
body: body,
}).then(response => response.json());
Example response (200):
{
"access_token": "verylongstring",
"expires_in": 86400,
"token_type": "Bearer"
}
Received response:
Request failed with error:
POST
https://osu.ppy.sh/oauth/token
Response Format
Successful requests will be issued an access token:
Name | Type | Description |
---|---|---|
token_type | string | The type of token, this should always be Bearer . |
expires_in | integer | The number of seconds the token will be valid for. |
access_token | string | The access token. |
Using the access token to access the API
With the access token, you can make requests to osu!api on behalf of a user.
The token should be included in the header of requests to the API.
Authorization: Bearer {{token}}
# With shell, you can just pass the correct header with each request curl "https://osu.ppy.sh/api/[version]/[endpoint]" -H "Authorization: Bearer {{token}}"
// This javascript example uses fetch()
fetch("https://osu.ppy.sh/api/[version]/[endpoint]", {
headers: {
Authorization: 'Bearer {{token}}'
}
});
Make sure to replace
{{token}}
with your OAuth2 token.
Resource Owner
The Resource Owner
is the user that a token acts on behalf of.
For Authorization Code Grant tokens, the Resource Owner is the user authorizing the token.
Client Credentials Grant tokens do not have a Resource Owner (i.e. is a guest user), unless they have been granted the delegate scope. The Resource Owner of tokens with the delegate scope is the owner of the OAuth Application that was granted the token.
Routes marked with requires user require the use of tokens that have a Resource Owner.
Client Credentials Delegation
Client Credentials Grant tokens may be allowed to act on behalf of the owner of the OAuth client (delegation) by requesting the delegate scope, in addition to other scopes supporting delegation. When using delegation, scopes that support delegation cannot be used together with scopes that do not support delegation. Delegation is only available to Chat Bots.
The following scopes currently support delegation:
Name |
---|
chat.write |
Scopes
The following scopes are currently supported:
Name | Description |
---|---|
chat.read | Allows read chat messages on a user's behalf. |
chat.write | Allows sending chat messages on a user's behalf. |
chat.write_manage | Allows joining and leaving chat channels on a user's behalf. |
delegate | Allows acting as the owner of a client; only available for Client Credentials Grant. |
forum.write | Allows creating and editing forum posts on a user's behalf. |
friends.read | Allows reading of the user's friend list. |
identify | Allows reading of the public profile of the user ( |
public | Allows reading of publicly available data on behalf of the user. |
identify
is the default scope for the Authorization Code Grant and always implicitly provided. The Client Credentials Grant does not currently have any default scopes.
Routes marked with lazer are intended for use by the osu!lazer client and not currently available for use with Authorization Code or Client Credentials grants.
Using the chat.write scope requires either
- a Chat Bot account to send messages on behalf of other users.
- Authorization code grant where the user is the same as the client's owner (send as yourself).
Managing OAuth applications
Your account settings page will show your registered OAuth applications, and all the OAuth applications you have granted permissions to.
Reset Client Secret
You can generate a new Client Secret
by choosing to "Reset client secret", however, this will disable all access tokens issued for the application.
Beatmap Packs
Get Beatmap Packs
Returns a list of beatmap packs.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmaps/packs?type=sed" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps/packs"
);
const params = {
"type": "sed",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmaps/packs
Response format
Field | Type |
---|---|
beatmap_packs | BeatmapPack[] |
Get Beatmap Pack
Gets the beatmap pack for the specified beatmap pack tag.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmaps/packs/eum?legacy_only=0" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps/packs/eum"
);
const params = {
"legacy_only": "0",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmaps/packs/{pack}
Response format
Returns BeatmapPack object. The following attributes are always included as well:
Attribute |
---|
beatmapsets |
user_completion_data |
Beatmaps
Lookup Beatmap
Returns beatmap.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmaps/lookup?checksum=molestiae&filename=nihil&id=earum" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps/lookup"
);
const params = {
"checksum": "molestiae",
"filename": "nihil",
"id": "earum",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
"See Beatmap object section"
Received response:
Request failed with error:
Request
GET
/beatmaps/lookup
Response format
See Get Beatmap
Get a User Beatmap score
Return a User's score on a Beatmap
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmaps/7/scores/users/20?legacy_only=0&mode=qui&mods=quod" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps/7/scores/users/20"
);
const params = {
"legacy_only": "0",
"mode": "qui",
"mods": "quod",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmaps/{beatmap}/scores/users/{user}
Response Format
Returns BeatmapUserScore
The position returned depends on the requested mode and mods.
Get a User Beatmap scores
Return a User's scores on a Beatmap
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmaps/8/scores/users/7/all?legacy_only=0&ruleset=osu" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps/8/scores/users/7/all"
);
const params = {
"legacy_only": "0",
"ruleset": "osu",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmaps/{beatmap}/scores/users/{user}/all
Response Format
Field | Type |
---|---|
scores | Score[] |
Get Beatmap scores
Returns the top scores for a beatmap. Depending on user preferences, this may only show legacy scores.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmaps/11/scores?legacy_only=0&mode=laboriosam&mods=qui&type=ea" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps/11/scores"
);
const params = {
"legacy_only": "0",
"mode": "laboriosam",
"mods": "qui",
"type": "ea",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmaps/{beatmap}/scores
Response Format
Returns BeatmapScores. Score
object inside includes user
and the included user
includes country
and cover
.
Get Beatmap scores (non-legacy)
Returns the top scores for a beatmap.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmaps/7/solo-scores?mode=rem&mods=deleniti&type=est" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps/7/solo-scores"
);
const params = {
"mode": "rem",
"mods": "deleniti",
"type": "est",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmaps/{beatmap}/solo-scores
Response Format
Returns BeatmapScores. Score
object inside includes user
and the included user
includes country
and cover
.
Get Beatmaps
Returns a list of beatmaps.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmaps?ids%5B%5D=1" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps"
);
const params = {
"ids[]": "1",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"beatmaps": [
{
"id": 1,
// Other Beatmap attributes...
}
]
}
Received response:
Request failed with error:
Request
GET
/beatmaps
Response format
Field | Type | Description |
---|---|---|
beatmaps | BeatmapExtended[] | Includes beatmapset (with ratings ), failtimes , and max_combo . |
Get Beatmap
Gets beatmap data for the specified beatmap ID.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmaps/10" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps/10"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
"See Beatmap object section."
Received response:
Request failed with error:
Request
GET
/beatmaps/{beatmap}
Response format
Returns BeatmapExtended object. Following attributes are included in the response object when applicable,
Attribute | Notes |
---|---|
beatmapset | Includes ratings property. |
failtimes | |
max_combo |
Get Beatmap Attributes
Returns difficulty attributes of beatmap with specific mode and mods combination.
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/beatmaps/2/attributes" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"mods\": 1,
\"ruleset\": \"osu\"
}"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps/2/attributes"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"mods": 1,
"ruleset": "osu"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());
Example response (200):
{
"attributes": {
"max_combo": 100,
...
}
}
Received response:
Request failed with error:
Request
POST
/beatmaps/{beatmap}/attributes
Response format
Field | Type |
---|---|
Attributes | DifficultyAttributes |
Beatmapset Discussions
Get Beatmapset Discussion Posts
Returns the posts of beatmapset discussions.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmapsets/discussions/posts?beatmapset_discussion_id=consectetur&limit=6&page=18&sort=deserunt&types%5B%5D=saepe&user=deleniti&with_deleted=sunt" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmapsets/discussions/posts"
);
const params = {
"beatmapset_discussion_id": "consectetur",
"limit": "6",
"page": "18",
"sort": "deserunt",
"types[]": "saepe",
"user": "deleniti",
"with_deleted": "sunt",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmapsets/discussions/posts
Response Format
Field | Type | Description |
---|---|---|
beatmapsets | Beatmapset | |
cursor_string | CursorString | |
posts | BeatmapsetDiscussionPost[] | |
users | User |
Get Beatmapset Discussion Votes
Returns the votes given to beatmapset discussions.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmapsets/discussions/votes?beatmapset_discussion_id=eos&limit=17&page=11&receiver=laudantium&score=eveniet&sort=reiciendis&user=voluptate&with_deleted=veritatis" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmapsets/discussions/votes"
);
const params = {
"beatmapset_discussion_id": "eos",
"limit": "17",
"page": "11",
"receiver": "laudantium",
"score": "eveniet",
"sort": "reiciendis",
"user": "voluptate",
"with_deleted": "veritatis",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmapsets/discussions/votes
Response Format
Field | Type | Description |
---|---|---|
cursor_string | CursorString | |
discussions | BeatmapsetDiscussion | |
users | User | |
votes | BeatmapsetDiscussionVote[] |
Get Beatmapset Discussions
Returns a list of beatmapset discussions.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmapsets/discussions?beatmap_id=odio&beatmapset_id=quam&beatmapset_status=qui&limit=9&message_types%5B%5D=eligendi&only_unresolved=praesentium&page=16&sort=voluptatem&user=quaerat&with_deleted=illo" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmapsets/discussions"
);
const params = {
"beatmap_id": "odio",
"beatmapset_id": "quam",
"beatmapset_status": "qui",
"limit": "9",
"message_types[]": "eligendi",
"only_unresolved": "praesentium",
"page": "16",
"sort": "voluptatem",
"user": "quaerat",
"with_deleted": "illo",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmapsets/discussions
Response Format
Field | Type | Description |
---|---|---|
beatmaps | BeatmapExtended[] | List of beatmaps associated with the discussions returned. |
cursor_string | CursorString | |
discussions | BeatmapsetDiscussion[] | List of discussions according to sort order. |
included_discussions | BeatmapsetDiscussion[] | Additional discussions related to discussions . |
reviews_config.max_blocks | integer | Maximum number of blocks allowed in a review. |
users | User[] | List of users associated with the discussions returned. |
Beatmapsets
TODO: documentation
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmapsets/search" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmapsets/search"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmapsets/search
GET api/v2/beatmapsets/lookup
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmapsets/lookup" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmapsets/lookup"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmapsets/lookup
GET api/v2/beatmapsets/{beatmapset}
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmapsets/ab" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmapsets/ab"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmapsets/{beatmapset}
GET api/v2/beatmapsets/{beatmapset}/download
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmapsets/eum/download" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmapsets/eum/download"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmapsets/{beatmapset}/download
Changelog
Get Changelog Build
Returns details of the specified build.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/changelog/stable40/20210520.2" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/changelog/stable40/20210520.2"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"id": 5778,
"version": "20210520.2",
"display_version": "20210520.2",
"users": 22093,
"created_at": "2021-05-20T14:28:04+00:00",
"update_stream": {
"id": 5,
"name": "stable40",
"display_name": "Stable",
"is_featured": true
},
"changelog_entries": [
{
"id": null,
"repository": null,
"github_pull_request_id": null,
"github_url": null,
"url": "https://osu.ppy.sh/home/news/2021-05-20-spring-fanart-contest-results",
"type": "fix",
"category": "Misc",
"title": "Spring is here!",
"message_html": "<div class='changelog-md'><p class=\"changelog-md__paragraph\">New seasonal backgrounds ahoy! Amazing work by the artists.</p>\n</div>",
"major": true,
"created_at": "2021-05-20T10:56:49+00:00",
"github_user": {
"display_name": "peppy",
"github_url": null,
"github_username": null,
"id": null,
"osu_username": "peppy",
"user_id": 2,
"user_url": "https://osu.ppy.sh/users/2"
}
}
],
"versions": {
"previous": {
"id": 5774,
"version": "20210519.3",
"display_version": "20210519.3",
"users": 10,
"created_at": "2021-05-19T11:51:48+00:00",
"update_stream": {
"id": 5,
"name": "stable40",
"display_name": "Stable",
"is_featured": true
}
}
}
}
Received response:
Request failed with error:
Request
GET
/changelog/{stream}/{build}
Response Format
A Build with changelog_entries
, changelog_entries.github_user
, and versions
included.
Get Changelog Listing
Returns a listing of update streams, builds, and changelog entries.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/changelog?message_formats%5B%5D=totam" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/changelog"
);
const params = {
"message_formats[]": "totam",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"streams": [
{
"id": 5,
"name": "stable40",
"display_name": "Stable",
"is_featured": true,
"latest_build": {
"id": 5778,
"version": "20210520.2",
"display_version": "20210520.2",
"users": 23683,
"created_at": "2021-05-20T14:28:04+00:00",
"update_stream": {
"id": 5,
"name": "stable40",
"display_name": "Stable",
"is_featured": true
}
},
"user_count": 23965
},
// ...
],
"builds": [
{
"id": 5823,
"version": "2021.619.1",
"display_version": "2021.619.1",
"users": 0,
"created_at": "2021-06-19T08:30:45+00:00",
"update_stream": {
"id": 7,
"name": "lazer",
"display_name": "Lazer",
"is_featured": false
},
"changelog_entries": [
{
"id": 12925,
"repository": "ppy/osu",
"github_pull_request_id": 13572,
"github_url": "https://github.com/ppy/osu/pull/13572",
"url": null,
"type": "fix",
"category": "Reliability",
"title": "Fix game crashes due to attempting localisation load for unsupported locales",
"message_html": null,
"major": true,
"created_at": "2021-06-19T08:09:39+00:00",
"github_user": {
"display_name": "bdach",
"github_url": "https://github.com/bdach",
"github_username": "bdach",
"id": 218,
"osu_username": null,
"user_id": null,
"user_url": null
}
}
]
},
// ...
],
"search": {
"stream": null,
"from": null,
"to": null,
"max_id": null,
"limit": 21
}
}
Received response:
Request failed with error:
Request
GET
/changelog
Response Format
Field | Type | Notes |
---|---|---|
builds | Build[] | Includes changelog_entries , changelog_entries.github_user , and changelog entry message in requested formats. |
search.from | string? | from input. |
search.limit | integer | Always 21 . |
search.max_id | integer? | max_id input. |
search.stream | string? | stream input. |
search.to | string? | to input. |
streams | UpdateStream[] | Always contains all available streams. Includes latest_build and user_count . |
Lookup Changelog Build
Returns details of the specified build.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/changelog/20210520.2?message_formats%5B%5D=accusantium" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/changelog/20210520.2"
);
const params = {
"message_formats[]": "accusantium",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
See "Get Changelog Build" response.
Received response:
Request failed with error:
Request
GET
/changelog/{changelog}
Response Format
See Get Changelog Build.
Chat
Chat Keepalive
Request periodically to reset chat activity timeout. Also returns an updated list of recent silences.
See Public channels and activity timeout
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/chat/ack?history_since=11" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/ack"
);
const params = {
"history_since": "11",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/chat/ack
Response Format
Field | Type |
---|---|
silences | UserSilence[] |
Create New PM
requires user OAuth chat.write
This endpoint allows you to create a new PM channel.
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/chat/new" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"target_id\": 6,
\"message\": \"delectus\",
\"is_action\": false,
\"uuid\": \"some-uuid-string\"
}"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/new"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"target_id": 6,
"message": "delectus",
"is_action": false,
"uuid": "some-uuid-string"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());
Example response (200):
{
"channel": [
{
"channel_id": 1234,
"current_user_attributes": {
"can_message": true,
"can_message_error": null,
"last_read_id": 9150005005
},
"name": "peppy",
"description": "",
"type": "PM",
"last_read_id": 9150005005,
"last_message_id": 9150005005
}
],
"message": {
"message_id": 9150005005,
"sender_id": 102,
"channel_id": 1234,
"timestamp": "2018-07-06T06:33:42+00:00",
"content": "i can haz featured artist plz?",
"is_action": false,
"uuid": "some-uuid-string",
"sender": {
"id": 102,
"username": "nekodex",
"profile_colour": "#333333",
"avatar_url": "https://a.ppy.sh/102?1500537068",
"country_code": "AU",
"is_active": true,
"is_bot": false,
"is_online": true,
"is_supporter": true
}
},
"new_channel_id": 1234,
}
Received response:
Request failed with error:
Request
POST
/chat/new
Response Format
Field | Type |
---|---|
channel | The new ChatChannel |
message | the sent ChatMessage |
new_channel_id | Deprecated; channel_id of newly created ChatChannel |
Get Updates
Returns the list of channels the current User is in along with an updated list of UserSilences.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/chat/updates?history_since=9" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/updates"
);
const params = {
"history_since": "9",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"presence": [
{
"channel_id": 5,
"current_user_attributes": {
"can_message": true,
"can_message_error": null,
"last_read_id": 9150005005
},
"name": "#osu",
"description": "The official osu! channel (english only).",
"type": "public",
"last_read_id": 9150005005,
"last_message_id": 9150005005
},
{
"channel_id": 12345,
"current_user_attributes": {
"can_message": true,
"can_message_error": null,
"last_read_id": 9150001235
},
"type": "PM",
"name": "peppy",
"icon": "https://a.ppy.sh/2?1519081077.png",
"users": [
2,
102
],
"last_read_id": 9150001235,
"last_message_id": 9150001234
}
],
"silences": [
{
"id": 1,
"user_id": 2
}
]
}
Received response:
Request failed with error:
Request
GET
/chat/updates
Response Format
Field | Type |
---|---|
messages | This field is not used and will be removed. |
presence | ChatChannel[]? |
silences | UserSilence[]? |
Get Channel Messages
This endpoint returns the chat messages for a specific channel.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/chat/channels/6/messages?limit=10&since=12&until=11" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/channels/6/messages"
);
const params = {
"limit": "10",
"since": "12",
"until": "11",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
[
{
"message_id": 9150005004,
"sender_id": 2,
"channel_id": 5,
"timestamp": "2018-07-06T06:33:34+00:00",
"content": "i am a lazerface",
"is_action": 0,
"sender": {
"id": 2,
"username": "peppy",
"profile_colour": "#3366FF",
"avatar_url": "https://a.ppy.sh/2?1519081077.png",
"country_code": "AU",
"is_active": true,
"is_bot": false,
"is_online": true,
"is_supporter": true
}
},
{
"message_id": 9150005005,
"sender_id": 102,
"channel_id": 5,
"timestamp": "2018-07-06T06:33:42+00:00",
"content": "uh ok then",
"is_action": 0,
"sender": {
"id": 102,
"username": "nekodex",
"profile_colour": "#333333",
"avatar_url": "https://a.ppy.sh/102?1500537068",
"country_code": "AU",
"is_active": true,
"is_bot": false,
"is_online": true,
"is_supporter": true
}
}
]
Received response:
Request failed with error:
Request
GET
/chat/channels/{channel}/messages
Response Format
Returns an array of ChatMessage
Send Message to Channel
requires user OAuth chat.write
This endpoint returns the chat messages for a specific channel.
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/chat/channels/18/messages" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"message\": \"accusamus\",
\"is_action\": true
}"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/channels/18/messages"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"message": "accusamus",
"is_action": true
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());
Example response (200):
{
"message_id": 9150005004,
"sender_id": 2,
"channel_id": 5,
"timestamp": "2018-07-06T06:33:34+00:00",
"content": "i am a lazerface",
"is_action": 0,
"sender": {
"id": 2,
"username": "peppy",
"profile_colour": "#3366FF",
"avatar_url": "https://a.ppy.sh/2?1519081077.png",
"country_code": "AU",
"is_active": true,
"is_bot": false,
"is_online": true,
"is_supporter": true
}
}
Received response:
Request failed with error:
Request
POST
/chat/channels/{channel}/messages
Response Format
The sent ChatMessage
Join Channel
requires user OAuth chat.write_manage
This endpoint allows you to join a public or multiplayer channel.
Example request:
curl --request PUT \
"https://osu.ppy.sh/api/v2/chat/channels/doloribus/users/tempore" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/channels/doloribus/users/tempore"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "PUT",
headers,
}).then(response => response.json());
Example response (200):
{
"channel_id": 5,
"current_user_attributes": {
"can_message": true,
"can_message_error": null
},
"description": "The official osu! channel (english only).",
"icon": "https://a.ppy.sh/2?1519081077.png",
"last_message_id": 1029,
"moderated": false,
"name": "#osu",
"type": "public"
"users": []
}
Received response:
Request failed with error:
Request
PUT
/chat/channels/{channel}/users/{user}
Response Format
Returns the joined ChatChannel.
Leave Channel
requires user OAuth chat.write_manage
This endpoint allows you to leave a public channel.
Example request:
curl --request DELETE \
"https://osu.ppy.sh/api/v2/chat/channels/deserunt/users/ut" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/channels/deserunt/users/ut"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());
Example response (204):
[Empty response]
Received response:
Request failed with error:
Request
DELETE
/chat/channels/{channel}/users/{user}
Response Format
empty response
Mark Channel as Read
This endpoint marks the channel as having being read up to the given message_id
.
Example request:
curl --request PUT \
"https://osu.ppy.sh/api/v2/chat/channels/autem/mark-as-read/molestias?channel_id=sed&message_id=tempore" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/channels/autem/mark-as-read/molestias"
);
const params = {
"channel_id": "sed",
"message_id": "tempore",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "PUT",
headers,
}).then(response => response.json());
Example response (204):
[Empty response]
Received response:
Request failed with error:
Request
PUT
/chat/channels/{channel}/mark-as-read/{message}
Response Format
empty response
Get Channel List
This endpoint returns a list of all joinable public channels.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/chat/channels" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/channels"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
[
{
"channel_id": 5,
"description": "The official osu! channel (english only).",
"icon": "https://a.ppy.sh/2?1519081077.png",
"moderated": false,
"name": "#osu",
"type": "public"
}
]
Received response:
Request failed with error:
Request
GET
/chat/channels
Response Format
Returns an array of ChatChannel
Create Channel
requires user OAuth chat.write_manage
Creates a new PM or announcement channel. Rejoins the PM channel if it already exists.
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/chat/channels" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"target_id\": 2,
\"type\": \"PM\"
}"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/channels"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"target_id": 2,
"type": "PM"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());
Example response (200):
{
"channel_id": 1,
"description": "best channel",
"icon": "https://a.ppy.sh/2?1519081077.png",
"moderated": false,
"name": "#pm_1-2",
"type": "PM",
"recent_messages": [
{
"message_id": 1,
"sender_id": 1,
"channel_id": 1,
"timestamp": "2020-01-01T00:00:00+00:00",
"content": "Happy new year",
"is_action": false,
"sender": {
"id": 2,
"username": "peppy",
"profile_colour": "#3366FF",
"avatar_url": "https://a.ppy.sh/2?1519081077.png",
"country_code": "AU",
"is_active": true,
"is_bot": false,
"is_online": true,
"is_supporter": true
}
}
]
}
Received response:
Request failed with error:
Request
POST
/chat/channels
Response Format
Returns ChatChannel with recent_messages
attribute; recent_messages
is deprecated and should not be used.
Get Channel
Gets details of a chat channel.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/chat/channels/necessitatibus" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/channels/necessitatibus"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"channel": {
"channel_id": 1337,
"current_user_attributes": {
"can_message": true,
"can_message_error": null
},
"name": "test channel",
"description": "wheeeee",
"icon": "/images/layout/avatar-guest@2x.png",
"type": "PM",
"last_message_id": 9150005005,
"moderated": false,
"users": [
2,
102
]
},
"users": [
{
"id": 2,
"username": "peppy",
"profile_colour": "#3366FF",
"avatar_url": "https://a.ppy.sh/2?1519081077.png",
"country_code": "AU",
"is_active": true,
"is_bot": false,
"is_deleted": false,
"is_online": true,
"is_supporter": true
},
{
"id": 102,
"username": "lambchop",
"profile_colour": "#3366FF",
"icon": "/images/layout/avatar-guest@2x.png",
"country_code": "NZ",
"is_active": true,
"is_bot": false,
"is_deleted": false,
"is_online": false,
"is_supporter": false
}
]
}
Received response:
Request failed with error:
Request
GET
/chat/channels/{channel}
Response Format
Field | Type | Description |
---|---|---|
channel | ChatChannel | |
users | User | Users are only visible for PM channels. |
Comments
Get Comments
Returns a list comments and their replies up to 2 levels deep.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/comments?commentable_type=beatmapset&commentable_id=1&parent_id=1&sort=new" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/comments"
);
const params = {
"commentable_type": "beatmapset",
"commentable_id": "1",
"parent_id": "1",
"sort": "new",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/comments
Response Format
Returns CommentBundle.
pinned_comments
is only included when commentable_type
and commentable_id
are specified.
Post a new comment
Posts a new comment to a comment thread.
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/comments" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/comments"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/comments
Response Format
Returns CommentBundle
Get a Comment
Gets a comment and its replies up to 2 levels deep.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/comments/itaque" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/comments/itaque"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/comments/{comment}
Response Format
Returns CommentBundle
Edit Comment
Edit an existing comment.
Example request:
curl --request PUT \
"https://osu.ppy.sh/api/v2/comments/placeat" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/comments/placeat"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "PUT",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
PUT
/comments/{comment}
PATCH
/comments/{comment}
Response Format
Returns CommentBundle
Delete Comment
Deletes the specified comment.
Example request:
curl --request DELETE \
"https://osu.ppy.sh/api/v2/comments/recusandae" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/comments/recusandae"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
DELETE
/comments/{comment}
Response Format
Returns CommentBundle
Add Comment vote
Upvotes a comment.
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/comments/nisi/vote" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/comments/nisi/vote"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/comments/{comment}/vote
Response Format
Returns CommentBundle
Remove Comment vote
Un-upvotes a comment.
Example request:
curl --request DELETE \
"https://osu.ppy.sh/api/v2/comments/voluptatem/vote" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/comments/voluptatem/vote"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
DELETE
/comments/{comment}/vote
Response Format
Returns CommentBundle
Events
Get Events
Returns a collection of Events in order of creation time.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/events" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/events"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
events: [
{
created_at: "2022-12-08T02:02:51+00:00",
id: 57,
type: "achievement",
achievement: { ... },
user: { ... }
},
...
],
cursor_string: "eyJldmVudF9pZCI6OH0"
}
Received response:
Request failed with error:
Request
GET
/events
Response Format
Field | Type |
---|---|
cursor_string | CursorString |
events | Event[] |
Forum
Reply Topic
requires user OAuth forum.write
Create a post replying to the specified topic.
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/forums/topics/1/reply" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"body\": \"hello\"
}"
const url = new URL(
"https://osu.ppy.sh/api/v2/forums/topics/1/reply"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"body": "hello"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/forums/topics/{topic}/reply
Response Format
ForumPost with body
included.
Create Topic
requires user OAuth forum.write
Create a new topic.
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/forums/topics" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"body\": \"hello\",
\"forum_id\": 1,
\"title\": \"untitled\",
\"with_poll\": true,
\"forum_topic_poll[options]\": \"item A...\",
\"forum_topic_poll[title]\": \"my poll\"
}"
const url = new URL(
"https://osu.ppy.sh/api/v2/forums/topics"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"body": "hello",
"forum_id": 1,
"title": "untitled",
"with_poll": true,
"forum_topic_poll[options]": "item A...",
"forum_topic_poll[title]": "my poll"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/forums/topics
Response Format
Field | Type | Includes |
---|---|---|
topic | ForumTopic | |
post | ForumPost | body |
Get Topic and Posts
Get topic and its posts.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/forums/topics/1" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/forums/topics/1"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"topic": {
"id": 1,
"...": "..."
},
"posts": [
{
"id": 1,
"...": "..."
},
{
"id": 2,
"...": "..."
}
],
"cursor_string": "eyJoZWxsbyI6IndvcmxkIn0",
"sort": "id_asc"
}
Received response:
Request failed with error:
Request
GET
/forums/topics/{topic}
Response Format
Field | Type | Notes |
---|---|---|
cursor_string | CursorString | |
posts | ForumPost[] | Includes body . |
search | Parameters used for current request excluding cursor. | |
topic | ForumTopic |
Edit Topic
Edit topic. Only title can be edited through this endpoint.
Example request:
curl --request PUT \
"https://osu.ppy.sh/api/v2/forums/topics/1" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"forum_topic[topic_title]\": \"titled\"
}"
const url = new URL(
"https://osu.ppy.sh/api/v2/forums/topics/1"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"forum_topic[topic_title]": "titled"
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());
Received response:
Request failed with error:
Request
PUT
/forums/topics/{topic}
PATCH
/forums/topics/{topic}
Response Format
The edited ForumTopic.
Edit Post
Edit specified forum post.
Example request:
curl --request PUT \
"https://osu.ppy.sh/api/v2/forums/posts/1" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"body\": \"hello\"
}"
const url = new URL(
"https://osu.ppy.sh/api/v2/forums/posts/1"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"body": "hello"
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());
Received response:
Request failed with error:
Request
PUT
/forums/posts/{post}
PATCH
/forums/posts/{post}
Response Format
ForumPost with body
included.
Home
Search
Searches users and wiki pages.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/search?mode=all&query=hello&page=1" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/search"
);
const params = {
"mode": "all",
"query": "hello",
"page": "1",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/search
Response Format
Field | Type | Description |
---|---|---|
user | SearchResult<User>? | For all or user mode. Only first 100 results are accessible |
wiki_page | SearchResult<WikiPage>? | For all or wiki_page mode |
SearchResult<T>
Field | Type | Description |
---|---|---|
data | T[] | |
total | integer |
Matches
Get Matches Listing
Returns a list of matches.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/matches" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/matches"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"matches": [
{
"id": 114428685,
"start_time": "2024-06-25T00:55:30+00:00",
"end_time": null,
"name": "peppy's game"
},
// ...
],
"params": {
"limit": 50,
"sort": "id_desc"
},
"cursor": {
"match_id": 114428685
},
"cursor_string": "eyJtYXRjaF9pZCI6MTE0NDI4Njg1fQ"
}
Received response:
Request failed with error:
Request
GET
/matches
Response Format
Field | Type | Notes |
---|---|---|
cursor | Cursor | |
cursor_string | CursorString | |
matches | Match[] | |
params.limit | integer | |
params.sort | string |
Get Match
Returns details of the specified match.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/matches/" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/matches/"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"match": {
"id": 16155689,
"start_time": "2015-05-16T09:44:51+00:00",
"end_time": "2015-05-16T10:55:08+00:00",
"name": "CWC 2015: (Australia) vs (Poland)"
},
"events": [
{
"id": 484385927,
"detail": {
"type": "match-created"
},
"timestamp": "2015-05-16T09:44:51+00:00",
"user_id": null
},
// ...
],
"users": [],
"first_event_id": 484385927,
"latest_event_id": 484410607,
"current_game_id": null
}
Received response:
Request failed with error:
Request
GET
/matches/{match}
Response Format
Field | Type | Notes |
---|---|---|
match | Match | |
events | MatchEvent[] | |
users | User[] | Includes country . |
first_event_id | integer | ID of the first MatchEvent in the match. |
latest_event_id | integer | ID of the lastest MatchEvent in the match. |
Multiplayer
Get User High Score
Returns detail of highest score of specified user and the surrounding scores.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/rooms/9/playlist/9/scores/users/6" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rooms/9/playlist/9/scores/users/6"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/rooms/{room}/playlist/{playlist}/scores/users/{user}
Response Format
Returns Score object.
Get Scores
Returns a list of scores for specified playlist item.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/rooms/5/playlist/7/scores?limit=12&sort=iste" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rooms/5/playlist/7/scores"
);
const params = {
"limit": "12",
"sort": "iste",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/rooms/{room}/playlist/{playlist}/scores
Response Format
Returns MultiplayerScores object.
Get a Score
Returns detail of specified score and the surrounding scores.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/rooms/16/playlist/10/scores/11" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rooms/16/playlist/10/scores/11"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/rooms/{room}/playlist/{playlist}/scores/{score}
Response Format
Returns Score object.
Get Multiplayer Rooms
Returns a list of multiplayer rooms.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/rooms" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rooms"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/rooms
News
Get News Listing
Returns a list of news posts and related metadata.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/news" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/news"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"news_posts": [
{
"id": 964,
"author": "RockRoller",
"edit_url": "https://github.com/ppy/osu-wiki/tree/master/news/2021-05-27-skinning-contest-results.md",
"first_image": "https://i.ppy.sh/d431ff921955d5c8792dc9bae40ac082d4e53131/68747470733a2f2f6f73752e7070792e73682f77696b692f696d616765732f7368617265642f6e6577732f323032312d30352d32372d736b696e6e696e672d636f6e746573742d726573756c74732f736b696e6e696e675f636f6e746573745f62616e6e65722e6a7067",
"published_at": "2021-05-27T12:00:00+00:00",
"updated_at": "2021-05-28T17:11:35+00:00",
"slug": "2021-05-27-skinning-contest-results",
"title": "Skinning Contest: Results Out",
"preview": "The ship full of skins is now back with your votes. Check out the results for our first-ever official skinning contest right here!"
},
// ...
],
"news_sidebar": {
"current_year": 2021,
"news_posts": [
{
"id": 964,
"author": "RockRoller",
"edit_url": "https://github.com/ppy/osu-wiki/tree/master/news/2021-05-27-skinning-contest-results.md",
"first_image": "https://i.ppy.sh/d431ff921955d5c8792dc9bae40ac082d4e53131/68747470733a2f2f6f73752e7070792e73682f77696b692f696d616765732f7368617265642f6e6577732f323032312d30352d32372d736b696e6e696e672d636f6e746573742d726573756c74732f736b696e6e696e675f636f6e746573745f62616e6e65722e6a7067",
"published_at": "2021-05-27T12:00:00+00:00",
"updated_at": "2021-05-28T17:11:35+00:00",
"slug": "2021-05-27-skinning-contest-results",
"title": "Skinning Contest: Results Out"
},
// ...
],
"years": [2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013]
},
"search": {
"limit": 12,
"sort": "published_desc"
},
"cursor_string": "WyJodHRwczpcL1wvd3d3LnlvdXR1YmUuY29tXC93YXRjaD92PWRRdzR3OVdnWGNRIl0"
}
Received response:
Request failed with error:
Request
GET
/news
Response Format
Field | Type | Notes |
---|---|---|
cursor_string | CursorString | |
news_posts | NewsPost[] | Includes preview . |
news_sidebar.current_year | integer | Year of the first post's publish time, or current year if no posts returned. |
news_sidebar.news_posts | NewsPost[] | All posts published during current_year . |
news_sidebar.years | integer[] | All years during which posts have been published. |
search.limit | integer | Clamped limit input. |
search.sort | string | Always published_desc . |
Get News Post
Returns details of the specified news post.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/news/2021-04-27-results-a-labour-of-love" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/news/2021-04-27-results-a-labour-of-love"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"id": 943,
"author": "pishifat",
"edit_url": "https://github.com/ppy/osu-wiki/tree/master/news/2021-04-27-results-a-labour-of-love.md",
"first_image": "https://i.ppy.sh/65c9c2eb2f8d9bc6008b95aba7d0ef45e1414c1e/68747470733a2f2f6f73752e7070792e73682f77696b692f696d616765732f7368617265642f6e6577732f323032302d31312d33302d612d6c61626f75722d6f662d6c6f76652f616c6f6c5f636f7665722e6a7067",
"published_at": "2021-04-27T20:00:00+00:00",
"updated_at": "2021-04-27T20:25:57+00:00",
"slug": "2021-04-27-results-a-labour-of-love",
"title": "Results - A Labour of Love",
"content": "<div class='osu-md osu-md--news'>...</div>",
"navigation": {
"newer": {
"id": 944,
"author": "pishifat",
"edit_url": "https://github.com/ppy/osu-wiki/tree/master/news/2021-04-28-new-featured-artist-emilles-moonlight-serenade.md",
"first_image": "https://i.ppy.sh/7e22cc5f4755c21574d999d8ce3a2f40a3268e84/68747470733a2f2f6173736574732e7070792e73682f617274697374732f3136302f6865616465722e6a7067",
"published_at": "2021-04-28T08:00:00+00:00",
"updated_at": "2021-04-28T09:51:28+00:00",
"slug": "2021-04-28-new-featured-artist-emilles-moonlight-serenade",
"title": "New Featured Artist: Emille's Moonlight Serenade"
},
"older": {
"id": 942,
"author": "pishifat",
"edit_url": "https://github.com/ppy/osu-wiki/tree/master/news/2021-04-24-new-featured-artist-grynpyret.md",
"first_image": "https://i.ppy.sh/acdce813b71371b95e8240f9249c916285fdc5a0/68747470733a2f2f6173736574732e7070792e73682f617274697374732f3135392f6865616465722e6a7067",
"published_at": "2021-04-24T08:00:00+00:00",
"updated_at": "2021-04-24T10:23:59+00:00",
"slug": "2021-04-24-new-featured-artist-grynpyret",
"title": "New Featured Artist: Grynpyret"
}
}
}
Received response:
Request failed with error:
Request
GET
/news/{news}
Response Format
Returns a NewsPost with content
and navigation
included.
Notification
Get Notifications
This endpoint returns a list of the user's unread notifications. Sorted descending by id
with limit of 50.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/notifications?max_id=autem" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/notifications"
);
const params = {
"max_id": "autem",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"has_more": true,
"notifications": [
{
"id": 1,
"name": "forum_topic_reply",
"created_at": "2019-04-24T07:12:43+00:00",
"object_type": "forum_topic",
"object_id": 1,
"source_user_id": 1,
"is_read": false,
"details": {
"title": "A topic",
"post_id": 2,
"username": "User",
"cover_url": "https://..."
}
}
],
"unread_count": 100,
"notification_endpoint": "wss://notify.ppy.sh"
}
Received response:
Request failed with error:
Request
GET
/notifications
Response Format
Returns an object containing Notification and other related attributes.
Field | Type |
---|---|
has_more | boolean whether or not there are more notifications |
notifications | array of Notification |
unread_count | total unread notifications |
notification_endpoint | url to connect to websocket server |
Mark Notifications as Read
This endpoint allows you to mark notifications read.
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/notifications/mark-read" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
const url = new URL(
"https://osu.ppy.sh/api/v2/notifications/mark-read"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());
Example response (204):
[Empty response]
Received response:
Request failed with error:
Request
POST
/notifications/mark-read
Response Format
empty response
OAuth Tokens
Revoke current token
Revokes currently authenticated token.
Example request:
curl --request DELETE \
"https://osu.ppy.sh/api/v2/oauth/tokens/current" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/oauth/tokens/current"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());
Example response (204):
[Empty response]
Received response:
Request failed with error:
Request
DELETE
/oauth/tokens/current
Ranking
Get Kudosu Ranking
Gets the kudosu ranking.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/rankings/kudosu?page=1" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rankings/kudosu"
);
const params = {
"page": "1",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/rankings/kudosu
Response format
Field | Type | Description |
---|---|---|
ranking | User[] | Includes kudosu . |
Get Ranking
Gets the current ranking for the specified type and game mode.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/rankings/mania/performance?country=JP&filter=all&variant=4k" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rankings/mania/performance"
);
const params = {
"country": "JP",
"filter": "all",
"variant": "4k",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/rankings/{mode}/{type}
Response Format
Returns Rankings
Get Spotlights
Gets the list of spotlights.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/spotlights" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/spotlights"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/spotlights
Response Format
Returns Spotlights
Undocumented
POST api/v2/session/verify
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/session/verify" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/session/verify"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/session/verify
POST api/v2/session/verify/reissue
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/session/verify/reissue" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/session/verify/reissue"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/session/verify/reissue
POST api/v2/beatmaps/{beatmap}/solo/scores
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/beatmaps/veritatis/solo/scores" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps/veritatis/solo/scores"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/beatmaps/{beatmap}/solo/scores
PUT api/v2/beatmaps/{beatmap}/solo/scores/{token}
Example request:
curl --request PUT \
"https://osu.ppy.sh/api/v2/beatmaps/est/solo/scores/neque" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmaps/est/solo/scores/neque"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "PUT",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
PUT
/beatmaps/{beatmap}/solo/scores/{token}
GET api/v2/beatmapsets/events
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/beatmapsets/events" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmapsets/events"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/beatmapsets/events
POST api/v2/beatmapsets/{beatmapset}/favourites
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/beatmapsets/sunt/favourites" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/beatmapsets/sunt/favourites"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/beatmapsets/{beatmapset}/favourites
GET api/v2/chat/presence
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/chat/presence" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/chat/presence"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/chat/presence
POST api/v2/reports
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/reports" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/reports"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/reports
PUT api/v2/rooms/{room}/users/{user}
Example request:
curl --request PUT \
"https://osu.ppy.sh/api/v2/rooms/autem/users/quibusdam" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rooms/autem/users/quibusdam"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "PUT",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
PUT
/rooms/{room}/users/{user}
DELETE api/v2/rooms/{room}/users/{user}
Example request:
curl --request DELETE \
"https://osu.ppy.sh/api/v2/rooms/qui/users/reprehenderit" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rooms/qui/users/reprehenderit"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
DELETE
/rooms/{room}/users/{user}
GET api/v2/rooms/{room}/leaderboard
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/rooms/veritatis/leaderboard" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rooms/veritatis/leaderboard"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/rooms/{room}/leaderboard
POST api/v2/rooms/{room}/playlist/{playlist}/scores
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/rooms/provident/playlist/enim/scores" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rooms/provident/playlist/enim/scores"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/rooms/{room}/playlist/{playlist}/scores
PUT api/v2/rooms/{room}/playlist/{playlist}/scores/{score}
Example request:
curl --request PUT \
"https://osu.ppy.sh/api/v2/rooms/distinctio/playlist/veniam/scores/molestias" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rooms/distinctio/playlist/veniam/scores/molestias"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "PUT",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
PUT
/rooms/{room}/playlist/{playlist}/scores/{score}
PATCH
/rooms/{room}/playlist/{playlist}/scores/{score}
POST api/v2/rooms
Example request:
curl --request POST \
"https://osu.ppy.sh/api/v2/rooms" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rooms"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
POST
/rooms
GET api/v2/rooms/{room}
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/rooms/exercitationem" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/rooms/exercitationem"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/rooms/{room}
GET api/v2/seasonal-backgrounds
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/seasonal-backgrounds" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/seasonal-backgrounds"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/seasonal-backgrounds
GET api/v2/scores/{score}/download
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/scores/aspernatur/download" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/scores/aspernatur/download"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/scores/{score}/download
GET api/v2/scores/{rulesetOrScore}/{score}/download
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/scores/ipsa/sit/download" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/scores/ipsa/sit/download"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/scores/{rulesetOrScore}/{score}/download
GET api/v2/scores/{rulesetOrScore}/{score?}
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/scores/voluptatum/reiciendis" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/scores/voluptatum/reiciendis"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/scores/{rulesetOrScore}/{score?}
GET api/v2/friends
requires user OAuth friends.read
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/friends" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/friends"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/friends
GET api/v2/me/download-quota-check
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/me/download-quota-check" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/me/download-quota-check"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/me/download-quota-check
GET api/v2/users/lookup
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/users/lookup" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/users/lookup"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/users/lookup
Users
Get Own Data
Similar to Get User but with authenticated user (token owner) as user id.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/me/osu" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/me/osu"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
"See User object section"
Received response:
Request failed with error:
Request
GET
/me/{mode?}
Response format
See Get User.
session_verified
attribute is included.
Additionally, statistics_rulesets
is included, containing statistics for all rulesets.
Get User Kudosu
Returns kudosu history.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/users/1/kudosu?limit=17&offset=1" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/users/1/kudosu"
);
const params = {
"limit": "17",
"offset": "1",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
[
{
"id": 1,
"other": "attributes..."
},
{
"id": 2,
"other": "attributes..."
}
]
Received response:
Request failed with error:
Request
GET
/users/{user}/kudosu
Response format
Array of KudosuHistory.
Get User Scores
This endpoint returns the scores of specified user.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/users/1/scores/best?legacy_only=0&include_fails=0&mode=osu&limit=18&offset=1" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/users/1/scores/best"
);
const params = {
"legacy_only": "0",
"include_fails": "0",
"mode": "osu",
"limit": "18",
"offset": "1",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
[
{
"id": 1,
"other": "attributes..."
},
{
"id": 2,
"other": "attributes..."
}
]
Received response:
Request failed with error:
Request
GET
/users/{user}/scores/{type}
Response format
Array of Score. Following attributes are included in the response object when applicable.
Attribute | Notes |
---|---|
beatmap | |
beatmapset | |
weight | Only for type best . |
Get User Beatmaps
Returns the beatmaps of specified user.
Type | Notes |
---|---|
favourite | |
graveyard | |
guest | |
loved | |
most_played | |
nominated | |
pending | Previously unranked |
ranked | Previously ranked_and_approved |
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/users/1/beatmapsets/favourite?limit=19&offset=1" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/users/1/beatmapsets/favourite"
);
const params = {
"limit": "19",
"offset": "1",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
[
{
"id": 1,
"other": "attributes..."
},
{
"id": 2,
"other": "attributes..."
}
]
Received response:
Request failed with error:
Request
GET
/users/{user}/beatmapsets/{type}
Response format
Array of BeatmapPlaycount when type
is most_played
;
array of BeatmapsetExtended, otherwise.
Get User Recent Activity
Returns recent activity.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/users/1/recent_activity?limit=2&offset=1" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/users/1/recent_activity"
);
const params = {
"limit": "2",
"offset": "1",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
[
{
"id": 1,
"other": "attributes..."
},
{
"id": 2,
"other": "attributes..."
}
]
Received response:
Request failed with error:
Request
GET
/users/{user}/recent_activity
Response format
Array of Event.
Get User
This endpoint returns the detail of specified user.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/users/1/osu?key=aut" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/users/1/osu"
);
const params = {
"key": "aut",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
"See User object section"
Received response:
Request failed with error:
Request
GET
/users/{user}/{mode?}
Response format
Returns UserExtended object. The following optional attributes on User are included:
- account_history
- active_tournament_banner
- badges
- beatmap_playcounts_count
- favourite_beatmapset_count
- follower_count
- graveyard_beatmapset_count
- groups
- loved_beatmapset_count
- mapping_follower_count
- monthly_playcounts
- page
- pending_beatmapset_count
- previous_usernames
- rank_highest
- rank_history
- ranked_beatmapset_count
- replays_watched_counts
- scores_best_count
- scores_first_count
- scores_recent_count
- statistics
- statistics.country_rank
- statistics.rank
- statistics.variants
- support_level
- user_achievements
Get Users
Returns list of users.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/users?ids%5B%5D=1" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/users"
);
const params = {
"ids[]": "1",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Example response (200):
{
"users": [
{
"id": 1,
"other": "attributes..."
},
{
"id": 2,
"other": "attributes..."
}
]
}
Received response:
Request failed with error:
Request
GET
/users
Response format
Field | Type | Description |
---|---|---|
users | User[] | Includes country , cover , groups , and statistics_rulesets . |
Wiki
Get Wiki Page
The wiki article or image data.
Example request:
curl --request GET \
--get "https://osu.ppy.sh/api/v2/wiki/en/Welcome" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://osu.ppy.sh/api/v2/wiki/en/Welcome"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
Received response:
Request failed with error:
Request
GET
/wiki/{locale}/{path}
Response Format
Returns WikiPage.
Using Chat
TODO: better title
Chat consists of HTTP-based and websocket-based APIs.
The Chat websocket API allows receiving updates in real-time; this requires a connection to the Notification Websocket. Sending messages is still performed through the HTTP-based API.
To begin receiving chat messages, clients should send the chat.start event across the socket connection. To stop receiving chat messages, send chat.end.
Public channels and activity timeout
To continue receiving chat messages in PUBLIC channels, clients must peridiocally request the Chat Keepalive endpoint to remain active; 30 seconds is a reasonable interval. When a client is no longer considered active, the server will stop sending messages in public channels to the client.
Private messages are not affected by this activity timeout.
Getting the user's channel list
TODO: update default parameter
To get the list of channels the user is in, make a request to Get Updates with the presence
as part of the includes
parameter.
e.g. GET
/chat/updates?includes[]=presence
Creating a channel
Make a request to the Create Channel endpoint.
Only PM
and ANNOUNCE
type channels may be created. Creating a channel will automatically join it.
Re-creating a PM
channel will simply rejoin the existing channel.
Joining a channel
Make a request to the Join Channel endpoint where channel
is the channel_id
.
A chat.channel.join event is sent over the websocket when the user joins a channel.
Leaving a channel
Make a request to the Leave Channel endpoint.
Leaving a channel will remove it from the User's channel list.
A chat.channel.part event is sent over the websocket when the user leaves a channel.
Sending messages
Channels should be joined or created before messages are sent to them. To send a message to a channel, make a request to the Send Message to Channel endpoint.
A chat.message.new event is sent over the websocket when the user receives a message.
Getting info about a channel
Make a request to the Get Channel endpoint.
Getting channel message history
Make a request to the Get Channel Messages endpoint.
Websocket
Connection
wscat -c "{notification_endpoint}"
-H "Authorization: Bearer {{token}}"
// Requires nodejs with using ESM.
// Browser WebSocket does not support header option.
import WebSocket from 'ws';
const url = 'notification-endpoint';
const token = 'some-token';
const headers = { Authorization: `Bearer ${token}`};
const ws = new WebSocket(url, [], { headers });
ws.on('message', (buffer) => console.log(buffer.toString()));
The above command will wait and display new notifications as they arrive
This endpoint allows you to receive notifications and chat events without constantly polling the server.
See Websocket Events for the structure of websocket messages.
Websocket Events
Websocket events generally have the following standard format:
{
"data": {},
"event": "some.event"
}
Field | Type | Description |
---|---|---|
event | string | Name of the event. |
data | object? | Event payload. |
logout event
User session using same authentication key has been logged out (not yet implemented for OAuth authentication). Server will disconnect session after sending this event so don't try to reconnect.
new event
Sent when a new notification is received.
Payload Format
See Notification object for notification types.
read event
Sent when a notification has been read.
TODO: ids
should be moved to data
to match other events.
Field | Type | Description |
---|---|---|
event | string | read |
ids | integer[] | id of Notifications which are read |
chat.channel.join
Broadcast to the user when the user joins a chat channel.
Payload Format
ChatChannel with current_user_attributes
, last_message_id
, users
additional attributes.
chat.channel.part
Broadcast to the user when the user leaves a chat channel.
Payload Format
ChatChannel with current_user_attributes
, last_message_id
, users
additional attributes.
chat.message.new
Sent to the user when the user receives a chat message.
Payload Format
Field | Type | Description |
---|---|---|
messages | ChatMessage[] | The messages received. |
users | User[] | The related users who sent the messages. |
Messages intented for a user are always sent even if the user does not currently have the channel open. Such messages include PM and Announcement messages.
Other messages, e.g. public channel messages are not sent if the user is no longer present in the channel.
Websocket Commands
Websocket commands have the format:
{
"event": "some.event"
}
Field | Type | Description |
---|---|---|
event | string | Name of the event. |
Commands currently do not have any payload.
chat.start
Send to the websocket to start receiving chat messages.
webSocket.send(JSON.stringify({ event: 'chat.start' }));
chat.end
Send to the websocket to stop receiving chat messages.
webSocket.send(JSON.stringify({ event: 'chat.end' }));
Object Structures
Beatmap
Represent a beatmap.
Field | Type | Description |
---|---|---|
beatmapset_id | integer | |
difficulty_rating | float | |
id | integer | |
mode | Ruleset | |
status | string | See Rank status for list of possible values. |
total_length | integer | |
user_id | integer | |
version | string |
Optional attributes:
Field | Type | Description |
---|---|---|
beatmapset | Beatmapset|BeatmapsetExtended|null | Beatmapset for Beatmap object, BeatmapsetExtended for BeatmapExtended object. null if the beatmap doesn't have associated beatmapset (e.g. deleted). |
checksum | string? | |
failtimes | Failtimes | |
max_combo | integer |
Failtimes
All fields are optional but there's always at least one field returned.
Field | Type | Description |
---|---|---|
exit | integer[]? | Array of length 100. |
fail | integer[]? | Array of length 100. |
BeatmapDifficultyAttributes
Represent beatmap difficulty attributes. Following fields are always present and then there are additional fields for different rulesets.
Field | Type |
---|---|
max_combo | integer |
star_rating | float |
osu
Field | Type |
---|---|
aim_difficulty | float |
approach_rate | float |
flashlight_difficulty | float |
overall_difficulty | float |
slider_factor | float |
speed_difficulty | float |
taiko
Field | Type |
---|---|
stamina_difficulty | float |
rhythm_difficulty | float |
colour_difficulty | float |
approach_rate | float |
great_hit_window | float |
fruits
Field | Type |
---|---|
approach_rate | float |
mania
Field | Type |
---|---|
great_hit_window | float |
score_multiplier | float |
BeatmapExtended
Represent a beatmap. This extends Beatmap with additional attributes.
Additional attributes:
Field | Type | Description |
---|---|---|
accuracy | float | |
ar | float | |
beatmapset_id | integer | |
bpm | float? | |
convert | boolean | |
count_circles | integer | |
count_sliders | integer | |
count_spinners | integer | |
cs | float | |
deleted_at | Timestamp? | |
drain | float | |
hit_length | integer | |
is_scoreable | boolean | |
last_updated | Timestamp | |
mode_int | integer | |
passcount | integer | |
playcount | integer | |
ranked | integer | See Rank status for list of possible values. |
url | string |
BeatmapPack
Represent a beatmap pack.
Field | Type | Description |
---|---|---|
author | string | |
date | Timestamp | |
name | string | |
no_diff_reduction | boolean | Whether difficulty reduction mods may be used to clear the pack. |
ruleset_id | integer | |
tag | string | The tag of the beatmap pack. Starts with a character representing the type (See the Tag column of BeatmapPackType) followed by an integer. |
url | string | The download url of the beatmap pack. |
Optional Attributes
Field | Type | Description |
---|---|---|
beatmapsets | Beatmapset[] | |
user_completion_data.beatmapset_ids | integer[] | IDs of beatmapsets completed by the user (according to the requirements of the pack) |
user_completion_data.completed | boolean | Whether all beatmapsets are completed or not |
BeatmapPackType
Available beatmap pack types:
Name | Tag | Description |
---|---|---|
standard | S | Standard |
featured | F | Featured Artist |
tournament | P | Tournament |
loved | L | Project Loved |
chart | R | Spotlights |
theme | T | Theme |
artist | A | Artist/Album |
BeatmapPlaycount
Represent the playcount of a beatmap.
Field | Type | Description |
---|---|---|
beatmap_id | integer | |
beatmap | Beatmap? | |
beatmapset | Beatmapset? | |
count | integer |
BeatmapScores
{
"scores": [],
"userScore": {}
}
Field | Type | Description |
---|---|---|
scores | Score[] | The list of top scores for the beatmap in descending order. |
userScore | BeatmapUserScore? | The score of the current user. This is not returned if the current user does not have a score. Note: will be moved to user_score in the future |
BeatmapUserScore
{
"position": 1,
"score": {}
}
Field | Type | Description |
---|---|---|
position | integer | The position of the score within the requested beatmap ranking. |
score | Score | The details of the score. |
Beatmapset
Represents a beatmapset.
Field | Type | Description |
---|---|---|
artist | string | |
artist_unicode | string | |
covers | Covers | |
creator | string | |
favourite_count | integer | |
id | integer | |
nsfw | boolean | |
offset | integer | |
play_count | integer | |
preview_url | string | |
source | string | |
status | string | |
spotlight | boolean | |
title | string | |
title_unicode | string | |
user_id | integer | |
video | boolean |
Those fields are optional.
Field | Type | Description |
---|---|---|
beatmaps | (Beatmap|BeatmapExtended)[] | |
converts | ||
current_nominations | Nomination[] | |
current_user_attributes | ||
description | ||
discussions | ||
events | ||
genre | ||
has_favourited | boolean | |
language | ||
nominations | ||
pack_tags | string[] | |
ratings | ||
recent_favourites | ||
related_users | ||
user | ||
track_id | integer |
Covers
Field | Type |
---|---|
cover | string |
cover@2x | string |
card | string |
card@2x | string |
list | string |
list@2x | string |
slimcover | string |
slimcover@2x | string |
Rank status
The possible values are denoted either as integer or string.
Integer | String |
---|---|
-2 | graveyard |
-1 | wip |
0 | pending |
1 | ranked |
2 | approved |
3 | qualified |
4 | loved |
BeatmapsetDiscussion
Represents a Beatmapset modding discussion.
Field | Type | Description |
---|---|---|
beatmap | Beatmap? | |
beatmap_id | integer? | |
beatmapset | Beatmapset? | |
beatmapset_id | integer | |
can_be_resolved | boolean | |
can_grant_kudosu | boolean | |
created_at | Timestamp | |
current_user_attributes | CurrentUserAttributes | |
deleted_at | Timestamp? | |
deleted_by_id | integer? | |
id | integer | |
kudosu_denied | boolean | |
last_post_at | Timestamp | |
message_type | MessageType | |
parent_id | integer? | |
posts | BeatmapsetDiscussionPost[]? | |
resolved | boolean | |
starting_post | BeatmapsetDiscussionPost? | |
timestamp | integer? | |
updated_at | Timestamp | |
user_id | integer |
MessageType
Name | Description |
---|---|
hype | |
mapper_note | |
praise | |
problem | |
review | |
suggestion |
BeatmapsetDiscussionPost
Represents a post in a BeatmapsetDiscussion.
Field | Type | Description |
---|---|---|
beatmapset_discussion_id | integer | |
created_at | Timestamp | |
deleted_at | Timestamp? | |
deleted_by_id | integer? | |
id | integer | |
last_editor_id | integer? | |
message | string | |
system | boolean | |
updated_at | Timestamp | |
user_id | integer |
BeatmapsetDiscussionVote
Represents a vote on a BeatmapsetDiscussion.
Field | Type | Description |
---|---|---|
beatmapset_discussion_id | integer | |
created_at | Timestamp | |
id | integer | |
score | integer | |
updated_at | Timestamp | |
user_id | integer |
BeatmapsetExtended
Represents a beatmapset. This extends Beatmapset with additional attributes.
Field | Type | Description |
---|---|---|
availability.download_disabled | boolean | |
availability.more_information | string? | |
bpm | float | |
can_be_hyped | boolean | |
deleted_at | Timestamp? | |
discussion_enabled | boolean | Deprecated, all beatmapsets now have discussion enabled. |
discussion_locked | boolean | |
hype.current | integer | |
hype.required | integer | |
is_scoreable | boolean | |
last_updated | Timestamp | |
legacy_thread_url | string? | |
nominations_summary.current | integer | |
nominations_summary.required | integer | |
ranked | integer | See Rank status for list of possible values. |
ranked_date | Timestamp? | |
source | string | |
storyboard | boolean | |
submitted_date | Timestamp? | |
tags | string |
The following attributes are always included as well:
Field |
---|
has_favourited |
Build
{
"id": 5778,
"version": "20210520.2",
"display_version": "20210520.2",
"users": 22059,
"created_at": "2021-05-20T14:28:04+00:00",
"update_stream": {
"id": 5,
"name": "stable40",
"display_name": "Stable",
"is_featured": true
}
}
Field | Type |
---|---|
created_at | Timestamp |
display_version | string |
id | integer |
update_stream | UpdateStream? |
users | integer |
version | string? |
youtube_id | string? |
Optional Attributes
The following are attributes which may be additionally included in responses. Relevant endpoints should list them if applicable.
Field | Type | Notes |
---|---|---|
changelog_entries | ChangelogEntry[] | If the build has no changelog entries, a placeholder is generated. |
versions | Versions |
Versions
Field | Type |
---|---|
next | Build? |
previous | Build? |
ChangelogEntry
{
"id": null,
"repository": null,
"github_pull_request_id": null,
"github_url": null,
"url": "https://osu.ppy.sh/home/news/2021-05-20-spring-fanart-contest-results",
"type": "fix",
"category": "Misc",
"title": "Spring is here!",
"message_html": "<div class='changelog-md'><p class=\"changelog-md__paragraph\">New seasonal backgrounds ahoy! Amazing work by the artists.</p>\n</div>",
"major": true,
"created_at": "2021-05-20T10:56:49+00:00"
}
Field | Type |
---|---|
category | string |
created_at | Timestamp? |
github_pull_request_id | integer? |
github_url | string? |
id | integer? |
major | boolean |
repository | string? |
title | string? |
type | string |
url | string? |
Optional Attributes
The following are attributes which may be additionally included in responses. Relevant endpoints should list them if applicable.
Field | Type | Notes |
---|---|---|
github_user | GithubUser | If the changelog entry has no GitHub user, a placeholder is generated. |
message | string? | Entry message in Markdown format. Embedded HTML is allowed. |
message_html | string? | Entry message in HTML format. |
ChatChannel
{
"channel_id": 1337,
"current_user_attributes": {
"can_message": true,
"can_message_error": null,
"last_read_id": 9150005005,
},
"name": "test channel",
"description": "wheeeee",
"icon": "/images/layout/avatar-guest@2x.png",
"type": "GROUP",
"last_read_id": 9150005005,
"last_message_id": 9150005005,
"moderated": false,
"users": [
2,
3,
102
]
}
Represents an individual chat "channel" in the game.
Field | Type | Description |
---|---|---|
channel_id | integer | |
name | string | |
description | string? | |
icon | string? | display icon for the channel |
type | ChannelType | type of channel |
message_length_limit | integer | |
moderated | boolean | user can't send message when the value is true |
uuid | string? | value from requests that is relayed back to the sender. |
Optional attributes:
Field | Type | Description |
---|---|---|
current_user_attributes | CurrentUserAttributes? | only present on some responses |
last_read_id | integer? | Deprecated; use current_user_attributes.last_read_id . |
last_message_id | integer? | message_id of last known message (only returned in presence responses) |
recent_messages | ChatMessage[]? | Deprecated; up to 50 most recent messages |
users | integer[]? | array of user_id that are in the channel (not included for PUBLIC channels) |
ChannelType
Type | Permission Check for Joining/Messaging |
---|---|
PUBLIC | |
PRIVATE | is player in the allowed groups? (channel.allowed_groups) |
MULTIPLAYER | is player currently in the mp game? |
SPECTATOR | |
TEMPORARY | deprecated |
PM | see below (user_channels) |
GROUP | is player in channel? (user_channels) |
ANNOUNCE | is user in the announce group? |
For PMs, two factors are taken into account:
- Is either user blocking the other? If so, deny.
- Does the target only accept PMs from friends? Is the current user a friend? If not, deny.
ChatMessage
{
"channel_id": 5,
"content": "i am a lazerface",
"is_action": false,
"message_id": 9150005004,
"sender_id": 2,
"timestamp": "2018-07-06T06:33:34+00:00",
"type": "plain",
"uuid": "some-uuid-string",
"sender": {
"id": 2,
"username": "peppy",
"profile_colour": "#3366FF",
"avatar_url": "https://a.ppy.sh/2?1519081077.png",
"country_code": "AU",
"is_active": true,
"is_bot": false,
"is_online": true,
"is_supporter": true
}
}
Represents an individual Message within a ChatChannel.
Field | Type | Description |
---|---|---|
channel_id | integer | channel_id of where the message was sent |
content | string | message content |
is_action | boolean | was this an action? i.e. /me dances |
message_id | integer | unique identifier for message |
sender_id | integer | user_id of the sender |
timestamp | Timestamp | when the message was sent, ISO-8601 |
type | string | type of message; 'action', 'markdown' or 'plain' |
uuid | string? | message identifier originally sent by client |
Optional attributes:
Field | Type | Description |
---|---|---|
sender | User | embedded User object to save additional api lookups |
Comment
{
"commentable_id": 407,
"commentable_type": "news_post",
"created_at": "2019-09-05T06:31:20+00:00",
"deleted_at": null,
"edited_at": null,
"edited_by_id": null,
"id": 276,
"legacy_name": null,
"message": "yes",
"message_html": "<div class='osu-md-default'><p class=\"osu-md-default__paragraph\">yes</p>\n</div>",
"parent_id": null,
"pinned": true,
"replies_count": 0,
"updated_at": "2019-09-05T06:31:20+00:00",
"user_id": 1,
"votes_count": 0
}
Represents a single comment.
Field | Type | Description |
---|---|---|
commentable_id | integer | ID of the object the comment is attached to |
commentable_type | string | type of object the comment is attached to |
created_at | Timestamp | ISO 8601 date |
deleted_at | Timestamp? | ISO 8601 date if the comment was deleted; null, otherwise |
edited_at | Timestamp? | ISO 8601 date if the comment was edited; null, otherwise |
edited_by_id | integer? | user id of the user that edited the post; null, otherwise |
id | integer | the ID of the comment |
legacy_name | string? | username displayed on legacy comments |
message | string? | markdown of the comment's content |
message_html | string? | html version of the comment's content |
parent_id | integer? | ID of the comment's parent |
pinned | boolean | Pin status of the comment |
replies_count | integer | Number of replies to the comment |
updated_at | Timestamp | ISO 8601 date |
user_id | integer | user ID of the poster |
votes_count | integer | Number of votes |
CommentBundle
{
"commentable_meta": [
{
"id": 407,
"title": "Clicking circles linked to increased performance",
"type": "news_post",
"url": "https://osu.ppy.sh/home"
}
],
"comments": [
{
"commentable_id": 407,
"commentable_type": "news_post",
"created_at": "2019-09-05T06:31:20+00:00",
"deleted_at": null,
"edited_at": null,
"edited_by_id": null,
"id": 276,
"legacy_name": null,
"message": "yes",
"message_html": "<div class='osu-md-default'><p class=\"osu-md-default__paragraph\">yes</p>\n</div>",
"parent_id": null,
"replies_count": 0,
"updated_at": "2019-09-05T06:31:20+00:00",
"user_id": 1,
"votes_count": 1337
},
{
"commentable_id": 407,
"commentable_type": "news_post",
"created_at": "2019-09-05T07:31:20+00:00",
"deleted_at": null,
"edited_at": null,
"edited_by_id": null,
"id": 277,
"legacy_name": null,
"message": "absolutely",
"message_html": "<div class='osu-md-default'><p class=\"osu-md-default__paragraph\">absolutely</p>\n</div>",
"parent_id": null,
"replies_count": 0,
"updated_at": "2019-09-05T07:31:20+00:00",
"user_id": 2,
"votes_count": 1337
}
],
"has_more": true,
"has_more_id": 276,
"included_comments": [],
"pinned_comments": [],
"sort": "new",
"user_follow": false,
"user_votes": [277],
"users": [
{
"avatar_url": "https://a.ppy.sh/2?1519081077.png",
"country_code": "AU",
"default_group": "pippi",
"id": 1,
"is_active": true,
"is_bot": false,
"is_online": true,
"is_supporter": true,
"last_visit": "2025-09-05T08:35:00+00:00",
"pm_friends_only": false,
"profile_colour": null,
"username": "pippi"
},
{
"avatar_url": "https://a.ppy.sh/2?1519081077.png",
"country_code": "AU",
"default_group": "yuzu",
"id": 2,
"is_active": true,
"is_bot": false,
"is_online": false,
"is_supporter": true,
"last_visit": "2025-09-04T09:28:00+00:00",
"pm_friends_only": false,
"profile_colour": null,
"username": "yuzu"
}
]
}
Comments and related data.
Field | Type | Description |
---|---|---|
commentable_meta | CommentableMeta[] | ID of the object the comment is attached to |
comments | Comment[] | Array of comments ordered according to sort ; |
cursor | Cursor | |
has_more | boolean | If there are more comments or replies available |
has_more_id | integer? | |
included_comments | Comment[] | Related comments; e.g. parent comments and nested replies |
pinned_comments | Comment[]? | Pinned comments |
sort | string | one of the CommentSort types |
top_level_count | integer? | Number of comments at the top level. Not returned for replies. |
total | integer? | Total number of comments. Not retuned for replies. |
user_follow | boolean | is the current user watching the comment thread? |
user_votes | integer[] | IDs of the comments in the bundle the current user has upvoted |
users | User[] | array of users related to the comments |
CommentSort
Available sort types are new
, old
, top
.
Type | Sort Fields |
---|---|
new | created_at (descending), id (descending) |
old | created_at (ascending), id (ascending) |
top | votes_count (descending), created_at (descending), id (descending) |
Building cursor for comments listing
The returned response will be for comments after the specified sort fields.
For example, use last loaded comment for the fields value to load more comments. Also make sure to use same sort
and parent_id
values.
CommentableMeta
{
"id": 407,
"title": "Clicking circles linked to increased performance",
"type": "news_post",
"url": "https://osu.ppy.sh/home/"
}
Metadata of the object that a comment is attached to.
If object is available:
Field | Type | Description |
---|---|---|
current_user_attributes | CurrentUserAttributes | |
id | integer | the ID of the object |
owner_id | integer? | User ID which owns the object |
owner_title | string? | Object owner type, used for display (MAPPER for beatmapset) |
title | string | display title |
type | string | the type of the object |
url | string | url of the object |
Otherwise if object has been deleted:
Field | Type | Description |
---|---|---|
title | string | display title |
CurrentUserAttributes
Field | Type | Description |
---|---|---|
can_new_comment_reason | string? | null if current user can comment on it, reason sentence otherwise |
CurrentUserAttributes
An object listing various related permissions and states for the current user, related to the object it is attached to.
BeatmapsetDiscussionPermissions
TODO: needs a better name.
Name | Description |
---|---|
can_destroy | Can delete the discussion. |
can_reopen | Can reopen the discussion. |
can_moderate_kudosu | Can allow or deny kudosu. |
can_resolve | Can resolve the discussion. |
vote_score | Current vote given to the discussion. |
ChatChannelUserAttributes
Name | Type | Description |
---|---|---|
can_message | boolean | Can send messages to this channel. |
can_message_error | string? | Reason messages cannot be sent to this channel |
last_read_id | integer | message_id of last message read. |
Cursor
{
"_id": 5,
"_score": 36.234
}
// query string: cursor[_id]=5&cursor[_score]=36.234
{
"page": 2,
}
// query string: cursor[page]=2
A structure included in some API responses containing the parameters to get the next set of results.
The values of the cursor should be provided to next request of the same endpoint to get the next set of results.
If there are no more results available, a cursor with a value of null
is returned: "cursor": null
.
Note that sort
option should also be specified for it to work.
CursorString
A string value included in some API responses containing the parameter to get the next set of results.
Its value will be null (or not defined) if there are no more results available.
Note that all parameters used in previous request also need to be passed.
Event
The object has different attributes depending on its type
. Following are attributes available to all types.
Field | Type | Description |
---|---|---|
created_at | Timestamp | |
id | integer | |
type | Event.Type |
Additional objects
Beatmap
Field | Type |
---|---|
title | string |
url | string |
Beatmapset
Field | Type |
---|---|
title | string |
url | string |
User
Field | Type | Description |
---|---|---|
username | string | |
url | string | |
previousUsername | string? | Only for usernameChange event. |
Available Types
achievement
When user obtained an achievement.
Field | Type |
---|---|
achievement | Achievement |
user | Event.User |
beatmapPlaycount
When a beatmap has been played for certain number of times.
Field | Type |
---|---|
beatmap | Event.Beatmap |
count | integer |
beatmapsetApprove
When a beatmapset changes state.
Field | Type | Description |
---|---|---|
approval | string | ranked , approved , qualified , loved . |
beatmapset | Event.Beatmapset | |
user | Event.User | Beatmapset owner. |
beatmapsetDelete
When a beatmapset is deleted.
Field | Type |
---|---|
beatmapset | Event.Beatmapset |
beatmapsetRevive
When a beatmapset in graveyard state is updated.
Field | Type | Description |
---|---|---|
beatmapset | Event.Beatmapset | |
user | Event.User | Beatmapset owner. |
beatmapsetUpdate
When a beatmapset is updated.
Field | Type | Description |
---|---|---|
beatmapset | Event.Beatmapset | |
user | Event.User | Beatmapset owner. |
beatmapsetUpload
When a new beatmapset is uploaded.
Field | Type | Description |
---|---|---|
beatmapset | Event.Beatmapset | |
user | Event.User | Beatmapset owner. |
rank
When a user achieves a certain rank on a beatmap.
Field | Type | Description |
---|---|---|
scoreRank | string | (FIXME) |
rank | integer | |
mode | Ruleset | |
beatmap | Event.Beatmap | |
user | Event.User |
rankLost
When a user loses first place to another user.
Field | Type |
---|---|
mode | Ruleset |
beatmap | Event.Beatmap |
user | Event.User |
userSupportAgain
When a user supports osu! for the second and onwards.
Field | Type |
---|---|
user | Event.User |
userSupportFirst
When a user becomes a supporter for the first time.
Field | Type |
---|---|
user | Event.User |
userSupportGift
When a user is gifted a supporter tag by another user.
Field | Type | Description |
---|---|---|
user | Event.User | Recipient user. |
usernameChange
When a user changes their username.
Field | Type | Description |
---|---|---|
user | Event.User | Includes previousUsername . |
Forum Post
Field | Type | Description |
---|---|---|
created_at | Timestamp | |
deleted_at | Timestamp? | |
edited_at | Timestamp? | |
edited_by_id | integer? | |
forum_id | integer | |
id | integer | |
topic_id | integer | |
user_id | integer |
Following fields are optional.
Field | Type | Description |
---|---|---|
body.html | string | Post content in HTML format. |
body.raw | string | Post content in BBCode format. |
Forum Topic
Field | Type |
---|---|
created_at | Timestamp |
deleted_at | Timestamp? |
first_post_id | integer |
forum_id | integer |
id | integer |
is_locked | boolean |
last_post_id | integer |
poll | Poll? |
post_count | integer |
title | string |
type | normal | sticky | announcement |
updated_at | Timestamp |
user_id | integer |
Poll
Field | Type |
---|---|
allow_vote_change | boolean |
ended_at | Timestamp? |
hide_incomplete_results | boolean |
last_vote_at | Timestamp? |
max_votes | integer |
options | PollOption[] |
started_at | Timestamp |
title.bbcode | string |
title.html | string |
total_vote_count | integer |
PollOption
Field | Type | Notes |
---|---|---|
id | integer | Unique only per-topic. |
text.bbcode | string | |
text.html | string | |
vote_count | integer? | Not present if the poll is incomplete and results are hidden. |
GithubUser
{
"display_name": "bdach",
"github_url": "https://github.com/bdach",
"github_username": "bdach",
"id": 218,
"osu_username": null,
"user_id": null,
"user_url": null
}
Field | Type |
---|---|
display_name | string |
github_url | string? |
github_username | string? |
id | integer? |
osu_username | string? |
user_id | integer? |
user_url | string? |
Group
This object is not returned by any endpoints yet. It is here only as a reference for UserGroup.
Field | Type | Description |
---|---|---|
colour | string? | |
has_listing | boolean | Whether this group displays a listing at /groups/{id} . |
has_playmodes | boolean | Whether this group associates Rulesets with users' memberships. |
id | integer | |
identifier | string | Unique string to identify the group. |
is_probationary | boolean | Whether members of this group are considered probationary. |
name | string | |
short_name | string | Short name of the group for display. |
Optional Attributes
The following are attributes which may be additionally included in responses. Relevant endpoints should list them if applicable.
Field | Type |
---|---|
description | Description? |
Description
Field | Type |
---|---|
html | string |
markdown | string |
KudosuHistory
Field | Type | Description |
---|---|---|
id | integer | |
action | string | One of give , vote.give , reset , vote.reset , revoke , or vote.revoke . |
amount | integer | |
model | string | Object type which the exchange happened on (forum_post , etc). |
created_at | Timestamp | |
giver | Giver? | Simple detail of the user who started the exchange. |
post | Post | Simple detail of the object for display. |
Giver
Field | Type |
---|---|
url | string |
username | string |
Post
Field | Type | Description |
---|---|---|
url | string? | Url of the object. |
title | string | Title of the object. It'll be "[deleted beatmap]" for deleted beatmaps. |
Match
Field | Type | Description |
---|---|---|
id | integer | |
start_time | Timestamp | |
end_time | Timestamp? | |
name | string |
MatchEvent
Field | Type | Description |
---|---|---|
id | integer | |
detail.type | MatchEventType | |
detail.text | string | |
timestamp | Timestamp | |
user_id | integer? |
Optional Attributes
Field | Type | Description |
---|---|---|
game | MatchGame | The game associated with the MatchEvent |
MatchEventType
Name | Description |
---|---|
host-changed | |
match-created | |
match-disbanded | |
other | |
player-joined | |
player-kicked | |
player-left |
MatchGame
Field | Type | Description |
---|---|---|
id | integer | |
beatmap | Beatmap | Includes beatmapset . |
beatmap_id | integer | |
start_time | Timestamp | |
end_time | Timestamp? | |
mode | Ruleset | |
mode_int | integer | |
mods | string[] | Mod combination used for this match game as an array of mod acronyms. |
scores | Score[] | List of scores set by each player for this match game. |
scoring_type | string | accuracy , combo , score , scorev2 . |
team_type | string | head-to-head , tag-coop , tag-team-vs , team-vs . |
MultiplayerScores
An object which contains scores and related data for fetching next page of the result.
Field | Type | Description |
---|---|---|
cursor_string | CursorString | To be used to fetch the next page. |
params | object | Parameters used for score listing. |
scores | Score[] | |
total | integer? | Index only. Total scores of the specified playlist item. |
user_score | Score? | Index only. Score of the accessing user if exists. |
MultiplayerScoresAround
Field | Type | Description |
---|---|---|
higher | MultiplayerScores | |
lower | MultiplayerScores |
MultiplayerScoresCursor
An object which contains pointer for fetching further results of a request. It depends on the sort option.
Field | Type | Description |
---|---|---|
score_id | integer | Last score id of current result (score_asc , score_desc ). |
total_score | integer | Last score's total score of current result (score_asc , score_desc ). |
MultiplayerScoresSort
Sort option for multiplayer scores index.
Name | Description |
---|---|
score_asc | Sort by scores, ascending. |
score_desc | Sort by scores, descending. |
NewsPost
Field | Type | Description |
---|---|---|
author | string | |
edit_url | string | Link to the file view on GitHub. |
first_image | string? | Link to the first image in the document. |
id | integer | |
published_at | Timestamp | |
slug | string | Filename without the extension, used in URLs. |
title | string | |
updated_at | Timestamp |
Optional Attributes
Field | Type | Description |
---|---|---|
content | string | HTML post content. |
navigation | Navigation | Navigation metadata. |
preview | string | First paragraph of content with HTML markup stripped. |
Navigation
Field | Type | Description |
---|---|---|
newer | NewsPost? | Next post. |
older | NewsPost? | Previous post. |
Nomination
Field | Type |
---|---|
beatmapset_id | integer |
rulesets | Ruleset[] |
reset | boolean |
user_id | integer |
Notification
{
"id": 1,
"name": "channel_message",
"created_at": "2019-04-24T07:12:43+00:00",
"object_type": "channel",
"object_id": 1,
"source_user_id": 1,
"is_read": true,
"details": {
"username": "someone",
...
}
}
Represents a notification object.
Field | Type | Description |
---|---|---|
id | integer | |
name | string | Name of the event |
created_at | Timestamp | ISO 8601 date |
object_type | string | |
object_id | integer | |
source_user_id | integer? | |
is_read | boolean | |
details | object | message_id of last known message (only returned in presence responses) |
Event Names
Name | Description |
---|---|
beatmapset_discussion_lock | Discussion on beatmap has been locked |
beatmapset_discussion_post_new | New discussion post on beatmap |
beatmapset_discussion_unlock | Discussion on beatmap has been unlocked |
beatmapset_disqualify | Beatmap was disqualified |
beatmapset_love | Beatmap was promoted to loved |
beatmapset_nominate | Beatmap was nominated |
beatmapset_qualify | Beatmap has gained enough nominations and entered the ranking queue |
beatmapset_remove_from_loved | Beatmap was removed from Loved |
beatmapset_reset_nominations | Nomination of beatmap was reset |
channel_message | Someone sent chat message |
forum_topic_reply | Someone replied on forum topic |
beatmapset_discussion_lock
Field | Type | Description |
---|---|---|
object_id | integer | Beatmapset id |
object_type | string | beatmapset |
source_user_id | integer | User who locked discussion |
Details object:
Field | Type | Description |
---|---|---|
cover_url | string | Beatmap cover |
title | string | Beatmap title |
username | string | Username of source_user_id |
beatmapset_discussion_post_new
Field | Type | Description |
---|---|---|
object_id | integer | Beatmapset id |
object_type | string | beatmapset |
source_user_id | integer | Poster of the discussion |
Details object:
Field | Type | Description |
---|---|---|
title | string | Beatmap title |
cover_url | string | Beatmap cover |
discussion_id | integer | |
post_id | integer | |
beatmap_id | integer? | null if posted to general all |
username | string | Username of source_user_id |
beatmapset_discussion_unlock
Field | Type | Description |
---|---|---|
object_id | integer | Beatmapset id |
object_type | string | beatmapset |
source_user_id | integer | User who unlocked discussion |
Details object:
Field | Type | Description |
---|---|---|
title | string | Beatmap title |
cover_url | string | Beatmap cover |
username | string | Username of source_user_id |
beatmapset_disqualify
Field | Type | Description |
---|---|---|
object_id | integer | Beatmapset id |
object_type | string | beatmapset |
source_user_id | integer | User who disqualified beatmapset |
Details object:
Field | Type | Description |
---|---|---|
title | string | Beatmap title |
cover_url | string | Beatmap cover |
username | string | Username of source_user_id |
beatmapset_love
Field | Type | Description |
---|---|---|
object_id | integer | Beatmapset id |
object_type | string | beatmapset |
source_user_id | integer | User who promoted beatmapset to loved |
Details object:
Field | Type | Description |
---|---|---|
title | string | Beatmap title |
cover_url | string | Beatmap cover |
username | string | Username of source_user_id |
beatmapset_nominate
Field | Type | Description |
---|---|---|
object_id | integer | Beatmapset id |
object_type | string | beatmapset |
source_user_id | integer | User who nominated beatmapset |
Details object:
Field | Type | Description |
---|---|---|
title | string | Beatmap title |
cover_url | string | Beatmap cover |
username | string | Username of source_user_id |
beatmapset_qualify
Field | Type | Description |
---|---|---|
object_id | integer | Beatmapset id |
object_type | string | beatmapset |
source_user_id | integer | User whom beatmapset nomination triggered qualification |
Details object:
Field | Type | Description |
---|---|---|
title | string | Beatmap title |
cover_url | string | Beatmap cover |
username | string | Username of source_user_id |
beatmapset_remove_from_loved
Field | Type | Description |
---|---|---|
object_id | integer | Beatmapset id |
object_type | string | beatmapset |
source_user_id | integer | User who removed beatmapset from Loved |
Details object:
Field | Type | Description |
---|---|---|
title | string | Beatmap title |
cover_url | string | Beatmap cover |
username | string | Username of source_user_id |
beatmapset_reset_nominations
Field | Type | Description |
---|---|---|
object_id | integer | Beatmapset id |
object_type | string | beatmapset |
source_user_id | integer | User who triggered nomination reset |
Details object:
Field | Type | Description |
---|---|---|
title | string | Beatmap title |
cover_url | string | Beatmap cover |
username | string | Username of source_user_id |
channel_message
Field | Type | Description |
---|---|---|
object_id | integer | Channel id |
object_type | string | channel |
source_user_id | integer | User who posted message |
Details object:
Field | Type | Description |
---|---|---|
title | string | Up to 36 characters of the message (ends with ... when exceeding 36 characters) |
cover_url | string | Avatar of source_user_id |
username | string | Username of source_user_id |
forum_topic_reply
Field | Type | Description |
---|---|---|
object_id | integer | Topic id |
object_type | string | forum_topic |
source_user_id | integer | User who posted message |
Details object:
Field | Type | Description |
---|---|---|
title | string | Title of the replied topic |
cover_url | string | Topic cover |
post_id | integer | Post id |
username | string? | Username of source_user_id |
RankingType
Available ranking types:
Name | Description |
---|---|
charts | Spotlight |
country | Country |
performance | Performance |
score | Score |
Rankings
{
"cursor": {
},
"ranking": [
{
"grade_counts": {
"a": 3,
"s": 2,
"sh": 6,
"ss": 2,
"ssh": 3
},
"hit_accuracy": 92.19,
"is_ranked": true,
"level": {
"current": 30,
"progress": 0
},
"maximum_combo": 3948,
"play_count": 228050,
"play_time": null,
"pp": 990,
"global_rank": 87468,
"ranked_score": 1502995536,
"replays_watched_by_others": 0,
"total_hits": 5856573,
"total_score": 2104193750,
"user": {
"avatar_url": "/images/layout/avatar-guest.png",
"country": {
"code": "GF",
"name": "French Guiana"
},
"country_code": "GF",
"cover": {
"custom_url": null,
"id": "3",
"url": "http://osuweb.test/images/headers/profile-covers/c3.jpg"
},
"default_group": "default",
"id": 458402,
"is_active": false,
"is_bot": false,
"is_online": false,
"is_supporter": true,
"last_visit": "2017-02-22T11:07:10+00:00",
"pm_friends_only": false,
"profile_colour": null,
"username": "serdman"
}
}
],
"total": 100
}
Field | Type | Description |
---|---|---|
beatmapsets | BeatmapsetExtended[]? | The list of beatmaps in the requested spotlight for the given mode ; only available if type is charts |
cursor | Cursor | A cursor |
ranking | UserStatistics[] | User statistics for the requested ruleset in order of descending rank. Includesuser , user.country , and user.cover .Includes rank_change_since_30_days if the ranking type is performance with no additional filters applied. |
spotlight | Spotlight? | Spotlight details; only available if type is charts |
total | integer | An approximate count of ranks available |
Ruleset
Available rulesets:
Name | Description |
---|---|
fruits | osu!catch |
mania | osu!mania |
osu | osu!standard |
taiko | osu!taiko |
Score
The following is the format returned when API v2 version header is 20220705 or higher. Exceptions apply (f.ex. doesn't apply for legacy match score).
Field | Type | Description |
---|---|---|
accuracy | float | |
beatmap_id | integer | |
best_id | integer? | |
build_id | integer? | |
classic_total_score | integer | Only for solo_score type |
ended_at | Timestamp | |
has_replay | boolean | |
id | integer | |
is_perfect_combo | boolean | |
legacy_perfect | boolean | |
legacy_score_id | integer? | |
legacy_total_score | integer | |
max_combo | integer | |
maximum_statistics | ScoreStatistics | |
mods | Mod[] | |
passed | boolean | |
playlist_item_id | integer | Only for multiplayer score |
pp | float? | |
preserve | boolean | Whether or not the score may eventually be deleted. Only for solo_score type |
processed | boolean | Only for solo_score type |
rank | string | |
ranked | boolean | Whether or not the score can have pp. Only for solo_score type |
room_id | integer | Only for multiplayer score |
ruleset_id | integer | |
started_at | Timestamp? | |
statistics | ScoreStatistics | |
total_score | integer | |
type | string | |
user_id | integer |
Initial version
The following is the format returned when API v2 version header is 20220704 or lower.
Field | Type | Description |
---|---|---|
id | ||
best_id | ||
user_id | ||
accuracy | ||
mods | ||
score | ||
max_combo | ||
perfect | ||
statistics.count_50 | ||
statistics.count_100 | ||
statistics.count_300 | ||
statistics.count_geki | ||
statistics.count_katu | ||
statistics.count_miss | ||
passed | boolean | |
pp | ||
rank | ||
created_at | ||
mode | ||
mode_int | ||
replay |
Optional attributes
Field | Type | Description |
---|---|---|
beatmap | ||
beatmapset | ||
current_user_attributes | integer? | |
match | Only for legacy match score | |
position | integer? | Only for multiplayer score |
rank_country | ||
rank_global | ||
scores_around | MultiplayerScoresAround? | Scores around the specified score. Only for multiplayer score |
user | ||
weight |
Spotlight
{
"end_date": "2019-03-22T00:00:00+00:00",
"id": 1,
"mode_specific": false,
"name": "Best spinning circles 2019",
"start_date": "2019-02-22T00:00:00+00:00",
"type": "yearly",
}
The details of a spotlight.
Field | Type | Description |
---|---|---|
end_date | Timestamp | The end date of the spotlight. |
id | integer | The ID of this spotlight. |
mode_specific | boolean | If the spotlight has different mades specific to each Ruleset. |
participant_count | integer? | The number of users participating in this spotlight. This is only shown when viewing a single spotlight. |
name | string | The name of the spotlight. |
start_date | Timestamp | The starting date of the spotlight. |
type | string | The type of spotlight. |
Spotlights
{
"spotlights": [
{
"end_date": "2019-03-22T00:00:00+00:00",
"id": 1,
"mode_specific": false,
"name": "Best spinning circles 2019",
"start_date": "2019-02-22T00:00:00+00:00",
"type": "yearly",
},
{
"end_date": "2019-03-22T00:00:00+00:00",
"id": 2,
"mode_specific": true,
"name": "Ultimate fruit collector February 2019",
"start_date": "2019-02-22T00:00:00+00:00",
"type": "monthly",
}
],
}
Field | Type | Description |
---|---|---|
spotlights | Spotlight[] | An array of spotlights |
Timestamp
"2020-01-01T00:00:00+00:00"
Timestamp string in ISO 8601 format.
UpdateStream
{
"id": 7,
"name": "lazer",
"display_name": "Lazer",
"is_featured": false
}
Field | Type |
---|---|
display_name | string? |
id | integer |
is_featured | boolean |
name | string |
Optional Attributes
The following are attributes which may be additionally included in responses. Relevant endpoints should list them if applicable.
Field | Type |
---|---|
latest_build | Build? |
user_count | integer |
User
{
"id": 2,
"username": "peppy",
"profile_colour": "#3366FF",
"avatar_url": "https://a.ppy.sh/2?1519081077.png",
"country_code": "AU",
"is_active": true,
"is_bot": false,
"is_deleted": false,
"is_online": true,
"is_supporter": true
}
Represents a user.
Field | Type | Description |
---|---|---|
avatar_url | string | url of user's avatar |
country_code | string | two-letter code representing user's country |
default_group | string? | Identifier of the default Group the user belongs to. |
id | integer | unique identifier for user |
is_active | boolean | has this account been active in the last x months? |
is_bot | boolean | is this a bot account? |
is_deleted | boolean | |
is_online | boolean | is the user currently online? (either on lazer or the new website) |
is_supporter | boolean | does this user have supporter? |
last_visit | Timestamp? | last access time. null if the user hides online presence |
pm_friends_only | boolean | whether or not the user allows PM from other than friends |
profile_colour | string? | colour of username/profile highlight, hex code (e.g. #333333 ) |
username | string | user's display name |
Optional attributes
Following are attributes which may be additionally included in the response. Relevant endpoints should list them if applicable.
Field | Type | Notes |
---|---|---|
account_history | User.UserAccountHistory[] | |
active_tournament_banner | User.ProfileBanner? | Deprecated, use active_tournament_banners instead. |
active_tournament_banners | User.ProfileBanner[] | |
badges | User.UserBadge[] | |
beatmap_playcounts_count | integer | |
blocks | ||
country | ||
cover | ||
favourite_beatmapset_count | integer | |
follow_user_mapping | integer[] | |
follower_count | integer | |
friends | ||
graveyard_beatmapset_count | integer | |
groups | UserGroup[] | |
guest_beatmapset_count | integer | |
is_restricted | boolean? | |
kudosu | User.Kudosu | |
loved_beatmapset_count | integer | |
mapping_follower_count | integer | |
monthly_playcounts | UserMonthlyPlaycount[] | |
page | ||
pending_beatmapset_count | ||
previous_usernames | ||
rank_highest | User.RankHighest? | |
rank_history | ||
ranked_beatmapset_count | ||
replays_watched_counts | ||
scores_best_count | integer | |
scores_first_count | integer | |
scores_recent_count | integer | |
session_verified | boolean | |
statistics | UserStatistics | |
statistics_rulesets | UserStatisticsRulesets | |
support_level | ||
unread_pm_count | ||
user_achievements | ||
user_preferences |
Kudosu
Field | Type |
---|---|
available | integer |
total | integer |
ProfileBanner
Field | Type | Description |
---|---|---|
id | integer | |
tournament_id | integer | |
image | string? | |
image@2x | string? |
ProfilePage
Section |
---|
me |
recent_activity |
beatmaps |
historical |
kudosu |
top_ranks |
medals |
RankHighest
Field | Type |
---|---|
rank | integer |
updated_at | Timestamp |
UserAccountHistory
Field | Type | Description |
---|---|---|
description | string? | |
id | integer | |
length | integer | In seconds. |
permanent | boolean | |
timestamp | Timestamp | |
type | string | note , restriction , or silence . |
UserBadge
Field | Type | Description |
---|---|---|
awarded_at | Timestamp | |
description | string | |
image@2x_url | string | |
image_url | string | |
url | string |
UserExtended
{
"avatar_url": "https://a.ppy.sh/1?1501234567.jpeg",
"country_code": "AU",
"default_group": "default",
"id": 1,
"is_active": true,
"is_bot": false,
"is_deleted": false,
"is_online": false,
"is_supporter": true,
"last_visit": "2020-01-01T00:00:00+00:00",
"pm_friends_only": false,
"profile_colour": "#000000",
"username": "osuuser",
"cover_url": "https://assets.ppy.sh/user-profile-covers/1/0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef.jpeg",
"discord": "osuuser#1337",
"has_supported": true,
"interests": null,
"join_date": "2010-01-01T00:00:00+00:00",
"kudosu": {
"total": 20,
"available": 10
},
"location": null,
"max_blocks": 50,
"max_friends": 500,
"occupation": null,
"playmode": "osu",
"playstyle": [
"mouse",
"touch"
],
"post_count": 100,
"profile_hue": 42,
"profile_order": [
"me",
"recent_activity",
"beatmaps",
"historical",
"kudosu",
"top_ranks",
"medals"
],
"title": null,
"twitter": "osuuser",
"website": "https://osu.ppy.sh",
"country": {
"code": "AU",
"name": "Australia"
},
"cover": {
"custom_url": "https://assets.ppy.sh/user-profile-covers/1/0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef.jpeg",
"url": "https://assets.ppy.sh/user-profile-covers/1/0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef.jpeg",
"id": null
},
"is_restricted": false,
"account_history": [],
"active_tournament_banner": null,
"badges": [
{
"awarded_at": "2015-01-01T00:00:00+00:00",
"description": "Test badge",
"image@2x_url": "https://assets.ppy.sh/profile-badges/test@2x.png",
"image_url": "https://assets.ppy.sh/profile-badges/test.png",
"url": ""
}
],
"favourite_beatmapset_count": 10,
"follower_count": 100,
"graveyard_beatmapset_count": 10,
"groups": [
{
"id": 1,
"identifier": "gmt",
"name": "gmt",
"short_name": "GMT",
"description": "",
"colour": "#FF0000"
}
],
"loved_beatmapset_count": 0,
"monthly_playcounts": [
{
"start_date": "2019-11-01",
"count": 100
},
{
"start_date": "2019-12-01",
"count": 150
},
{
"start_date": "2020-01-01",
"count": 20
}
],
"page": {
"html": "<div class='bbcode bbcode--profile-page'><center>Hello</center></div>",
"raw": "[centre]Hello[/centre]"
},
"pending_beatmapset_count": 0,
"previous_usernames": [],
"ranked_beatmapset_count": 10,
"replays_watched_counts": [
{
"start_date": "2019-11-01",
"count": 10
},
{
"start_date": "2019-12-01",
"count": 12
},
{
"start_date": "2020-01-01",
"count": 1
}
],
"scores_first_count": 0,
"statistics": {
"level": {
"current": 60,
"progress": 55
},
"pp": 100,
"global_rank": 2000,
"ranked_score": 2000000,
"hit_accuracy": 90.5,
"play_count": 1000,
"play_time": 100000,
"total_score": 3000000,
"total_hits": 6000,
"maximum_combo": 500,
"replays_watched_by_others": 270,
"is_ranked": true,
"grade_counts": {
"ss": 10,
"ssh": 5,
"s": 50,
"sh": 0,
"a": 40
},
"rank": {
"global": 15000,
"country": 30000
}
},
"support_level": 3,
"user_achievements": [
{
"achieved_at": "2020-01-01T00:00:00+00:00",
"achievement_id": 1
}
],
"rank_history": {
"mode": "osu",
"data": [
16200,
15500,
15000
]
}
}
Represents a user. Extends User object with additional attributes.
Field | Type | Description |
---|---|---|
cover_url | string | url of profile cover. Deprecated, use cover.url instead. |
discord | string? | |
has_supported | boolean | Whether or not the user has a current or past osu!supporter tag. |
interests | string? | |
join_date | Timestamp | |
location | string? | |
max_blocks | integer | maximum number of users allowed to be blocked |
max_friends | integer | maximum number of friends allowed to be added |
occupation | string? | |
playmode | Ruleset | |
playstyle | string[] | Device choices of the user. |
post_count | integer | Number of forum posts |
profile_hue | integer? | Custom colour hue in HSL degrees (0–359). |
profile_order | ProfilePage[] | ordered array of sections in user profile page |
title | string? | user-specific title |
title_url | string? | |
string? | ||
website | string? |
In addition, the following optional attributes on User are included:
- country
- cover
- is_restricted (present only if this is the currently authenticated user)
- kudosu
UserGroup
Describes a Group membership of a User. It contains all of the attributes of the Group, in addition to what is listed here.
Field | Type | Description |
---|---|---|
playmodes | string[]? | Rulesets associated with this membership (null if has_playmodes is unset). |
UserSilence
{
"id": 1,
"user_id": 5
}
A record indicating a User was silenced.
Field | Type | Description |
---|---|---|
id | integer | id of this object. |
user_id | integer | id of the User that was silenced |
UserStatistics
{
"count_100": 0,
"count_300": 0,
"count_50": 0,
"count_miss": 0,
"grade_counts": {
"a": 3,
"s": 2,
"sh": 6,
"ss": 2,
"ssh": 3
},
"hit_accuracy": 92.19,
"is_ranked": true,
"level": {
"current": 30,
"progress": 0
},
"maximum_combo": 3948,
"play_count": 228050,
"play_time": null,
"pp": 990,
"global_rank": 87468,
"ranked_score": 1502995536,
"replays_watched_by_others": 0,
"total_hits": 5856573,
"total_score": 2104193750,
"user": {
"avatar_url": "https://a.ppy.sh/2?1519081077.png",
"country": {
"code": "AU",
"name": "Australia"
},
"country_code": "AU",
"cover": {
"custom_url": null,
"id": "3",
"url": "https://assets.ppy.sh/user-profile-covers/2/baba245ef60834b769694178f8f6d4f6166c5188c740de084656ad2b80f1eea7.jpeg"
},
"default_group": "ppy",
"id": 2,
"is_active": false,
"is_bot": false,
"is_online": false,
"is_supporter": true,
"last_visit": "2019-02-22T11:07:10+00:00",
"pm_friends_only": false,
"profile_colour": "#3366FF",
"username": "peppy"
}
}
A summary of various gameplay statistics for a User. Specific to a Ruleset
Field | Type | Description |
---|---|---|
count_100 | integer | |
count_300 | integer | |
count_50 | integer | |
count_miss | integer | |
country_rank | integer? | Current country rank according to pp. |
grade_counts.a | integer | Number of A ranked scores. |
grade_counts.s | integer | Number of S ranked scores. |
grade_counts.sh | integer | Number of Silver S ranked scores. |
grade_counts.ss | integer | Number of SS ranked scores. |
grade_counts.ssh | integer | Number of Silver SS ranked scores. |
hit_accuracy | float | Hit accuracy percentage |
is_ranked | boolean | Is actively ranked |
level.current | integer | Current level. |
level.progress | float | Progress to next level. |
maximum_combo | integer | Highest maximum combo. |
play_count | integer | Number of maps played. |
play_time | integer | Cumulative time played. |
pp | float | Performance points |
pp_exp | float | Experimental (lazer) performance points |
global_rank | integer? | Current rank according to pp. |
global_rank_exp | integer? | Current rank according to experimental (lazer) pp. |
ranked_score | integer | Current ranked score. |
replays_watched_by_others | integer | Number of replays watched by other users. |
total_hits | integer | Total number of hits. |
total_score | integer | Total score. |
Optional attributes
Field | Type | Description |
---|---|---|
rank_change_since_30_days | integer? | Difference between current rank and rank 30 days ago, according to pp. |
user | User |
WikiPage
{
"available_locales": ["en", "id", "ja", "pt-br"],
"layout": "markdown_page",
"locale": "en",
"markdown": "# osu! (game mode)\n\n![Gameplay of osu!](/wiki/shared/Interface_osu.jpg \"osu! Interface\")\n\nMarkdownMarkdownTruncated",
"path": "Game_Modes/osu!",
"subtitle": "Game Modes",
"tags": ["tap", "circles"],
"title": "osu! (game mode)"
}
Represents a wiki article
Field | Type | Description |
---|---|---|
available_locales | string[] | All available locales for the article. |
layout | string | The layout type for the page. |
locale | string | All lowercase BCP 47 language tag. |
markdown | string | Markdown content. |
path | string | Path of the article. |
subtitle | string? | The article's subtitle. |
tags | string[] | Associated tags for the article. |
title | string | The article's title. |