Stats

API change history

API that provides statistical data about Players and Matches.

Halo 5 - Player Match History

Retrieves a list of Matches that the Player has participated in and which have completed processing. If the Player is currently in a match, it is not returned in this API.

This endpoint will include games played on Local Servers with the Custom Local Game Mode for games that occurred or after December 22, 2017.


Changelog

February 1, 2019:

  • Enabled support for viewing the time component of the "MatchCompletedDate" via the "{include-times}" Request Parameter.

December 22, 2017:

  • Added support for the Custom Local Game mode.

February 21, 2017:

  • Renamed Endpoint from "Matches for Player" to "Halo 5 - Player Match History".
  • Removed "{title}" Request Parameter.

April 20, 2016:

  • Clarified documentation for the "MapVariant" and "GameVariant" fields.
  • Corrected "OwnerType" values for the "MapVariant" and "GameVariant" fields.

Try it

Request

Request URL

Request parameters

  • string

    The Player's Gamertag.

  • (optional)
    string

    Indicates what Game Mode(s) the client is interested in getting Matches for (arena, campaign, custom, customlocal, or warzone).

    When the parameter is omitted or empty, Matches from all modes are returned. When a client would like to receive Matches spanning multiple Modes, separate the Modes with a comma (e.g. "arena,custom"). There is no significance to the order the Modes are specified in this parameter.

    When an invalid Mode is specified, HTTP 400 ("Bad Request") is returned.

    When a valid Mode is specified more than once, HTTP 400 ("Bad Request") is returned.

  • (optional)
    number

    When specified, this indicates the starting index (0-based) for which the batch of results will begin at. For example, "start=0" indicates that the first qualifying result will be returned, no items are 'skipped'. Passing "start=10" indicates that the result will begin with the 11th item, the first 10 will be 'skipped'.

    When omitted, zero is assumed.

    When the value contains a non-digit, HTTP 400 ("Bad Request") is returned.

  • (optional)
    number

    When specified, this indicates the maximum quantity of items the client would like returned in the response.

    When omitted, 25 is assumed.

    When the value contains a non-digit or is exactly "0", HTTP 400 ("Bad Request") is returned.

    When the value is greater than the allowed range [1,25], the maximum allowed value is used instead. The "Count" field in the response will confirm the actual value that was used.

  • (optional)
    boolean

    When set to "true", this indicates that the time component of the "MatchCompletedDate" field should be populated.

    Otherwise, when set to "false" or when omitted, the time component will be set to "00:00:00".

    When the value contains a non-boolean, HTTP 400 ("Bad Request") is returned.

Request headers

  • string
    Subscription key which provides access to this API. Found in your Profile.

Request body

Responses

200 OK

The response body will contain the Player's recent Matches. An empty list will be returned if the Player has not played any Matches in the specified Game Mode(s).

Representations

