Skip to content

Latest commit

 

History

History
853 lines (606 loc) · 47 KB

_modio.md

File metadata and controls

853 lines (606 loc) · 47 KB

Getting Started

--parse_sitename API --parse_version

Welcome to the official documentation for --parse_sitename, an API for developers to add mod support to their games. Using our SDKs and plugins for popular and custom game engines, getting your creator community started and making the mods they create discoverable and installable via your in-game menu is straight forward, with full cross-platform support. If you are a game developer, you can manage your games and API access via your --parse_sitename content dashboard. If you are a user creating tools and apps, you can request API access via your --parse_sitename account.

API path: --parse_apiurl (see your API access dashboard)

Swagger JSON: --parse_apiswaggerurl

Current version: --parse_vdropdown

View Version Changelog

How It Works

Compatible with all builds of your game on all platforms and stores, --parse_sitename is a clientless and standalone solution which gives you complete control over your modding ecosystem.

--parse_sitename Overview

Implementation

Once you have added your game to --parse_sitename and got your game ID and API key, you can start integrating the --parse_sitename REST API into your game, tools and sites. There are 3 options to get connected which you can use interchangeably depending on your needs. Here's the breakdown of each option.

Option Usage Suited for Docs
API For connecting directly to the --parse_sitename REST API. Web apps that need a JSON REST API, or game developers that like a challenge and want control over their implementation. You are reading them
SDK Drop our open source C/C++ SDK into your game to call --parse_sitename functionality. Game developers that want a SDK that abstracts the uploading, downloading and unzip flows behind easy to use function calls. Here
Tools/Plugins Use tools, plugins and wrappers created by the community to make implementation in various engines easy. Game developers that want a pre-built modding solution for their engine (Unity, Unreal, GameMaker, Construct) of choice. Available below

Official Tools

Plugins and wrappers made or supported by the --parse_sitename team

| - | - | - --- | --- | --- | --- Unity Plugin | Unity Plugin
SDK
Getting Started
Sample Project
| Unreal Plugin | Unreal Plugin
SDK
Getting Started
UE4 Sample Project
UE5 Sample Project
GameMaker | GameMaker
SDK
Getting Started
| C/C++ SDK | C/C++ SDK
SDK
Getting Started
Discord Bot | Discord Bot
Instructions
Invite
|

Community Tools

Plugins and wrappers made by our awesome community. Is there a tool out there that should be added to the list? [Get in touch!](mailto:--parse_email?subject=Publish Tool)

| - | - | - --- | --- | --- | --- Construct 2 | Construct 2 Plugin
SDK
Getting Started
| Haxe Wrapper | Haxe Wrapper
SDK
Getting Started
Modio.NET | Modio.NET
SDK
Getting Started
| Rust Wrapper | Rust Wrapper
SDK
Getting Started
Tutorials
Python Wrapper | Python Wrapper
SDK
Getting Started
Tutorials
| Command Lisp | Common Lisp
Github
Getting Started
Command Line Tool | Command Line Tool
CMD
Getting Started
| GitHub Action Mod Uploader | GitHub Action Mod Uploader
GitHub
Usage

Here is a brief list of the things to know about our API, as explained in more detail in the following sections.

  • All requests to the API must be made over HTTPS (TLS).
  • All API responses are in application/json format.
  • Any POST request with a binary payload must supply the Content-Type: multipart/form-data header.
  • Any non-binary POST, PUT and DELETE requests must supply the Content-Type: application/x-www-form-urlencoded header.
  • Any non-binary payload can be supplied in JSON format using the input_json parameter.

Authentication

Authentication can be done via 5 ways:

All users and games are issued an API key which must be included when querying the API. It is quick and easy to use but limited to read-only GET requests, due to the limited security it offers. If you want players to be able to add, edit, rate and subscribe to content, you will need to use an authentication method that generates an OAuth 2 Access token. These authentication methods are explained in detail here.

Authentication Type In HTTP Methods Abilities Purpose
API Key Query GET Read-only GET requests and authentication flows. Browsing and downloading content. Retrieving access tokens on behalf of users.
Access Token (OAuth 2) Header GET, POST, PUT, DELETE Read, create, update, delete. View, add, edit and delete content the authenticated user has subscribed to or has permission to change.

You can use an OAuth 2.0 bearer token instead of an API key for GET endpoints (excluding Authentication endpoints). But remember, if you provide both an Access Token (OAuth 2) and an API key in one request, the access token takes precedence and the API key is ignored. So, always ensure you use a valid access token and have the process in place to get a new token when the old one expires.

Web Overlay Authentication

