NAV -image
bash javascript

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.

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 (not yet public, consider unstable and expect breaking changes)
v1 legacy api provided by the old site, will be deprecated soon

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

  1. have registered an OAuth Application.
  2. 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:

  1. Requesting authorization from users
  2. Users are redirected back to your site
  3. 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

Query Parameters

client_id  number  

The Client ID you received when you registered.

redirect_uri  string  

The URL in your application where users will be sent after authorization. This must match the registered Application Callback URL exactly.

response_type  string  

This should always be code when requesting authorization.

scope  string optional  

A space-delimited string of scopes.

state  string optional  

Data that will be returned when a temporary code is issued. It can be used to provide a token for protecting against cross-site request forgery attacks.

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 -X POST \
    "https://osu.ppy.sh/oauth/token" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d '{"client_id":1,"client_secret":"clientsecret","code":"receivedcode","grant_type":"authorization_code","redirect_uri":"http:\/\/localhost:4000"}'
const url = new URL(
    "https://osu.ppy.sh/oauth/token"
);

let headers = {
    "Accept": "application/json",
    "Content-Type": "application/json",
};

let body = {
    "client_id": 1,
    "client_secret": "clientsecret",
    "code": "receivedcode",
    "grant_type": "authorization_code",
    "redirect_uri": "http:\/\/localhost:4000"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):

{
    "access_token": "verylongstring",
    "expires_in": 86400,
    "refresh_token": "anotherlongstring",
    "token_type": "Bearer"
}

POST https://osu.ppy.sh/oauth/token

Body Parameters

client_id  string  

The client ID of your application.

client_secret  string  

The client secret of your application.

code  string  

The code you received.

grant_type  string  

This must always be authorization_code

redirect_uri  string  

The URL in your application where users will be sent after authorization.

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 number 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 -X POST \
    "https://osu.ppy.sh/oauth/token" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d '{"client_id":1,"client_secret":"clientsecret","grant_type":"client_credentials","scope":"public"}'
const url = new URL(
    "https://osu.ppy.sh/oauth/token"
);

let headers = {
    "Accept": "application/json",
    "Content-Type": "application/json",
};

let body = {
    "client_id": 1,
    "client_secret": "clientsecret",
    "grant_type": "client_credentials",
    "scope": "public"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):

{
    "access_token": "verylongstring",
    "expires_in": 86400,
    "token_type": "Bearer"
}

POST https://osu.ppy.sh/oauth/token

Body Parameters

client_id  number  

The Client ID you received when you registered.

client_secret  string  

The client secret of your application.

grant_type  string  

This must always be client_credentials.

scope  string  

Must be public; other scopes have no meaningful effect.

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 number 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.write Allows sending chat messages 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 (/me).
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

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.

Changelog

For a full list of changes, see the Changelog on the site.

Breaking Changes

2021-09-01

2021-08-11

2021-06-14

2021-06-09

2021-04-20

2021-02-25

2020-09-08

2020-08-28

2020-05-01

2020-02-18

2019-10-09

2019-07-18

Authenticating requests

Authenticate requests to this API's endpoints by sending an Authorization header with the value "Bearer {YOUR_AUTH_KEY}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

You can retrieve your token by visiting your dashboard and clicking Generate API token.

Beatmaps

Lookup Beatmap

Returns beatmap.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmaps/lookup?checksum=necessitatibus&filename=rem&id=ut" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmaps/lookup"
);

let params = {
    "checksum": "necessitatibus",
    "filename": "rem",
    "id": "ut",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

"See Beatmap object section"

Request   

GET /beatmaps/lookup

Query Parameters

checksum  string optional  

A beatmap checksum.

filename  string optional  

A filename to lookup.

id  string optional  

A beatmap ID to lookup.

Response format

See Get Beatmap

Get a User Beatmap score

Return a User's score on a Beatmap

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmaps/16/scores/users/15?mode=ullam&mods=iusto" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmaps/16/scores/users/15"
);

let params = {
    "mode": "ullam",
    "mods": "iusto",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /beatmaps/{beatmap}/scores/users/{user}

URL Parameters

beatmap  integer  

Id of the Beatmap.

user  integer  

Id of the User.

Query Parameters

mode  string optional  

The GameMode to get scores for.

mods  string optional  

An array of matching Mods, or none // TODO.

Response Format

Returns BeatmapUserScore

The position returned depends on the requested mode and mods.

Get Beatmap scores

Returns the top scores for a beatmap

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmaps/19/scores?mode=sit&mods=doloremque&type=et" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmaps/19/scores"
);

let params = {
    "mode": "sit",
    "mods": "doloremque",
    "type": "et",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /beatmaps/{beatmap}/scores

URL Parameters

beatmap  integer  

Id of the Beatmap.

Query Parameters

mode  string optional  

The GameMode to get scores for.

mods  string optional  

An array of matching Mods, or none // TODO.

type  string optional  

Beatmap score ranking type // TODO.

Response Format

Returns BeatmapScores

Get Beatmap

Gets beatmap data for the specified beatmap ID.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmaps/6" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmaps/6"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

"See Beatmap object section."

Request   

GET /beatmaps/{beatmap}

URL Parameters

beatmap  integer  

The ID of the beatmap.

Response format

Returns Beatmap object. Following attributes are included in the response object when applicable,

Attribute Notes
beatmapset Includes ratings property.
failtimes
max_combo

Beatmapset Discussions

Get Beatmapset Discussion Posts

Returns the posts of beatmapset discussions.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmapsets/discussions/posts?beatmapset_discussion_id=qui&limit=4&page=8&sort=magni&types[]=eligendi&user=vel&with_deleted=voluptatem" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmapsets/discussions/posts"
);

let params = {
    "beatmapset_discussion_id": "qui",
    "limit": "4",
    "page": "8",
    "sort": "magni",
    "types[]": "eligendi",
    "user": "vel",
    "with_deleted": "voluptatem",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /beatmapsets/discussions/posts

Query Parameters

beatmapset_discussion_id  string optional  

id of the BeatmapsetDiscussion.

limit  integer optional  

Maximum number of results.

page  integer optional  

Search result page.

sort  string optional  

id_desc for newest first; id_asc for oldest first. Defaults to id_desc.

types[]  string optional  

first, reply, system are the valid values. Defaults to reply.

user  string optional  

The id of the User.

with_deleted  string optional  

This param has no effect as api calls do not currently receive group permissions.

Response Format

Field Type Description
beatmapsets BeatmapsetCompact
cursor Cursor
posts BeatmapsetDiscussionPost[]
users UserCompact

Get Beatmapset Discussion Votes

Returns the votes given to beatmapset discussions.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmapsets/discussions/votes?beatmapset_discussion_id=qui&limit=7&page=14&receiver=fugit&score=omnis&sort=sint&user=consequuntur&with_deleted=ex" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmapsets/discussions/votes"
);

