Working with Game Items

Create and manage game items.

All Items

You can retrieve a unified list of all items registered in your game by making a GET http request to https://api.gameshift.dev/nx/items:

curl --request GET \
     --url https://api.gameshift.dev/nx/items \
     --header 'accept: application/json' \
     --header 'x-api-key: <your api key>'

You can apply filters while fetching items to narrow down the results:

  • types: A list of item types to include. Can be any combination of UniqueAsset and Currency.
  • forSale: Only include items that are listed for sale on the marketplace.
  • collectionId: Only include items that belong to this collection. This will automatically exclude Currencies since those cannot belong to any collection.
  • ownerReferenceId: Only include items that belong to this user. This will include all registered Currencies, even if the amount held by the user is 0.

The response will be a list of items registered in the game, with each item's type clearly denoted:

{
  "data": [
    {
      "type": "Currency",
      "item": {
        "id": "USDC",
        "mintAddress": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
        "name": "USD Coin",
        "symbol": "USDC"
      }
    },
    {
      "type": "Currency",
      "item": {
        "id": "SOL",
        "mintAddress": "11111111111111111111111111111111",
        "name": "SOL",
        "symbol": "SOL"
      }
    },
    {
      "type": "UniqueAsset",
      "item": {
        "id": "c01c7111-e327-4f5d-b0f9-c75425ef6962",
        "collection": {
          "id": "6809eccc-a54f-4bc9-8527-7a42b1623b99",
          "name": "Example Collection",
          "description": "Example of a collection",
          "environment": "Development",
          "imported": false,
          "mintAddress": "9TLcFuCyWeHR3tySiMr7PjGmeUHhpFDiaJ4ykUQ2RyDu",
          "created": 1709219450063
        },
        "created": 1710169624330,
        "attributes": [],
        "name": "Example Asset",
        "description": "Example of an asset",
        "environment": "Development",
        "forSale": false,
        "imageUrl": "https://solana.com/src/img/branding/solanaLogoMark.png",
        "imported": false,
        "price": null,
        "status": "Committed",
        "mintAddress": "DP7geA17WLnb2XQ9w2nRNkbwDeJA6kQxGheN7N1iYzPs",
        "owner": {
          "address": "buFuaYE5B5w8gtkAp64ubM7ytuAxq7h5HYQPDk4MWVuy",
          "referenceId": "exampleOwnerId"
        }
      }
    },
  ],
  "meta": {
    "page": 1,
    "perPage": 50,
    "totalPages": 1,
    "totalResults": 3
  }
}

Unique Assets

Creating a Unique Asset

GameShift allows you to programmatically create on-chain game assets by providing data to an API call, or through an asset template.

To create an asset directly, make a POST http request to https://api.gameshift.dev/nx/unique-assets:

curl --request POST \
     --url https://api.gameshift.dev/nx/unique-assets \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your key here>' \
     --data '
{
  "details": {
    "collectionId": "9a3e53b0-e3f3-4e01-8538-788d5b886c81",
    "description": "Example description",
    "imageUrl": "https://solana.com/src/img/branding/solanaLogoMark.png",
    "name": "Example Asset",
    "attributes": [
      {
        "traitType": "attribute-name",
        "value": "attribute-value"
      }
    ]
  },
  "destinationUserReferenceId": "exampleUserId"
}
'

Assets require the following values in the “details” object:

  • collectionId: Specifies which collection the asset should be assigned to.

  • description: 64-character string providing information about the asset, which may be displayed to the user later

  • name: 32-character string that identifies the asset, which may be displayed to the user later

  • imageUrl: direct link to the image representing the asset

An asset’s details also supports additional properties called “attributes”. Each “attribute” contains:

  • traitType: a code-appropriate name

  • value: attribute’s value

Finally, specify the user receiving the asset by setting destinationUserReferenceId to an existing referenceId

If successful, you’ll receive a response reflecting the newly-created asset.