At the moment it is not possible to open the --parse_sitename website in-game with the user pre-authenticated, however you can provide a hint by appending ?portal=PORTAL to the end of the URL. What this tells --parse_sitename, is that when the user attempts to perform an action that requires authentication, they will be prompted to login with their PORTAL account. For example if you want to take a mod creator to their mod webpage in-game on Steam, the URL would look something like: --parse_gameurl/m/modname?portal=steam. You can optionally add &login=auto as well to automatically start the login process. Supported portals can be found here.

Scopes (OAuth 2)

--parse_sitename allows you to specify the permission each access token has (default is read+write), this is done by the use of scopes. See below for a full list of scopes available, you must include at least one scope when generating a new token.

Scope Abilities
read When authenticated with a token that only contains the read scope, you will only be able to read data via GET requests.
write When authenticated with a token that contains the write scope, you are able to add, edit and remove resources.
read+write The above scopes combined. Default for email and external ticket verification flow.

Making Requests

Requests to the --parse_sitename API are to be over HTTPS (Port 443), any requests made over HTTP will return a 400 Bad Request response.

Using an API Key

curl -X get --parse_apiurl/games?api_key=xxxxxxxxxxxxxxxx

To authenticate using your unique 32-character API key, append the api_key=xxxxxxxxxxxxxxxx parameter to the end of your request. Remember that using an API key means requests are read-only, if you want to create, update or delete resources - authentication via OAuth 2 is required which you can set up with your api key.

Using an Access Token

Example POST request with no binary files

curl -X POST --parse_apiurl/games/1/mods/1/tags \
  -H 'Authorization: Bearer your-token-here' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'tags[]=Unity' \
  -d 'tags[]=FPS'

To authenticate using an OAuth 2 access token, you must include the HTTP header Authorization in your request with the value Bearer your-token-here. Verification via Access Token allows much greater power including creating, updating and deleting resources that you have access to. Also because OAuth 2 access tokens are tied to a user account, you can personalize the output by viewing content they are subscribed and connected to via the me endpoint and by using relevant filters.

Access Token Lifetime & Expiry

By default, all access token's are long-lived - meaning they are valid for a common year (not leap year) from the date of issue. You should architect your application to smoothly handle the event in which a token expires or is revoked by the user themselves or a --parse_sitename admin, triggering a 401 Unauthorized API response.

If you would like tokens issued through your game to have a shorter lifespan, you can do this by providing the date_expires parameter on any endpoint that returns an access token such as the Email Exchange or Authenticate via Steam endpoints. If the parameter is not supplied, it will default to 1 year from the request date, if the supplied parameter value is above one year or below the current server time it will be ignored and the default value restored.

Request Content-Type

If you are making a request that includes a file, your request Content-Type header must be multipart/form-data, otherwise if the request contains data (but no files) it should be application/x-www-form-urlencoded, which is UTF-8 encoded.

Example POST request with binary file

curl -X POST --parse_apiurl/games/1/mods \
  -H 'Authorization: Bearer your-token-here' \
  -H 'Content-Type: multipart/form-data' \ 
  -F 'logo=@path/to/image.jpg' \
  -F 'name=Rogue Knight Clear Skies' \
  -F 'homepage=http://www.clearsies-rk.com/' \
  -F 'summary=It rains in Rogue Knight an awful lot, want sunshine all the time? Yeah you do.'
Body Contains Method Content-Type
Binary Files POST multipart/form-data
Non-Binary Data POST, PUT, DELETE application/x-www-form-urlencoded
Nothing GET No Content-Type required.

If the endpoint you are making a request to expects a file it will expect the correct Content-Type as mentioned. Supplying an incorrect Content-Type header will return a 415 Unsupported Media Type response.

JSON Request Data

Example json-encoded POST request

curl -X POST --parse_apiurl/games/1/mods/1/team \
  -H 'Authorization: Bearer your-token-here' \
  -H 'Content-Type: application/x-www-form-urlencoded' \  
  -d 'input_json={
		"email": "--parse_email",
		"level": 8,
		"position": "King in the North"
	  }'

For POST & PUT requests that do not submit files you have the option to supply your data as HTTP POST parameters, or as a UTF-8 encoded JSON object inside the parameter input_json which contains all payload data. Regardless, whether you use JSON or not the Content-Type of your request still needs to be application/x-www-form-urlencoded with the data provided in the body of the request.

NOTE: If you supply identical key-value pairs as a request parameter and also as a parameter in your JSON object, the JSON object will take priority.

Response Content-Type

Responses will always be returned in application/json format.

Response Codes

Here is a list of the most common HTTP response codes you will see while using the API.

