Crafting

Consume Items and issue new ones

Crafting allows users to convert items in their possession into new items.

Basic Concepts

Crafting works as a two step process. First, you create a "recipe" that defines the inputs to the crafting operation which the user will need to provide. Then, once the user provides the inputs, you will deliver the crafted item to the user.

To create a recipe, you will specify a list of items and their quantities required for crafting the new item. GameShift will provide you with a consent URL where you will redirect the user for them to approve relinquishing the required crafting inputs.

After the player visits the consent page and approves the transactions to provide the items in the recipe, you will receive a webhook event from GameShift. Alternatively, you can poll to wait until the recipe is fulfilled. After you receive notice that the recipe is fulfilled, you then call out the necessary GameShift APIs to issue/create the target "crafted" item(s).

This process can work with a mix of on-chain and off-chain assets. To support this use case, you simply create the GameShift recipe containing the on-chain assets. When you receive notification of the transaction approval, you can safely deduct the requisite off-chain assets from the user’s balance.

Step 1: Creating a Recipe

To create a recipe, make a POST http request to https://api.gameshift.dev/nx/crafting-recipes:

curl --request POST \
     --url https://api.gameshift.dev/nx/crafting-recipes \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your key here>' \
     --data '
{
  "craftingUserReferenceId": "exampleReferenceId",
  "metadata": {
    "title": "Craft +2 Sword",
    "description": "Craft a more powerful sword",
    "image": "https://example.image.png",
    "attributes": [
      {
        "traitType": "Example Property",
        "value": "10"
      }
    ]
  },
  "consumes": [
    // Items to consume; explained below
  ]
}
'

You will need to provide the following fields:

  • craftingUserReferenceId: This is the user that will fulfill the recipe.
  • metadata: (Optional) Additional fields you can provide that will reflect in the UI for the consent flow. All fields within this object are also optional.
  • consume: A list of items that will be consumed when the recipe is fulfilled.

consumes

The consumes property during recipe creation is a list of items that will be consumed. Each of the items in the list can be one of the following types of consumption items:

  • ConsumeCurrencyItemDto
  • ConsumeUniqueAssetItemDto
  • ConsumeStackableAssetItemDto

The shape of these is further expanded below:

ConsumeCurrencyItemDto

A ConsumeCurrencyItemDto has the following shape:

{
  "type": "Currency",
  "id": "81016eb1-ec78-4ca8-a304-44866ca30304",
  "naturalAmount": "1000"
}
  • type: This must always be "Currency", as that defines that the item to be consumed is a currency.
  • id: Specifies the currency that will be consumed by the recipe.
  • naturalAmount: Specifies the quantity that will be consumed.

ConsumeUniqueAssetItemDto

A ConsumeUniqueAssetItemDto has the following shape:

{
  "type": "UniqueAsset",
  "id": "7bc5c81c-c024-4e73-b385-34516c5db510",
  "method": "Transfer" // or "Destroy"
}
  • type: This must always be "UniqueAsset", as that defines that the item to be consumed is a Unique Asset.
  • id: Specifies the Unique Asset that will be consumed by the recipe.
  • method: (Optional) Specifies how the Unique Asset will be consumed. If set to "Transfer", the asset will be moved to your developer wallet. If set to "Destroy", the asset will be burned on chain. NOTE: Currently, only "Transfer" is supported.

ConsumeStackableAssetItemDto

A ConsumeStackableAssetItemDto has the following shape:

{
  "type": "StackableAsset",
  "id": "c377fee4-9e19-4aed-a9a0-f333f3cf7457",
  "naturalAmount": "1000",
}
  • type: This must always be "StackableAsset", as that defines that the item to be consumed is a Stackable Asset.
  • id: Specifies the Stackable Asset that will be consumed by the recipe.
  • naturalAmount: Specifies the quantity of the Stackable Asset that will be consumed by the recipe.

Putting it all together

You can specify multiple items of different types in your recipe. For example, a recipe that requires multiple Unique Assets, Stackable Assets, and Currencies might look like:

curl --request POST \
     --url https://api.gameshift.dev/nx/crafting-recipes \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your key here>' \
     --data '
{
  "craftingUserReferenceId": "exampleReferenceId",
  "metadata": {
    "title": "Craft +2 Sword",
    "description": "Craft a more powerful sword",
    "image": "https://example.image.png"
  },
  "consumes": [
    {
      "type": "Currency",
      "id": "81016eb1-ec78-4ca8-a304-44866ca30304",
      "naturalAmount": "1000"
    },
    {
      "type": "UniqueAsset",
      "id": "7bc5c81c-c024-4e73-b385-34516c5db510"
    },
    {
      "type": "UniqueAsset",
      "id": "4b969959-3ad1-4354-bb22-5990e1d6678e"
    },
    {
      "type": "StackableAsset",
      "id": "c377fee4-9e19-4aed-a9a0-f333f3cf7457",
      "naturalAmount": "1000"
    }
  ]
}
'

