Create a Dynamic NFT

Estimated completion time: 30 minutes.

A dynamic NFT is an NFT with traits and data that can be changed/updated based on external events.

Using our Minting APIs, you can create dynamic NFTs very easily. No previous blockchain experience needed - just follow along. ✌️

Enhanced APIs

This tutorial covers:

  1. How to mint an NFT

  2. How to update the metadata of the NFT

  3. How to automatically update the metadata of the NFT

Pre-requirements

  1. Sign up for your free API key

1. How to mint an NFT

Using our APIs you can deploy your own contract, upload files to IPFS, and mint an NFT.

Step A: Deploy your fully owned contract

Deploy a standard ERC-721 smart contract where your can mint your NFTs. Add your API key, set Content-Type as application/json and fill parameters with your own values. Set metadata_updatable as true so that the metadata of the NFT can be changed as required.

For API reference and more code samples, see Deploy a contract for NFT products.

Deploy contract

curl --request POST \
  --url https://api.nftport.xyz/v0/contracts \
  --header 'Authorization: <<apiKey>>' \
  --header 'Content-Type: application/json' \
  --data '{
  "chain": "polygon",
  "name": "Polypunks",
  "symbol": "PP",
  "owner_address": "Your wallet address here",
  "metadata_updatable": true
}'
import requests

url = "https://api.nftport.xyz/v0/contracts"

payload = {
    "chain": "polygon",
    "name": "Polypunks",
    "symbol": "PP",
    "owner_address": "Your wallet address here",
    "metadata_updatable": True
}
headers = {
    "Content-Type": "application/json",
    "Authorization": "<<apiKey>>"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/json', Authorization: '<<apiKey>>'},
  body: '{
  	"chain":"polygon",
  	"name":"Polypunks",
  	"symbol":"PP",
  	"owner_address":"Your wallet address here",
  	"metadata_updatable":true
	}'
};

fetch('https://api.nftport.xyz/v0/contracts', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));

After the transaction is confirmed and contract is deployed on chain, use the transaction_hash from the previous response to retrieve your contract address. For API reference and more code examples, see Retrieve a deployed contract. You can also see your deployed contracts with List all your deployed contracts.

Get contract address of the deployed contract

curl --request GET \
  --url 'https://api.nftport.xyz/v0/contracts/transaction_hash?chain=polygon' \
  --header 'Authorization: <<apiKey>>' \
  --header 'Content-Type: application/json'
import requests

url = "https://api.nftport.xyz/v0/contracts/transaction_hash"

querystring = {"chain":"polygon"}

headers = {
    "Content-Type": "application/json",
    "Authorization": "<<apiKey>>"
}

response = requests.request("GET", url, headers=headers, params=querystring)

print(response.text)
const options = {
  method: 'GET',
  headers: {'Content-Type': 'application/json', Authorization: '<<apiKey>>'}
};

fetch('https://api.nftport.xyz/v0/contracts/transaction_hash?chain=polygon', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));

Step B: Upload your assets to IPFS

Upload your files to IPFS which makes your NFT storage decentralized and immutable. For API reference and more code samples, see Upload a file to IPFS. If you have multiple assets, for example, an image for every part of the day, then you should upload all the files to IPFS.

curl --request POST \
    --url 'https://api.nftport.xyz/v0/files' \
    --header 'Authorization: <<apiKey>>' \
    --header 'Content-Type: multipart/form-data' \
    --form 'file=@/path/to/file_to_upload.png;type=image/png'
import requests

file = open("image.png", "rb")

response = requests.post(
    "https://api.nftport.xyz/v0/files",
    headers={"Authorization": "<<apiKey>>"},
    files={"file": file}
)
const fs = require('fs');
const fetch = require('node-fetch');
const FormData = require('form-data');

const form = new FormData();
const fileStream = fs.createReadStream('image.jpg');
form.append('file', fileStream);

const options = {
  method: 'POST',
  body: form,
  headers: {
    'Authorization': '<<apiKey>>',
  },
};

fetch('https://api.nftport.xyz/v0/files', options)
  .then(response => {
    return response.json()
  })
  .then(responseJson => {
    // Handle the response
    console.log(responseJson);
  })

Step C: Create and upload your NFT metadata to IPFS

Upload your metadata to IPFS which makes your NFT metadata decentralized and immutable. For API reference, full customization and more code samples, see Upload metadata to IPFS. If you have multiple assets, for example, an image for every part of the day, then you should create a different metadata file for every asset.