Response Code Meaning
200 OK -- Your request was successful.
201 Created -- Resource created, inspect Location header for newly created resource URL.
204 No Content -- Request was successful and there was no data to be returned.
400 Bad Request -- Server cannot process the request due to malformed syntax or invalid request message framing.
401 Unauthorized -- Your API key/access token is incorrect, revoked, or expired.
403 Forbidden -- You do not have permission to perform the requested action.
404 Not Found -- The requested resource could not be found.
405 Method Not Allowed -- The method of your request is incorrect.
406 Not Acceptable -- You supplied or requested an incorrect Content-Type.
409 Conflict -- The request could not be completed due to a competing request (duplicate POST requests).
422 Unprocessable Entity -- The request was well formed but unable to be followed due to semantic errors.
429 Too Many Requests -- You have made too many requests, inspect headers for reset time.
500 Internal Server Error -- The server encountered a problem processing your request. Please try again. (rare)
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later. (rare)

Errors

Error object

"error": {
	"code": 403,
	"error_ref": --parse_errorref_MOD_NO_VIEW_PERMISSION,
	"message": "You do not have the required permissions to access this resource."
}

If an error occurs, --parse_sitename returns an error object with the HTTP code, error_ref and message to describe what happened and when possible how to avoid repeating the error. It's important to know that if you encounter errors that are not server errors (500+ codes) - you should review the error message before continuing to send requests to the endpoint.

When requests contain invalid input data or query parameters (for filtering), an optional field object called errors can be supplied inside the error object, which contains a list of the invalid inputs. The nested errors object is only supplied with 422 Unprocessable Entity responses. Be sure to review the Response Codes to be aware of the HTTP codes that the --parse_sitename API returns.

Error object with input errors

"error": {
	"code": 422,
	"error_ref": --parse_errorref_VALIDATION_GENERIC,
	"message": "Validation Failed. Please see below to fix invalid input.",
	"errors": {
		"summary":"The mod summary cannot be more than 200 characters long.",
	}
}

Remember that Rate Limiting applies whether an error is returned or not, so to avoid exceeding your daily quota be sure to always investigate error messages - instead of continually retrying.

Error Codes

Along with generic HTTP response codes, we also provide --parse_sitename specific error codes to help you better understand what has gone wrong with a request. Below is a list of the most common error_ref codes you could encounter when consuming the API, as well as the reason for the error occuring. For error codes specific to each endpoint, click the 'Show All Responses' dropdown on the specified endpoint documentation.

Example request with malformed api_key

curl -X GET --parse_apiurl/games?api_key=malformed_key
{
    "error": {
        "code": 401,
        "error_ref": --parse_errorref_API_KEY_MALFORMED,
        "message": "We cannot complete your request due to a malformed/missing api_key in your request. Refer to documentation at --parse_docsurl"
    }
}
Error Reference Code Meaning
--parse_errorref_UNEXPECTED_SERVICE_OUTAGE --parse_sitename is currently experiencing an outage. (rare)
--parse_errorref_CORS_GENERIC Cross-origin request forbidden.
--parse_errorref_UNEXPECTED_OPERATION_FAILURE --parse_sitename failed to complete the request, please try again. (rare)
--parse_errorref_API_VERSION_INVALID API version supplied is invalid.
--parse_errorref_API_KEY_MISSING api_key is missing from your request.
--parse_errorref_API_KEY_MALFORMED api_key supplied is malformed.
--parse_errorref_API_KEY_INVALID api_key supplied is invalid.
--parse_errorref_TOKEN_MISSING_SCOPE_WRITE Access token is missing the write scope to perform the request.
--parse_errorref_TOKEN_MISSING_SCOPE_READ Access token is missing the read scope to perform the request.
--parse_errorref_TOKEN_EXPIRED_OR_REVOKED Access token is expired, or has been revoked.
--parse_errorref_USER_DELETED Authenticated user account has been deleted.
--parse_errorref_USER_BANNED Authenticated user account has been banned by --parse_sitename admins.
--parse_errorref_RATE_LIMITED_GLOBAL You have been ratelimited globally for making too many requests. See Rate Limiting.
--parse_errorref_RATE_LIMITED_ENDPOINT You have been ratelimited from calling this endpoint again, for making too many requests. See Rate Limiting.
--parse_errorref_FILE_CORRUPTED The submitted binary file is corrupted.
--parse_errorref_FILE_UNREADABLE The submitted binary file is unreadable.
--parse_errorref_JSON_MALFORMED You have used the input_json parameter with semantically incorrect JSON.
--parse_errorref_MISSING_CONTENT_TYPE The Content-Type header is missing from your request.
--parse_errorref_INCORRECT_CONTENT_TYPE The Content-Type header is not supported for this endpoint.
--parse_errorref_JSON_RESPONSE_ONLY You have requested a response format that is not supported (JSON only).
--parse_errorref_VALIDATION_GENERIC The request contains validation errors for the data supplied. See the attached errors field within the Error Object to determine which input failed.
--parse_errorref_RESOURCE_NOT_FOUND The requested resource does not exist.
--parse_errorref_GAME_NOT_FOUND The requested game could not be found.
--parse_errorref_GAME_DELETED The requested game has been deleted.
--parse_errorref_MODFILE_NOT_FOUND The requested modfile could not be found.
--parse_errorref_MOD_NOT_FOUND The requested mod could not be found.
--parse_errorref_MOD_DELETED The requested mod has been deleted.
--parse_errorref_COMMENT_NOT_FOUND The requested comment could not be found.
--parse_errorref_USER_NOT_FOUND The requested user could not be found.

