Skip to main content
Core API v1 will be retired on July 31, 2026. After that date, encryption_context-based wallet access and recovery_key will no longer be supported, and v1 requests will stop working. Wallets that have not been migrated to v2 by that date will be permanently inaccessible.

What Changed

The key difference between v1 and v2 is how operations are authorized:
v1v2
Wallet creationencryption_context (user secret)auth_jwt (user’s IdP JWT)
Signing / operationsencryption_context + access_keyop_jwt + access_key
Recoveryrecovery_key stored in your DBHandled by your identity provider
Wallet bindingPassphrase-derived secretCryptographic JWT identity binding
In v2, the Nitro Enclave verifies the op_jwt offline against JWKS baked into the enclave image. No long-lived secret is transmitted per request.

Migration Steps

1

Update wallet creation

Replace encryption_context with auth_jwt — the user’s JWT from your identity provider.v1:
cURL
curl -X POST 'https://tee.magiclabs.com/v1/api/wallet' \
  -H 'Content-Type: application/json' \
  -H 'x-magic-secret-key: sk_live_XXXXXXXX' \
  -d '{
    "encryption_context": "hashed_passcode",
    "network": "eth_mainnet",
    "wallet_group_id": "58a08494-3c83-439a-8a07-551f20xxxxxx"
  }'
v2:
cURL
curl -X POST 'https://tee.magiclabs.com/v2/api/wallet' \
  -H 'Content-Type: application/json' \
  -H 'x-magic-secret-key: sk_live_XXXXXXXX' \
  -d '{
    "auth_jwt": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMyIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2F1dGgueW91cmFwcC5jb20iLCJzdWIiOiJ1c2VyXzEyMzQ1NiIsImF1ZCI6Imh0dHBzOi8vdGVlLm1hZ2ljbGFicy5jb20iLCJpYXQiOjE3NTE2NzIwMDAsImV4cCI6MTc1MTY3MjMwMH0.SIGNATURE",
    "network": "eth_mainnet",
    "wallet_group_id": "58a08494-3c83-439a-8a07-551f20xxxxxx"
  }'
v2 wallet creation no longer returns a recovery_key. You only need to store wallet_id and access_key.
2

Update signing operations

Replace encryption_context with op_jwt. The access_key and wallet_id remain the same.v1:
cURL
curl -X POST 'https://tee.magiclabs.com/v1/api/wallet/sign_data' \
  -H 'Content-Type: application/json' \
  -H 'x-magic-secret-key: sk_live_XXXXXXXX' \
  -d '{
    "encryption_context": "hashed_passcode",
    "raw_data_hash": "0xabc...",
    "access_key": "access_key",
    "wallet_id": "e982b4a3-14d3-4d66-a3ac-fadfc3xxxxxx"
  }'
v2:
cURL
curl -X POST 'https://tee.magiclabs.com/v2/api/wallet/sign_data' \
  -H 'Content-Type: application/json' \
  -H 'x-magic-secret-key: sk_live_XXXXXXXX' \
  -d '{
    "op_jwt": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMyIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2F1dGgueW91cmFwcC5jb20iLCJzdWIiOiJ1c2VyXzEyMzQ1NiIsImF1ZCI6Imh0dHBzOi8vdGVlLm1hZ2ljbGFicy5jb20iLCJpYXQiOjE3NTE2NzIwMDAsImV4cCI6MTc1MTY3MjMwMH0.SIGNATURE",
    "raw_data_hash": "0xabc...",
    "access_key": "access_key",
    "wallet_id": "e982b4a3-14d3-4d66-a3ac-fadfc3xxxxxx"
  }'
The same pattern applies to sign_message and sign_transaction — swap encryption_context for op_jwt and update the path from /v1/ to /v2/.
3

Issue op_jwt tokens

Add a mechanism to issue short-lived op_jwt tokens (max 5 minutes) for your users from your identity provider. The JWT must be issued by the same IdP configured for your Magic application.
Generate op_jwt as close to the signing call as possible to minimize its validity window.
4

Update database schema

Stop storing recovery_key for new v2 wallets. You only need wallet_id and access_key.Existing recovery_key values for v1 wallets should be retained until those wallets are migrated (see below).

Migrating Existing v1 Wallets

Existing v1 wallets are migrated to v2 on first use — no bulk migration is needed. On the first v2 signing call for a v1 wallet, include encryption_context alongside op_jwt and access_key:
cURL
curl -X POST 'https://tee.magiclabs.com/v2/api/wallet/sign_data' \
  -H 'Content-Type: application/json' \
  -H 'x-magic-secret-key: sk_live_XXXXXXXX' \
  -d '{
    "op_jwt": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMyIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2F1dGgueW91cmFwcC5jb20iLCJzdWIiOiJ1c2VyXzEyMzQ1NiIsImF1ZCI6Imh0dHBzOi8vdGVlLm1hZ2ljbGFicy5jb20iLCJpYXQiOjE3NTE2NzIwMDAsImV4cCI6MTc1MTY3MjMwMH0.SIGNATURE",
    "raw_data_hash": "0xabc...",
    "access_key": "access_key",
    "wallet_id": "e982b4a3-14d3-4d66-a3ac-fadfc3xxxxxx",
    "encryption_context": "hashed_passcode"
  }'
The enclave will re-key the wallet to v2 JWT binding as a side effect. After the first successful v2 operation, encryption_context is no longer required or accepted for that wallet.
If you call a v2 endpoint on a v1 wallet without encryption_context, the request will fail with MIGRATION_REQUIRED. You must provide it on the first v2 call.
Once all v1 wallets for a user have been migrated, you can stop passing encryption_context and remove recovery_key from your database.