Step 2: Fulfilling the recipe

After creating a recipe, you will see a response that looks something like this:

{
  "recipeId": "c0e2f267-d336-45bd-b3b9-a0a4dc33e81f",
  "consentUrl": "https://app.gameshift.dev/consent?id=ea307b18-af43-45a9-9e2b-c213f4ba4864"
}

You should store the recipeId -- this is what you will use later to know when the recipe has been fulfilled.

In addition, you must navigate the user to the url specified by the consentUrl field. Here, the user will be presented with a page where they can provide consent for the consumption of the various items in the recipe.

You have two options in how to be informed when a recipe is fulfilled.

Option 1: Using Webhooks (recommended)

The first option would be to set up a webhook event. This is the recommended option as it is far easier to manage multiple recipes using this technique.

First, you must subscribe to the correct webhook following this guide: Webhooks Look for the webhooks titled "recipe.initiated", "recipe.completed", "recipe.failed".

After you have set up your webhook, any recipes you create and/or fulfill will send an event with the following payload:

{
  "type": "recipe",
  "id": "c0e2f267-d336-45bd-b3b9-a0a4dc33e81f",
  "status": "initiated", // or "completed" or "failed"
  "recipe": {
    "id":  "c0e2f267-d336-45bd-b3b9-a0a4dc33e81f",
    "metadata": {
      "title": "Craft +2 Sword",
      "description": "Craft a more powerful sword",
      "image": "https://example.image.png"
    },
    "craftingUserReferenceId": "exampleReferenceId",
    "consumes": [
      {
        "type": "Currency",
        "id": "81016eb1-ec78-4ca8-a304-44866ca30304",
        "naturalAmount": "1000",
      },
      {
        "type": "UniqueAsset",
        "id": "7bc5c81c-c024-4e73-b385-34516c5db510"
      },
      {
        "type": "UniqueAsset",
        "id": "4b969959-3ad1-4354-bb22-5990e1d6678e"
      },
      {
        "type": "StackableAsset",
        "id": "c377fee4-9e19-4aed-a9a0-f333f3cf7457",
        "naturalAmount": "1000"
      }
    ]
  }
}

Option 2: Polling for fulfillment status

The second option is to simply poll for the latest state of the recipe. You can get the recipe's status by making a GET http request to https://api.gameshift.dev/nx/crafting-recipes/{id-of-the-recipe}.

curl --request GET \
     --url https://api.gameshift.dev/nx/crafting-recipes/c0e2f267-d336-45bd-b3b9-a0a4dc33e81f \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: <your key here>'

The response will include details about the recipe as well as its current status.

{
  "id":  "c0e2f267-d336-45bd-b3b9-a0a4dc33e81f",
  "metadata": {
    "title": "Craft +2 Sword",
    "description": "Craft a more powerful sword",
    "image": "https://example.image.png"
  },
  "craftingUserReferenceId": "exampleReferenceId",
  "consumes": [
    {
      "type": "Currency",
      "id": "81016eb1-ec78-4ca8-a304-44866ca30304",
      "naturalAmount": "1000",
    },
    {
      "type": "UniqueAsset",
      "id": "7bc5c81c-c024-4e73-b385-34516c5db510"
    },
    {
      "type": "UniqueAsset",
      "id": "4b969959-3ad1-4354-bb22-5990e1d6678e"
    },
    {
      "type": "StackableAsset",
      "id": "c377fee4-9e19-4aed-a9a0-f333f3cf7457",
      "naturalAmount": "1000"
    }
  ],
  "status": "Pending", // or "Failed", "Confirmed", or "Expired"
  "transactions": [
    {
    	"id": "ea307b18-af43-45a9-9e2b-c213f4ba4864",
      "created": "2024-05-12",
      "status": {
        "status": "Confirmed",
        "txHash": "5fJVtHGk2t5HzqBVGjc3qvkHkzyokA3k9eH4VwUnKK1jMm7MLeqW5r8nC719ABoq3wLQEkZaHsFJ3ovJZtec9xEA"
      }
    },
    {
      "id": "ca684e4c-695c-4ed9-98ae-20715047b47b",
      "created": "2024-05-12",
      "status": {
        "status": "Pending",
      }
    }
  ]
}

Step 3: Issuing a new Item

Once you have confirmed that the recipe has been fulfilled, you can then issue a new item. To do so, you can either create a new Unique Asset (v3) Working with Game Items, issue some quantity of a Stackable Asset (coming soon), or transfer from currency from your game wallet.