Response Formats

Single object response

{
    "id": 2,
    "mod_id": 2,
    "date_added": 1499841487,
    "date_scanned": 1499841487,
    "virus_status": 0,
    "virus_positive": 0,
    "virustotal_hash": "f9a7bf4a95ce20787337b685a79677cae2281b83c63ab0a25f091407741692af-1508147401",
    "filesize": 15181,
    "filehash": {
      "md5": "2d4a0e2d7273db6b0a94b0740a88ad0d"
    },
    "filename": "rogue-knight-v1.zip",
    "version": "1.3",
    "changelog": "VERSION 1.3 -- Changes -- Fixed critical castle floor bug.",
    "metadata_blob": "rogue,hd,high-res,4k,hd-textures",
    "download": {
      "binary_url": "--parse_apiurl/games/1/mods/1/files/1/download",
      "date_expires": 1579316848
    }
}

The way in which --parse_sitename formats responses is entirely dependant on whether the requesting endpoint is returning a single item or a collection of items.

Single item Responses

For single items, --parse_sitename returns a single JSON object which contains the requested resource. There is no nesting for single responses.

Multiple item Responses

Endpoints that return more than one result, return a JSON object which contains a data array and metadata fields:

  • data - contains all data returned from the request.
  • metadata fields - contains pagination metadata to help you paginate through the API.

Multiple objects response

{
	"data": [
		{
    		"id": 2,
    		"mod_id": 2,
    		"date_added": 1499841487,
    		"date_scanned": 1499841487,
    		"virus_status": 0,
    		"virus_positive": 0,
    		"virustotal_hash": "f9a7bf4a95ce20787337b685a79677cae2281b83c63ab0a25f091407741692af-1508147401",
    		"filesize": 15181,
    		"filehash": {
    		  "md5": "2d4a0e2d7273db6b0a94b0740a88ad0d"
    		},
    		"filename": "rogue-knight-v1.zip",
    		"version": "1.3",
    		"changelog": "VERSION 1.3 -- Changes -- Fixed critical castle floor bug.",
    		"metadata_blob": "rogue,hd,high-res,4k,hd-textures",
    		"download": {
    		  "binary_url": "--parse_apiurl/games/1/mods/1/files/1/download/c489a0354111a4d76640d47f0cdcb294",
    		  "date_expires": 1579316848
    		}
		},
		{
			...
		},
	],
	"result_count": 100,
	"result_limit": 100,
	"result_offset": 0,
	"result_total": 127
}  

Status & Visibility

To manage games and mods via the API we use the fields status and visible. The values of these fields determines what is returned in API requests, so it is important to understand who is authorized to view what content.

Visible attribute states & privileges

Only mods use the visible attribute allowing mod admins to control their availability. Public is the default value:

Meaning Value Description Modify Authorization Filter Authorization
Hidden --parse_value_hidden Resource is hidden and not returned when browsing.

If requested directly it will be returned provided the user is an admin or subscribed to the content. All resources are always returned via the /me endpoints.
Game & Mod Admins Game & Mod Admins
Public --parse_value_public Resource is visible and returned via all endpoints. Game & Mod Admins Everyone

Status attribute states & privileges

Games and mods use the status attribute allowing game admins to control their availability. For mods this is important because it allows game admins to control which mods are available without changing the visible value set by the mod admin. Not accepted is the default value until changed by a game admin, or if a file is added to a mods profile it will be moved to an accepted state (provided the game developer has elected "not to curate" new mods):

Meaning Value Description Modify Authorization Filter Authorization
Not Accepted --parse_value_notaccepted Resource is not accepted and not returned when browsing.

Games will be returned if requested directly provided the user is an admin or the api_key used belongs to the game.

