# Tokenization API

## Overview

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

***

## Authentication

All Tokenization API mutations require an API key.

### Obtaining an API Key

To request an API key and access to the full technical integration guide:

1. Join our [Discord community](https://t.co/L0VEiy4Bjk)
2. Contact the Molecule team with:
   * Your use case and project details
   * Expected volume of minting/tokenization
3. You'll receive:
   * **API Key** for authentication
   * **Technical Integration Guide** with complete code examples and ABI files

### Using Your API Key

Include the API key in all requests using the `x-api-key` header:

```bash
x-api-key: YOUR_API_KEY
```

***

## API Endpoint

```
Production: https://production.graphql.api.molecule.xyz/graphql
Staging:    https://staging.graphql.api.molecule.xyz/graphql
```

***

## IP-NFT Minting Workflow

Creating an IP-NFT involves 9 steps combining API calls and blockchain transactions.

### High-Level Flow

```
┌─────────────────────────────────────────────────────────────┐
│                    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 ✓
```

### Key Mutations

#### 1. generateAssignmentAgreement

Generates a legal IP assignment agreement and uploads it to IPFS.

**Input:**

* `projectData` (AWSJSON): Stringified JSON with project details

**Required Fields in projectData:**

```json
{
  "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:**

```json
{
  "agreementCid": "QmXnnyufdzAWL...",
  "agreementUri": "ipfs://QmXnnyufdzAWL...",
  "agreementContentHash": "0xabcdef...",
  "isSuccess": true
}
```

#### 2. generateImageUploadUrl

Creates a presigned URL for uploading IP-NFT artwork.

**Input:**

* `filename` (String): Image filename
* `contentType` (String): MIME type (e.g., "image/png")
* `ipnftId` (String): Reservation ID from Step 1
* `expiresIn` (Int, optional): URL expiration in seconds

**Response:**

```json
{
  "uploadUrl": "https://s3.amazonaws.com/...",
  "key": "ipnft-images/...",
  "expiresAt": "2024-01-15T10:45:00.000Z",
  "isSuccess": true
}
```

#### 3. uploadMetadataWithImageKey

Uploads NFT metadata with image reference to IPFS.

**Input:**

* `metadata` (AWSJSON): Stringified metadata object
* `imageKey` (String): S3 key from Step 3
* `ipnftId` (String): Reservation ID

**Response:**

```json
{
  "metadataCid": "QmYnZkpT9X...",
  "metadataUrl": "ipfs://QmYnZkpT9X...",
  "isSuccess": true
}
```

#### 4. getTermsMessage

Generates the terms acceptance message for wallet signing.

**Input:**

* `metadataCid` (String): CID from Step 5
* `minter` (String): Wallet address
* `chainId` (Int): Blockchain network ID

**Response:**

```json
{
  "message": "I accept all terms for IPNFT...",
  "digest": "0xabcdef...",
  "isSuccess": true
}
```

#### 5. signoffMetadata

Backend authorization for minting after terms are signed.

**Input:**

* `ipnftId` (String): Reservation ID
* `tokenURI` (String): Metadata URL from Step 5
* `chainId` (Int): Network ID
* `minter` (String): Wallet address
* `to` (String): Recipient address
* `termsSignature` (String): Signature from Step 7

**Response:**

```json
{
  "authorization": "0x1234567890abcdef...",
  "isSuccess": true
}
```

### Example Request (Step 2)

```bash
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\"}"
    }
  }'
```

***

## IPT Tokenization Workflow

Creating fungible IP Tokens from an IP-NFT involves 5 steps.

### High-Level Flow

```
┌─────────────────────────────────────────────────────────────┐
│                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 ✓
```

### Key Mutations

#### 1. generateIptMembershipAgreement

Generates IPT membership agreement and uploads to IPFS.

**Input:**

* `agreementData` (AWSJSON): Stringified object

**Required Fields:**

```json
{
  "ipnftId": "123",
  "symbol": "IPT-SYMBOL",
  "title": "IP Token Title"
}
```

**Response:**

```json
{
  "agreementCid": "QmAbc123...",
  "agreementUri": "ipfs://QmAbc123...",
  "agreementContentHash": "0xdef456...",
  "isSuccess": true
}
```

#### 2. getIptTermsMessage

Generates the IPT terms acceptance message for signing.

**Input:**

* `agreementCid` (String): CID from Step 2
* `ipnftId` (String): IP-NFT identifier
* `chainId` (Int): Blockchain network ID

**Response:**

```json
{
  "message": "I accept IPT terms...",
  "digest": "0x789ghi...",
  "isSuccess": true
}
```

### Example Request (Step 2)

```bash
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\"}"
    }
  }'
```

***

## Blockchain Integration

### Smart Contract Addresses

**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](broken://pages/TMpLloOogfGTEgz5hp9I).

### On-Chain Transactions

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):**

```javascript
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')
});
```

***

## Requirements

### For IP-NFT Minting

* **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)

### For IPT Tokenization

* **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

***

## Error Handling

All mutations follow a consistent error response format:

```json
{
  "isSuccess": false,
  "error": {
    "message": "Error description",
    "code": "ERROR_CODE",
    "retryable": true
  }
}
```

### Common Errors

| 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         |

### Troubleshooting

**"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 `minter` parameter 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

***

## Complete End-to-End Examples

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**.

### Basic Example Structure

```javascript
// 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);
```

***

## Smart Contract Details

### IPNFT Contract Functions

**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): Recipient
  * `reservationId` (uint256): From reserve()
  * `tokenURI` (string): IPFS metadata URL
  * `symbol` (string): IP-NFT symbol
  * `authorization` (bytes): Backend signature
* Requires: 0.001 ETH payment
* Returns: Token ID (emitted in Transfer event)

### Tokenizer Contract Functions

**tokenizeIpnft():**

* Creates ERC-20 IPT from IP-NFT
* Parameters:
  * `ipnftId` (uint256): IP-NFT token ID
  * `tokenAmount` (uint256): Initial IPT supply (in wei)
  * `tokenSymbol` (string): IPT ticker symbol
  * `agreementCid` (string): Membership agreement CID
  * `termsSignature` (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 Information

### Supported Networks

| Network          | Chain ID | IPNFT Contract                               |
| ---------------- | -------- | -------------------------------------------- |
| Ethereum Mainnet | 1        | `0xcaD88677CA87a7815728C72D74B4ff4982d54Fc1` |
| Sepolia Testnet  | 11155111 | `0x152B444e60C526fe4434C721561a077269FcF61a` |

### Gas Fee Estimates

* **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*

***

## Best Practices

### Workflow Management

* 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

### Security

* Never expose API keys in client-side code
* Use environment variables for credentials
* Implement proper wallet key management
* Verify all signatures and authorizations

### Metadata Quality

* Use high-resolution artwork (minimum 512x512px)
* Provide complete project descriptions
* Include all relevant research lead information
* Ensure legal agreement accuracy

### Testing

* Use testnet (Sepolia) for development
* Test complete workflow end-to-end
* Verify metadata renders correctly
* Check IPFS pinning is successful

***

## Getting Support

For assistance with the Tokenization API:

* **Technical Integration Guide**: Contact Molecule team to receive complete documentation
* **Discord**: Join our [community](https://t.co/L0VEiy4Bjk) for support
* **Smart Contracts**: See [contract addresses](broken://pages/TMpLloOogfGTEgz5hp9I)

***

*Last updated: December 2024*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.molecule.xyz/api-reference/tokenization-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
