Using the Enjin API

Harness the full power of the Enjin Platform.

GraphQL is a sophisticated API language that allows you to meticulously define the structure of your operations, facilitating the precise retrieval of essential data.

With GraphQL, you gain the capability to seamlessly access properties across multiple resources while effortlessly traversing references between them.

In stark contrast to traditional REST APIs, GraphQL streamlines data retrieval for your application, eliminating the need for multiple requests to various endpoints, resulting in a more efficient and elegant data-fetching process.

📘

What you'll need:

Access Tokens

Access tokens assume a pivotal role in facilitating your application's interaction with the GraphQL API.

These tokens serve a dual purpose:

  1. They grant your application access to the platform.
  2. They allow for automatic request approval and signing using the Wallet Daemon.

To get started

  1. login to the Testnet Enjin Platform to create your account
  2. Create an API token
  3. When making HTTP requests to the GraphQL endpoints, add your API token to the headers to be authenticated, like so:
"Authorization": "<API Token Key Here>"
  1. To automate requests made from the Enjin Platform using a wallet daemon, you need to configure your daemon with the API token.
    For more details head over to Using the Wallet Daemon

HTTP

Every data transfer strictly adheres to the HTTP/1.1 standard, with an imperative requirement for HTTPS encryption across all endpoints.

Given that the GraphQL API is rooted in HTTP, it seamlessly aligns with any programming language boasting an HTTP library, encompassing well-known options like cURL and urllib.

👍

GraphQL Endpoints

Testnet:

  • Core Operations http://platform.canary.enjin.io/graphql
  • Fuel Tanks http://platform.canary.enjin.io/graphql/fuel-tanks
  • Marketplace http://platform.canary.enjin.io/graphql/marketplace
  • Beam http://platform.canary.enjin.io/graphql/beam

Mainnet:

  • Core Operations http://platform.enjin.io/graphql
  • Fuel Tanks http://platform.canary.enjin.io/graphql/fuel-tanks
  • Marketplace http://platform.canary.enjin.io/graphql/marketplace
  • Beam http://platform.canary.enjin.io/graphql/beam

API Reference

We offer three options for API Referencing:

GraphQL Playground

This platform serves three purposes:

  1. Explore available operations.
  2. Write operations using an intuitive interface.
  3. View responses and test your operations before coding them.

Step 1: Open GraphiQL Playground

Choose between Testnet or Mainnet.

Explore "Core Operations" for core operations like managing tokens, wallets, users, and transactions.

👍

GraphiQL Playground:

Please be aware that the provided links are specifically for the GraphiQL Playground, a graphical user interface designed for exploring and interacting with GraphQL APIs, specifically for the Enjin Platform.

If you wish to execute GraphQL requests programmatically from your local environment or a cloud-based application, you will need to utilize the actual GraphQL endpoint URLs. These can be found in the HTTP section of our documentation.

Testnet:

Mainnet:

Step 2: Open the explorer

Click the Show GraphQL Explorer button.

Here, you can view a complete list of available queries and mutations, along with the associated fields and arguments for each of them.

Step3: Add a query or mutation to start building your operation

Add a query or mutation into the "write" panel, and you'll see the list of available options in the explorer update to suit the operation type.

Step 4: Select which operations and datapoints you require

Click the required data points to automatically add them to the write column.

This feature eliminates any guesswork when structuring your operations and helps you make the most of the Enjin Platform Schema.

Step 5: Click the play button to execute your operation

To execute your operation and view the response, simply click the Execute Query button.

You can execute any on-chain operation here. You can even mint tokens and view wallet data on Mainnet.

📘

Dig deeper into the Enjin API Schema.

GraphQL Operation Structures

The Enjin API features an intricately crafted Platform Schema that is finely tuned to empower the development of scalable and high-speed blockchain-based games, ensuring an immersive experience for players.

To interface with it directly, you will need to understand how GraphQL operations are structured.

Operation Name

The Operation Name such as GetTokenInfo is a user-defined identifier for a specific operation.

It allows you to organize and distinguish different operations within a single request, making it easier to handle responses and manage complex queries or mutations efficiently.

