# Cardano Token Registry

## Complete Guide: Registering a Native Token in the Cardano Token Registry

> Last updated: February 2026

***

### Table of Contents

1. Overview
2. Official Documentation Links
3. Prerequisites
4. Phase 1 - Environment Setup (WSL + Ubuntu)
5. Phase 2 - Install token-metadata-creator
6. Phase 3 - Prepare Your Policy Keys
7. Phase 4 - Prepare Your Logo
8. Phase 5 - Create the Metadata Entry
9. Phase 6 - Sign and Finalize
10. Phase 7 - Verify the JSON
11. Phase 8 - Submit the Pull Request
12. Registry Field Reference
13. Common Mistakes & How to Avoid Them
14. Best Practices Checklist

***

### Overview

The Cardano Token Registry is an off-chain metadata repository maintained by the Cardano Foundation. It maps native token subjects (policy ID + asset name hex) to human-readable metadata like names, tickers, descriptions, and logos.

**Key facts:**

* Entirely off-chain — no ADA or blockchain transaction required
* Metadata is submitted via GitHub Pull Request
* Signatures prove policy ownership cryptographically
* The process works on Windows via WSL (Windows Subsystem for Linux)

***

### Official Documentation Links

| Resource                        | URL                                                                                                          |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Cardano Token Registry (GitHub) | <https://github.com/cardano-foundation/cardano-token-registry>                                               |
| token-metadata-creator tool     | <https://github.com/input-output-hk/offchain-metadata-tools>                                                 |
| Tool manual                     | <https://input-output-hk.github.io/offchain-metadata-tools/>                                                 |
| Registry submission guide       | <https://github.com/cardano-foundation/cardano-token-registry/wiki/How-to-prepare-an-entry-for-the-registry> |
| CIP-26 (off-chain metadata)     | <https://github.com/cardano-foundation/CIPs/tree/master/CIP-0026>                                            |

***

### Prerequisites

Before starting, you need:

* **Policy ID** of your native token
* **Policy signing key** (`.skey` file, used during minting)
* **Policy script** file (`.script` or `.json`)
* **Asset name** in hex (e.g. `fSLVR` → `66534c5652`)
* **Logo** image (see Phase 4 for format requirements)
* **GitHub account**
* Windows PC with WSL, or a Linux machine

> 💡 **Finding your asset name in hex:** You can convert ASCII to hex online at <https://string-functions.com/string-hex.aspx> or in Linux: `echo -n "YOURTOKEN" | xxd -p`

> 💡 **Your subject** is always: `{policyID}{assetNameHex}` — concatenated with no separator.

***

### Phase 1 - Environment Setup (WSL + Ubuntu)

> Skip this phase if you already have Linux.

#### Install WSL on Windows

Open **PowerShell as Administrator** and run:

```powershell
wsl --install
```

Restart your computer when prompted.

After restart, Ubuntu will open and ask you to create a UNIX user.

> ⚠️ Your UNIX username **must be lowercase**. Ubuntu will reject uppercase usernames.

#### Verify WSL is working

Open the Ubuntu terminal and run:

```bash
whoami
```

You should see your lowercase username.

> 💡 **Accessing Windows files from Ubuntu:** Your Windows drives are mounted at `/mnt/c/`, `/mnt/d/` etc. Example: `C:\Users\YourUsername\Desktop\` → `/mnt/c/Users/YourUsername/Desktop/`

***

### Phase 2 - Install token-metadata-creator

In your Ubuntu terminal:

```bash
# Update package list and install dependencies
sudo apt update && sudo apt install git wget -y

# Create working directory
mkdir ~/tokenreg && cd ~/tokenreg

# Download the tool (check for latest release at https://github.com/input-output-hk/offchain-metadata-tools/releases)
wget https://github.com/input-output-hk/offchain-metadata-tools/releases/download/v0.4.0.0/token-metadata-creator.tar.gz

# Extract
tar -xzf token-metadata-creator.tar.gz

# Move to system path
sudo mv token-metadata-creator /usr/local/bin/