Mods will be returned if requested directly provided the user is an admin or subscribed to the content. All resources are always returned via the /me endpoints.
Game Admins Only Game Admins Only
Accepted --parse_value_accepted Resource is accepted and returned via all endpoints. Game Admins Only Everyone
Deleted --parse_value_deleted Resource is deleted and only returned via the /me endpoints. Game Admins Only Game Admins Only

Game admin privileges

As a game admin, you can modify your games status to show or hide it from API requests. When a game is not accepted you can still view it provided you are the games admin or using the games api_key. You can call Get User Games endpoint to retrieve all games associated with the authenticated user regardless of their status.

By default mods connected to a game will not be returned if they are hidden or not accepted. As a game admin, you can modify a mods status and visible fields and filter by these values (to view content normal users cannot see). We recommend you only change the status and let mod admins control the visible field.

Mod admin privileges

As a mod admin, you can modify visible to show or hide your mod from API requests. You cannot modify the status of your mod. When a mod is hidden you can still view it provided you are the mods admin or subscribed to the mod. You can call Get User Mods endpoint to retrieve all mods associated with the authenticated user regardless of their status and visible.

Valid status & visibility filters

status=1
status-in=0,1
visible=1 
visible-in=0,1

Game Admin Only status & visibility filters

status-not-in=1,2
status-gt=1
visible-not-in=1
visible-st=1

Important Note When Filtering

Due to the requirement of certain status & visible values only being available to administrators. We have restricted the amount of filters available for non-game admins and thus for both of these fields only direct matches = and -in are permitted. Attempting to apply game admin filters without the required permissions will result in a 403 Forbidden error response.

Pagination

When requesting data from endpoints that contain more than one object, you can supply an _offset and _limit to paginate through the results. Think of it as a page 1, 2, 3... system but you control the number of results per page, and the page to start from. Appended to each response will be the pagination metadata:

Metadata example

"result_count": 100,
"result_limit": 100,
"result_offset": 0,
"result_total": 127
Parameter Value
result_count Number of results returned in the current request.
result_limit Maximum number of results returned. Defaults to 100 unless overridden by _limit.
result_offset Number of results skipped over. Defaults to 0 unless overridden by _offset.
result_total Total number of results found.

_limit (Limit)

--parse_version/games?_limit=5

Limit the number of results for a request. By default 100 results are returned per request:

  • ?_limit=5 - Limit the request to 5 individual results.

_offset (Offset)

--parse_version/games?_offset=30

Use _offset to skip over the specified number of results, regardless of the data they contain. This works the same way offset does in a SQL query:

  • ?_offset=30 - Will retrieve 100 results after ignoring the first 30 (31 - 130).

Combining offset with a limit

--parse_version/games?_offset=30&_limit=5

You can combine offset with a limit to build queries that return exactly the number of results you want:

  • ?_offset=30&_limit=5 - Will retrieve 5 results after ignoring the first 30 (31 - 35).

If the result_count parameter matches the result_limit parameter (5 in this case) in the response, that means there are probably more results to get, so our next query might be:

  • ?_offset=35&_limit=5 - Will retrieve the next 5 results after ignoring the first 35 (36 - 40).

Sorting

All endpoints are sorted by the id column in ascending order by default (oldest first). You can override this by including a _sort with the column you want to sort by in the request. You can sort on all columns in the parent object only. You cannot sort on columns in nested objects, so if a game contains a tags object you cannot sort on the tag name column, but you can sort by the games name since the games name resides in the parent object.

_sort (Sort)

--parse_version/games?_sort=name

Sort by a column, in ascending or descending order.

  • ?_sort=name - Sort name in ascending order

  • ?_sort=-name - Sort name in descending order (by prepending a -)

Filtering

--parse_sitename has powerful filtering available to assist you when making requests to the API. You can filter on all columns in the parent object only. You cannot apply filters to columns in nested objects, so if a game contains a tags object you cannot filter by the tag name column, but you can filter by the games name since the games name resides in the parent object.

or_fields (Filter grouping)

By default, multiple filters are combined using an "AND" operation. However, with or_fields, you can group filters together to be combined using an "OR" operation.

For example, if you want to find all mods that have been tagged with "Level" but also include mods made by the creator "UltimateModder", you can achieve this with the following query parameters:

--parse_version/games/your-game/mods?tags=level&submitted_by_display_name=UltimateModder&or_fields[]=tags,submitted_by_display_name

This would be interpreted as "Fetch all mods where (tags in level OR submitted_by like UltimateModder)". Without the or_fields parameter, it would be treated as AND.

A few things to note:

  • The or_fields parameter must be provided as an array.
  • A maximum of --parse_maxorgroups or_fields can be present in a query at any time.
  • A maximum of --parse_maxorfieldspergroup fields per or_fields.

