A reference implementation of a Cardano CIP-26 compliant offchain metadata registry with CIP-68 support.
The registry is a Spring Boot application backed by PostgreSQL. It serves token metadata from two sources:
- CIP-26 (offchain): metadata is synced from a GitHub repository on a scheduled basis (every 60 minutes by default).
- CIP-68 (on-chain): metadata is read directly from the Cardano blockchain via Yaci Store, which connects to a Cardano node and indexes CIP-68 reference NFT datums.
The V2 API queries both standards by priority (CIP_68,CIP_26 by default). CIP-68 on-chain data takes precedence when available.
Note
By default, Yaci Store connects to a public Cardano node (STORE_CARDANO_HOST in .env). You can point it to your own node if preferred.
See the API Reference for the full API definition.
- Docker and Docker Compose
- 2+ CPU cores, 4GB RAM, 10GB storage
docker compose updocker compose --env-file .env.preprod up| Method | Path | Description |
|---|---|---|
| GET | /api/v2/subjects/{subject} |
Token metadata with CIP priority selection |
| POST | /api/v2/subjects/query |
Batch query with priority and detail options |
For the full API reference (including V1 endpoints and query parameters), see the API Reference.
| Method | Path | Description | Kubernetes Probe |
|---|---|---|---|
| GET | /actuator/health |
Aggregated health status with details for all indicators | — |
| GET | /actuator/health/startup |
Checks database connectivity and Cardano node connection | Startup |
| GET | /actuator/health/liveness |
Checks offchain sync status and Cardano node connection | Liveness |
| GET | /actuator/health/readiness |
Checks offchain sync, on-chain sync progress (100%), and database | Readiness |
| GET | /actuator/info |
Application info | — |
| GET | /actuator/prometheus |
Prometheus metrics (Micrometer) | — |
| GET | /actuator/metrics |
Micrometer metrics listing and details | — |
| GET | /health |
Deprecated — legacy sync status endpoint, use /actuator/health/readiness instead |
— |
All settings are controlled via environment variables. See .env (mainnet) and .env.preprod (preprod) for the full list.
| Variable | Description | Default |
|---|---|---|
TOKEN_METADATA_SYNC_JOB |
Enable scheduled GitHub sync | true |
CIP_QUERY_PRIORITY |
CIP priority order for V2 queries | CIP_68,CIP_26 |
STORE_CARDANO_HOST |
Cardano node host for CIP-68 sync | backbone.mainnet.cardanofoundation.org |
STORE_CARDANO_PROTOCOL_MAGIC |
Network protocol magic | 764824073 (mainnet) |
API_DOCKERFILE |
Dockerfile variant for docker compose build |
api/Dockerfile.jvm |
Two Docker image variants are available:
| Variant | Base image | Startup | Memory | Image size | Use case |
|---|---|---|---|---|---|
| JVM | Eclipse Temurin 25 LTS | ~15s | ~2 GB | ~637 MB | Production, development |
| Native | GraalVM 25 LTS (AOT-compiled) | ~3s | ~150 MB | ~200 MB | Experimental |
The default docker compose build builds a JVM image:
docker compose buildOr build it directly:
docker build -t cardanofoundation/cf-token-metadata-registry-api:latest -f api/Dockerfile.jvm .The native image compiles the application ahead-of-time into a standalone binary. No JVM is needed at runtime.
docker build -t cardanofoundation/cf-token-metadata-registry-api:latest -f api/Dockerfile.native .Note
The native image build takes 10-15 minutes and requires 8+ GB of RAM during compilation.
Note
The native image is built with Oracle GraalVM under the GraalVM Free Terms and Conditions (GFTC). Oracle GraalVM is free for development and production use, but redistribution of the GraalVM SDK itself is restricted. This does not affect the final Docker image or binary — the multi-stage build ensures only the compiled native binary (not the GraalVM toolchain) is included in the runtime image. Users who build from source need to accept the GFTC to pull the Oracle GraalVM build image.
By default, docker compose uses the JVM Dockerfile. To use the native image instead, set API_DOCKERFILE:
# Mainnet (JVM, default) — full sync mode
docker compose up -d
# Mainnet (native image)
API_DOCKERFILE=api/Dockerfile.native docker compose up -d --build
# Preprod
docker compose --env-file .env.preprod up -d
# Read-only mode (no sync, no node connection)
COMPOSE_PROFILES=ro docker compose up -dNote
The .env file sets COMPOSE_PROFILES=rw by default, which starts the full read-write API. Two profiles are available:
rw(default) — full API with CIP-26 GitHub sync and CIP-68 on-chain indexingro— read-only API on port8081(configurable viaAPI_RO_LOCAL_BIND_PORT) that serves queries from the existing database without connecting to a Cardano node or syncing metadata
To start fresh (wipe database and resync from scratch):
docker compose down -v
docker compose up -dOnce started, the API syncs both offchain (GitHub) and on-chain (Cardano node) metadata. Check the health endpoints:
# Startup probe — is the app initialized?
curl http://localhost:8080/actuator/health/startup
# Readiness probe — is the app ready to serve traffic?
curl http://localhost:8080/actuator/health/readiness
# Liveness probe — is the app still healthy?
curl http://localhost:8080/actuator/health/liveness
# Prometheus metrics (sync progress, token counts)
curl http://localhost:8080/actuator/prometheus | grep cftr_Key metrics to watch during sync:
cftr_sync_status— offchain sync:0=not started,1=in progress,2=donecftr_tokens_cip26_count— number of CIP-26 tokens loaded from GitHubcftr_tokens_cip68_count— number of CIP-68 tokens indexed from chainyaci_store_current_block— current block being processed
Tip
A full mainnet sync from genesis takes approximately 15 hours. The readiness probe will report OUT_OF_SERVICE until the on-chain sync reaches 98%.
For building from source you need:
- Apache Maven
- Java SDK 25 LTS (e.g. Amazon Corretto or Eclipse Temurin)
- Git
git clone git@github.com:cardano-foundation/cf-token-metadata-registry.git
cd cf-token-metadata-registry
mvn clean package -DskipTestsTo build a native binary without Docker, you need GraalVM 25 LTS:
# Using SDKMAN
sdk install java 25.0.2-graal
sdk use java 25.0.2-graal
# Build the native binary
mvn clean package -pl api,common -am -DskipTests -Pnative
# The binary is at api/target/api- CIP-26 compliant REST API
- CIP-68 fungible token support (V2 API with priority-based querying)
- Prometheus metrics (
/actuator/prometheus) - Kubernetes / Helm deployment support (
deploy/)
Python-based regression tests validate all V1 and V2 business endpoints against database snapshots.
cd tests
python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txt
python end2end/mainnet/fixtures/generate_fixtures.py
cd end2end/mainnet && python -m pytest -vSee tests/README.md for full details on fixture generation, test markers, Allure reports, and configuration options.
File an issue or a PR or reach out directly to us if you want to contribute.
When contributing to this project and interacting with others, please follow our Contributing Guidelines and Code of Conduct.
Thanks for visiting and enjoy ❤️!