let params = {
    "beatmapset_discussion_id": "qui",
    "limit": "7",
    "page": "14",
    "receiver": "fugit",
    "score": "omnis",
    "sort": "sint",
    "user": "consequuntur",
    "with_deleted": "ex",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /beatmapsets/discussions/votes

Query Parameters

beatmapset_discussion_id  string optional  

id of the BeatmapsetDiscussion.

limit  integer optional  

Maximum number of results.

page  integer optional  

Search result page.

receiver  string optional  

The id of the User receiving the votes.

score  string optional  

1 for up vote, -1 for down vote.

sort  string optional  

id_desc for newest first; id_asc for oldest first. Defaults to id_desc.

user  string optional  

The id of the User giving the votes.

with_deleted  string optional  

This param has no effect as api calls do not currently receive group permissions.

Response Format

Field Type Description
cursor Cursor
discussions BeatmapsetDiscussion
users UserCompact
votes BeatmapsetDiscussionVote[]

Get Beatmapset Discussions

Returns a list of beatmapset discussions.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmapsets/discussions?beatmap_id=et&beatmapset_id=possimus&beatmapset_status=voluptatem&limit=15&message_types[]=vel&only_unresolved=vel&page=20&sort=alias&user=laboriosam&with_deleted=mollitia" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmapsets/discussions"
);

let params = {
    "beatmap_id": "et",
    "beatmapset_id": "possimus",
    "beatmapset_status": "voluptatem",
    "limit": "15",
    "message_types[]": "vel",
    "only_unresolved": "vel",
    "page": "20",
    "sort": "alias",
    "user": "laboriosam",
    "with_deleted": "mollitia",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /beatmapsets/discussions

Query Parameters

beatmap_id  string optional  

id of the Beatmap.

beatmapset_id  string optional  

id of the Beatmapset.

beatmapset_status  string optional  

One of all, ranked, qualified, disqualified, never_qualified. Defaults to all. TODO: better descriptions.

limit  integer optional  

Maximum number of results.

message_types[]  string optional  

suggestion, problem, mapper_note, praise, hype, review. Blank defaults to all types. TODO: better descriptions.

only_unresolved  string optional  

true to show only unresolved issues; false, otherwise. Defaults to false.

page  integer optional  

Search result page.

sort  string optional  

id_desc for newest first; id_asc for oldest first. Defaults to id_desc.

user  string optional  

The id of the User.

with_deleted  string optional  

This param has no effect as api calls do not currently receive group permissions.

Response Format

Field Type Description
beatmaps Beatmap[] List of beatmaps associated with the discussions returned.
cursor Cursor
discussions BeatmapsetDiscussion[] List of discussions according to sort order.
included_discussions BeatmapsetDiscussion[] Additional discussions related to discussions.
reviews_config.max_blocks number Maximum number of blocks allowed in a review.
users UserCompact[] List of users associated with the discussions returned.

Changelog

Get Changelog Build

Returns details of the specified build.

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/changelog/stable40/20210520.2" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/changelog/stable40/20210520.2"
);

let 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": {
                "id": null,
                "display_name": "peppy",
                "github_url": 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
            }
        }
    }
}

Request   

GET /changelog/{stream}/{build}

URL Parameters

stream  string  

Update stream name.

build  string  

Build version.

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 -X GET \
    -G "https://osu.ppy.sh/api/v2/changelog?message_formats[]=odit" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/changelog"
);

let params = {
    "message_formats[]": "odit",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let 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": {
            "id": 218,
            "display_name": "bdach",
            "github_url": "https://github.com/bdach",
            "osu_username": null,
            "user_id": null,
            "user_url": null
          }
        }
      ]
    },
    // ...
  ],
  "search": {
    "stream": null,
    "from": null,
    "to": null,
    "max_id": null,
    "limit": 21
  }
}

Request   

GET /changelog

Query Parameters

from  string optional  

Minimum build version.

max_id  integer optional  

Maximum build ID.

stream  string optional  

Stream name to return builds from.

to  string optional  

Maximum build version.

message_formats[]  string optional  

html, markdown. Default to both.

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 number Always 21.
search.max_id number? 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 -X GET \
    -G "https://osu.ppy.sh/api/v2/changelog/20210520.2?message_formats[]=error" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/changelog/20210520.2"
);

let params = {
    "message_formats[]": "error",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let 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.

Request   

GET /changelog/{changelog}

URL Parameters

changelog  string  

Build version, update stream name, or build ID.

Query Parameters

key  string optional  

Unset to query by build version or stream name, or id to query by build ID.

message_formats[]  string optional  

html, markdown. Default to both.

Response Format

See Get Changelog Build.

Chat

Create New PM

This endpoint allows you to create a new PM channel.

requires user OAuth chat.write

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/chat/new" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"target_id":17,"message":"dolor","is_action":true}'
const url = new URL(
    "https://osu.ppy.sh/api/v2/chat/new"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "target_id": 17,
    "message": "dolor",
    "is_action": true
}

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,
        "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": 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
    }
  },
  "new_channel_id": 1234,
}

Request   

POST /chat/new

Body Parameters

target_id  integer  

user_id of user to start PM with

message  string  

message to send

is_action  boolean  

whether the message is an action

Response Format

Field Type
new_channel_id channel_id of newly created ChatChannel
presence array of ChatChannel
message the sent ChatMessage

Get Updates

This endpoint returns new messages since the given message_id along with updated channel 'presence' data.

requires user OAuth lazer

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/chat/updates?channel_id=9&history_since=4&includes[]=qui&limit=8&since=7" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/chat/updates"
);

let params = {
    "channel_id": "9",
    "history_since": "4",
    "includes[]": "qui",
    "limit": "8",
    "since": "7",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let 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,
                "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,
                "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
        }
    ],
    "messages": [
        {
            "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
            }
        }
    ],
    "silences": [
        {
            "id": 1,
            "user_id": 2
        }
    ]
}

Request   

GET /chat/updates

Query Parameters

channel_id  integer optional  

If provided, will only return messages for the given channel the user is in.

history_since  integer optional  

UserSilence after the specified id to return.

includes  string[] optional  

List of presence, messages, silences fields to include in the response. Returns all if not specified.

limit  integer optional  

Maximum number of messages to return (max of 50).

since  integer  

Messages after the specified message_id to return.

Response Format

Field Type
messages ChatMessage[]?
presence ChatChannel[]?
silences UserSilence[]?

Get Channel Messages

This endpoint returns the chat messages for a specific channel.

requires user OAuth lazer

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/chat/channels/2/messages?limit=14&since=18&until=1" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/chat/channels/2/messages"
);

let params = {
    "limit": "14",
    "since": "18",
    "until": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let 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
        }
    }
]

Request   

GET /chat/channels/{channel}/messages

URL Parameters

channel  integer  

The ID of the channel to retrieve messages for

Query Parameters

limit  integer optional  

number of messages to return (max of 50)

since  integer optional  

messages after the specified message id will be returned

until  integer optional  

messages up to but not including the specified message id will be returned

Response Format

Returns an array of ChatMessage

Send Message to Channel

