Search by

kris-kuiper / igdbv4

Wrapper for IGDB API v4

Maintainers

Package info

github.com/Kris-Kuiper/IGDB-v4-API

Issues

pkg:composer/kris-kuiper/igdbv4

Transparency log

Statistics

Installs: 859

Dependents: 0

Suggesters: 0

Stars: 5

v2.3.0 2026-09-05 21:39 UTC

README

License Total Downloads

Introduction

This package is a PHP wrapper for the IGDB version 4 API for retrieving game information. It contains the following:

  • All the IGDB v4 endpoints
  • Authentication package for retrieving the access token
  • Advanced query builder
  • Webhook management and incoming notification handling

System Requirements

Requires PHP 8.4 or later; Using the latest PHP version whenever possible is recommended. The HTTP client is Guzzle: both ^7.15.2 and ^8.0 are supported. Anywhere this readme constructs a GuzzleHttp\Client, any GuzzleHttp\ClientInterface implementation will do.

Installation

Run the following to install this package:

$ composer require kris-kuiper/igdbv4

Authentication

To use the IGDB API you must have a Client ID and Access Token. Full information regarding acquiring these can be found at https://dev.twitch.tv/docs/authentication.

However, to get started immediately:

  • Sign Up with Twitch for a free account
  • Register your application
  • Manage your newly created application
  • Generate a Client Secret by pressing [New Secret]
  • Take note of the Client ID and Client Secret

When you got the Client ID and Client Secret, you can use the Authentication class to get an access token.

Example retrieving the access token

use KrisKuiper\IGDBV4\Authentication\AuthConfig;
use KrisKuiper\IGDBV4\Authentication\Authentication;
use GuzzleHttp\Client;

$config = new AuthConfig('your client id', 'your secret');
$client = new Client();
$authentication = new Authentication($client, $config);
$token = $authentication->obtainToken();

//The token will hold all the information you need to create a request to the IGDB API
$token->getAccessToken(); 
$token->getExpiration(); //The amount of seconds this token is valid

Note: An access token is approximately valid for 60 days. It is recommended to save the access token and expiration time for later use, so there is no need to generate a new access token for every request.

Endpoints

Every endpoint listed can be request by calling the endpoints name and has the following methods:

  • findById() - Find an item by its identifier (i.e. find a game by id)
  • list() - Returns a list of items (i.e. list all screenshots of a specific game)
  • query() - Execute a raw query on the current endpoint (i.e. execute a custom query to find a specific genre)
  • count() - Returns how many items match a query, without fetching them (i.e. count all games with a rating above 75)

Only the game, platform, collection, character and theme endpoints supports also the search() method.

Below is a list of the supported endpoints.

Age rating Date format Language support type
Age rating category Entity type Multiplayer mode
Age rating content description Event Network type
Age rating content description type Event logo Platform
Age rating content description v2 Event network Platform family
Age rating organization External game Platform logo
Alternative name External game source Platform type
Artwork Franchise Platform version
Artwork type Game Platform version company
Character Game engine Platform version release date
Character gender Game engine logo Platform website
Character mug shot Game localization Player perspective
Character species Game mode Popularity primitive
Collection Game release format Popularity type
Collection membership Game status Region
Collection membership type Game time to beat Release date
Collection relation Game type Release date region
Collection relation type Game version Release date status
Collection type Game version feature Report
Company Game version feature value Report type
Company logo Game video Screenshot
Company size Genre Search
Company status Image type Theme
Company type Involved company Website
Company type history Keyword Website type
Company website Language
Cover Language support

Two of these are deprecated by IGDB and kept only so existing code keeps working: ageRatingContentDescription() (use ageRatingContentDescriptionV2() instead) and artworkType() (use imageType() instead).

Example fetching game(s), platform(s) and genre(s):

use GuzzleHttp\Client;
use KrisKuiper\IGDBV4\IGDB;
use KrisKuiper\IGDBV4\Authentication\ValueObjects\AccessConfig;

$client = new Client();
$config = new AccessConfig('your client id', 'your access token');
$igdb = new IGDB($client, $config);

