This is the documentation for the pointercrate application programming interface (short: API). If you dont know what an API is or have no idea how you even got to this page, this link takes you back to the demonlist. If you rather want to read source code of the implementation directly, head over to the github repository instead. It also contains the markdown files these documentation pages are generated from, so if you find any error here feel free to submit a pull request!
The API can be used to retrieve data about the demonlist and is internally used to manage it. All endpoints described here are located under https://pointercrate.com/api/v1/
unless a different api version is explicitly provided, in which case the v1
part of the URL needs to be amended. Currently, there are only a few endpoints using a v2
scheme.
It is always good practice setting the Accept
header in requests to application/json
(or at least give application/json
a higher preference than text/html
), so that in case of errors, you receive a JSON response instead of the HTML error page.
All HTTP traffic is automatically redirected to HTTPS. All requests to URLs without a trailing slash are automatically redirected to URLs with one.
In case of a client or server error, the API returns an error response. Errors that are specific to a given endpoint are always listed in that endpoint’s documentation. Following is an exhaustive list of errors that can occur at any endpoint in the API. Note that the errors with status code 500 INTERNAL SERVER ERROR
should (obviously) not occur and are only listed for completeness sake. An complete list of all errors can be found at the bottom on this page.
Status code | Error code | Description | Data |
---|---|---|---|
400 | 40002 | A header in the request was malformed and couldn’t be processed | header : The name of the malformed header |
405 | 40500 | 405 METHOD NOT ALLOWED error |
allowed_methods : A list of allowed HTTP methods for this endpoint |
409 | 40900 | 409 CONFLICT error. The resources you attempted to modify or delete has been concurrently modified by another client. Try again after re-requesting the resource |
|
412 | 41200 | The value provided in the If-Match header doesn’t match the current state of the object |
|
418 | 41800 | No If-Match header was provided, although the request needs to be conditional |
|
500 | 50000 | The server encountered an unexpected state and couldn’t recover | |
500 | 50001 | Same as above, but we actually know what happened | cause : The cause of the error |
500 | 50003 | The database unexpectedly returned an error while accessing the data required to perform the request | |
500 | 50005 | Failure to connect to the database | |
503 | 50300 | The requested endpoint is currently down for maintenance |
In the case that you do not receive any response at all, or receive a Apache/Nginx error page you can assume that the pointercrate server crashed and couldn’t recover. If this is the case all hope is lost.
409
versus 412
The cases in which a 409 CONFLICT
error or a 412 PRECONDITION FAILED
error is returned are very similar. In fact, handling for both errors should probably be identical. A 409
error is returned if the request you were making contained a valid hash of the object you were trying to access, however the same was true for another concurrent request. Which ever of the requests commits its database level transaction might now receive the CONFLICT
error. A 412
error means that a modification to the object you were trying to access happen at some point prior to your current request (or the hash you sent along was invalid in the first place).
Both cases need to be handled the same way: You’ll have to re-GET
the object to retrieve its updated ETag
and retry the request (simply retrying after a 409
error will most likely yield a 412
error directly after)
Some endpoints in the API require you to authenticate using HTTP Basic Authentication. Since all communication with the API is enforced to be done via HTTPS, this is OK.
Pointercrate requires you to have a valid access token to issue requests to most endpoints. An access token for your account can be retrieved via a successful call to the login endpoint.
Pointercrate access tokens are JSON Web Tokens and can be parsed by any standard compliant implementation.
Each access token is valid until you change your password, or is invalidated via a call to invalidate.
When an endpoint requires authentication via an access token, the Authorization
header has to be set to the word Bearer
followed by a space, followed by your access token.
Theoretically, it is possible to authenticate using cookies. Any requests made from your browser through the web interface are authenticated this way. Practically, you cannot use this authentication method (attempting to do so will simply result in a 401 UNAUTHORIZED
response)
These error conditions apply to any endpoint that require authentication and are thus not repeated for every one of them.
Status code | Error code | Description |
---|---|---|
401 | 40100 | A generic 401 UNAUTHORIZED error, indicating that authorization failed (e.g. because of a bad username, wrong password, wrong authorization method ) |
Different endpoints require different kinds of permissions to be used. Additionally, access to user objects via the sub-endpoints of /users/
is also governed by permissions. In particular, you can only access accounts of users who have permissions that you can assign (with the exception of people having MODERATOR
privileges, who can access all user accounts).
If an endpoints requires special permissions to be accessed, it’s documentation will contain a notice similar to this one:
Access Restrictions:
Access to this endpoint requires at least LIST_HELPER
permissions.
A user’s permissions are saved as a bitmask, and by default every user has no permissions.
The following permissions exist. If a permissions A
implies some other permission B
, then a user with permission A
can do everything a user with permission B
can do, without needing to explicitly having the bit for permission B
set. For example, a user with only the LIST_MODERATOR
bit set also has all privileges that the LIST_HELPER
bit grants. Note that implication of permissions in transitive, e.g. a user with only the LIST_ADMINISTRATOR
bit set still has all privileges that the LIST_HELPER
bit grants, since LIST_ADMINISTRATOR
implies LIST_MODERATOR
, which implies LIST_HELPER
.
If a permission A
assigns some other permission B
then a user with permission A
can modify the bit for permission B
via PATCH /users/user_id/
of users he has access to.
Permission | Bit | Description | Implies | Assigns |
---|---|---|---|---|
LIST_HELPER |
0x2 | Users that help out in managing the demonlist by reviewing records | None | None |
LIST_MODERATOR |
0x4 | Users that moderate the demonlist and manage the demon placements | LIST_HELPER |
None |
LIST_ADMINISTRATOR |
0x8 | Users that administrate the demonlist | LIST_MODERATOR |
LIST_HELPER , LIST_MODERATOR |
MODERATOR |
0x2000 | Users that have access to the pointercrate user list | None | None |
ADMINISTRATOR |
0x4000 | Users that can manage other users, including granting them permissions | MODERATOR |
LIST_ADMINISTRATOR , LIST_HELPER |
These error conditions can occur at any endpoint expecting requiring specific access permissions and are thus not listed specifically for each of them.
Status code | Error code | Description | Data |
---|---|---|---|
403 | 40301 | You do not have the permissions required to perform this request | required : A list of permission-bitmasks that would allow you to perform the request |
Some endpoints in the pointercrate API support or require pagination due to the potentially huge amount of data they can return. This mostly applies to the endpoints that return lists of objects, like GET /records/
.
Objects returned by endpoints supporting pagination are totally ordered by an ID field, which is specified in the endpoint’s documentation.
If an endpoint supports pagination, it’s documentation will contain a notice similar to this one:
Pagination:
This endpoint supports pagination and filtering via query parameters. Please see the documentation on pagination for information on the additional request and response headers.
Pagination is done via specific query parameters, which tell pointercrate which part of the result set to return.
Note that there is no way to get the total amount of pages, as both page bounds and size can be chosen abitrarily.
Query Parameter | Description | Default |
---|---|---|
limit | The maximum amount of object to return. Must lie between 1 and 100 |
50 |
after | The id of the last object on the previous page, thus specifying the start point of the current page | null |
before | The id of the first object on the next page, thus specifying the end point of the current page | null |
Omitting before
or after
, which implicitly sets them to null
, makes the server act like they’re set to negative/positive infinity respectively.
Paginatable endpoints provide the Links
header to simply access to the next, previous, first and last page, using the limit
set on the request. The header is set to a comma-seperated list of links in the form <[link]>; rel=[page]
, where page is one of next
, prev
, first
or last
.
Note that the next
and prev
links are only provided if there actually is a next or previous page of results respectively. The server always provides the first
and last
links.
Most endpoints that support pagination also support filtering their results beyond simply using the pagination parameters.
If this is supported, the documentation specifies the filterable fields for a given endpoint. It is then possible to specify conditions in the query string, which the returned objects must meet.
There are two ways of filtering the result set:
/api/v1/players/?banned=true
__lt
or __gt
, and the value to check for inequality against in the query string, i.e. /api/v1/records/?progress__gt=75
. Note that this doesn’t work for all fields (since a lexicographical filtering on the record status hardly seems useful)_contains
.Multiple conditions can be combined, i.e. /api/v1/records/?after=200&limit=10&status=APPROVED&progress__lt=100
. This request would return the first 10 approved records with a record ID greater than 200 and a progress less than 100.
Note that filtering explicitly on the ID field is not possible. You have to use the special before
and after
parameters for that. You also cannot use equality filtering on the ID field. Use the specific endpoint for retrieving single objects instead.
These error conditions can occur at any endpoint supporting pagination and are thus not listed specifically for each of them.
Status code | Error code | Description |
---|---|---|
422 | 42207 | The limit parameter is smaller than 1 or greater than 100 |
422 | 42227 | In pagination, the after value was smaller than the before value |
Pointercrate only accepts videos from a specific set of hosting services. It further normalizes all videos from a given host into one specific URL format and ensures that every video link actually leads to a valid video. All query parameters, including timestamps on youtube videos, are stripped from URLs.
If a host you want to see supported is missing or a URL format for one of the provided hosts is missing, please open an issue on the GitHub repository.
Please note that pointercrate asynchronously performs HEAD
requests to any video URL submitted and discards any that don’t return a successful response.
The accepted URL formats are:
Video host | URL formats |
---|---|
YouTube | http[s]://www.youtube.com/watch?v={id} |
YouTube | http[s]://m.youtube.com/watch?v={id} |
YouTube | http[s]://youtube.com/watch?v={id} |
YouTube | http[s]://youtu.be/{id} |
Twitch | http[s]://www.twitch.tv/videos/{id} |
Twitch | http[s]://twitch.tv/videos/{id} |
Twitch | http[s]://www.twitch.tv/{name}/v/{id} |
Twitch | http[s]://twitch.tv/{name}/v/{id} |
Everyplay | http[s]://www.everyplay.com/videos/{id} |
Everyplay | http[s]://everyplay.com/videos/{id} |
Vimeo | http[s]://www.vimeo.com/{id} |
Vimeo | http[s]://vimeo.com/{id} |
Bilibili | http[s]://www.bilibili.com/video/{id} |
Bilibili | http[s]://bilibili.com/video/{id} |
They are normalized into the following:
Video host | URL format |
---|---|
YouTube | https://www.youtube.com/watch?v={id} |
Twitch | https://www.twitch.tv/videos/{id} |
Everyplay | https://everyplay.com/videos/{id} |
Vimeo | https://vimeo.com/{id} |
Bilibili | https://www.bilibili.com/video/{id} |
These error conditions can occur at any endpoint expecting a video URL and are thus not listed specifically for each of them.
Status code | Error code | Description | Data |
---|---|---|---|
422 | 42222 | Invalid protocol encountered while processing an URL. Only http and https are supported |
- |
422 | 42223 | Authentication information was discovered while processing an URL | - |
422 | 42224 | An unknown/unsupported video host has been discovered while processing an URL (no, pornhub is no acceptable host, what is wrong with you people??) | - |
422 | 42225 | The video URL does not match the expected format for the given host | expected : The expected URL format for this host |
In general it is the goal to have the API provide as detailed errors as possible. The generic error variants should be returned as rarely as possible. If you feel like a specific error could be communicated better, feel free to open an issue in the GitHub repository!
Status code | Error code | Description | Data |
---|---|---|---|
400 | 40000 | A generic 400 BAD REQUEST error |
- |
400 | 40001 | Provided video or channel URL was malformed | - |
400 | 40002 | A header in the request was malformed and couldn’t be processed | header : The name of the malformed header |
401 | 40100 | A generic 401 UNAUTHORIZED error, indicating that authorization failed (e.g. because of a bad username, wrong password, wrong authorization method ) |
- |
403 | 40300 | A generic 403 FORBIDDEN error |
- |
403 | 40301 | You do not have the permissions required to perform this request | required : A list of permission-bitmasks that would allow you to perform the request |
403 | 40302 | Attempt to delete your own account via the administrative endpoints | - |
403 | 40303 | Attempt to modify your own account via the administrative endpoints | - |
403 | 40304 | You have been banned from submitting records | - |
403 | 40305 | Attempt to assign someone permissions that you do not have the permissions to assign | non_assignable : A list of permission bitmasks that you cannot assign |
403 | 40306 | The claim you are trying to modify is unverified | - |
403 | 40307 | An attempt to geolocate through a VPN was detected | - |
403 | 40308 | You are not authorized to submit a record for this player | - |
404 | 40400 | A generic 404 NOT FOUND error |
- |
404 | 40401 | Some object referenced in the request couldn’t be found | - |
405 | 40500 | 405 METHOD NOT ALLOWED error |
allowed_methods : A list of allowed HTTP methods for this endpoint |
409 | 40900 | 409 CONFLICT error. The resources you attempted to modify or delete has been concurrently modified by another client. Try again after re-requesting the resource |
- |
409 | 40902 | The username you chose is already in use | - |
409 | 40905 | The given player is already registered as a creator | - |
409 | 40906 | Duplicate video when patching record | id : ID of the record already using the specified video |
409 | 40907 | Attempting to set a subnation without a nation set | - |
409 | 40908 | Two players have conflicting verified user claims during merge | player1 : First (base) player nameplayer2 : Second player name |
411 | 41100 | A generic 411 LENGTH REQUIRED error |
- |
412 | 41200 | 412 PRECONDITION FAILED error. The provided If-Match header doesn’t match the current state of the object |
- |
413 | 41300 | 413 PAYLOAD TOO LARGE error |
- |
415 | 41500 | 415 UNSUPPORTED MEDIA TYPE error. Returned if you try to send anything that’s not a JSON request body |
expected : The expected media type. Currently always application/json |
422 | 42200 | A generic 422 UNPROCESSABLE ENTITY error |
- |
422 | 42202 | The username provided during registration is shorter than 3 characters or isn’t trimmed | - |
422 | 42204 | The password provided during registration is shorter than 10 characters | - |
422 | 42207 | The limit pagination parameter is smaller than 1 or greater than 100 |
- |
422 | 42212 | A demon was attempted to be added with a record requirement outside the interval [0, 100] |
- |
422 | 42213 | A demon was attempted to be added out-of-bounds | maximal : The largest position it is acceptable to add a demon at |
422 | 42215 | A record with invalid progress was submitted | requirement : The record requirement for the demon the record was submitted on |
422 | 42217 | A record that’s already in the database was submitted | status : The status of the existing recordexisting : The ID of the existing record |
422 | 42218 | The record holder of a submission is banned | - |
422 | 42219 | A record for a legacy demon was submitted | - |
422 | 42220 | A non-100% record was submitted for the extended list | - |
422 | 42222 | Invalid protocol encountered while processing an URL. Only http and https are supported |
- |
422 | 42223 | Authentication information was discovered while processing an URL | - |
422 | 42224 | An unknown/unsupported video host has been discovered while processing an URL (no, pornhub is no acceptable host, what is wrong with you people??) | - |
422 | 42225 | The video URL does not match the expected format for the given host | expected : The expected URL format for this host |
422 | 42226 | A YouTube url was expected | - |
422 | 42227 | In pagination, the after value was smaller than the before value |
- |
422 | 42228 | A demon was specified by name, but multiple demons with the given name exist | demons : A list of MinimalDemon objects sharing the given name |
422 | 42229 | Your request body tries to simultaneously use mutually exclusive fields (e.g. demon_id together with demon_name ) |
- |
422 | 42230 | The record note is empty | - |
422 | 42231 | Player already has an associated verified claim | - |
422 | 42232 | A record without raw footage was submitted | - |
422 | 42233 | Provided raw footage was not a valid URL | - |
428 | 42800 | Missing If-Match header on a request that’s required to be conditional |
- |
429 | 42900 | You are being rate limited | remaining : The time you have to wait before successfully making the request |
500 | 50000 | The server encountered an unexpected state and couldn’t recover | - |
500 | 50003 | The database unexpectedly returned an error while accessing the data required to perform the request | - |
500 | 50005 | Failure to connect to the database | - |
503 | 50301 | The server is in maintenance mode and rejects all mutating requests | - |