This endpoint returns the chat messages for a specific channel.

requires user OAuth lazer

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/chat/channels/19/messages" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"message":"et","is_action":true}'
const url = new URL(
    "https://osu.ppy.sh/api/v2/chat/channels/19/messages"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "message": "et",
    "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
    }
}

Request   

POST /chat/channels/{channel}/messages

URL Parameters

channel  integer  

The channel_id of the channel to send message to

Body Parameters

message  string  

message to send

is_action  boolean  

whether the message is an action

Response Format

The sent ChatMessage

Join Channel

This endpoint allows you to join a public or multiplayer channel.

requires user OAuth lazer

Example request:

curl -X PUT \
    "https://osu.ppy.sh/api/v2/chat/channels/perspiciatis/users/sunt" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/chat/channels/perspiciatis/users/sunt"
);

let 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
  },
  "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": []
}

Request   

PUT /chat/channels/{channel}/users/{user}

URL Parameters

channel  string  

user  string  

Response Format

Returns the joined ChatChannel.

Leave Channel

This endpoint allows you to leave a public channel.

requires user OAuth lazer

Example request:

curl -X DELETE \
    "https://osu.ppy.sh/api/v2/chat/channels/adipisci/users/soluta" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/chat/channels/adipisci/users/soluta"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (204):

<Empty response>

Request   

DELETE /chat/channels/{channel}/users/{user}

URL Parameters

channel  string  

user  string  

Response Format

empty response

Mark Channel as Read

This endpoint marks the channel as having being read up to the given message_id.

requires user OAuth lazer

Example request:

curl -X PUT \
    "https://osu.ppy.sh/api/v2/chat/channels/doloribus/mark-as-read/sit?channel_id=velit&message_id=eaque" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/chat/channels/doloribus/mark-as-read/sit"
);

let params = {
    "channel_id": "velit",
    "message_id": "eaque",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "PUT",
    headers,
}).then(response => response.json());

Example response (204):

<Empty response>

Request   

PUT /chat/channels/{channel}/mark-as-read/{message}

URL Parameters

channel  string  

message  string  

Query Parameters

channel_id  string  

The channel_id of the channel to mark as read

message_id  string  

The message_id of the message to mark as read up to

Response Format

empty response

Get Channel List

This endpoint returns a list of all joinable public channels.

requires user OAuth lazer

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/chat/channels" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/chat/channels"
);

let 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"
    }
]

Request   

GET /chat/channels

Response Format

Returns an array of ChatChannel

Create Channel

This endpoint creates a new channel if doesn't exist and joins it. Currently only for rejoining existing PM channels which the user has left.

requires user OAuth lazer

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/chat/channels" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"type":"laboriosam","target_id":16}'
const url = new URL(
    "https://osu.ppy.sh/api/v2/chat/channels"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "type": "laboriosam",
    "target_id": 16
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):

{
    "channel_id": 1,
    "name": "#pm_1-2",
    "description": "",
    "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
        }
    ]
}

Request   

POST /chat/channels

Body Parameters

type  string  

channel type (currently only supports "PM")

target_id  integer optional  

target user id for type PM

Response Format

Returns ChatChannel with recent_messages attribute. Note that if there's no existing PM channel, most of the fields will be blank. In that case, send a message instead to create the channel.

Get Channel

Gets details of a chat channel.

requires user OAuth lazer

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/chat/channels/in" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/chat/channels/in"
);

let 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
        },
        "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
        }
    ]
}

Request   

GET /chat/channels/{channel}

URL Parameters

channel  string  

Response Format

Field Type Description
channel ChatChannel
users UserCompact 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 -X GET \
    -G "https://osu.ppy.sh/api/v2/comments?commentable_type=reprehenderit&commentable_id=cum&cursor=quo&parent_id=error&sort=hic" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/comments"
);

let params = {
    "commentable_type": "reprehenderit",
    "commentable_id": "cum",
    "cursor": "quo",
    "parent_id": "error",
    "sort": "hic",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (422):

{
    "error": null
}

Request   

GET /comments

Query Parameters

commentable_type  string optional  

The type of resource to get comments for.

commentable_id  string optional  

The id of the resource to get comments for.

cursor  string optional  

Pagination option. See CommentSort for detail. The format follows Cursor except it's not currently included in the response.

parent_id  string optional  

Limit to comments which are reply to the specified id. Specify 0 to get top level comments.

sort  string optional  

Sort option as defined in CommentSort. Defaults to new for guests and user-specified default when authenticated.

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.

requires user OAuth lazer

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/comments" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/comments"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST /comments

Query Parameters

comment.commentable_id  string optional  

Resource ID the comment thread is attached to

comment.commentable_type  string optional  

Resource type the comment thread is attached to

comment.message  string optional  

Text of the comment

comment.parent_id  string optional  

The id of the comment to reply to, null if not a reply

Response Format

Returns CommentBundle

Get a Comment

Gets a comment and its replies up to 2 levels deep.

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/comments/vel" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/comments/vel"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (404):

{
    "error": null
}

Request   

GET /comments/{comment}

URL Parameters

comment  string  

Response Format

Returns CommentBundle

Edit Comment

Edit an existing comment.

requires user OAuth lazer

Example request:

curl -X PUT \
    "https://osu.ppy.sh/api/v2/comments/dolores" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/comments/dolores"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "PUT",
    headers,
}).then(response => response.json());

Request   

PUT /comments/{comment}

PATCH /comments/{comment}

URL Parameters

comment  string  

Query Parameters

comment.message  string optional  

New text of the comment

Response Format

Returns CommentBundle

Delete Comment

Deletes the specified comment.

requires user OAuth lazer

Example request:

curl -X DELETE \
    "https://osu.ppy.sh/api/v2/comments/alias" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/comments/alias"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Request   

DELETE /comments/{comment}

URL Parameters

comment  string  

Response Format

Returns CommentBundle

Add Comment vote

Upvotes a comment.

requires user OAuth lazer

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/comments/sit/vote" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/comments/sit/vote"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST /comments/{comment}/vote

URL Parameters

comment  string  

Response Format

Returns CommentBundle

Remove Comment vote

Un-upvotes a comment.

requires user OAuth lazer

Example request:

curl -X DELETE \
    "https://osu.ppy.sh/api/v2/comments/doloremque/vote" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/comments/doloremque/vote"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Request   

DELETE /comments/{comment}/vote

URL Parameters

comment  string  

Response Format

Returns CommentBundle

Forum

Reply Topic

Create a post replying to the specified topic.

requires user OAuth forum.write

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/forums/topics/1/reply" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"body":"hello"}'
const url = new URL(
    "https://osu.ppy.sh/api/v2/forums/topics/1/reply"
);

let 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());

Request   

POST /forums/topics/{topic}/reply

URL Parameters

topic  integer  

Id of the topic to be replied to.

Body Parameters

body  string  

Content of the reply post.

Response Format

ForumPost with body included.

Create Topic

Create a new topic.

