Migration from Wallet API v1
The waltid-wallet-migration tool migrates data from the old waltid-wallet-api (v1) database schema to the new waltid-wallet-api2 schema. This guide covers the migration process, what gets migrated, and how to run it.
Important: Always back up your v1 database before running the migration. The migration tool is designed to be idempotent (running it twice won't duplicate data), but having a backup is essential.
What Gets Migrated
The migration tool transfers the following data from v1 to v2:
| v1 Table | v2 Table(s) | Description |
|---|---|---|
wallets | wallet2_wallets + store registration tables | Wallet records with auto-created stores |
wallet_keys | wallet2_keys | Keys (re-serialized with type inference) |
credentials | wallet2_credentials | Credentials (re-parsed into the v2 credential format) |
wallet_dids | wallet2_dids | DIDs with documents |
account_wallet_mapping | wallet2_account_wallets | Account-to-wallet ownership |
Store Creation
For each migrated wallet, the tool automatically creates:
- One key store:
wallet-{id}-keys - One credential store:
wallet-{id}-creds - One DID store:
wallet-{id}-dids
These deterministic IDs ensure the migration is idempotent.
Prerequisites
- Source database: Your existing v1 wallet database (SQLite or PostgreSQL)
- Target database: A new or empty v2 database (SQLite or PostgreSQL)
- Java 17+: Required to run the migration tool
Running the Migration
Using Gradle
From the waltid-identity repository root:
SQLite to SQLite:
./gradlew :waltid-services:waltid-wallet-migration:run \
--args="--source jdbc:sqlite:/path/to/old/wallet.db --target jdbc:sqlite:/path/to/new/wallet2.db"
PostgreSQL to PostgreSQL:
./gradlew :waltid-services:waltid-wallet-migration:run \
--args="--source 'jdbc:postgresql://localhost:5432/walletv1?user=wallet&password=secret' --target 'jdbc:postgresql://localhost:5432/walletv2?user=wallet&password=secret'"
Cross-database (SQLite to PostgreSQL):
./gradlew :waltid-services:waltid-wallet-migration:run \
--args="--source jdbc:sqlite:/path/to/wallet.db --target 'jdbc:postgresql://localhost:5432/walletv2?user=wallet&password=secret'"
Dry Run Mode
Add --dry-run to preview what would be migrated without writing anything:
./gradlew :waltid-services:waltid-wallet-migration:run \
--args="--source jdbc:sqlite:/path/to/wallet.db --target jdbc:sqlite:/path/to/wallet2.db --dry-run"
Command Line Arguments
| Argument | Required | Description |
|---|---|---|
--source | Yes | JDBC URL for the v1 source database |
--target | Yes | JDBC URL for the v2 target database |
--dry-run | No | Preview migration without writing data |
Migration Output
The migration tool logs progress and provides a summary at the end:
INFO - Source: jdbc:sqlite:/path/to/wallet.db
INFO - Target: jdbc:sqlite:/path/to/wallet2.db
INFO - Found 5 wallets to migrate
INFO -
INFO - ═══════════════════════════════════════════
INFO - Migration complete
INFO - Wallets: 5
INFO - Keys: 12
INFO - Credentials: 28
INFO - DIDs: 5
INFO - Account mappings: 5
INFO - ═══════════════════════════════════════════
If any items fail to migrate, warnings are logged with details:
WARN - Failed to migrate credential abc123 for wallet xyz789: Invalid credential format
Post-Migration Steps
1. Verify the Migration
After migration, verify the data was transferred correctly:
Point wallet2-persistence.conf at the migrated database (e.g. jdbcUrl = "jdbc:sqlite:/data/wallet2.db"), then start wallet-api2 with your config directory and the database mounted:
docker run \
-p 7005:7005 \
-v /path/to/config:/waltid-wallet-api2/config \
-v /path/to/data:/data \
waltid/wallet-api2
# List wallets
curl http://localhost:7005/wallet
2. Update Your Configuration
Update your deployment to use the new wallet-api2 service and database:
wallet2-persistence.conf:
# wallet2-persistence.conf
jdbcUrl = "jdbc:sqlite:/data/wallet2.db"
driverClassName = "org.sqlite.JDBC"
Or for PostgreSQL:
# wallet2-persistence.conf
jdbcUrl = "jdbc:postgresql://localhost:5432/walletv2"
driverClassName = "org.postgresql.Driver"
username = "wallet"
password = "secret"
maximumPoolSize = 10
See the Persistence configuration reference for all options.
3. Update API Calls
The v2 API has some differences from v1. Key changes:
| v1 Endpoint | v2 Endpoint | Notes |
|---|---|---|
/api/wallet/{walletId}/... | /wallet/{walletId}/... | Simplified path |
| Presentation Exchange | DCQL | Different query format for OID4VP |
/api/wallet/{walletId}/credentials/usePresentationRequest | /wallet/{walletId}/credentials/present | New presentation endpoint |
Troubleshooting
"Key store not found" errors
The migration creates stores with deterministic IDs. If you see this error, ensure the target database is empty or the migration completed successfully.
Credential parsing failures
Some v1 credentials may use formats not fully supported in v2. Check the warning logs for specific credential IDs and manually verify/re-import if needed.
Database connection issues
Ensure the JDBC URLs are correct and the databases are accessible:
- SQLite: File path must exist and be writable
- PostgreSQL: User must have CREATE TABLE permissions
Rollback
If you need to rollback:
- Stop the wallet-api2 service
- Restore your v1 database from backup
- Start the wallet-api (v1) service pointing to the restored database
The migration does not modify the source database, so your v1 data remains intact.