//Games
$igdb->game()->findById(375); //Find a game by id with optional selecting fields
$igdb->game()->findById(375, ['name', 'storyline', 'platforms.*']); //Find a game by id and specifying the fields to return
$igdb->game()->search('Metal Gear Solid'); //Search games by title
$igdb->game()->search('Metal Gear Solid', ['name', 'storyline', 'platforms.*']); //Search games by title and specifying the fields to return
$igdb->game()->list(); //List all games (limit will be 500 as default)
$igdb->game()->list(50, 20); //Setting an offset and limit (for pagination purposes)
$igdb->game()->query('fields name, storyline, platforms.*; where platforms = (7,9); sort id asc; limit 50'); //Using a custom query (see the Advanced Query builder section for creating queries programmatically)
$igdb->game()->count(); //Count all games
$igdb->game()->count('where rating > 75;'); //Count all games matching a filter

//Platforms
$igdb->platform()->findById(5, ['name', 'slug']);
$igdb->platform()->list();
$igdb->platform()->search('Playstation');
$igdb->platform()->query('fields name, slug; limit 500; sort id;');

//Genres
$igdb->genre()->findById(5, ['name', 'slug']);
$igdb->genre()->list();
$igdb->genre()->query('fields name, slug; limit 500; sort id;');

Note: All the listed endpoints are available through the IGDB class.

Counting

Every endpoint has a counting variant that reports how many items match a filter, so there is no need to page through a list to find out. Call count() with an apicalypse query, or without one to count everything on the endpoint.

$igdb->game()->count(); //Count all games
$igdb->game()->count('where rating > 75;'); //Count all games with a rating above 75
$igdb->platform()->count('where platform_type = 1;'); //Count all platforms of a given type

Only the filters are meaningful while counting: selecting fields, sorting and paginating have nothing to act on. A query built for a list call can be passed in unchanged, but a filter is all that is needed:

use KrisKuiper\IGDBV4\QueryBuilder\Query;

//where platforms = (7, 9) & genres != 45;
$query = (new Query())
    ->where('platforms', [7, 9])
    ->where('genres', 45, '!=')
    ->build();

$igdb->game()->count($query);

Advanced Query Builder

The query builder lets you programmatically create queries which you can use for each endpoint calling the query() method.