{
  // The starting point that was used. When the "start" query string parameter is
  // specified, this value is identical. When "start" is omitted, the default value is
  // returned.
  "Start": "int",  

  // The number of results that the service attempted to retrieve to satisfy this
  // request. Normally this value is equal to the "count" parameter. If the client
  // specified a count parameter greater than the maximum allowed, this value contains
  // the maximum allowed amount.
  "Count": "int",

  // The number of results that are actually being returned in this response. This field
  // is named "ResultCount" to avoid confusion with "Count".
  "ResultCount": "int",

  // A list of recent matches. Matches are listed in reverse chronological order with the
  // most recently started match first.
  "Results": [
    {
      // Internal use only. A set of related resource links.
      "Links": "links",

      "Id": {

        // The ID for this match. More match details are available via the applicable
        // Match Result Endpoint.
        "MatchId": "guid",

        // The game mode applicable to this match. Options are: 
        //   Error = 0, 
        //   Arena = 1, 
        //   Campaign = 2, 
        //   Custom = 3, 
        //   Warzone = 4,
        //   CustomLocal = 6.
        "GameMode": "int",

      },

      // The ID of the playlist (aka "Hopper") for the match. 
      // Hoppers are used in Arena and Warzone. In Arena, they function just as you would
      // expect, similar to previous Halo titles. Warzone uses hoppers as well. There
      // will be multiple Warzone hoppers which contain a rotating playlist of scenarios
      // to play. 
      // Null for campaign & custom games. 
      // Playlists are available via the Metadata API.
      "HopperId": "guid",

      // The ID of the base map for this match. Maps are available via the Metadata API.
      "MapId": "guid",

      // The variant of the map for this match. There are two sources of map variants:
      // official map variants available via the Metadata API and user-generated map
      // variants which are not available via the APIs currently. This will be null for
      // campaign games.
      "MapVariant": {

        // The resource type. 3 indicates map variant.
        "ResourceType": 3,

        // The ID of the map variant. Official map variants are available via the
        // Metadata API.
        "ResourceId": "guid",

        // The source of the map variant. Options are:
        //   Unknown = 0,
        //   User-generated = 1,
        //   Official = 3.
        "OwnerType": "int",

        // The gamertag of the user that created the map variant if this is a
        // user-generated map variant, or null otherwise. 
        "Owner": "string"
      },

      // The ID of the game base variant for this match. Game base variants are available
      // via the Metadata API.
      "GameBaseVariantId": "guid",

      // The variant of the game for this match. There are two sources of game variants:
      // official game variants available via the Metadata API and user-generated game
      // variants which are not available via the APIs currently. This will be null for
      // campaign games.
      "GameVariant": {

        // The resource type. 2 indicates game variant.
        "ResourceType": 2,

        // The ID of the game variant. Official game variants are available via the
        // Metadata API.
        "ResourceId": "guid",        

        // The source of the game variant. Options are:
        //   Unknown = 0,
        //   User-generated = 1,
        //   Official = 3.
        "OwnerType": "int",

        // The gamertag of the user that created the game variant if this is a
        // user-generated game variant, or null otherwise. 
        "Owner": "string"
      },

      // The length of the match. This is expressed as an ISO 8601 Duration.
      "MatchDuration": "string",

      // The date and time when the match ended. Note that this is different than the
      // processing date, once matches end they typically take a small amount of time to
      // process. The processing date is not available through this API. The time
      // component of this date is set to "00:00:00" unless the "{include-times}" request
      // parameter is set to "true". This is expressed as an ISO 8601 combined Date and
      // Time.
      "MatchCompletedDate": {

        "ISO8601Date": "string"
      },

      // Provides team data. This list contains all team that Won or Tied. Losing teams
      // are not included. This list is empty for campaign games. 
      "Teams": [
        {
          // The ID for the team. The team's ID dictates the team's color. Team colors
          // are available via the Metadata API.
          "Id": "int",

          // The team's score at the end of the match. The way the score is determined is
          // based off the game base variant being played: 
          //   Breakout = number of rounds won,
          //   CTF = number of flag captures,
          //   Slayer = number of kills,
          //   Strongholds = number of points,
          //   Warzone = number of points.
          // Score can be a negative value. Unfortunately, this value is returned as an
          // unsigned 32-bit integer. This means that if the score is -1, the score
          // reported is 4,294,967,295.
          "Score": "uint32",

          // The team's rank at the end of the match.
          "Rank": "int"
        }
      ],

      // This field contains the player's data. This will only contain data for the
      // player specified in the request.
      "Players": [
        {          
          "Player": {

            // The player's gamertag.
            "Gamertag": "string",

            // Internal use only. This will always be null.
            "Xuid": null
          },

          // The ID of the team that the player was on when the match ended. Zero for
          // campaign games.
          "TeamId": "int",

          // The player's team-agnostic ranking in this match.
          "Rank": "int",

          // Indicates what result the player received at the conclusion of the match.
          // Options are:
          //   Did Not Finish = 0, 
          //   Lost = 1, 
          //   Tied = 2, 
          //   Won = 3. 
          // Did Not Finish: The player was not present when the match ended.
          // Lost: The player was on a team that was assigned a loss, typically this is
          // when a team does not have rank = 1. 
          // Won: The player was on the team that was assigned the win, typically this is
          // the team that has rank = 1. 
          // Tied: The player was on the team that was awarded a tie. Typically this is
          // when the player is on the team with rank = 1, and there is at least one
          // other team with rank = 1. Ties are only for rank = 1 teams. Consider the
          // scenario when exactly one team is rank = 1, and two teams are rank = 2.
          // Players on the rank=1 team will have "Won", players on the rank = 2 teams
          // will have "Lost". For ties, this documentation states 'typically' because
          // the game may have unique rules for multi-team and FFA scenarios, in which
          // multiple teams are awarded a win.
          "Result": "int",

          // The number of enemy kills the player had during this match. This includes
          // other Spartans and Enemy AI.
          "TotalKills": "int",

          // The number of times this player died during the match.
          "TotalDeaths": "int",

          // The number of assists credited to the player during the match. This includes
          // other Spartans and Enemy AI.
          "TotalAssists": "int",

          // Internal use only. This will always be null.
          "PreMatchRatings": null,

          // Internal use only. This will always be null.
          "PostMatchRatings": null
        }
      ],

      // Whether this was a team-based game or not (e.g. free-for-all).
      "IsTeamGame": "boolean",

      // The ID of the season for this match if it was played in a seasonal playlist.
      // Null if the match was played in a non-seasonal playlist. This will only be set
      // for Arena matches and will be null for all other game modes.
      "SeasonId": null,

      // Internal use only. Do not use.
      "MatchCompletedDateFidelity": "int"
    }
  ]
}