curl --request POST \
  --url https://api.nftport.xyz/v0/metadata \
  --header 'Authorization: <<apiKey>>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Your NFT name",
  "description": "Your NFT description",
  "file_url": "URL of the file that you wish to turn into an NFT"
}'
import requests

url = "https://api.nftport.xyz/v0/metadata"

payload = {
    "name": "Your NFT name",
    "description": "Your NFT description",
    "file_url": "The ipfs_url you got from the previous request response"
}
headers = {
    "Content-Type": "application/json",
    "Authorization": "<<apiKey>>"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/json', Authorization: '<<apiKey>>'},
  body: '{
  	"name":"Your NFT name",
  	"description":"Your NFT description",
  	"file_url":"The ipfs_url you got from the previous request response"
	}'
};

fetch('https://api.nftport.xyz/v0/metadata', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));

Step D: Mint NFTs to your contract

Mint NFTs to the contract you just deployed. For API reference, full customization and more code samples, see Customizable minting.

curl --request POST \
  --url https://api.nftport.xyz/v0/mints/customizable \
  --header 'Authorization: <<apiKey>>' \
  --header 'Content-Type: application/json' \
  --data '{
  "chain": "polygon",
  "contract_address": "The contract address which you got from step 1 A",
  "metadata_uri": "Metadata URI that you got from the response of uploading metadata to IPFS",
  "mint_to_address": "Account address where the NFT will be sent. For example, your Metamask wallet address if you wish to send it to yourself"
}'
import requests

url = "https://api.nftport.xyz/v0/mints/customizable"

payload = {
    "chain": "polygon",
    "contract_address": "The contract address which you got from step 1 A",
    "metadata_uri": "Metadata URI that you got from the response of uploading metadata to IPFS",
    "mint_to_address": "Account address where the NFT will be sent. For example, your Metamask wallet address if you wish to send it to yourself"
}
headers = {
    "Content-Type": "application/json",
    "Authorization": "<<apiKey>>"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/json', Authorization: '<<apiKey>>'},
  body: '{
  	"chain":"polygon",
  	"contract_address":"The contract address which you got from step 1 A",
  	"metadata_uri":"Metadata URI that you got from the response of uploading metadata to IPFS",
  	"mint_to_address":"Account address where the NFT will be sent. For example, your Metamask wallet address if you wish to send it to yourself"
	}'
};

fetch('https://api.nftport.xyz/v0/mints/customizable', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));

Get token ID of the minted NFT

curl --request GET \
  --url 'https://api.nftport.xyz/v0/mints/transaction_hash?chain=polygon' \
  --header 'Authorization: <<apiKey>>' \
  --header 'Content-Type: application/json'
import requests

url = "https://api.nftport.xyz/v0/mints/transaction_hash"

querystring = {"chain":"polygon"}

headers = {
    "Content-Type": "application/json",
    "Authorization": "<<apiKey>>"
}

response = requests.request("GET", url, headers=headers, params=querystring)

print(response.text)
const options = {
  method: 'GET',
  headers: {'Content-Type': 'application/json', Authorization: '<<apiKey>>'}
};

fetch('https://api.nftport.xyz/v0/mints/transaction_hash?chain=polygon', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));

Here's how our freshly minted NFT on Polygon looks like:

AWS Lambda

2. How to update the metadata of the NFT

Use our API to update the metadata of the NFT. For API reference and more code samples, see Update a minted NFT.

curl --request POST \
  --url https://api.nftport.xyz/v0/mints/customizable \
  --header 'Authorization: <<apiKey>>' \
  --header 'Content-Type: application/json' \
  --data '{
  "chain": "polygon",
  "contract_address": "The contract address which you got from step 1 a",
  "token_id": "The token ID which you got from step 1 d",
  "metadata_uri": "The new metadata uri with which you want your NFT to be linked"
}'
import requests

url = "https://api.nftport.xyz/v0/mints/customizable"

payload = {
    "chain": "polygon",
    "contract_address": "The contract address which you got from step 1 a",
    "token_id": "The token ID which you got from step 1 D",
    "metadata_uri": "The new metadata uri with which you want your NFT to be linked"
}
headers = {
    "Content-Type": "application/json",
    "Authorization": "<<apiKey>>"
}

response = requests.request("PUT", url, json=payload, headers=headers)

print(response.text)
const options = {
  method: 'PUT',
  headers: {'Content-Type': 'application/json', Authorization: '<<apiKey>>'},
  body: '{"chain":"polygon","contract_address":"The contract address which you got from step 1 a","token_id":"The token ID which you got from step 1 D","metadata_uri":"The new metadata uri with which you want your NFT to be linked"}'
};