{
  "id": "dcde5bc8-b30b-46b6-b4da-0763953b2484",
  "collectionId": "36c97125-04a5-4dc3-b92a-029d74a42287",
  "created": 1710169624330,
  "attributes": [
    {
      "traitType": "attribute-name",
      "value": "attribute-value"
    }
  ],
  "name": "Example Asset",
  "collection": {
    "id": "36c97125-04a5-4dc3-b92a-029d74a42287",
    "name": "Example Collection",
    "description": "Example collection description",
    "environment": "Development",
    "imageUrl": "https://solana.com/src/img/branding/solanaLogoMark.png",
    "imported": false,
    "mintAddress": "9TLcFuCyWeHR3tySiMr7PjGmeUHhpFDiaJ4ykUQ2RyDu",
    "created": "1709219450063"
  },
  "description": "Example description",
  "imageUrl": "https://solana.com/src/img/branding/solanaLogoMark.png",
  "status": "Processing",
  "imported": false,
  "forSale": false,
  "price": null,
  "mintAddress": "",
  "owner": null,
}

Newly created assets remain in a “Processing” state until created on-chain. Poll for the latest status of an asset by making a GET http request to https://api.gameshift.dev/nx/items/{the-id-of-the-asset}:

{
  "type": "UniqueAsset",
  "item": {
    "id": "dcde5bc8-b30b-46b6-b4da-0763953b2484",
    "collection": {
      "id": "36c97125-04a5-4dc3-b92a-029d74a42287",
      "name": "Example Collection",
      "description": "Example collection description",
      "environment": "Development",
      "imageUrl": "https://solana.com/src/img/branding/solanaLogoMark.png",
      "imported": false,
      "mintAddress": "9TLcFuCyWeHR3tySiMr7PjGmeUHhpFDiaJ4ykUQ2RyDu",
      "created": "1709219450063"
    },
    "created": 1710169624330,
    "attributes": [
      {
        "traitType": "attribute-name",
        "value": "attribute-value"
      }
    ],
    "name": "Example Asset",
    "description": "Example description",
    "environment": "Development",
    "forSale": false,
    "imageUrl": "https://solana.com/src/img/branding/solanaLogoMark.png",
    "imported": false,
    "price": null,
    "status": "Committed",
    "mintAddress": "DP7geA17WLnb2XQ9w2nRNkbwDeJA6kQxGheN7N1iYzPs",
    "owner": {
      "address": "BuHuaXF6N5w6gtkApJ4ubM7ytuAxq7h5HYQPDk4MWVuy",
      "referenceId": "exampleUserId"
    }
  }
}

Unique Assets committed to the blockchain include the owner’s wallet address and their referenceId.

Created Unique Assets are assigned to Collections. You can create your own Collections (see “Creating Collections”) and pass its id when creating an asset to assign an asset to it.

Modifying a Unique Asset

Assets can be modified by making a PUT http request to https://api.gameshift.dev/nx/unique-assets/{the-id-of-the-asset}:

curl --request PUT \
     --url https://api.gameshift.dev/nx/unique-assets/dcde5bc8-b30b-46b6-b4da-0763953b2484 \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your api key>' \
     --data '
{
  "imageUrl": "updated-img-url",
  "attributes": [
    {
      "traitType": "trait-1",
      "value": "value-1"
    }
  ]
}
'

Not all fields are modifiable. The fields you can change are:

  • imageUrl: You can set this field to change the underlying image of the Asset
  • attributes: You can set this field to entirely replace the existing set of attributes for the Asset

Selling a Unique Asset

GameShift provides the ability to sell newly created unique assets to users with fiat payment instruments (e.g. debit and credit cards). To complete this flow, you must implement three specific steps:

  1. Request payment from the user
  2. Receive a payment.completedwebhook event
  3. Create the new unique asset and deliver it to the user's wallet

First, create a payment.completed webhook in the GameShift admin app at https://app.gameshift.dev(Webhooks => New Webhook). You may also want to create a webhook for the payment.failed event in order to notify the user if their payment fails and instruct them to retry.

In order to request payment from the user, you can make a POST http request to https://api.gameshift.dev/nx/payments.

curl --request POST \
     --url https://api.gameshift.dev/nx/payments \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '
{
  "price": {
    "currencyId": "USD",
    "naturalAmount": "5.99"
  },
  "title": "Example Item",
  "description": "Example Item",
  "quantity": 1,
  "buyerId": "user1"
}
'

Store the payment id returned by this request for future purchase fulfillment.

In your webhook handler, you can implement the logic to create a new unique asset upon receiving the payment.completed event. For this step, you can follow the instructions above in Creating a Unique Asset.