requires user OAuth forum.write

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/forums/topics" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"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"
);

let 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());

Request   

POST /forums/topics

Body Parameters

body  string  

Content of the topic.

forum_id  number  

Forum to create the topic in.

title  string  

Title of the topic.

with_poll  boolean optional  

Enable this to also create poll in the topic (default: false).

forum_topic_poll[hide_results]  boolean optional  

Enable this to hide result until voting period ends (default: false).

forum_topic_poll[length_days]  number optional  

Number of days for voting period. 0 means the voting will never ends (default: 0). This parameter is required if hide_results option is enabled.

forum_topic_poll[max_options]  number optional  

Maximum number of votes each user can cast (default: 1).

forum_topic_poll[options]  string  

Newline-separated list of voting options. BBCode is supported.

forum_topic_poll[title]  string  

Title of the poll.

forum_topic_poll[vote_change]  boolean optional  

Enable this to allow user to change their votes (default: false).

Response Format

Field Type Includes
topic ForumTopic
post ForumPost body

Get Topic and Posts

Get topic and its posts.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/forums/topics/1" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/forums/topics/1"
);

let 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": {
        "id": 1
    },
    "sort": "id_asc"
}

Request   

GET /forums/topics/{topic}

URL Parameters

topic  integer  

Id of the topic.

Query Parameters

cursor  string optional  

Cursor for pagination.

sort  string optional  

Post sorting option. Valid values are id_asc (default) and id_desc.

limit  integer optional  

Maximum number of posts to be returned (20 default, 50 at most).

start  string optional  

First post id to be returned with sort set to id_asc. This parameter is ignored if cursor is specified.

end  string optional  

First post id to be returned with sort set to id_desc. This parameter is ignored if cursor is specified.

Response Format

Field Type Notes
cursor Cursor
search Parameters used for current request excluding cursor.
posts ForumPost[] Includes body.
topic ForumTopic

Edit Topic

Edit topic. Only title can be edited through this endpoint.

OAuth forum.write

Example request:

curl -X PUT \
    "https://osu.ppy.sh/api/v2/forums/topics/1" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"forum_topic[topic_title]":"titled"}'
const url = new URL(
    "https://osu.ppy.sh/api/v2/forums/topics/1"
);

let 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());

Request   

PUT /forums/topics/{topic}

PATCH /forums/topics/{topic}

URL Parameters

topic  integer  

Id of the topic.

Body Parameters

forum_topic[topic_title]  string optional  

New topic title.

Response Format

The edited ForumTopic.

Edit Post

Edit specified forum post.

OAuth forum.write

Example request:

curl -X PUT \
    "https://osu.ppy.sh/api/v2/forums/posts/1" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"body":"hello"}'
const url = new URL(
    "https://osu.ppy.sh/api/v2/forums/posts/1"
);

let 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());

Request   

PUT /forums/posts/{post}

PATCH /forums/posts/{post}

URL Parameters

post  integer  

Id of the post.

Body Parameters

body  string  

New post content in BBCode format.

Response Format

ForumPost with body included.

Home

Search

Searches users and wiki pages.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/search?mode=0&query=hello&page=1" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/search"
);

let params = {
    "mode": "0",
    "query": "hello",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Response Format

Field Type Description
user SearchResult<UserCompact>? 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 number

Multiplayer

Get User High Score

Returns detail of highest score of specified user and the surrounding scores.

requires user OAuth lazer

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/rooms/4/playlist/7/scores/users/18" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rooms/4/playlist/7/scores/users/18"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /rooms/{room}/playlist/{playlist}/scores/users/{user}

URL Parameters

room  integer  

Id of the room.

playlist  integer  

Id of the playlist item.

user  integer  

User id.

Response Format

Returns MultiplayerScore object.

Get Scores

Returns a list of scores for specified playlist item.

requires user OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/rooms/20/playlist/7/scores?limit=8&sort=exercitationem&cursor=est" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rooms/20/playlist/7/scores"
);

let params = {
    "limit": "8",
    "sort": "exercitationem",
    "cursor": "est",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /rooms/{room}/playlist/{playlist}/scores

URL Parameters

room  integer  

Id of the room.

playlist  integer  

Id of the playlist item.

Query Parameters

limit  integer optional  

Number of scores to be returned.

sort  string optional  

MultiplayerScoresSort parameter.

cursor  string optional  

MultiplayerScoresCursor parameter.

Response Format

Returns MultiplayerScores object.

Get a Score

Returns detail of specified score and the surrounding scores.

requires user OAuth lazer

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/rooms/14/playlist/1/scores/19" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rooms/14/playlist/1/scores/19"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /rooms/{room}/playlist/{playlist}/scores/{score}

URL Parameters

room  integer  

Id of the room.

playlist  integer  

Id of the playlist item.

score  integer  

Id of the score.

Response Format

Returns MultiplayerScore object.

News

Get News Listing

Returns a list of news posts and related metadata.

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/news" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/news"
);

let 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": {
    "published_at": "2021-05-09T18:00:00.000000Z",
    "id": 953
  }
}

Request   

GET /news

Query Parameters

limit  integer optional  

Maximum number of posts (12 default, 1 minimum, 21 maximum).

year  integer optional  

Year to return posts from.

cursor  string optional  

Cursor for pagination.

Response Format

Field Type Notes
cursor Cursor
news_posts NewsPost[] Includes preview.
news_sidebar.current_year number 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 number[] All years during which posts have been published.
search.limit number Clamped limit input.
search.sort string Always published_desc.

Get News Post

Returns details of the specified news post.

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/news/2021-04-27-results-a-labour-of-love" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/news/2021-04-27-results-a-labour-of-love"
);

let 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"
        }
    }
}

Request   

GET /news/{news}

URL Parameters

news  string  

News post slug or ID.

Query Parameters

key  string optional  

Unset to query by slug, or id to query by ID.

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.

requires user OAuth lazer

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/notifications?max_id=nam" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/notifications"
);

let params = {
    "max_id": "nam",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let 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"
}

Request   

GET /notifications

Query Parameters

max_id  string optional  