_q (Full text search)

--parse_version/games?_q=Gravity Bounce

Full-text search is a lenient search filter that is only available if the endpoint you are querying contains a name column. Wildcards should not be applied to this filter as they are ignored.

  • ?_q=Gravity Bounce - This will return every result where the name column contains any of the following words: 'Gravity', 'Bounce'.

= (Equals)

--parse_version/games?id=10

The simplest filter you can apply is columnname equals. This will return all rows which contain a column matching the value provided.

  • ?id=10 - Get all results where the id column value is 10.

-not (Not Equal To)

--parse_version/games?curation-not=1

Where the preceding column value does not equal the value specified.

  • ?curation-not=1 - Where the curation column does not equal 1.

-lk (Like + Wildcards)

--parse_version/games?name-lk=texture

--parse_version/games?name-lk=texture*

--parse_version/games?name-lk=*texture*

Where the string supplied matches the preceding column value. This is equivalent to SQL's LIKE. Wildcard's * can be used to find content that partially matches as described below.

  • ?name-lk=texture - Get all results where the name column value is 'texture'.
  • ?name-lk=texture* - Get all results where the name column value begins with 'texture'. This means the query would return results for 'texture', 'textures' and 'texture pack'
  • ?name-lk=*texture* - Get all results where the name column value contains 'texture'. This means the query would return results for 'texture', 'HD textures' and 'armor texture pack'

-not-lk (Not Like + Wildcards)

--parse_version/games?name-not-lk=dungeon

Where the string supplied does not match the preceding column value. This is equivalent to SQL's NOT LIKE. Wildcard's * can be used as described above.

  • ?name-not-lk=dungeon - Get all results where the name column value is not 'dungeon'.

-in (In)

--parse_version/games?id-in=3,11,16,29

Where the supplied list of values appears in the preceding column value. This is equivalent to SQL's IN.

  • ?id-in=3,11,16,29 - Get all results where the id column value is 3, 11, 16 and 29.

-not-in (Not In)

--parse_version/games?modfile-not-in=8,13,22

Where the supplied list of values does not equal the preceding column value. This is equivalent to SQL's NOT IN

  • ?modfile-not-in=8,13,22 - Get all results where id column does not equal 8, 13 and 22.

-max (Smaller Than or Equal To)

--parse_version/games?game-max=40

Where the preceding column value is smaller than or equal to the value specified.

  • ?game-max=40 - Get all results where the game smaller than or equal to 40.

-min (Greater Than or Equal To)

--parse_version/games?game-min=20

Where the preceding column value is greater than or equal to the value specified.

  • ?game-min=20 - Get all results where the game column is greater than or equal to 20.

-bitwise-and (Bitwise AND)

--parse_version/games?maturity_option-bitwise-and=5

Some columns are stored as bits within an integer. Their value depends on the bits selected. For example, suppose a column has 4 options:

  • 1 = Option A
  • 2 = Option B
  • 4 = Option C
  • 8 = Option D

You can combine any of these options by adding them together which means there are (2 ^ 4 = 16 possible combinations). For example Option A (1) and Option C (4) would be (1 + 4 = 5), Option A (1), Option C (4) and Option D (8) would be (1 + 4 + 8 = 13), all Options together would be (1 + 2 + 4 + 8 = 15).

The number of combinations makes using equals, in and other filters a little complex. To solve this we support Bitwise AND (&) which makes it easy to match a column which contains any of the options you want.

  • ?maturity_option-bitwise-and=5 - Will match the maturity_option column values 1, 3, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15 (since these values contain the bits 1, 4 or both).

Localization

Localized Responses

Example HTTP Header Request
---------------------
HTTP/2.0 200 OK
...
...
Accept-Language: de

Example response (assuming a validation error occurred)

{
    "error": {
        "code": 422,
        "message": "Überprüfung fehlgeschlagen. Bitte lesen Sie unten, um ungültige Eingaben zu korrigieren:",
        "errors": {
            "name": "Name darf maximal 50 Zeichen haben."
        }
    }
}

The --parse_sitename API provides localization for a collection of languages. To specify responses from the API to be in a particular language, simply provide the Accept-Language header with an ISO 639 compliant language code. If a valid language code is not provided and the user is authenticated, the language they have selected in their profile will be used. All other requests will default to English (US). The list of supported codes includes:

Language Code Language
en English (US) default
bg Bulgarian
fr French
de German
id Indonesian
it Italian
pl Polish
pt Portuguese
hu Hungarian
ja Japanese
ko Korean
ru Russian
es Spanish (Spain)
es-419 Spanish (Latin America)
th Thai
tr Turkish
uk Ukrainian
zh-CN Chinese (Simplified)
zh-TW Chinese (Traditional)