400 Bad Request

An unsupported value was provided for a query string parameter.

Representations

404 Not Found

Specified Player was not found.

Representations

500 Internal Server Error

Internal Server Error

Representations

503 Service Unavailable

Service Unavailable

Representations

Code samples

@ECHO OFF

curl -v -X GET "https://www.haloapi.com/stats/h5/players/{player}/matches?modes={string}&start={number}&count={number}&include-times={boolean}"
-H "Ocp-Apim-Subscription-Key: {subscription key}"

--data-ascii "{body}" 
using System;
using System.Net.Http.Headers;
using System.Text;
using System.Net.Http;
using System.Web;

namespace CSHttpClientSample
{
    static class Program
    {
        static void Main()
        {
            MakeRequest();
            Console.WriteLine("Hit ENTER to exit...");
            Console.ReadLine();
        }
        
        static async void MakeRequest()
        {
            var client = new HttpClient();
            var queryString = HttpUtility.ParseQueryString(string.Empty);

            // Request headers
            client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");

            // Request parameters
            queryString["modes"] = "{string}";
            queryString["start"] = "{number}";
            queryString["count"] = "{number}";
            queryString["include-times"] = "{boolean}";
            var uri = "https://www.haloapi.com/stats/h5/players/{player}/matches?" + queryString;

            var response = await client.GetAsync(uri);
        }
    }
}	
// // This sample uses the Apache HTTP client from HTTP Components (http://hc.apache.org/httpcomponents-client-ga/)
import java.net.URI;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class JavaSample 
{
    public static void main(String[] args) 
    {
        HttpClient httpclient = HttpClients.createDefault();

        try
        {
            URIBuilder builder = new URIBuilder("https://www.haloapi.com/stats/h5/players/{player}/matches");

            builder.setParameter("modes", "{string}");
            builder.setParameter("start", "{number}");
            builder.setParameter("count", "{number}");
            builder.setParameter("include-times", "{boolean}");

            URI uri = builder.build();
            HttpGet request = new HttpGet(uri);
            request.setHeader("Ocp-Apim-Subscription-Key", "{subscription key}");


            // Request body
            StringEntity reqEntity = new StringEntity("{body}");
            request.setEntity(reqEntity);

            HttpResponse response = httpclient.execute(request);
            HttpEntity entity = response.getEntity();

            if (entity != null) 
            {
                System.out.println(EntityUtils.toString(entity));
            }
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
    }
}

<!DOCTYPE html>
<html>
<head>
    <title>JSSample</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
</head>
<body>

<script type="text/javascript">
    $(function() {
        var params = {
            // Request parameters
            "modes": "{string}",
            "start": "{number}",
            "count": "{number}",
            "include-times": "{boolean}",
        };
      
        $.ajax({
            url: "https://www.haloapi.com/stats/h5/players/{player}/matches?" + $.param(params),
            beforeSend: function(xhrObj){
                // Request headers
                xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key","{subscription key}");
            },
            type: "GET",
            // Request body
            data: "{body}",
        })
        .done(function(data) {
            alert("success");
        })
        .fail(function() {
            alert("error");
        });
    });
</script>
</body>
</html>
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
    NSString* path = @"https://www.haloapi.com/stats/h5/players/{player}/matches";
    NSArray* array = @[
                         // Request parameters
                         @"entities=true",
                         @"modes={string}",
                         @"start={number}",
                         @"count={number}",
                         @"include-times={boolean}",
                      ];
    
    NSString* string = [array componentsJoinedByString:@"&"];
    path = [path stringByAppendingFormat:@"?%@", string];

    NSLog(@"%@", path);

    NSMutableURLRequest* _request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:path]];
    [_request setHTTPMethod:@"GET"];
    // Request headers
    [_request setValue:@"{subscription key}" forHTTPHeaderField:@"Ocp-Apim-Subscription-Key"];
    // Request body
    [_request setHTTPBody:[@"{body}" dataUsingEncoding:NSUTF8StringEncoding]];
    
    NSURLResponse *response = nil;
    NSError *error = nil;
    NSData* _connectionData = [NSURLConnection sendSynchronousRequest:_request returningResponse:&response error:&error];

    if (nil != error)
    {
        NSLog(@"Error: %@", error);
    }
    else
    {
        NSError* error = nil;
        NSMutableDictionary* json = nil;
        NSString* dataString = [[NSString alloc] initWithData:_connectionData encoding:NSUTF8StringEncoding];
        NSLog(@"%@", dataString);
        
        if (nil != _connectionData)
        {
            json = [NSJSONSerialization JSONObjectWithData:_connectionData options:NSJSONReadingMutableContainers error:&error];
        }
        
        if (error || !json)
        {
            NSLog(@"Could not parse loaded json with error:%@", error);
        }
        
        NSLog(@"%@", json);
        _connectionData = nil;
    }
    
    [pool drain];

    return 0;
}
<?php
// This sample uses the Apache HTTP client from HTTP Components (http://hc.apache.org/httpcomponents-client-ga/)
require_once 'HTTP/Request2.php';