fetch('https://api.nftport.xyz/v0/mints/customizable', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));

Here's how our updated NFT looks like:

AWS Lambda

3. How to automatically update the metadata of the NFT

You can create an AWS Lambda function (event-driven serverless computing platform by Amazon), to automatically trigger updates to your NFT's metadata. For example, if you want to change the NFT metadata based on the time of the day, you can setup the lambda function to get triggered every x hours. See AWS developer guide to learn more.

The AWS Lambda free tier includes one million free requests per month which is a lot more than the 3x30 = 90 requests we'll make per month.

Step A: Create a Lambda function

Create a basic Lambda function using the runtime of your choice. We'll be using Python 3.9 in this tutorial.

AWS Lambda

Step B: Update the metadata of the NFT using AWS Lambda

Replace the values of the variables as required - api_key, metadata URIs, etc.

This updates the metadata of the NFT according to the time of the day. You can customize as you see fit. You can even use a weather API to set the NFT image according to the weather.

  • 4 a.m. to 12 p.m. - Image A displayed in the morning
  • 12 p.m. to 8 p.m. - Image B displayed during the afternnon
  • 8 p.m. to 4 a.m. - Image C displayed at night
# lambda_function.py

import requests
import json
from datetime import datetime

API_KEY = "<<apiKey>>"

# Replace with your metadata URIs
MORNING_URI = "ipfs://QmcFQ7K8N1XgtQvU3fB8VFmc9jHBmvpMkvSiKrJsgWQ6Sj" 
AFTERNOON_URI = "ipfs://QmTmcL1KWgj5q2QwPM2KmmP3kSExTAp25MLBxaf39sjP6S"
NIGHT_URI = "ipfs://QmdMqg9vYoG3p6FeQko3kLrGivQ6mgZQRgvbFR8SXhutUF"
URL = "https://api.nftport.xyz/v0/mints/customizable"
    
    
def lambda_handler(event, context):
    time = datetime.now().hour
    if time >=4 and time <12:
        metadata_uri = MORNING_URI
    elif time >=12 and time<20:
        metadata_uri = AFTERNOON_URI
    else:
        metadata_uri = NIGHT_URI

    # Replace with the contract_address you got from 1 A and token_ID from 1 D
    payload = {
                "chain":"polygon",
                "contract_address": "0x5bc18431304b4218e2b2bffaa97e608f8e500544",
                "token_id": "293425161759338263480",
                "metadata_uri": metadata_uri
        
    }
    headers = {
                "Content-Type": "application/json",
                "Authorization": API_KEY
    }
    response = requests.request("PUT", URL, data=json.dumps(payload), headers=headers)
    return {
        'statusCode': 200,
        'body': json.dumps(response.json())
    }

Step C: Configure installations and upload files to AWS Lambda

Unfortunately, python requests library does not come pre installed and the vendored version of requests from Botocore will be removed soon. We'll therefore need to install requests to run our code.

On your local machine, create a folder and install requests inside it by adding -t.

mkdir lambda && cd lambda
pip install requests -t .

Inside this folder create a file lambda_function.py. The Lambda handler will look for this exact file during execution. Copy the code in step B and paste it into this file.

Zip all the files in the folder (do not zip the whole folder as the files should be at the root when unzipped inside Lambda) inlcuding the lambda_function.py and the requests library, and upload it to AWS Lambda. Use the Upload from button at the top right and then click .zip file to upload your zipped file.

Upload files

Your file structure should look like this :

AWS Lambda

Click the deploy button to save the changes.

Step D: Setup a trigger to automatically call your lambda function

We'll setup a trigger to automate this process. Click Add trigger to setup a trigger to call the lambda function.

AWS Lambda

Set the trigger configuration to EventBridge (CloudWatch Events). We'll set the rate as 8 hours since we are going to update the NFT metadata every 8 hours. Yo
u can customize the rate of fire as per your liking, see the guide here to know more.

AWS Lambda

Once you setup the trigger, the complete configuration should look like this.

AWS Lambda

Your dynamic NFT is ready to rock'n'roll 😎

How our dynamic NFT looks like:

AWS Lambda

You can see our dynamic NFT on Opensea. Click on the Refresh metadata button on Opensea to get the updated NFT asset. The image displayed will depend on the time of the day (UTC).

Join the Community for Support and to Build Together

Join our Discord community if you need support from our team and a space to discuss NFT related topics, voice feature requests, and engage with other like-minded NFT developers.