Maximum id fetched. Can be used to load earlier notifications. Defaults to no limit (fetch latest 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.

requires user OAuth lazer

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/notifications/mark-read" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"ids":[1,2,3]}'
const url = new URL(
    "https://osu.ppy.sh/api/v2/notifications/mark-read"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "ids": [
        1,
        2,
        3
    ]
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (204):

<Empty response>

Request   

POST /notifications/mark-read

Body Parameters

ids  integer[]  

id of notifications to be marked as read

Response Format

empty response

OAuth Tokens

Revoke current token

Revokes currently authenticated token.

OAuth

Example request:

curl -X DELETE \
    "https://osu.ppy.sh/api/v2/oauth/tokens/current" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/oauth/tokens/current"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (204):

<Empty response>

Request   

DELETE /oauth/tokens/current

Ranking

Get Ranking

Gets the current ranking for the specified type and game mode.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/rankings/mania/performance?country=0&filter=all&variant=4k" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rankings/mania/performance"
);

let params = {
    "country": "0",
    "filter": "all",
    "variant": "4k",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /rankings/{mode}/{type}

URL Parameters

mode  string  

GameMode.

type  string  

RankingType.

Query Parameters

country  integer optional  

Filter ranking by country code. Only available for type of performance.

cursor  string optional  

Cursor.

filter  string optional  

Either all (default) or friends.

spotlight  string optional  

The id of the spotlight if type is charts. Ranking for latest spotlight will be returned if not specified.

variant  string optional  

Filter ranking to specified mode variant. For mode of mania, it's either 4k or 7k. Only available for type of performance.

Response Format

Returns Rankings

Get Spotlights

Gets the list of spotlights.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/spotlights" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/spotlights"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /spotlights

Response Format

Returns Spotlights

Undocumented

/beatmaps/{beatmap}/solo/scores

requires user OAuth lazer

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/beatmaps/qui/solo/scores" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmaps/qui/solo/scores"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST /beatmaps/{beatmap}/solo/scores

URL Parameters

beatmap  string  

/beatmaps/{beatmap}/solo/scores/{token}

requires user OAuth lazer

Example request:

curl -X PUT \
    "https://osu.ppy.sh/api/v2/beatmaps/vel/solo/scores/qui" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmaps/vel/solo/scores/qui"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "PUT",
    headers,
}).then(response => response.json());

Request   

PUT /beatmaps/{beatmap}/solo/scores/{token}

URL Parameters

beatmap  string  

token  string  

/beatmapsets/events

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmapsets/events" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmapsets/events"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /beatmapsets/events

/beatmapsets/{beatmapset}/favourites

requires user OAuth lazer

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/beatmapsets/aut/favourites" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmapsets/aut/favourites"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST /beatmapsets/{beatmapset}/favourites

URL Parameters

beatmapset  string  

/chat/presence

requires user OAuth lazer

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/chat/presence" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/chat/presence"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /chat/presence

/matches

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/matches" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/matches"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /matches

/matches/{match}

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/matches/et" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/matches/et"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /matches/{match}

URL Parameters

match  string  

/rooms/{mode?}

requires user OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/rooms/beatae" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rooms/beatae"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /rooms/{mode?}

URL Parameters

mode  string optional  

/rooms/{room}/users/{user}

requires user OAuth lazer

Example request:

curl -X PUT \
    "https://osu.ppy.sh/api/v2/rooms/quo/users/ut" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rooms/quo/users/ut"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "PUT",
    headers,
}).then(response => response.json());

Request   

PUT /rooms/{room}/users/{user}

URL Parameters

room  string  

user  string  

/rooms/{room}/users/{user}

requires user OAuth lazer

Example request:

curl -X DELETE \
    "https://osu.ppy.sh/api/v2/rooms/occaecati/users/voluptatem" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rooms/occaecati/users/voluptatem"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Request   

DELETE /rooms/{room}/users/{user}

URL Parameters

room  string  

user  string  

/rooms/{room}/leaderboard

requires user OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/rooms/at/leaderboard" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rooms/at/leaderboard"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /rooms/{room}/leaderboard

URL Parameters

room  string  

/rooms/{room}/playlist/{playlist}/scores

requires user OAuth lazer

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/rooms/aspernatur/playlist/repellendus/scores" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rooms/aspernatur/playlist/repellendus/scores"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST /rooms/{room}/playlist/{playlist}/scores

URL Parameters

room  string  

playlist  string  

/rooms/{room}/playlist/{playlist}/scores/{score}

requires user OAuth lazer

Example request:

curl -X PUT \
    "https://osu.ppy.sh/api/v2/rooms/aut/playlist/dolorem/scores/nobis" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rooms/aut/playlist/dolorem/scores/nobis"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "PUT",
    headers,
}).then(response => response.json());

Request   

PUT /rooms/{room}/playlist/{playlist}/scores/{score}

PATCH /rooms/{room}/playlist/{playlist}/scores/{score}

URL Parameters

room  string  

playlist  string  

score  string  

/reports

requires user OAuth lazer

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/reports" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/reports"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST /reports

/rooms

requires user OAuth lazer

Example request:

curl -X POST \
    "https://osu.ppy.sh/api/v2/rooms" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rooms"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST /rooms

/rooms/{room}

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/rooms/ut" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/rooms/ut"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /rooms/{room}

URL Parameters

room  string  