# Verify installation
token-metadata-creator --help
```

If you see the help output, the tool is installed correctly.

***

### Phase 3 - Prepare Your Policy Keys

You need two files in your working directory:

#### policy.script

Create this file with your policy script. Example for a simple signature policy:

```bash
cat > ~/tokenreg/policy.script << 'EOF'
{
  "type": "all",
  "scripts": [
    {
      "type": "sig",
      "keyHash": "YOUR_KEY_HASH_HERE"
    }
  ]
}
EOF
```

#### policy.skey

This is your **signing key** — the private key used to prove ownership of the policy. It should be in the Cardano key envelope format:

```json
{
  "type": "PaymentSigningKeyShelley_ed25519",
  "description": "Payment Signing Key",
  "cborHex": "5820YOUR_CBOR_HEX_HERE"
}
```

> 💡 **Finding your keyHashes:** Go to your NFT Project - click "Project Info" in the side bar - open "Cardano Policy" and press "Export Policy Keys".&#x20;
>
> ⚠️ **Security:** Never share your `.skey` file. It proves ownership of your policy and could be used to sign transactions.

Create the policy skripts and copy both files to your working directory:

```bash
cp /path/to/policy.script ~/tokenreg/
cp /path/to/policy.skey ~/tokenreg/
```

***

### Phase 4 - Prepare Your Logo

This phase is the most error-prone. Follow carefully.

#### Requirements

| Property    | Requirement                                             |
| ----------- | ------------------------------------------------------- |
| Format      | **PNG only** (not JPEG, WebP, SVG)                      |
| Dimensions  | Maximum 200×200 pixels (recommended)                    |
| Base64 size | **Must be under 65,536 characters** when base64-encoded |
| Color mode  | RGBA recommended (supports transparency)                |

> ⚠️ **Common mistake:** Many token logos exist online as JPEG or WebP. Even if the file is named `.png`, it might be a JPEG. Always verify and convert if needed.

#### Step 1 - Check your image format

```bash
python3 -c "
with open('your_logo.png', 'rb') as f:
    header = f.read(8)
print('Format:', 'PNG' if header[:8] == b'\\x89PNG\\r\\n\\x1a\\n' else 'NOT PNG - header: ' + header[:4].hex())
"
```

#### Step 2 - Convert and resize to 200×200 PNG

Install Pillow if needed:

```bash
pip install Pillow --break-system-packages
```

Run the conversion:

```python
python3 << 'EOF'
from PIL import Image
import io, base64

# Open your image (works with JPEG, WebP, PNG, etc.)
img = Image.open('your_logo_original.png')
print(f"Original: {img.format}, {img.size}, mode={img.mode}")

# Convert to RGBA (supports transparency)
img = img.convert('RGBA')

# Resize to 200x200
img = img.resize((200, 200), Image.LANCZOS)

# Save as PNG
buf = io.BytesIO()
img.save(buf, format='PNG', optimize=True)
png_data = buf.getvalue()

# Check base64 size
b64 = base64.b64encode(png_data).decode('ascii')
print(f"PNG size: {len(png_data):,} bytes")
print(f"Base64 length: {len(b64):,} chars (limit: 65,536)")
print(f"Within limit: {len(b64) <= 65536}")

# Save
with open('logo.png', 'wb') as f:
    f.write(png_data)
print("Saved as logo.png")
EOF
```

#### Step 3 - Verify the logo

```python
python3 << 'EOF'
import base64, struct

with open('logo.png', 'rb') as f:
    data = f.read()

b64 = base64.b64encode(data).decode('ascii')
print(f"Valid PNG: {data[:8].hex() == '89504e470d0a1a0a'}")
w = struct.unpack('>I', data[16:20])[0]
h = struct.unpack('>I', data[20:24])[0]
print(f"Dimensions: {w}x{h}")
print(f"Base64 length: {len(b64)} chars")
print(f"PNG size: {len(data):,} bytes")
EOF
```

All checks should pass before proceeding.

> 💡 **If you exceed 65,536 base64 chars:** Try reducing to 150×150 or increase PNG compression. The base64 length is roughly 1.37× the PNG byte size.

***

### Phase 5 - Create the Metadata Entry

Set your subject as an environment variable (saves typing):

```bash
export SUBJECT="YOUR_POLICY_ID_HEX_YOUR_ASSET_NAME_HEX"
# Example:
# export SUBJECT="1674af42f614956176bab5d8ac573afb42c13ad89fc8dd0651f5cb8b66534c5652"
```

Navigate to your working directory:

```bash
cd ~/tokenreg
```

Initialize the draft:

```bash
token-metadata-creator entry --init $SUBJECT
```

This creates a `.json.draft` file.

Add all metadata fields in one command:

```bash
token-metadata-creator entry $SUBJECT \
  --name "YourTokenName" \
  --description "Your token description here. Be precise and informative." \
  --ticker "TICKER" \
  --url "https://yourwebsite.com" \
  --logo logo.png \
  --decimals 6 \
  --policy policy.script