Currencies (SPL Tokens)

You can use GameShift to interact with SPL Tokens (called "Currencies" in GameShift) that are in your users' wallets. You can view balances and initiate a request to transfer Currencies to other GameShift users or other Solana wallet addresses.

You cannot use GameShift to create any Currencies, but you can "import" existing Currencies into GameShift. In addition, GameShift user wallets can accept any valid SPL Tokens, however, in order to view balances via the GameShift API, you must first explicitly import the Currency. By default, GameShift auto-imports two commonly used Currencies: SOL and USDC.

Importing Currencies

Note: Importing Currencies will require a minor amount of Solana blockchain knowledge.

In order to import a Currency into GameShift, you can make a POST http request to https://api.gameshift.dev/nx/currencies/import.

curl --request POST \
     --url https://api.gameshift.dev/nx/currencies/import \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your api key>' \
     --data '
{
  "mintAddress": "Bb9bsTQa1bGEtQ5KagGkvSHyuLqDWumGUcRqFusFNJWC"
}
'

You must provide the following fields in the request body:

  • mintAddress: This is the address that defines the SPL Token you wish to import as a Currency.

The response will include some details about the Currency you just imported, including an id that you can use to refer to the Currency in other api requests.

{
  "id": "0a6fdc5c-5bef-4736-97ee-977d1ba952ab",
  "mintAddress": "Bb9bsTQa1bGEtQ5KagGkvSHyuLqDWumGUcRqFusFNJWC",
  "name": "Example Currency",
  "symbol": "EXMP"
}

If the Currency you imported has well defined metadata (such as a name and/or symbol), these will be picked up automatically. If not, GameShift will leave those fields as empty strings.

Viewing User Balances

You can view the balances of Currencies for any given user by using filter. You can start by making a GET http request to https://api.gameshift.dev/nx/users/{referenceId}/items?type=Currency.

curl --request GET \
     --url 'https://api.gameshift.dev/nx/users/exampleUserId/items?types=Currency' \
     --header 'accept: application/json' \
     --header 'x-api-key: <your api key>'

The response will include a paginated list of Currencies, and the quantity of each Currency possessed by the user.

{
  "data": [
    {
      "type": "Currency",
      "item": {
        "id": "SOL",
        "mintAddress": "11111111111111111111111111111111",
        "name": "SOL",
        "symbol": "SOL"
      },
      "quantity": "1.09796072"
    },
    {
      "type": "Currency",
      "item": {
        "id": "USDC",
        "mintAddress": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
        "name": "USD Coin",
        "symbol": "USDC"
      },
      "quantity": "25.5"
    },
    {
      "type": "Currency",
      "item": {
        "id": "b3e6a7ff-d692-4843-8455-9f3777aae146",
        "mintAddress": "DuhbFTUND4Zv75bWbXtXthg2GLNNRvDGziYGZCR9EXFk",
        "name": "Example Currency",
        "symbol": "EXMP"
      },
      "quantity": "0"
    },
  ],
  "meta": {
    "page": 1,
    "perPage": 50,
    "totalPages": 1,
    "totalResults": 3
  }
}

Asset Collections

Collections help you create logical groupings for your assets that also exist on-chain. You can assign Unique Assets you create to collections that you create.

Create a collection by making a POST http request to https://api.gameshift.dev/nx/asset-collections:

curl --request POST \
     --url https://api.gameshift.dev/nx/asset-collections \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your api key>' \
     --data '
{
  "name": "New Example Collection",
  "description": "An example collection",
  "imageUrl": "https://solana.com/src/img/branding/solanaLogoMark.png"
}
'

Collections require the following:

  • name: 32-character string that identifies the collection

  • description: 64-character string providing information about the collection

  • imageUrl: direct link to the image representing the collection

Transferring Items

Items can be transferred only with the asset owner’s permission. Item transfers consist of a request to transfer from an owner, followed by a consenting response from that user. Items can be transferred between users registered by you on GameShift, or from a GameShift-registered user to an arbitrary blockchain wallet address.

Items transferred can be Unique Assets or Currencies.

Initiate a transfer between users by making a POST http request to https://api.gameshift.dev/nx/users/{id-of-the-item-owner}/items/{id-of-the-item}/transfer:

curl --request POST \
     --url https://api.gameshift.dev/nx/users/exampleUserId/items/USDC/transfer \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your api key>' \
     --data '
{
  "quantity": "10",
  "destinationUserReferenceId": "exampleDestinationId"
}
'

You must provide values for the following fields:

  • quantity: how many of the item you want to transfer. If you are transferring a Unique Asset, this must have the value 1.

  • destinationUserReferenceId: the user intended to receive the asset.

Initiate a transfer to an arbitrary blockchain wallet address by making a GET http request to the same endpoint and with destinationWallet instead of a user’s id:

curl --request POST \
     --url https://api.gameshift.dev/nx/users/exampleUserId/items/USDC/transfer \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your api key>' \
     --data '
{
  "quantity": "10",
  "destinationWallet": "example-wallet-address"
}
'

All requests return a “consent URL”- a link that the asset owner must visit to provide consent for the transaction.

{
  "transactionId": "48007108-fbd3-4306-a02e-ac6141b7c83e",
  "consentUrl": "https://app.gameshift.dev/consent?transaction=48007108-fbd3-4306-a02e-ac6141b7c83e"
}

When the asset owner visits the URL, they’ll be asked for permission to complete the transaction.

img img

Once permission is granted, the owner receives a one-time-passcode (OTP) delivered to their email. The OTP must be entered into the consent form to complete the transfer.

Lending Items

Items can be easily lent and borrowed between users by creating a lending grant that reflects an agreement between two users to lend/borrow and asset. Currently, the only available item type for lending is Unique Assets. The lender can revoke the lending grant at any time, but while an item is lent, the owner cannot transfer or sell the item. While the lending grant is active, the borrower is considered by GameShift as the holder of the item. Note that items that are lent out currently remain in the lender's on-chain wallet, so on-chain analytics will not recognize the effect of the lending grant.

Initiate lending an Asset by making a POST http request to https://api.gameshift.dev/nx/users/{id-of-the-lender}/items/{id-of-the-item}/lend:

curl --request POST \
     --url https://api.gameshift.dev/nx/users/exampleUserId/items/6ba6e801-258c-4d5d-86b9-4f65c522bb1c/lend \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your api key>' \
     --data '
{
  "destinationUserReferenceId": "borrower-id"
}
'

You must provide the following fields:

  • destinationUserReferenceId: the user intending to borrow the asset

You can also provide the following optional fields:

  • expiration: the date and time (representing in ms) that the grant should expire. If left blank, will default to 30days from the request date.

On a successful request, you'll receive a reference for the lending grant:

{
  "id": "string",
  "itemId": "string",
  "ownerReferenceId": "string",
  "borrowerReferenceId": "string",
  "expiration": "2023-12-14T22:35:14.292Z",
  "created": "2023-12-14T22:35:14.292Z",
  "status": "Pending",
  "environment": "Development"
}

Once a lending grant is created, it must be accepted by the user intending to borrow the asset. You can make a request to accept the grant by making a POST http request to https://api.gameshift.dev/nx/lending-grants/{id-of-the-lending-grant}/accept:

curl --request POST \
     --url https://api.gameshift.dev/nx/lending-grants/6ba6e801-258c-4d5d-86b9-4f65c522bb1c/accept \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your api key>' \
     --data '
{
  "borrowerReferenceId": "borrower-id"
}
'

You can also return the asset to the original owner at any time by making a POST http request to https://api.gameshift.dev/nx/lending-grants/{id-of-the-lending-grant}/return:

curl --request POST \
     --url https://api.gameshift.dev/nx/lending-grants/6ba6e801-258c-4d5d-86b9-4f65c522bb1c/return \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your api key>' \
     --data '
{
  "borrowerReferenceId": "borrower-id"
}
'

Alternatively, you can cancel the grant. This would represent the original owner reclaiming their borrowed asset. You can initiate this cancel by making a DELETE http request to https://api.gameshift.dev/nx/lending-grants/{id}:

curl --request DELETE \
     --url https://api.gameshift.dev/nx/lending-grants/6ba6e801-258c-4d5d-86b9-4f65c522bb1c \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your api key>' \
     --data '
{
  "lenderReferenceId": "current-owner"
}
'