{"id":19649143,"url":"https://github.com/ingmferrer/haloinfinite","last_synced_at":"2025-04-28T16:30:34.192Z","repository":{"id":44584898,"uuid":"456053726","full_name":"ingmferrer/haloinfinite","owner":"ingmferrer","description":"Library written in Python that wraps Halo Infinite API.","archived":true,"fork":false,"pushed_at":"2022-02-06T22:16:05.000Z","size":22,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-03-14T20:17:24.172Z","etag":null,"topics":["api","halo","infinite","library","python","wrapper"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ingmferrer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-06T04:17:51.000Z","updated_at":"2024-09-10T16:32:48.000Z","dependencies_parsed_at":"2022-09-25T01:01:27.254Z","dependency_job_id":null,"html_url":"https://github.com/ingmferrer/haloinfinite","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ingmferrer%2Fhaloinfinite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ingmferrer%2Fhaloinfinite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ingmferrer%2Fhaloinfinite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ingmferrer%2Fhaloinfinite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ingmferrer","download_url":"https://codeload.github.com/ingmferrer/haloinfinite/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251345743,"owners_count":21574766,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","halo","infinite","library","python","wrapper"],"created_at":"2024-11-11T14:51:43.575Z","updated_at":"2025-04-28T16:30:33.809Z","avatar_url":"https://github.com/ingmferrer.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# haloinfinite\nLibrary written in Python that wraps Halo Infinite API.\n\n## Before start\nIt's unofficial, reverse-engineered, neither stable nor production ready Halo Infinite web API.\n\nYou need to [register an Azure Active Directory application](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) and set a Client Secret for your application.\n\n## Credits\nCredits to [Den Delimarsky](https://github.com/dend) for the reverse-engineering. If you want to learn more then check his [Halo Infinite Web API blog series](https://den.dev/series/halo-infinite-web-api). Also you can use his [API wrapper written in C#](https://github.com/dend/grunt).\n\n## Installing\n#### From Pip (recommended)\n```\npip install haloinfinite\n```\n\n#### From Github\n```\npip install git+https://github.com/ingmferrer/haloinfinite.git\n```\n\n#### From tar.gz file\nDownload haloinfinite-X.Y.Z.tar.gz from the [Releases page](https://github.com/ingmferrer/haloinfinite/releases).\n\n```\npip install haloinfinite-X.Y.Z.tar.gz\n```\n\n## Usage\n### Client instantiation\n```\nfrom haloinfinite.client import HaloInfiniteAPIClient as Client\nclient = Client(client_id, client_secret, user_token=None, xbox_user_token=None, xsts_xbox_token=None, xsts_halo_token=None, spartan_token=None, clearance_token=None)\n```\n\n### OAuth 2.0\n#### Get authorization url\n```\nurl = client.get_authorization_url(redirect_uri, scope=[\"Xboxlive.signin\", \"Xboxlive.offline_access\"], state=None)\n```\n\n#### Exchange the code for an user token\n```\nuser_token = client.exchange_code(redirect_uri, code)\n\n# print(user_token.data)\n{\n    \"token_type\": \"bearer\",\n    \"expires_in\": 3600,\n    \"scope\": \"XboxLive.signin XboxLive.offline_access\",\n    \"access_token\": \"...\",\n    \"refresh_token\": \"...\",\n    \"user_id\": \"...\",\n}\n```\n\n#### Refresh user token\n```\nuser_token = client.refresh_token(redirect_uri, user_token[\"refresh_token\"])\n\n# print(user_token.data)\n{\n    \"token_type\": \"bearer\",\n    \"expires_in\": 3600,\n    \"scope\": \"XboxLive.signin XboxLive.offline_access\",\n    \"access_token\": \"...\",\n    \"refresh_token\": \"...\",\n    \"user_id\": \"...\",\n}\n```\n\n#### Set user token\n```\nclient.set_user_token(user_token)\n```\n\n#### Get xbox user token\n```\nxbox_user_token = client.get_xbox_user_token()\n\n# print(xbox_user_token.data)\n{\n    \"IssueInstant\": \"2022-02-06T01:00:03.6132203Z\",\n    \"NotAfter\": \"2022-02-20T01:00:03.6132203Z\",\n    \"Token\": \"...\",\n    \"DisplayClaims\": {\"xui\": [{\"uhs\": \"...\"}]},\n}\n```\n\n#### Set xbox user token\n```\nclient.set_xbox_user_token(token=xbox_user_token)\n```\n\n#### Get xsts xbox token\n```\nxsts_xbox_token = client.get_xsts_xbox_token()\n\n# print(xsts_xbox_token.data)\n{\n    \"IssueInstant\": \"2022-02-06T01:35:40.7628209Z\",\n    \"NotAfter\": \"2022-02-06T17:35:40.7628209Z\",\n    \"Token\": \"...\",\n    \"DisplayClaims\": {\n        \"xui\": [\n            {\n                \"gtg\": \"...\",\n                \"xid\": \"...\",\n                \"uhs\": \"...\",\n                \"agg\": \"Adult\",\n                \"usr\": \"...\",\n                \"utr\": \"...\",\n                \"prv\": \"...\",\n            }\n        ]\n    },\n}\n```\n\n#### Set xsts xbox token\n```\nclient.set_xsts_xbox_token(token=xsts_xbox_token)\n```\n\n#### Get xsts halo token\n```\nxsts_halo_token = client.get_xsts_xbox_token()\n\n# print(xsts_halo_token.data)\n{\n    \"IssueInstant\": \"2022-02-06T01:12:27.9108457Z\",\n    \"NotAfter\": \"2022-02-06T05:12:27.9108457Z\",\n    \"Token\": \"...\",\n    \"DisplayClaims\": {\"xui\": [{\"uhs\": \"...\"}]},\n}\n```\n\n#### Set xsts halo token\n```\nclient.set_xsts_halo_token(token=xsts_halo_token)\n```\n\n#### Get spartan token\n```\nspartan_token = client.get_xsts_xbox_token()\n\n# print(spartan_token.data)\n{\n    \"SpartanToken\": \"...\",\n    \"ExpiresUtc\": {\"ISO8601Date\": \"2022-02-06T05:12:27Z\"},\n    \"TokenDuration\": \"PT3H34M12.4226916S\",\n}\n```\n\n#### Set spartan token\n```\nclient.set_spartan_token(token=spartan_token)\n```\n\n#### Get clearance token\n```\nclearance_token = client.get_clearance_token()\n\n# print(clearance_token.data)\n{\n    \"FlightConfigurationId\": \"...\",\n}\n```\n\n#### Set clearance token\n```\nclient.set_clearance_token(token=clearance_id)\n```\n\n## Match API\n\n#### Match privacy\n```\nresponse = client.match.get_match_privacy()\n\n# print(response.data)\n{'MatchmadeGames': 1, 'OtherGames': 2}\n```\n\n#### Match count\n```\nresponse = client.match.get_match_count()\n\n# print(response.data)\n{'CustomMatchesPlayedCount': 6, 'MatchesPlayedCount': 885, 'MatchmadeMatchesPlayedCount': 879, 'LocalMatchesPlayedCount': 0}\n```\n\n#### Match history\n```\nresponse = client.match.get_match_history()\n\n# print(response.data)\n{'Count': 25,\n 'Links': {},\n 'ResultCount': 25,\n 'Results': [{'LastTeamId': 0,\n              'MatchId': '...',\n              'MatchInfo': {'ClearanceId': '...',\n                            'Duration': 'PT9M22.8961519S',\n                            'EndTime': '2022-02-05T23:30:32.564Z',\n                            'GameVariantCategory': 9,\n                            'LevelId': '...',\n                            'LifecycleMode': 3,\n                            'MapVariant': {'AssetId': '...',\n                                           'AssetKind': 2,\n                                           'VersionId': '...'},\n                            'PlayableDuration': 'PT9M22.875S',\n                            'Playlist': {'AssetId': '...',\n                                         'AssetKind': 3,\n                                         'VersionId': '...'},\n                            'PlaylistExperience': 5,\n                            'PlaylistMapModePair': {'AssetId': '...',\n                                                    'AssetKind': 7,\n                                                    'VersionId': '...'},\n                            'SeasonId': 'Seasons/Season6.json',\n                            'StartTime': '2022-02-05T23:20:39.923Z',\n                            'TeamScoringEnabled': True,\n                            'TeamsEnabled': True,\n                            'UgcGameVariant': {'AssetId': '...',\n                                               'AssetKind': 6,\n                                               'VersionId': '...'}},\n              'Outcome': 3,\n              'PresentAtEndOfMatch': True,\n              'Rank': 6},\n              ...\n 'Start': 0}\n```\n\n#### Match stats\n```\nresponse = client.match.get_match_stats(match_id)\n\n# print(response.data)\n{'MatchId': '...',\n 'MatchInfo': {'ClearanceId': '...',\n               'Duration': 'PT9M22.8961519S',\n               'EndTime': '2022-02-05T23:30:32.564Z',\n               'GameVariantCategory': 9,\n               'LevelId': '...',\n               'LifecycleMode': 3,\n               'MapVariant': {'AssetId': '...',\n                              'AssetKind': 2,\n                              'VersionId': '...'},\n               'PlayableDuration': 'PT9M22.875S',\n               'Playlist': {'AssetId': '...',\n                            'AssetKind': 3,\n                            'VersionId': '...'},\n               'PlaylistExperience': 5,\n               'PlaylistMapModePair': {'AssetId': '...',\n                                       'AssetKind': 7,\n                                       'VersionId': '...'},\n               'SeasonId': 'Seasons/Season6.json',\n               'StartTime': '2022-02-05T23:20:39.923Z',\n               'TeamScoringEnabled': True,\n               'TeamsEnabled': True,\n               'UgcGameVariant': {'AssetId': '...',\n                                  'AssetKind': 6,\n                                  'VersionId': '...'}},\n 'Players': [...],\n 'Teams': [...],\n```\n\n#### Match skill\n```\nresponse = client.match.get_match_skill(match_id, player_id)\n\n# print(response.data)\n{'Value': [{'Id': 'xuid(...)',\n            'Result': {'Counterfactuals': {'SelfCounterfactuals': {'Deaths': 12.38441050555862,\n                                                                   'Kills': 11.805217023995946},\n                                           'TierCounterfactuals': {}},\n                       'RankRecap': {'PostMatchCsr': {'InitialMeasurementMatches': 0,\n                                                      'MeasurementMatchesRemaining': 0,\n                                                      'NextSubTier': 0,\n                                                      'NextTier': '',\n                                                      'NextTierStart': 0,\n                                                      'SubTier': 0,\n                                                      'Tier': '',\n                                                      'TierStart': 0,\n                                                      'Value': 0},\n                                     'PreMatchCsr': {'InitialMeasurementMatches': 0,\n                                                     'MeasurementMatchesRemaining': 0,\n                                                     'NextSubTier': 0,\n                                                     'NextTier': '',\n                                                     'NextTierStart': 0,\n                                                     'SubTier': 0,\n                                                     'Tier': '',\n                                                     'TierStart': 0,\n                                                     'Value': 0}},\n                       'RankedRewards': None,\n                       'StatPerformances': {'Deaths': {'Count': 9,\n                                                       'Expected': 12.38441050555862,\n                                                       'StdDev': 4.498181792537211},\n                                            'Kills': {'Count': 13,\n                                                      'Expected': 11.805217023995946,\n                                                      'StdDev': 4.750282423640629}},\n                       'TeamId': 0,\n                       'TeamMmr': 1149.370133486992,\n                       'TeamMmrs': {'0': 1149.370133486992,\n                                    '1': 1151.942592441846}},\n            'ResultCode': 0}]}\n```\n\n#### Match progression\n```\nresponse = client.match.get_match_progression(match_id)\n\n# print(response.data)\n{'ChallengeProgressState': [{'Id': '...',\n                             'Path': 'ChallengeContent/ClientChallengeDefinitions/S1CapstoneChallenges/CSamuraiMedalKilljoy.json',\n                             'PreviousProgress': 1,\n                             'Progress': 3},\n                            {'Id': '...',\n                             'Path': 'ChallengeContent/ClientChallengeDefinitions/DailyChallenges/PlayNew/d0NPlayB1.json',\n                             'PreviousProgress': 0,\n                             'Progress': 1}],\n 'ClearanceId': '...',\n 'RewardId': '...'}\n```\n\n## Requirements\n- requests\n- python-dateutil\n\n## Tests\n- Not yet\n\n## Contributing\nWe are always grateful for any kind of contribution including but not limited to bug reports, code enhancements, bug fixes, and even functionality suggestions.\n\n#### You can report any bug you find or suggest new functionality with a new [issue](https://github.com/ingmferrer/haloinfinite/issues).\n\n#### If you want to add yourself some functionality to the wrapper:\n1. Fork it ( https://github.com/ingmferrer/haloinfinite )\n2. Create your feature branch (git checkout -b my-new-feature)\n3. Commit your changes (git commit -am 'Adds my new feature')\n4. Push to the branch (git push origin my-new-feature)\n5. Create a new Pull Request\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fingmferrer%2Fhaloinfinite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fingmferrer%2Fhaloinfinite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fingmferrer%2Fhaloinfinite/lists"}