```

> ⚠️ **Critical field notes:**
>
> * `--logo` expects a **PNG file path**, not a base64 string. The tool encodes it internally.
> * `--decimals` must match exactly what was set during minting. **Double-check this value!**
> * `--ticker` maximum 9 characters.
> * `--url` must be a valid HTTPS URL.

***

### Phase 6 - Sign and Finalize

Sign the entry with your policy signing key:

```bash
token-metadata-creator entry $SUBJECT -a policy.skey
```

This adds cryptographic signatures to all attestable fields.

Finalize (produces the final JSON):

```bash
token-metadata-creator entry $SUBJECT --finalize
```

This outputs: `{SUBJECT}.json`

***

### Phase 7 - Verify the JSON

**Never skip this step.** Run this verification before submitting:

```bash
cat ${SUBJECT}.json | python3 -c "
import json, sys, base64, struct

d = json.load(sys.stdin)

# Check all required fields
print('subject:', d.get('subject', 'MISSING'))
print('name:', d['name']['value'])
print('ticker:', d['ticker']['value'])
print('decimals:', d['decimals']['value'])
print('url:', d['url']['value'])
print('policy:', d.get('policy', 'MISSING'))

# Check logo
b64 = d['logo']['value']
png = base64.b64decode(b64)
valid_png = png[:8].hex() == '89504e470d0a1a0a'
w = struct.unpack('>I', png[16:20])[0]
h = struct.unpack('>I', png[20:24])[0]
print(f'Logo b64 length: {len(b64)} chars (limit: 65,536)')
print(f'Logo valid PNG: {valid_png}')
print(f'Logo dimensions: {w}x{h}')
print(f'Logo PNG size: {len(png):,} bytes')

# Check signatures exist
for field in ['name', 'ticker', 'decimals', 'url', 'logo', 'description']:
    sigs = len(d.get(field, {}).get('signatures', []))
    print(f'  {field}: {sigs} signature(s)')

# File size
import os
size = os.path.getsize(f'{d[\"subject\"]}.json')
print(f'File size: {size:,} bytes (limit: 370,000)')
"
```

**Expected output:**

* Valid PNG: True
* Dimensions: 200x200
* Base64 length under 65,536
* All fields have 1+ signatures
* File size under 370,000 bytes

> 💡 **Visually inspect the logo too!** Decode it and open it:
>
> ```bash
> python3 -c "
> import json, base64
> with open('${SUBJECT}.json') as f:
>     d = json.load(f)
> with open('/tmp/preview_logo.png', 'wb') as f:
>     f.write(base64.b64decode(d['logo']['value']))
> print('Saved to /tmp/preview_logo.png')
> "
> # Copy to Windows Desktop to view
> cp /tmp/preview_logo.png /mnt/c/Users/YOURNAME/Desktop/
> ```

***

### Phase 8 - Submit the Pull Request

#### Step 1 - Fork the registry

Go to <https://github.com/cardano-foundation/cardano-token-registry> and click **Fork → Create fork**.

Settings:

* Owner: your GitHub account
* Repository name: `cardano-token-registry` (keep default)
* Copy master branch only: checked
* Description: leave empty

#### Step 2 - Create a GitHub Personal Access Token

Go to <https://github.com/settings/tokens> → **Generate new token (classic)**

Settings:

* Note: `Cardano Token Registry`
* Expiration: 30 days (sufficient)
* Scope: tick **repo** only

Click **Generate token** and **copy it immediately** — GitHub shows it only once.

#### Step 3 - Clone your fork

```bash
git config --global user.email "your@email.com"
git config --global user.name "YourGitHubUsername"

git clone https://github.com/YOURUSERNAME/cardano-token-registry.git
cd cardano-token-registry
```

When prompted for password, paste your **Personal Access Token** (not your GitHub password).

#### Step 4 - Create a branch, add file, commit, push

```bash
# Create branch
git checkout -b add-YOURTOKEN-token

# Copy your finalized JSON
cp ~/tokenreg/${SUBJECT}.json mappings/

# Verify it's there
ls mappings/${SUBJECT}.json

# Stage, commit, push
git add mappings/${SUBJECT}.json
git commit -m "Add YOURTOKEN token metadata"
git push origin add-YOURTOKEN-token
```

#### Step 5 - Open the Pull Request

Go to the URL shown in the terminal output (or navigate to your fork on GitHub).

**PR description template:**

```
Adding metadata for the YOURTOKEN token.