Example request updating specified fields with Polish translations.

curl -X POST --parse_apiurl/games/1/mods/1 \
	-H 'Authorization: Bearer your-token-here' \
	-H 'Content-Type: application/x-www-form-urlencoded' \
	-H 'Content-Language: pl' \
	-d 'name=Zaawansowany rozkwit Wiedźmina' \
	-d 'summary=Zobacz zaawansowany mod oświetlenia w Kaer Morhen w zupełnie nowym świetle' 

Attempt to retrieve Polish translations within supported fields.

curl -X GET --parse_apiurl/games/1/mods/1 \
	-H 'Authorization: Bearer your-token-here' \
	-H 'Accept-Language: pl'

NOTE: Localization for --parse_sitename is currently a work-in-progress and thus not all responses may be in the desired language.

Response

{
	"id": 1,
	"game_id": 1,
	...
	"name": "Zaawansowany rozkwit Wiedźmina", 
	"summary": "Zobacz zaawansowany mod oświetlenia w Kaer Morhen w zupełnie nowym świetle"
}

Localized Requests

Specific endpoints also allow you to submit fields in the supported languages above. To tell the API you are submitting non-english content you must supply the Content-Language header in the request with a valid language code (see above). When you supply the Content-Language header in your request, you are explicitly indicating to the API that all eligible fields have been translated into the supplied language and if a user (or client) requests the respective language, the value for that supplied field will be returned.

A brief summary when dealing with localized requests and responses:

  • English is still required as the default value when creating and updating a resource.
  • If you don't supply a valid Content-Language header value, all input data will be assumed English.
  • If you don't supply a valid Accept-Language header value, all response data will be in English.
  • If you supply a valid Accept-Language header value, all response data will be in English unless translations exist in the requested language.
  • Only fields that contain the localization icon in the parameter section of the endpoint can be submitted in different languages.

Rate Limiting

--parse_sitename implements rate limiting to stop users abusing the service. Exceeding the rate limit will result in requests receiving a 429 Too Many Requests response until the reset time is reached.

It is highly recommended you architect your app to check for the 429 Too Many Requests HTTP response code, and ensure you do not continue to make requests until the duration specified in the retry-after header (in seconds) passes. Be aware we enforce global rate limits which will result in all requests being blocked (error ref --parse_errorref_RATE_LIMITED_GLOBAL). We also enforce per-endpoint rate limits which will only result in requests to that endpoint being blocked (error ref --parse_errorref_RATE_LIMITED_ENDPOINT) until the duration specified in the retry-after header (in seconds) passes, allowing you to continue to call other endpoints. Users who continue to send requests despite a 429 response could potentially have their credentials revoked. The following limits are implemented by default:

Global API key Rate Limiting

  • API keys linked to a game have unlimited requests.
  • API keys linked to a user have 60 requests per minute.

Global OAuth2 Rate Limiting

  • User tokens are limited to 120 requests per minute.
  • User token writes are limited to 60 requests per minute.

Global IP Rate Limiting

  • IPs are limited to 1000 requests per minute.
  • IP writes are limited to 60 requests per minute.

Per-Endpoint Rate Limiting

  • Certain endpoints may override the defaults for security, spam or other reasons.
  • When this (error ref --parse_errorref_RATE_LIMITED_ENDPOINT) is encountered, its ok to continue requesting other endpoints, as the retry-after only applies to this endpoint.

Headers

Example HTTP Header Response
---------------------
HTTP/2.0 429 Too Many Requests
...
...
retry-after: 57

Example ratelimit JSON response

{
	"error": {
		"code": 429,
		"error_ref": --parse_errorref_RATE_LIMITED_GLOBAL,
		"message": "You have made too many requests in a short period of time, please wait and try again soon."
	}
}

If the rate limit is exceeded, the following header will be returned alongside the 429 Too Many Requests HTTP response code.

  • retry-after - Number of seconds before you can attempt to make another request to API. NOTE: If the retry-after value is 0, that means you have hit a rolling ratelimit. Rolling ratelimits don't block for a set timeframe once the limit is reached, instead they permit a certain number of requests within the timeframe (see this explanation). If you encounter a 0, we recommend retrying the endpoint again after 60 seconds.

Deprecation Notice

From November 20th, 2022 - the rate limit headers below will no longer be returned. If you have written a custom mod.io SDK or library, you should replace any usage of these headers with retry-after.

  • X-RateLimit-Limit - Number of requests you can make from the supplied API key/access token per minute.
  • X-RateLimit-Remaining - Number of requests remaining until requests are rejected.
  • X-RateLimit-RetryAfter - Amount of seconds until reset once you have been throttled (Only returned once rate limit exceeded).