/seasonal-backgrounds

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/seasonal-backgrounds" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/seasonal-backgrounds"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "ends_at": "2021-12-01T16:00:00+00:00",
    "backgrounds": [
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9205\/e1aab983fe3961f3f769c52d7d73d4f2e9311a0288c5925ebffef2f34e55fbb9_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/14634525?1632541152.jpeg",
                "country_code": "CA",
                "default_group": "default",
                "id": 14634525,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": "2021-10-21T06:47:36+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "Kondroel"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9237\/fe003ea57d44ee6d29b494cfb17a514d0ce335710716f5efab19b951db74efb9_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/3607337?1616760060.jpeg",
                "country_code": "CA",
                "default_group": "default",
                "id": 3607337,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": "2021-10-21T10:07:17+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "Phoebe Yu"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9255\/816f19dcc18fd27d7be78e8057a9959e605eb28fe9defe3b9c5b45e40fb519a1_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/10682807?1625548335.jpeg",
                "country_code": "NO",
                "default_group": "default",
                "id": 10682807,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": "2021-10-20T19:52:11+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "Tin Can"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9262\/7ef0b22eb8cde92f05c0bf6605c04a6175712ffe00478ae384ec9d9b4fc3a871_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/29089?1608397453.jpeg",
                "country_code": "FI",
                "default_group": "default",
                "id": 29089,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": "2021-10-21T09:45:57+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "Sutsuka"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9263\/725955912ff3a6901d2e1741d736f24d12e23febe8a29a623f878887e8049808_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/12694139?1632457778.jpeg",
                "country_code": "CA",
                "default_group": "default",
                "id": 12694139,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": "2021-10-21T05:33:39+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "McFriedFries"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9283\/f1b43a6de6cb38339822a92245ee9b5716908d995d5c9dea2ee6acbb79defae4_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/osu.ppy.sh\/images\/layout\/avatar-guest.png",
                "country_code": "JP",
                "default_group": "default",
                "id": 21567829,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": "2021-10-17T06:38:25+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "kabandayo"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9291\/c99d5f2d77ba18cd246a5c3cf9f15847f75d6319b34f897cf75da38cc422bcd6_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/11215996?1630988010.jpeg",
                "country_code": "US",
                "default_group": "default",
                "id": 11215996,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": "2021-10-21T03:15:32+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "SvenJing"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9297\/585503467d70850429504def323db7cdf89fc688d88f2dfc5c5badfa6776a184_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/13103233?1628659397.gif",
                "country_code": "ID",
                "default_group": "default",
                "id": 13103233,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": "2021-10-21T10:28:12+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "Dreamxiety"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9307\/aed4aa72677f1a867fe6447dc67b24ebecb8ab33747495af60e3a7db4325ea29_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/10275467?1634718882.png",
                "country_code": "KR",
                "default_group": "default",
                "id": 10275467,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": true,
                "is_supporter": true,
                "last_visit": "2021-10-21T10:37:09+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "Ayamy"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9313\/5840231a437b3e8169abfaace5cf56f1fc3f31d03a39c8c3ffdbc5a7c685fd30_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/460210?1399363750.jpg",
                "country_code": "SE",
                "default_group": "default",
                "id": 460210,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": "2021-10-21T07:00:48+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "Loichuu"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9316\/e1e8732afdddbf0932ca855eb6870d929450dc516f2b433da88690b9b1e20ce6_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/14406940?1610194830.jpeg",
                "country_code": "ID",
                "default_group": "default",
                "id": 14406940,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": null,
                "pm_friends_only": true,
                "profile_colour": null,
                "username": "not slepp"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9325\/23bf0dc4bc1d81ba81f1f1739f7b92f1182958ca9f0da9c801e988501d733e39_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/7206818?1630910797.png",
                "country_code": "RU",
                "default_group": "default",
                "id": 7206818,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": true,
                "is_supporter": true,
                "last_visit": "2021-10-21T10:38:12+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "Dem4eg-"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9326\/f773213492241da1cb0eb9cd55f92e629c792853e30739ea1b5417c66d0a2224_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/11516014?1578351707.jpeg",
                "country_code": "MX",
                "default_group": "default",
                "id": 11516014,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": null,
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "Kwms024"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9330\/f87d534ce85889abd9e1370922c09c00ad724de943bef373f19c4fd534c91626_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/12992775?1629697145.jpeg",
                "country_code": "HK",
                "default_group": "default",
                "id": 12992775,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": "2021-10-20T21:04:42+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "Porukana"
            }
        },
        {
            "url": "https:\/\/assets.ppy.sh\/user-contest-entries\/9337\/a446cff8b547442ccacacba61225b81d5c02873563e83d26e738e1fa7e4845a8_opt.jpg",
            "user": {
                "avatar_url": "https:\/\/a.ppy.sh\/8678404?1609236503.jpeg",
                "country_code": "ID",
                "default_group": "default",
                "id": 8678404,
                "is_active": true,
                "is_bot": false,
                "is_deleted": false,
                "is_online": false,
                "is_supporter": true,
                "last_visit": "2021-10-20T05:37:37+00:00",
                "pm_friends_only": false,
                "profile_colour": null,
                "username": "Ravioli-"
            }
        }
    ]
}

Request   

GET /seasonal-backgrounds

/scores/{mode}/{score}/download

requires user OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/scores/dolorem/quia/download" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/scores/dolorem/quia/download"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /scores/{mode}/{score}/download

URL Parameters

mode  string  

score  string  

/scores/{mode}/{score}

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/scores/minus/sit" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/scores/minus/sit"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /scores/{mode}/{score}

URL Parameters

mode  string  

score  string  

/beatmapsets/search/{filters?}

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmapsets/search/perferendis" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmapsets/search/perferendis"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /beatmapsets/search/{filters?}

URL Parameters

filters  string optional  

/beatmapsets/lookup

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmapsets/lookup" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmapsets/lookup"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /beatmapsets/lookup

/beatmapsets/{beatmapset}/download

OAuth lazer

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmapsets/optio/download" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmapsets/optio/download"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /beatmapsets/{beatmapset}/download

URL Parameters

beatmapset  string  

/beatmapsets/{beatmapset}

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/beatmapsets/et" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/beatmapsets/et"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /beatmapsets/{beatmapset}

URL Parameters

beatmapset  string  

/friends

requires user OAuth friends.read

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/friends" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/friends"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /friends

/me/download-quota-check

requires user OAuth lazer

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/me/download-quota-check" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/me/download-quota-check"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "authentication": "basic"
}

Request   

GET /me/download-quota-check

Users

Get Own Data

Similar to Get User but with authenticated user (token owner) as user id.

requires user OAuth identify

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/me/osu" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/me/osu"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

"See User object section"

Request   

GET /me/{mode?}

URL Parameters

mode  string optional  

GameMode. User default mode will be used if not specified.

Response format

See Get User.

Get User Kudosu

Returns kudosu history.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/users/1/kudosu?limit=12&offset=1" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/users/1/kudosu"
);

let params = {
    "limit": "12",
    "offset": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let 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..."
    }
]

Request   

GET /users/{user}/kudosu

URL Parameters

user  integer  

Id of the user.

Query Parameters

limit  integer optional  

Maximum number of results.

offset  string optional  

Result offset for pagination.

Response format

Array of KudosuHistory.

Get User Scores

This endpoint returns the scores of specified user.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/users/1/scores/best?include_fails=0&mode=osu&limit=2&offset=1" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/users/1/scores/best"
);

let params = {
    "include_fails": "0",
    "mode": "osu",
    "limit": "2",
    "offset": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let 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..."
    }
]

Request   

GET /users/{user}/scores/{type}

URL Parameters

user  integer  

Id of the user.

type  string  

Score type. Must be one of these: best, firsts, recent.

Query Parameters

include_fails  string optional  

Only for recent scores, include scores of failed plays. Set to 1 to include them. Defaults to 0.

mode  string optional  

GameMode of the scores to be returned. Defaults to the specified user's mode.

limit  integer optional  

Maximum number of results.

offset  string optional  

Result offset for pagination.

Response format

Array of Score. Following attributes are included in the response object when applicable.

Attribute Notes
beatmap
beatmapset
weight Only for type best.
user

Get User Beatmaps

Returns the beatmaps of specified user.

Type Notes
favourite
graveyard
loved
most_played
pending Previously unranked
ranked Previously ranked_and_approved

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/users/1/beatmapsets/favourite?limit=9&offset=1" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/users/1/beatmapsets/favourite"
);

let params = {
    "limit": "9",
    "offset": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let 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..."
    }
]

Request   

GET /users/{user}/beatmapsets/{type}

URL Parameters

user  integer  

Id of the user.

type  string  

Beatmap type.

Query Parameters

limit  integer optional  

Maximum number of results.

offset  string optional  

Result offset for pagination.

Response format

Array of BeatmapPlaycount when type is most_played; array of Beatmapset, otherwise.

Get User Recent Activity

Returns recent activity.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/users/1/recent_activity?limit=9&offset=1" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/users/1/recent_activity"
);

let params = {
    "limit": "9",
    "offset": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let 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..."
    }
]

Request   

GET /users/{user}/recent_activity

URL Parameters

user  integer  

Id of the user.

Query Parameters

limit  integer optional  

Maximum number of results.

offset  string optional  

Result offset for pagination.

Response format

Array of Event.

Get User

This endpoint returns the detail of specified user.

OAuth public

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/users/1/osu?key=unde" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/users/1/osu"
);