Policy ID: YOUR_POLICY_ID
Ticker: YOURTICKER
Decimals: X
URL: https://yourwebsite.com
```

#### Step 6 - Wait for CI and review

After submitting, two automated checks will run:

* **CI / approve** — checks PR format
* **CI / Validate-Metadata** — validates your JSON structure and signatures

Both must pass. The "Merging is blocked" message is normal — a Cardano Foundation maintainer must approve and merge. This typically takes a few days to a week.

***

### Registry Field Reference

| Field         | Required       | Max Length          | Notes                       |
| ------------- | -------------- | ------------------- | --------------------------- |
| `subject`     | ✅              | —                   | policyID + assetNameHex     |
| `name`        | ✅              | 50 chars            | Human-readable token name   |
| `description` | ✅              | 500 chars           | What the token represents   |
| `ticker`      | Optional       | 9 chars             | Trading ticker symbol       |
| `url`         | Optional       | 250 chars           | Must be HTTPS               |
| `logo`        | Optional       | 65,536 base64 chars | PNG only, max 200×200px     |
| `decimals`    | 6 is standard  | —                   | Integer, must match minting |
| `policy`      | Auto-generated | —                   | CBOR-encoded policy script  |

***

### Common Mistakes & How to Avoid Them

#### Wrong decimals value

**Problem:** Setting decimals to `0` when the token was minted with `6` decimals (or any other value).

**Fix:** Always verify your decimals **before** creating the metadata. Check your minting transaction or NMKR/minting platform settings. Decimals must match exactly what was encoded at mint time.

***

#### Logo not a valid PNG

**Problem:** Logo file is actually a JPEG or WebP even though it has a `.png` extension. This produces a broken or corrupted logo in the registry.

**Fix:** Always check the file header bytes. If the first 8 bytes are not `89 50 4E 47 0D 0A 1A 0A`, it is not a PNG. Convert explicitly with Pillow as shown in Phase 4.

***

#### Logo base64 too large

**Problem:** A 256×256 PNG may exceed the 65,536 base64 character limit.

**Fix:** Use 200×200 maximum. Check the base64 length before proceeding. Reduce to 150×150 if still too large.

***

#### Logo path vs base64 confusion

**Problem:** Passing a pre-encoded base64 file to `--logo` instead of the PNG file path.

**Fix:** The `--logo` flag expects a **PNG file path**. The tool encodes it to base64 internally. Example: `--logo logo.png` ✅ not `--logo logo.b64` ❌

***

#### WSL username with uppercase

**Problem:** Trying to create a UNIX user like `Flo` — Ubuntu rejects it.

**Fix:** Always use lowercase for UNIX usernames: `flo`, `john`, `tokenadmin`.

***

#### Using GitHub password instead of Personal Access Token

**Problem:** `git push` fails with authentication error.

**Fix:** GitHub no longer accepts passwords for CLI operations. Generate a Personal Access Token with `repo` scope and use that as the password.

***

#### Not visually verifying the logo

**Problem:** The JSON passes all automated checks (valid PNG bytes, correct dimensions) but the actual image is broken or wrong.

**Fix:** Always decode the base64 logo from your final JSON and visually inspect it before submitting the PR. Open it in an image viewer to confirm it looks correct.

***

#### Subject lowercase requirement

**Problem:** The filename must be `{subject}.json` where subject is all lowercase hex.

**Fix:** Policy IDs and asset name hex are always lowercase. The `token-metadata-creator` tool handles this automatically.

***

### Best Practices Checklist

Before submitting your PR, confirm all of the following:

**Metadata correctness:**

* Subject is correct: policyID + assetNameHex (no separator)
* Decimals match exactly what was set at minting time
* Description is accurate and informative (max 500 chars)
* URL is live and HTTPS
* Ticker is correct (max 9 chars)

**Logo:**

* File is a true PNG (verified by header bytes)
* Dimensions are 200×200 or smaller
* Base64 length is under 65,536 characters
* Visually inspected and looks correct
* RGBA mode for transparency support

**Signatures:**

* Signed with the correct policy.skey
* All fields have signatures
* Policy field is present

**File:**

* JSON filename matches subject exactly
* File is in the `mappings/` directory
* File size is under 370KB
* JSON is valid (no syntax errors)

**GitHub:**

* Forked from `cardano-foundation/cardano-token-registry`
* PR targets `master` branch
* Both CI checks pass
* PR description includes policy ID, ticker, decimals

***

### Cleanup After Submission

Once your PR is submitted, you can safely clean up your local files:

```bash
# Remove working files
rm -rf ~/tokenreg
rm -rf ~/cardano-token-registry

# Remove downloaded tool archive
rm -f ~/token-metadata-creator.tar.gz*

# Return to home directory
cd ~
```

The `token-metadata-creator` binary remains installed at `/usr/local/bin/` — useful if you register more tokens in the future.


---

# 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.nmkr.io/helpful-links/cardano-token-registry.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.