It contains the following methods:

  • fields() (selecting specific fields)
  • exclude() (excluding specific fields)
  • search()
  • where() (where, whereIn and grouping where's)
  • orWhere() (only after a where)
  • sort()
  • offset()
  • limit()

Example using the query builder with the "games" endpoint

use GuzzleHttp\Client;
use KrisKuiper\IGDBV4\IGDB;
use KrisKuiper\IGDBV4\Authentication\ValueObjects\AccessConfig;
use KrisKuiper\IGDBV4\QueryBuilder\Query;

$client = new Client();
$config = new AccessConfig('your client id', 'your access token');
$igdb = new IGDB($client, $config);

//fields name, storyline, platforms.*; where platforms = (7, 9) & genres != 45; sort id asc; limit 20;
$query = (new Query())
    ->fields('name', 'storyline', 'platforms.*')
    ->where('platforms', [7, 9])
    ->where('genres', 45, '!=')
    ->sort('id')
    ->limit(20)
    ->build();
    
$igdb->game()->query($query);

Examples using the query builder

use KrisKuiper\IGDBV4\QueryBuilder\Query;

//fields name, storyline; platforms.*; where id = 375;
$query = (new Query())
    ->fields('name', 'storyline', 'platforms.*')
    ->where('id', 375)
    ->build();
    
//fields name, storyline; search "Metal Gear Solid; limit 50;
$query = (new Query())
    ->fields('name', 'storyline', 'platforms.*')
    ->search('Metal Gear Solid')
    ->limit(50)
    ->build();

//fields *; exclude genres, platforms, keywords; sort name desc; limit 50;
$query = (new Query())
    ->fields('*')
    ->exclude('genres', 'platforms', 'keywords')
    ->limit(50)
    ->sort('name', 'desc')
    ->build();

Query builder advanced where conditions

use KrisKuiper\IGDBV4\QueryBuilder\Query;

//fields name; where genres = 25 & platforms = 5;
$query = (new Query())
    ->fields('name')
    ->where('genres', 25)
    ->where('platforms', 5)
    ->build();

//fields name; where platforms >= 5 & platforms <= 10;
$query = (new Query())
    ->fields('name')
    ->where('platforms', 5, '>=')
    ->where('platforms', 10, '<=')
    ->build();
    
//fields name; where genres = 25 | platforms = (5, 7, 9);
$query = (new Query())
    ->fields('name')
    ->where('genres', 25)
    ->orWhere('platforms', [5, 7, 9])
    ->build();

//fields name; where genres = 25 | (platforms = 5 | platforms = 9 | platforms = 12) & id = 375;
$query = (new Query())
    ->fields('name')
    ->where('genres', 25)
    ->orWhere(function($query) {
        $query
            ->where('platforms', 5)
            ->orWhere('platforms', 9)
            ->orWhere('platforms', 12);
    })
    ->where('id', 375)
    ->build();

Webhooks

Instead of polling the API for changes, IGDB can push data to you whenever an entity is added, updated or deleted. This package supports both managing your webhooks and handling the incoming notifications.

Full information can be found in the IGDB webhook documentation.

Managing webhooks

Webhooks are registered per endpoint and per method (create, update or delete). The secret is a value of your choice that IGDB will send back in the X-Secret header of every notification, so you can verify the request really came from IGDB.

use GuzzleHttp\Client;
use KrisKuiper\IGDBV4\IGDB;
use KrisKuiper\IGDBV4\Authentication\ValueObjects\AccessConfig;
use KrisKuiper\IGDBV4\Enums\WebhookMethod;

$client = new Client();
$config = new AccessConfig('your client id', 'your access token');
$igdb = new IGDB($client, $config);

//Register a webhook that fires when a new game is created
$webhook = $igdb->webhooks()->register('games', 'https://example.com/igdb/webhook', WebhookMethod::CREATE, 'your-secret');
$webhook->getId();      //The unique webhook id
$webhook->isActive();   //Whether the webhook is currently active

//Retrieve all registered webhooks (returns a typed WebhookCollection)
foreach ($igdb->webhooks()->all() as $webhook) {
    $webhook->getUrl();
}

//Retrieve a single webhook by its id (returns null when it does not exist)
$igdb->webhooks()->find($webhook->getId());

//Send a test notification: delivers the game with id 1337 to your registered "games" create webhook
$igdb->webhooks()->test('games', $webhook->getId(), 1337);

//Remove a webhook (returns the deleted webhook id)
$igdb->webhooks()->delete($webhook->getId());

Tip: A webhook is set to inactive after 5 failed deliveries. Re-register it on service start to make sure it is always active.

Handling incoming notifications

When IGDB delivers a notification, validate and parse it with the WebhookReceiver. It is framework-agnostic and accepts any PSR-7 ServerRequestInterface. It verifies the X-Secret and User-Agent headers for you and throws a WebhookException when the request can not be trusted.

use KrisKuiper\IGDBV4\Webhooks\WebhookReceiver;
use KrisKuiper\IGDBV4\Exceptions\WebhookException;
use KrisKuiper\IGDBV4\Enums\WebhookMethod;

//$request is a PSR-7 ServerRequestInterface provided by your framework
$receiver = new WebhookReceiver('your-secret');

try {
    $payload = $receiver->receive($request);
} catch (WebhookException $exception) {
    //Invalid secret, wrong user agent or an unparsable body: reject the request
    http_response_code(403);
    return;
}

$payload->getEndpoint();    //e.g. "games"
$payload->getOperation();   //WebhookMethod::CREATE, ::UPDATE or ::DELETE
$payload->getId();          //The id of the affected entity
$payload->getData();        //The unexpanded entity (only the id is present for delete notifications)

//Always answer within 15 seconds with a 200 OK so IGDB keeps the webhook active
http_response_code(200);

Note: incoming X-Endpoint values are normalized to their lowercase slug (IGDB delivers Games while webhooks are registered as games), and the X-Operation value is matched case-insensitively.

Handling test deliveries

Deliveries triggered through the test API ($igdb->webhooks()->test(...)) differ from real deliveries: IGDB sends them with a generic Java/<version> user agent and without the X-Endpoint and X-Operation headers (the X-Secret header is present). They would therefore always be rejected by receive(). Use receiveTest() instead, which only verifies the secret and returns the raw entity:

$receiver = new WebhookReceiver('your-secret');
$data = $receiver->receiveTest($request); //Verifies X-Secret, returns the entity object
$data->id;

Run Unit Test

Install phpunit in your environment and run:

$ php ./vendor/bin/phpunit

Questions and Feedback

Questions that are not addressed in the manual should be directed to the relevant repository, as linked above.

If you find code in this release behaving in an unexpected manner or contrary to its documented behavior, please create an issue with the relevant repository, as linked above.

License

You can find a copy of this license in LICENSE.md.