The Tokenization API enables developers to programmatically mint IP-NFTs (Intellectual Property NFTs) and tokenize them into fungible IP Tokens (IPTs). This API combines off-chain GraphQL mutations with on-chain blockchain transactions to create legally-bound, tradeable intellectual property assets.
Capabilities:
- Mint new IP-NFTs with legal assignment agreements
- Upload artwork and metadata to IPFS
- Create fungible IP Tokens (IPTs) from existing IP-NFTs
- Manage the complete tokenization lifecycle
- Integrate with smart contracts via viem/ethers
All Tokenization API mutations require an API key.
To request an API key and access to the full technical integration guide:
- Join our Discord community
- Contact the Molecule team with:
- Your use case and project details
- Expected volume of minting/tokenization
- You'll receive:
- API Key for authentication
- Technical Integration Guide with complete code examples and ABI files
Include the API key in all requests using the x-api-key header:
x-api-key: YOUR_API_KEYProduction: https://production.graphql.api.molecule.xyz/graphql
Staging: https://staging.graphql.api.molecule.xyz/graphql
Creating an IP-NFT involves 9 steps combining API calls and blockchain transactions.
┌─────────────────────────────────────────────────────────────┐
│ IP-NFT MINTING FLOW │
└─────────────────────────────────────────────────────────────┘
Step 1: Reserve Token ID (BLOCKCHAIN)
↓ Smart contract: IPNFT.reserve()
↓ Fee: 0.001 ETH
↓ Returns: reservationId
Step 2: Generate Assignment Agreement (API)
↓ Mutation: generateAssignmentAgreement
↓ Returns: agreementCid, agreementContentHash
Step 3: Generate Image Upload URL (API)
↓ Mutation: generateImageUploadUrl
↓ Returns: presigned S3 URL
Step 4: Upload Image (DIRECT S3)
↓ HTTP PUT to presigned URL
↓ Upload: artwork image file
Step 5: Upload Metadata (API)
↓ Mutation: uploadMetadataWithImageKey
↓ Returns: metadataCid, metadataUrl (IPFS)
Step 6: Get Terms Message (API)
↓ Query: getTermsMessage
↓ Returns: message to sign
Step 7: Sign Terms (CLIENT-SIDE)
↓ Wallet signature using viem/ethers
↓ Returns: signature
Step 8: Signoff Metadata (API)
↓ Mutation: signoffMetadata
↓ Returns: authorization signature
Step 9: Mint IP-NFT (BLOCKCHAIN)
↓ Smart contract: IPNFT.mintReservation()
↓ Fee: 0.001 ETH + gas
↓ Result: IP-NFT minted ✓
Generates a legal IP assignment agreement and uploads it to IPFS.
Input:
projectData(AWSJSON): Stringified JSON with project details
Required Fields in projectData:
{
"project": {
"name": "Project Name",
"description": "Project description",
"initialSymbol": "SYMBOL",
"organization": "Organization Name",
"research_lead": {
"name": "Dr. Name",
"email": "email@example.com"
},
"topic": "Research Topic",
"funding_amount": {
"value": 50000,
"currency": "USD",
"currency_type": "ISO4217",
"decimals": 2
}
},
"connectedWalletAddress": "0x...",
"chainId": 1,
"ipnftId": "reservationId"
}Response:
{
"agreementCid": "QmXnnyufdzAWL...",
"agreementUri": "ipfs://QmXnnyufdzAWL...",
"agreementContentHash": "0xabcdef...",
"isSuccess": true
}Creates a presigned URL for uploading IP-NFT artwork.
Input:
filename(String): Image filenamecontentType(String): MIME type (e.g., "image/png")ipnftId(String): Reservation ID from Step 1expiresIn(Int, optional): URL expiration in seconds
Response:
{
"uploadUrl": "https://s3.amazonaws.com/...",
"key": "ipnft-images/...",
"expiresAt": "2024-01-15T10:45:00.000Z",
"isSuccess": true
}Uploads NFT metadata with image reference to IPFS.
Input:
metadata(AWSJSON): Stringified metadata objectimageKey(String): S3 key from Step 3ipnftId(String): Reservation ID
Response:
{
"metadataCid": "QmYnZkpT9X...",
"metadataUrl": "ipfs://QmYnZkpT9X...",
"isSuccess": true
}Generates the terms acceptance message for wallet signing.
Input:
metadataCid(String): CID from Step 5minter(String): Wallet addresschainId(Int): Blockchain network ID
Response:
{
"message": "I accept all terms for IPNFT...",
"digest": "0xabcdef...",
"isSuccess": true
}Backend authorization for minting after terms are signed.
Input:
ipnftId(String): Reservation IDtokenURI(String): Metadata URL from Step 5chainId(Int): Network IDminter(String): Wallet addressto(String): Recipient addresstermsSignature(String): Signature from Step 7
Response:
{
"authorization": "0x1234567890abcdef...",
"isSuccess": true
}curl -X POST https://production.graphql.api.molecule.xyz/graphql \
-H 'Content-Type: application/json' \
-H 'x-api-key: YOUR_API_KEY' \
-d '{
"query": "mutation GenerateAssignmentAgreement($projectData: AWSJSON!) { generateAssignmentAgreement(projectData: $projectData) { agreementCid agreementUri agreementContentHash isSuccess error { message } } }",
"variables": {
"projectData": "{\"project\":{\"name\":\"Research Project\",\"description\":\"Novel research\",\"initialSymbol\":\"RES001\",\"organization\":\"University Lab\",\"research_lead\":{\"name\":\"Dr. Smith\",\"email\":\"smith@uni.edu\"},\"topic\":\"Biomedical\",\"funding_amount\":{\"value\":50000,\"currency\":\"USD\",\"currency_type\":\"ISO4217\",\"decimals\":2}},\"connectedWalletAddress\":\"0x...\",\"chainId\":1,\"ipnftId\":\"123\"}"
}
}'Creating fungible IP Tokens from an IP-NFT involves 5 steps.
┌─────────────────────────────────────────────────────────────┐
│ IPT TOKENIZATION FLOW │
└─────────────────────────────────────────────────────────────┘
Step 1: Verify Ownership (BLOCKCHAIN READ)
↓ Smart contract: IPNFT.ownerOf(tokenId)
↓ Verify: You own the IP-NFT
Step 2: Generate Membership Agreement (API)
↓ Mutation: generateIptMembershipAgreement
↓ Returns: agreementCid
Step 3: Get IPT Terms Message (API)
↓ Query: getIptTermsMessage
↓ Returns: message to sign
Step 4: Sign IPT Terms (CLIENT-SIDE)
↓ Wallet signature using viem/ethers
↓ Returns: signature
Step 5: Tokenize (BLOCKCHAIN)
↓ Smart contract: Tokenizer.tokenizeIpnft()
↓ Fee: Gas only
↓ Result: ERC-20 IPT contract deployed ✓
Generates IPT membership agreement and uploads to IPFS.
Input:
agreementData(AWSJSON): Stringified object
Required Fields:
{
"ipnftId": "123",
"symbol": "IPT-SYMBOL",
"title": "IP Token Title"
}Response:
{
"agreementCid": "QmAbc123...",
"agreementUri": "ipfs://QmAbc123...",
"agreementContentHash": "0xdef456...",
"isSuccess": true
}Generates the IPT terms acceptance message for signing.
Input:
agreementCid(String): CID from Step 2ipnftId(String): IP-NFT identifierchainId(Int): Blockchain network ID
Response:
{
"message": "I accept IPT terms...",
"digest": "0x789ghi...",
"isSuccess": true
}curl -X POST https://production.graphql.api.molecule.xyz/graphql \
-H 'Content-Type: application/json' \
-H 'x-api-key: YOUR_API_KEY' \
-d '{
"query": "mutation GenerateIptAgreement($agreementData: AWSJSON!) { generateIptMembershipAgreement(agreementData: $agreementData) { agreementCid agreementUri isSuccess error { message } } }",
"variables": {
"agreementData": "{\"ipnftId\":\"123\",\"symbol\":\"CART-IPT\",\"title\":\"Cancer Research IP Token\"}"
}
}'Mainnet (Ethereum):
- IPNFT Contract:
0xcaD88677CA87a7815728C72D74B4ff4982d54Fc1 - Tokenizer Contract: Contact team for address
Testnet (Sepolia):
- IPNFT Contract:
0x152B444e60C526fe4434C721561a077269FcF61a - Tokenizer Contract: Contact team for address
For complete contract addresses and ABIs, see Smart Contract Addresses.
The minting and tokenization workflows include blockchain transactions that require:
Requirements:
- Ethereum wallet with private key access
- ETH for gas fees
- 0.001 ETH for IP-NFT minting fee
- viem or ethers.js library for transaction signing
Example (using viem):
import { createWalletClient, http } from 'viem';
import { mainnet } from 'viem/chains';
const walletClient = createWalletClient({
chain: mainnet,
transport: http()
});
// Step 1: Reserve token ID
const reserveTx = await walletClient.writeContract({
address: '0xcaD88677CA87a7815728C72D74B4ff4982d54Fc1',
abi: IPNFT_ABI, // Request from Molecule team
functionName: 'reserve',
value: parseEther('0.001')
});
// Step 9: Mint IP-NFT
const mintTx = await walletClient.writeContract({
address: '0xcaD88677CA87a7815728C72D74B4ff4982d54Fc1',
abi: IPNFT_ABI,
functionName: 'mintReservation',
args: [
recipientAddress,
reservationId,
metadataUrl,
symbol,
authorizationSignature
],
value: parseEther('0.001')
});- API Key: Obtained from Molecule team
- Wallet: Ethereum wallet with private key
- ETH Balance: Minimum 0.002 ETH (0.001 reserve + 0.001 mint + gas)
- Project Data: Name, description, organization, research lead info
- Artwork: Image file (PNG, JPEG, WebP, SVG - max 5MB recommended)
- API Key: Obtained from Molecule team
- IP-NFT Ownership: Must own the IP-NFT you want to tokenize
- ETH Balance: Sufficient for gas fees
- Token Details: Symbol, name, initial supply amount
All mutations follow a consistent error response format:
{
"isSuccess": false,
"error": {
"message": "Error description",
"code": "ERROR_CODE",
"retryable": true
}
}| Error Code | Description | Solution |
|---|---|---|
| 401 Unauthorized | Missing or invalid API key | Check x-api-key header |
| 400 Bad Request | Invalid parameters or malformed JSON | Verify input data format |
INVALID_TERMS_SIGNATURE |
Terms signature doesn't match signer address | Ensure same wallet signs terms |
INVALID_METADATA |
Metadata schema validation failed | Check required metadata fields |
SYMBOL_ALREADY_TAKEN |
IP-NFT symbol already exists | Use a unique symbol |
ALREADY_TOKENIZED |
IP-NFT has already been tokenized | Each IP-NFT can only be tokenized once |
MUST_CONTROL_IPNFT |
Caller doesn't own the IP-NFT | Only IP-NFT owner can tokenize |
"INVALID_TERMS_SIGNATURE" Error:
- Ensure the same wallet address is used throughout the flow
- Verify signature is generated from the exact message returned by
getTermsMessage - Check that
minterparameter matches the signing wallet
"SYMBOL_ALREADY_TAKEN" Error:
- Choose a unique symbol for your IP-NFT
- Symbols must be alphanumeric (no special characters)
- Check existing IP-NFTs to avoid conflicts
Blockchain Transaction Failures:
- Verify sufficient ETH balance (0.001 ETH + gas)
- Check that wallet has approved spending
- Ensure using correct contract address for your network
- Wait for transaction confirmation before proceeding
For complete code examples including:
- All 9 IP-NFT minting steps with code
- All 5 IPT tokenization steps with code
- Smart contract ABIs and interfaces
- Error handling and retry logic
- Safe multisig integration
Contact the Molecule team to receive the full Technical Integration Guide.
// 1. Reserve token ID on-chain
const reservationId = await reserveIpnft();
// 2. Generate legal agreement
const agreement = await generateAssignmentAgreement(projectData);
// 3-4. Upload artwork
const imageKey = await uploadArtwork(imageFile);
// 5. Upload metadata to IPFS
const metadata = await uploadMetadata(imageKey, agreement);
// 6-7. Get and sign terms
const termsMessage = await getTermsMessage(metadata.cid);
const termsSignature = await signTerms(termsMessage);
// 8. Get backend authorization
const authorization = await signoffMetadata(termsSignature);
// 9. Mint IP-NFT on-chain
const txHash = await mintReservation(reservationId, metadata.url, authorization);
console.log('IP-NFT minted!', txHash);reserve():
- Reserves a token ID for minting
- Requires: 0.001 ETH payment
- Returns: Reservation ID (emitted in event)
mintReservation():
- Mints the reserved IP-NFT
- Parameters:
to(address): RecipientreservationId(uint256): From reserve()tokenURI(string): IPFS metadata URLsymbol(string): IP-NFT symbolauthorization(bytes): Backend signature
- Requires: 0.001 ETH payment
- Returns: Token ID (emitted in Transfer event)
tokenizeIpnft():
- Creates ERC-20 IPT from IP-NFT
- Parameters:
ipnftId(uint256): IP-NFT token IDtokenAmount(uint256): Initial IPT supply (in wei)tokenSymbol(string): IPT ticker symbolagreementCid(string): Membership agreement CIDtermsSignature(bytes): Signed terms acceptance
- Returns: IPT contract address (emitted in event)
Contract ABIs:
- Request full ABIs from Molecule team as part of the Technical Integration Guide
| Network | Chain ID | IPNFT Contract |
|---|---|---|
| Ethereum Mainnet | 1 | 0xcaD88677CA87a7815728C72D74B4ff4982d54Fc1 |
| Sepolia Testnet | 11155111 | 0x152B444e60C526fe4434C721561a077269FcF61a |
- Reserve: ~50,000 gas + 0.001 ETH fee
- Mint Reservation: ~150,000 gas + 0.001 ETH fee
- Tokenize IPNFT: ~2,000,000 gas (deploys new ERC-20 contract)
Gas estimates are approximate and vary by network conditions
- Store intermediate results (CIDs, signatures) securely
- Implement retry logic for failed API calls
- Wait for blockchain transaction confirmations
- Validate each step before proceeding to next
- Never expose API keys in client-side code
- Use environment variables for credentials
- Implement proper wallet key management
- Verify all signatures and authorizations
- Use high-resolution artwork (minimum 512x512px)
- Provide complete project descriptions
- Include all relevant research lead information
- Ensure legal agreement accuracy
- Use testnet (Sepolia) for development
- Test complete workflow end-to-end
- Verify metadata renders correctly
- Check IPFS pinning is successful
For assistance with the Tokenization API:
- Technical Integration Guide: Contact Molecule team to receive complete documentation
- Discord: Join our community for support
- Smart Contracts: See contract addresses
Last updated: December 2024