let params = {
    "key": "unde",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

"See User object section"

Request   

GET /users/{user}/{mode?}

URL Parameters

user  integer  

Id or username of the user. Id lookup is prioritised unless key parameter is specified. Previous usernames are also checked in some cases.

mode  string optional  

GameMode. User default mode will be used if not specified.

Query Parameters

key  string optional  

Type of user passed in url parameter. Can be either id or username to limit lookup by their respective type. Passing empty or invalid value will result in id lookup followed by username lookup if not found.

Response format

Returns User object. The following optional attributes on UserCompact are included:

Get Users

Returns list of users.

OAuth lazer

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/users?ids[]=1" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/users"
);

let params = {
    "ids[]": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let 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..."
        }
    ]
}

Request   

GET /users

Query Parameters

ids[]  string optional  

User id to be returned. Specify once for each user id requested. Up to 50 users can be requested at once.

Response format

Field Type Description
users UserCompact[] Includes: country, cover, groups, statistics_fruits, statistics_mania, statistics_osu, statistics_taiko.

Wiki

Get Wiki Page

The wiki article or image data.

Example request:

curl -X GET \
    -G "https://osu.ppy.sh/api/v2/wiki/en/Welcome" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://osu.ppy.sh/api/v2/wiki/en/Welcome"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (302):


<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="refresh" content="0;url='https://osu.ppy.sh/api/v2/wiki/en/Main_Page'" />

        <title>Redirecting to https://osu.ppy.sh/api/v2/wiki/en/Main_Page</title>
    </head>
    <body>
        Redirecting to <a href="https://osu.ppy.sh/api/v2/wiki/en/Main_Page">https://osu.ppy.sh/api/v2/wiki/en/Main_Page</a>.
    </body>
</html>

Request   

GET /wiki/{locale}/{path}

URL Parameters

locale  string  

Two-letter language code of the wiki page.

path  string  

The path name of the wiki page.

Response Format

Returns WikiPage.

Notification Websocket

Connection

wscat -c "{notification_endpoint}"
  -H "Authorization: Bearer {{token}}"

The above command will wait and display new notifications as they arrive

This endpoint allows you to receive notifications without constantly polling the server. Correct notification will be a JSON string with at least event field:

Field Type Description
event string See below

Events:

logout event

Server will disconnect session after sending this event so don't try to reconnect.

Field Type Description
event string logout

new event

New notification. See Notification object for notification types.

Field Type Description
event string new
data Notification

read event

Notification has been read.

Field Type Description
event string read
ids number[] id of Notifications which are read

Object Structures

Beatmap

Represent a beatmap. This extends BeatmapCompact 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

BeatmapCompact

Represent a beatmap.

Field Type Description
beatmapset_id integer
difficulty_rating float
id integer
mode GameMode
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|BeatmapsetCompact|null Beatmapset for Beatmap object, BeatmapsetCompact for BeatmapCompact 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.

BeatmapPlaycount

Represent the playcount of a beatmap.

Field Type Description
beatmap_id number
beatmap BeatmapCompact?
beatmapset BeatmapsetCompact?
count number

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 number The position of the score within the requested beatmap ranking.
score Score The details of the score.

Beatmapset

Represents a beatmapset. This extends BeatmapsetCompact with additional attributes.

Field Type Description
availability.download_disabled boolean
availability.more_information string?
bpm float
can_be_hyped boolean
creator string Username of the mapper at the time of beatmapset creation.
discussion_enabled boolean
discussion_locked boolean
hype.current integer
hype.required integer
is_scoreable boolean
last_updated Timestamp
legacy_thread_url string?
nominations.current integer
nominations.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

BeatmapsetCompact

Represents a beatmapset.

Field Type Description
artist string
artist_unicode string
covers Covers
creator string
favourite_count number
id number
nsfw boolean
play_count number
preview_url string
source string
status string
title string
title_unicode string
user_id number
video string

Those fields are optional.

Field Type Description
beatmaps Beatmap[]
converts
current_user_attributes
description
discussions
events
genre
has_favourited boolean
language
nominations
ratings
recent_favourites
related_users
user

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 BeatmapCompact?
beatmap_id number
beatmapset BeatmapsetCompact?
beatmapset_id number
can_be_resolved boolean
can_grant_kudosu boolean
created_at Timestamp
current_user_attributes CurrentUserAttributes
deleted_at Timestamp?
deleted_by_id number
id number
kudosu_denied boolean
last_post_at Timestamp
message_type MessageType
parent_id number?
posts BeatmapsetDiscussionPost[]
resolved boolean
starting_post BeatmapsetDiscussionPost
timestamp number?
updated_at Timestamp
user_id number
votes object[] TODO: change structure

MessageType

Name Description
hype
mapper_note
praise
problem
review
suggestion

BeatmapsetDiscussionPost

Represents a post in a BeatmapsetDiscussion.

Field Type Description
beatmapset_discussion_id number
created_at Timestamp
deleted_at Timestamp?
deleted_by_id number
id number
last_editor_id number
message string
system boolean
updated_at Timestamp
user_id number

BeatmapsetDiscussionVote

Represents a vote on a BeatmapsetDiscussion.

Field Type Description
beatmapset_discussion_id number
created_at Timestamp
id number
score number
updated_at Timestamp
user_id number

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 number
update_stream UpdateStream?
users number
version 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 number?
github_url string?
id number?
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,
    "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 number
current_user_attributes CurrentUserAttributes? only present on some responses
name string
description string?
icon* string display icon for the channel
type string see channel types below
last_read_id* number? Deprecated; use current_user_attributes.last_read_id.
last_message_id* number? message_id of last known message (only returned in presence responses)
recent_messages ChatMessage[]? up to 50 most recent messages
moderated* boolean user can't send message when the value is true (only returned in presence responses)
users* number[]? array of user_id that are in the channel (not included for PUBLIC channels)

Channel Types

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)

For PMs, two factors are taken into account:

ChatMessage

{
  "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
  }
}

Represents an individual Message within a ChatChannel.

Field Type Description
message_id number unique identifier for message
sender_id number user_id of the sender
channel_id number channel_id of where the message was sent
timestamp string when the message was sent, ISO-8601
content string message content
is_action boolean was this an action? i.e. /me dances
sender UserCompact embedded UserCompact 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 an single comment.

Field Type Description
commentable_id number ID of the object the comment is attached to
commentable_type string type of object the comment is attached to
created_at string ISO 8601 date
deleted_at string? ISO 8601 date if the comment was deleted; null, otherwise
edited_at string? ISO 8601 date if the comment was edited; null, otherwise
edited_by_id number? user id of the user that edited the post; null, otherwise
id number 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 number? ID of the comment's parent
pinned boolean Pin status of the comment
replies_count number number of replies to the comment
updated_at string ISO 8601 date
user_id number user ID of the poster
votes_count number 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 number?
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 number? Number of comments at the top level. Not returned for replies.
total number? Total number of comments. Not retuned for replies.
user_follow boolean is the current user watching the comment thread?
user_votes number[] IDs of the comments in the bundle the current user has upvoted
users UserCompact[] 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.