From January 1st, 2024 - the error ref --parse_errorref_RATE_LIMITED_ENDPOINT will be returned when a rate limit applies only to the endpoint being called. Error ref --parse_errorref_RATE_LIMITED_GLOBAL will continue to be returned in all other scenarios where the rate limit applies to all endpoints.

Optimize your requests

You should always plan to minimize requests and cache API responses. It will make your app feel fluid and fast for your users. If your usage is excessive we shall reach out to discuss ways of optimizing, but our aim is to never restrict legitimate use of the API. We have set high limits that should cover 99% of use-cases, and are happy to discuss your scenario if you require more.

Testing

To help familiarize yourself with the --parse_sitename API and to ensure your implementation is battle-hardened and operating as intended, you can setup test games profiles on --parse_sitename which will be available via your content. By default all game profiles are hidden and accessible only by users who you add to the games team, or invite using the preview system. This is until you set a game live, which will make it accessible for everyone.

Each game added will be assigned it's own api_url, api_key and game_id. When switching between game builds (i.e. production, test, staging) you will need to ensure each build is pointing to the right game profile on --parse_sitename.

Note: If your game is in stealth, we recommend using codenames and non-descriptive screenshots when uploading content. While your game won't be shown as long as it remains hidden, content connected to your game may appear in the profile of users who you have given permission to interact with it, including your own profile.

Whitelabel

If you are a large studio or publisher and require a private, in-house, custom solution that accelerates your time to market with a best-in-class product, reach out to --parse_email to discuss the licensing options available.

Contact

If you spot any errors within the --parse_sitename documentation, have feedback on how we can make it easier to follow or simply want to discuss how awesome mods are, feel free to reach out to --parse_email or come join us in our discord channel. We are here to help you grow and maximise the potential of mods in your game.

Platforms

Targeting a Platform

--parse_sitename supports mods on all platforms. Games can enable per-platform mod file support in their dashboard, if they wish to control which platforms each mod and their corresponding files can be accessed on. Otherwise, all mods and their files will be available on all platforms the game supports. To make this system work, it's important the following headers are included in all API requests as explained below. If you have any questions about setting up cross-platform mod support in your game, please reach out to --parse_email.

When making API requests you should include the X-Modio-Platform header (with one of the values below), to tell --parse_sitename what Platform the request is originating from. This header is important because it enables --parse_sitename to return data that is approved for the platform such as:

  • Supported mods and files
  • Supported tags the player can filter on
  • Localization of content for the platform
  • It also enables platform specific metrics

For example, passing the HTTP header X-Modio-Platform: xboxseriesx in your API request tells --parse_sitename your player is on Xbox Series X.

Official --parse_sitename Plugins and SDKs will automatically supply this value for you providing you have specified the correct platform in the tools' settings. We strongly recommend you supply this header in every request with the correct platform to enable --parse_sitename to provide the best cross-platform experience for your players. Please see a list of supported platforms below:

Target Platform Header Value
Source source
Windows windows
Mac mac
Linux linux
Android android
iOS ios
Xbox One xboxone
Xbox Series X xboxseriesx
PlayStation 4 ps4
PlayStation 5 ps5
Switch switch
Oculus oculus

These are the only supported values and are case-insensitive, anything else will be ignored and default to windows. Have we missed a platform you are using? Get in touch!

Targeting a Portal

When making API requests you should include the X-Modio-Portal header (with one of the values below), to tell --parse_sitename what Portal (eg. Store or App) the request is originating from. This header is important because it enables --parse_sitename to fine-tune the experience, such as returning display names used by players on that portal (which can be a certification requirement).

For example, passing the HTTP header X-Modio-Portal: epicgames in your API request tells --parse_sitename your player is coming via the Epic Games Store.

You can also instruct the --parse_sitename website to authenticate the player using a portal from the list above (provided it is supported), as explained in Web Overlay Authentication. For example, if your game client has logged the player into --parse_sitename on PlayStation using their PlayStation™Network account, and you want to open the --parse_sitename website in-game with the player logged in using the same authentication method, you would add ?portal=psn to the end of the URL: --parse_gameurl?portal=psn. You can optionally add &login=auto as well to automatically start the login process.

Target Portal Header Value
Apple apple
Discord discord
Epic Games Store epicgames
Facebook facebook
GOG gog
Google google
itch.io itchio
Nintendo nintendo
PlayStation™Network psn
SSO sso
Steam steam
Xbox Live xboxlive

These are the only supported values and are case-insensitive, anything else will be ignored. Have we missed a portal you are using? Get in touch!