query GetTokenInfo { #'GetTokenInfo' is the Operation Name that distinguishes this operation from others
  GetToken(
    collectionId: 7153
    tokenId: { integer: 10 }
  ) {
    supply
  }
}
{
  "data": {
    "GetToken": {
      "supply": "1000"
    }
  }
}

Fields

Fields serve as a means to precisely specify the data you want to retrieve in the response of an operation.

Fields enable you to fine-tune the granularity of data retrieval, ensuring you receive precisely what you need.

When crafting Queries and Mutations, the Enjin Platform defines what fields are available for you to request.

For instance, when using the GetToken query, you can request the supply field, which corresponds to a specific piece of information stored on the blockchain.

query {
  GetToken(
    collectionId: 7153
    tokenId: { integer: 10 }
  ) {
    supply # supply is a Field that returns the token's supply
  }
}
{
  "data": {
    "GetToken": {
      "supply": "1000"
    }
  }
}

Arguments

You can pass data into an operation by using arguments.

Most Queries and Mutations define a set of input data you can use, for example in the GetToken query you can pass in a collectionId and a tokenId argument.

query {
  GetToken(
    collectionId: 7153 #collectionId is an argument defining which collection to pull data from
    tokenId: { integer: 10 } #tokenId is an argument defining which token to pull data from
  ) {
    supply
  }
}
{
  "data": {
    "GetToken": {
      "supply": "1000"
    }
  }
}

Sometimes arguments will be required, sometimes they will be optional, and some operations may not take any arguments at all.

The API will tell you if you try to run an operation without a required argument.

Aliases

The alias, such as TokenInfo and CurrentSupply in the queries provided below, serve as a custom labels for specific fields within the operation.

Aliases allow you to rename the field in the response, making the data more intuitive and organized, especially when dealing with multiple fields or nested queries within a GraphQL request.

Operation Alias:

Usually used in batch operations, it allows you to provide a clear and descriptive name for each operations.

You might use it to distinguish between multiple similar queries or to provide context for the purpose of the query.

query GetTokenInfo {
  TokenInfo: GetToken( #TokenInfo is the ALIAS that labels the field
    collectionId: 7153
    tokenId: { integer: 10 }
  ) {
    supply
  }
}
{
  "data": {
    "TokenInfo": {
      "supply": "1000"
    }
  }
}

Field Alias:

This option is useful when you want to label a specific field within the response.

It allows you to rename individual fields in the response for clarity or to avoid naming conflicts.

query GetTokenInfo {
  GetToken(
    collectionId: 7153
    tokenId: { integer: 10 }
  ) {
    CurrentSupply: supply
  }
}
{
  "data": {
    "GetToken": {
      "CurrentSupply": "1000"
    }
  }
}

Variables

Various code blocks in the Enjin Documentation use variables instead of hardcoding arguments. This allows the dynamic insertion of data as you run mutations and queries.

For example, when a player picks up an item, your game needs to fetch the token information using the token's ID. To dynamically insert the token ID to the query, we should use a variable.

That way, we will have one "template" for token fetching query, and the game will decide which token to fetch based on the player actions.

To work with variables in GraphQL, we first need to declare the $variableName, as the variables accepted by the operation. Our operations has two arguments - Collection ID and Token ID, so we'll name the variables $collection_id and $token_id respectively. Both arguments are of type BigInt, so the variable declaration will look like that:

query GetTokenInfo($collection_id: BigInt! $token_id: BigInt) {

Note the exclamation mark (!) after the first variable declaration type BigInt. This represents a non-nullable variable (essentially a required field).

We also need to replace the static value in the operation with the $variableName

GetToken(
  collectionId: $collection_id //Collection ID 7153 was hardcoded here
  tokenId: { integer: $token_id } //Token ID 10 was hardcoded here
)

And the final step is to pass variableName: value in a separate, transport-specific (usually JSON) variables dictionary:

{
  "collection_id": 7153,
  "token_id": 10
}

Here's the final operation code:

Query:

query GetTokenInfo($collection_id: BigInt! $token_id: BigInt) {
  GetToken(
    collectionId: $collection_id
    tokenId: { integer: $token_id }
  ) {
    supply
  }
}

Variables:

{
  "collection_id": 37108,
  "token_id": 0
}

Types

Types in GraphQL serve as blueprints for defining the shape and composition of the data available through the API, encompassing a collection of fields representing specific pieces of information.

These structures lay the foundation for shaping queries and mutations, ensuring precise data retrieval and manipulation.

Query:

A query is used to retrieve data from the Enjin Platform.

In this example, we're querying for information about a specific token.

query GetTokenInfo {
  GetToken(
    collectionId: 7153
    tokenId: { integer: 10 }
  ) {
    supply # Returns the current supply of the token
  }
}
{
  "data": {
    "TokenInfo": {
      "supply": "1000"
    }
  }
}

The GetToken query retrieves token information.

We specify the collectionId and tokenId as parameters to identify the token we want.

The fields tokenId and supply indicate the data we want to receive in the response.

Mutation:

A mutation is used to modify data on the Enjin Platform. For example, you can use a mutation to update a user's profile information.

In this example, we're minting a new token.

mutation MintToken {
  MintToken(
    recipient: "0xaa89f9099742a928051c41eadba188ad4e863539ff96f16722ae7850271c2921"
    collectionId: "7154"
    params: {
      amount: 1
      tokenId: { integer: 6533 }
    }
  ) {
    id # Returns the transaction ID
  }
}
{
  "data": {
    "MintToken": {
      "id": "1234" // request ID
    }
  }
}

The MintToken mutation mints a new token.

We provide the necessary arguments, such as recipient, collectionId, and params, to define the minting process.

The field id indicate the data we want to receive in the response.

Batch Query:

A batch query allows you to send multiple mutation operations in a single request to reduce network overhead.

Each query have its own set of parameters and return data.

query BatchGetTokenInfo {
  TokenInfo1: GetToken(
    collectionId: 7153 # Specifies the collection ID for the first token
    tokenId: { integer: 10 } # Specifies the unique identifier of the first token
  ) {
    supply # Returns the current supply of the first token
  }
  TokenInfo2: GetToken(
    collectionId: 4553 # Specifies the collection ID for the second token
    tokenId: { integer: 55 } # Specifies the unique identifier of the second token
  ) {
    supply # Returns the current supply of the second token
  }
}
{
  "data": {
    "TokenInfo1": {
      "supply": 100 // Current supply of the first token
    },
    "TokenInfo2": {
      "supply": 200 // Current supply of the second token
    }
  }
}

In this batch query, we retrieve information for two different tokens with distinct collectionId and tokenId.

Each token's data is aliased using TokenInfo1 and TokenInfo2.

Batch Mutation

A batch mutation allows you to send multiple mutation operations in a single request to reduce network overhead.

Each mutation can have its own set of parameters and return data.

mutation {
  MintToken1: MintToken(
    recipient: "0xaa89f9099742a928051c41eadba188ad4e863539ff96f16722ae7850271c2921" # Specifies the recipient's address for the first MintToken operation
    collectionId: "7154" # Specifies the collection ID for the first MintToken operation
    params: {
      amount: 1 # Specifies the amount to mint for the first MintToken operation
      tokenId: { integer: 6533 } # Specifies the unique identifier of the first token to mint
    }
  ) {
    id # Returns the request ID for the first MintToken operation
  }
  MintToken2: MintToken(
    recipient: "0x1234567890abcdef" # Specifies the recipient's address for the second MintToken operation
    collectionId: "7155" # Specifies the collection ID for the second MintToken operation
    params: {
      amount: 2 # Specifies the amount to mint for the second MintToken operation
      tokenId: { integer: 6534 } # Specifies the unique identifier of the second token to mint
    }
  ) {
    id # Returns the request ID for the second MintToken operation
  }
}

{
  "data": {
    "MintToken1": {
      "id": "1234" // request ID for the first MintToken operation
    },
    "MintToken2": {
      "id": "1235" // request ID for the second MintToken operation
    }
  }
}

In this batch mutation, we have two separate MintToken mutations, labeled using the MintToken1 and MintToken2 aliases.

Both mutations are minting two different tokens into two separate addresses.

Pagination

Some GraphQL queries returns results in multiple pages. In GraphQL, these are called "Connections", and each of the elements in the connection is called "Edge".

For example, the GetWallet query returns an object of type Wallet. Wallet objects contains tokenAccount which is of type TokenAccountConnection. Since this object is of type 'connection', it uses pagination.

By default, if you don't specify which page to query, the first page will be returned.
To check if the response contains another page for a certain object, use the pageInfo.hasNextPage property from the connection.

query FetchingWalletTokens{
  GetWallet(account: "cxKnfok66R8BAuzGcypxqirYcqW7E9Spn4z5UZSVRuUHAcrTQ"){
    tokenAccounts{
      pageInfo{
        hasNextPage #Returns whether there's a next page or not
      }
      edges{
        node{
          token{
            tokenId
          }
          balance
        }
      }
    }
  }
}
{
  "data": {
    "GetWallet": {
      "tokenAccounts": {
        "pageInfo": {
          "hasNextPage": true // Indicates that there is another page available.
        },
        "edges": [
          {
            "node": {
              "token": {
                "tokenId": "5"
              },
              "balance": "1"
            }
          },
          {...},
          {...}
        ]
      }
    }
  }
}

By default, this connection returns 15 edges (tokens) per page.

Note: The amount of edges per page can be adjusted by using slicing.

To navigate to the next page, use pagination combined with the edge cursor.
First, add the cursor field to the query response. (Alternatively, you can add the pageInfo.endCursor field to fetch the cursor of the last edge in the connection)

query FetchingWalletTokens{
  GetWallet(account: "cxKnfok66R8BAuzGcypxqirYcqW7E9Spn4z5UZSVRuUHAcrTQ"){
    tokenAccounts{
      pageInfo{
        hasNextPage
        endCursor #Returns The cursor of the last tokenAccount in the current page
      }
      edges{
        cursor #Returns The tokenAccount cursor
        node{
          token{
            tokenId
          }
          balance
        }
      }
    }
  }
}
{
  "data": {
    "GetWallet": {
      "tokenAccounts": {
        "pageInfo": {
          "hasNextPage": true,
          "endCursor": "eyJpZCI6Mjk0NzQsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0" // The cursor of the last tokenAccount in the current page
        },
        "edges": [
          {
            "cursor": "eyJpZCI6MzU3NCwiX3BvaW50c1RvTmV4dEl0ZW1zIjp0cnVlfQ", // The tokenAccount cursor
            "node": {
              "token": {
                "tokenId": "5"
              },
              "balance": "1"
            }
          },
          {...},
          {...},
          {
            "cursor": "eyJpZCI6Mjk0NzQsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0", // The tokenAccount cursor
            "node": {
              "token": {
                "tokenId": "11"
              },
              "balance": "1"
            }
          }
        ]
      }
    }
  }
}

Now we have the cursor of the last edge of the current page.
To navigate to the next page, add the after parameter to the tokenAccounts connection, and insert the cursor of the last edge of the current page.

query FetchingWalletTokens{
  GetWallet(account: "cxKnfok66R8BAuzGcypxqirYcqW7E9Spn4z5UZSVRuUHAcrTQ"){
    tokenAccounts(after: "eyJpZCI6Mjk0NzQsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0"){ #Indicates that we want to fetch tokenAccounts after the specified cursor.
      pageInfo{
        hasNextPage
        endCursor
      }
      edges{
        cursor
        node{
          token{
            tokenId
          }
          balance
        }
      }
    }
  }
}
{
  "data": {
    "GetWallet": {
      "tokenAccounts": {
        "pageInfo": {
          "hasNextPage": true,
          "endCursor": "eyJpZCI6NTE2MzgsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0"
        },
        "edges": [
          {
            "cursor": "eyJpZCI6Mzc2MTYsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0",
            "node": {
              "token": {
                "tokenId": "9"
              },
              "balance": "1"
            }
          },
          {...},
          {...},
          {
            "cursor": "eyJpZCI6NTE2MzgsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0",
            "node": {
              "token": {
                "tokenId": "1"
              },
              "balance": "1"
            }
          }
        ]
      }
    }
  }
}

To get all edges in the connection, continue navigating to the next page with a loop.
You'll know that you reached the last page when the hasNextPage returns false.

📘

For more information, refer to the official GraphQL documentation.

👍

Or, If you're ready to start building... Create a Collection.