Field Type Description
id number the ID of the object
title string display title
type string the type of the object
url string url of the object

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.
last_read_id number 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.

Event

The object has different attributes depending on its type. Following are attributes available to all types.

Field Type Description
created_at Timestamp
id number
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 number

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 number
mode GameMode
beatmap Event.Beatmap
user Event.User

rankLost

When a user loses first place to another user.

Field Type
mode GameMode
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 number
forum_id number
id number
topic_id number
user_id number

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 Description
created_at Timestamp
deleted_at Timestamp
first_post_id number
forum_id number
id number
is_locked boolean
last_post_id number
post_count number
title string
type string normal, sticky, or announcement
updated_at Timestamp
user_id number

GameMode

Available game modes:

Name Description
fruits osu!catch
mania osu!mania
osu osu!standard
taiko osu!taiko

GithubUser

{
  "id": 218,
  "display_name": "bdach",
  "github_url": "https://github.com/bdach",
  "osu_username": null,
  "user_id": null,
  "user_url": null
}
Field Type
display_name string
github_url string?
id number?
osu_username string?
user_id number?
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 GameModes with users' memberships.
id number
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 number
action string Either give, reset, or revoke.
amount number
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.

MultiplayerScore

Score data.

Field Type Description
id number
user_id number
room_id number
playlist_item_id number
beatmap_id number
rank rank
total_score number
accuracy number
max_combo number
mods Mod[]
statistics Statistics
passed bool
position number?
scores_around MultiplayerScoresAround? Scores around the specified score.
user User

MultiplayerScores

An object which contains scores and related data for fetching next page of the result.

Field Type Description
cursor MultiplayerScoresCursor To be used to fetch the next page.
params object To be used to fetch the next page.
scores MultiplayerScore[]
total number? Index only. Total scores of the specified playlist item.
user_score MultiplayerScore? Index only. Score of the accessing user if exists.

To fetch the next page, make request to scores index with relevant room and playlist, with parameters which consists of:

For example, given a response which params contains

Key Value
sort score_asc
limit 10

and cursor of

Key Value
score_id 1
total_score 10

then the parameters would be

Field Value
sort score_asc
limit 10
cursor[score_id] 1
cursor[total_score] 10

and thus the query string is sort=score_asc&limit=10&cursor[score_id]=1&cursor[total_score]=10.

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 number Last score id of current result (score_asc, score_desc).
total_score number 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 number
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.

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 number
name string Name of the event
created_at string ISO 8601 date
object_type string
object_id number
source_user_id number?
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 number Beatmapset id
object_type string beatmapset
source_user_id number 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 number Beatmapset id
object_type string beatmapset
source_user_id number Poster of the discussion

Details object:

Field Type Description
title string Beatmap title
cover_url string Beatmap cover
discussion_id number
post_id number
beatmap_id number? null if posted to general all
username string Username of source_user_id

beatmapset_discussion_unlock

Field Type Description
object_id number Beatmapset id
object_type string beatmapset
source_user_id number 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 number Beatmapset id
object_type string beatmapset
source_user_id number 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 number Beatmapset id
object_type string beatmapset
source_user_id number 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 number Beatmapset id
object_type string beatmapset
source_user_id number 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 number Beatmapset id
object_type string beatmapset
source_user_id number 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 number Beatmapset id
object_type string beatmapset
source_user_id number 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 number Beatmapset id
object_type string beatmapset
source_user_id number 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 number Channel id
object_type string channel
source_user_id number 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 number Topic id
object_type string forum_topic
source_user_id number User who posted message

Details object:

Field Type Description
title string Title of the replied topic
cover_url string Topic cover
post_id number 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 Beatmapset[]? The list of beatmaps in the requested spotlight for the given mode; only available if type is charts
cursor Cursor A cursor
ranking UserStatistics[] Score details ordered by rank in descending order.
spotlight Spotlight? Spotlight details; only available if type is charts
total number An approximate count of ranks available

Score

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
rank_country
rank_global
weight
user
match

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 DateTime The end date of the spotlight.
id number The ID of this spotlight.
mode_specific boolean If the spotlight has different mades specific to each GameMode.
participant_count number? 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 DateTime 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 number
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 number

User

{
  "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_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_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 UserCompact 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 ever being a supporter in the past
interests string?
join_date Timestamp
kudosu.available number
kudosu.total number
location string?
max_blocks number maximum number of users allowed to be blocked
max_friends number maximum number of friends allowed to be added
occupation string?
playmode GameMode
playstyle string[] Device choices of the user.
post_count number number of forum posts
profile_order ProfilePage[] ordered array of sections in user profile page
title string? user-specific title
title_url string?
twitter string?
website string?

In addition, the following optional attributes on UserCompact are included:

ProfilePage

Section
me
recent_activity
beatmaps
historical
kudosu
top_ranks
medals

UserCompact

{
  "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
}

Mainly used for embedding in certain responses to save additional api lookups.

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 number 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
account_history UserAccountHistory[]
active_tournament_banner UserCompact.ProfileBanner?
badges UserBadge[]
beatmap_playcounts_count number
blocks
country
cover
favourite_beatmapset_count number
follower_count number
friends
graveyard_beatmapset_count number
groups UserGroup[]
is_restricted boolean?
loved_beatmapset_count number
monthly_playcounts UserMonthlyPlaycount[]
page
pending_beatmapset_count
previous_usernames
rank_history
ranked_beatmapset_count
replays_watched_counts
scores_best_count number
scores_first_count number
scores_recent_count number
statistics
statistics_rulesets UserStatisticsRulesets
support_level
unread_pm_count
user_achievements
user_preferences

ProfileBanner

Field Type Description
id number
tournament_id number
image string

UserAccountHistory

Field Type Description
description string?
id number
length number In seconds.
timestamp Timestamp
type string note, restriction, or silence.

UserBadge

Field Type Description
awarded_at Timestamp
description string
image_url string
url string

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[]? GameModes 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 number id of this object.
user_id number id of the User that was silenced

UserStatistics

{
  "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 GameMode

Field Type Description
grade_counts.a number Number of A ranked scores.
grade_counts.s number Number of S ranked scores.
grade_counts.sh number Number of Silver S ranked scores.
grade_counts.ss number Number of SS ranked scores.
grade_counts.ssh number Number of Silver SS ranked scores.
hit_accuracy number Hit accuracy percentage
is_ranked boolean Is actively ranked
level.current number Current level.
level.progress number Progress to next level.
maximum_combo number Highest maximum combo.
play_count number Number of maps played.
play_time number Cumulative time played.
pp number Performance points
global_rank number? Current rank according to pp.
ranked_score number Current ranked score.
replays_watched_by_others number Number of replays watched by other users.
total_hits number Total number of hits.
total_score number Total score.
user UserCompact The associated 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.