$request = new Http_Request2('https://www.haloapi.com/stats/h5/players/{player}/matches');
$url = $request->getUrl();

$headers = array(
    // Request headers
    'Ocp-Apim-Subscription-Key' => '{subscription key}',
);

$request->setHeader($headers);

$parameters = array(
    // Request parameters
    'modes' => '{string}',
    'start' => '{number}',
    'count' => '{number}',
    'include-times' => '{boolean}',
);

$url->setQueryVariables($parameters);

$request->setMethod(HTTP_Request2::METHOD_GET);

// Request body
$request->setBody("{body}");

try
{
    $response = $request->send();
    echo $response->getBody();
}
catch (HttpException $ex)
{
    echo $ex;
}

?>
########### Python 2.7 #############
import httplib, urllib, base64

headers = {
    # Request headers
    'Ocp-Apim-Subscription-Key': '{subscription key}',
}

params = urllib.urlencode({
    # Request parameters
    'modes': '{string}',
    'start': '{number}',
    'count': '{number}',
    'include-times': '{boolean}',
})

try:
    conn = httplib.HTTPSConnection('www.haloapi.com')
    conn.request("GET", "/stats/h5/players/{player}/matches?%s" % params, "{body}", headers)
    response = conn.getresponse()
    data = response.read()
    print(data)
    conn.close()
except Exception as e:
    print("[Errno {0}] {1}".format(e.errno, e.strerror))

####################################

########### Python 3.2 #############
import http.client, urllib.request, urllib.parse, urllib.error, base64

headers = {
    # Request headers
    'Ocp-Apim-Subscription-Key': '{subscription key}',
}

params = urllib.parse.urlencode({
    # Request parameters
    'modes': '{string}',
    'start': '{number}',
    'count': '{number}',
    'include-times': '{boolean}',
})

try:
    conn = http.client.HTTPSConnection('www.haloapi.com')
    conn.request("GET", "/stats/h5/players/{player}/matches?%s" % params, "{body}", headers)
    response = conn.getresponse()
    data = response.read()
    print(data)
    conn.close()
except Exception as e:
    print("[Errno {0}] {1}".format(e.errno, e.strerror))

####################################
require 'net/http'

uri = URI('https://www.haloapi.com/stats/h5/players/{player}/matches')

query = URI.encode_www_form({
    # Request parameters
    'modes' => '{string}',
    'start' => '{number}',
    'count' => '{number}',
    'include-times' => '{boolean}'
})

if uri.query && uri.query.length > 0
    uri.query += '&' + query
else
    uri.query = query
end

request = Net::HTTP::Get.new(uri.request_uri)
# Request headers
request['Ocp-Apim-Subscription-Key'] = '{subscription key}'
# Request body
request.body = "{body}"

response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
    http.request(request)
end

puts response.body