Overview
The Turnkey Swift SDK provides a straightforward way to create and manage wallets in your Swift application. You can create wallets, derive accounts, import/export, and refresh wallet state from TurnkeyContext.
Before you start, make sure you’re familiar with Wallets and Wallet Accounts.
Creation
There are two ways to create wallets and accounts:
- During signup (sub-organization creation): Configure default wallet/accounts in your signup parameters so users get a wallet at account creation time. See Sub-organization customization for how to set
CreateSubOrgParams globally or per auth method.
- After authentication (active session): Create wallets programmatically using the
TurnkeyContext once the user is authenticated.
Wallet
Create a wallet with one Ethereum account using an active session:
import SwiftUI
import TurnkeySwift
struct CreateWalletButton: View {
@EnvironmentObject private var turnkey: TurnkeyContext
var body: some View {
Button("Create Wallet") {
Task {
do {
let accounts: [WalletAccountParams] = [
WalletAccountParams(
addressFormat: .address_format_ethereum,
curve: .curve_secp256k1,
path: "m/44'/60'/0'/0/0",
pathFormat: .path_format_bip32
)
]
try await turnkey.createWallet(
walletName: "My New Wallet",
accounts: accounts
)
} catch {
print("Error creating wallet:", error)
}
}
}
}
}
Wallet accounts
You can derive additional addresses for an existing wallet using the HTTP client:
import TurnkeyHttp
import TurnkeyTypes
import TurnkeySwift
guard
let client = TurnkeyContext.shared.client,
let orgId = TurnkeyContext.shared.session?.organizationId
else { return }
let newAccounts: [WalletAccountParams] = [
WalletAccountParams(
addressFormat: .address_format_ethereum,
curve: .curve_secp256k1,
path: "m/44'/60'/0'/0/1",
pathFormat: .path_format_bip32
)
]
_ = try await client.createWalletAccounts(TCreateWalletAccountsBody(
organizationId: orgId,
accounts: newAccounts,
walletId: "<wallet_id_here>"
))
Private keys
Private keys are typically created when creating wallet accounts or by importing existing key material. See Importing → Private key.
Listing wallets in the UI
The TurnkeyContext maintains wallets for the active session. You can render them in your views:
import SwiftUI
import TurnkeySwift
struct WalletList: View {
@EnvironmentObject private var turnkey: TurnkeyContext
var body: some View {
List(turnkey.wallets, id: \.walletId) { wallet in
VStack(alignment: .leading) {
Text(wallet.walletName)
Text(wallet.walletId).font(.caption).foregroundColor(.gray)
}
}
}
}
Refreshing wallets
Call refreshWallets() to re-fetch wallets and accounts for the current session:
Task {
try? await turnkey.refreshWallets()
}
Exporting
The Swift SDK lets you securely import/export wallets, accounts, and private keys. You can return decrypted values for developer workflows or handle encrypted bundles explicitly.
Wallet
Default: decrypt locally and return the mnemonic (developer-friendly).
import TurnkeySwift
let mnemonic = try await turnkey.exportWallet(walletId: "<wallet_id>")
// Do not display secrets in production UIs
Wallet account
import TurnkeyHttp
import TurnkeyCrypto
import TurnkeySwift
let (targetPublicKey, _, _) = TurnkeyCrypto.generateP256KeyPair()
guard
let client = TurnkeyContext.shared.client,
let orgId = TurnkeyContext.shared.session?.organizationId
else { return }
let resp = try await client.exportWalletAccount(TExportWalletAccountBody(
organizationId: orgId,
address: "<wallet_account_address>",
targetPublicKey: targetPublicKey
))
let exportBundle = resp.exportBundle
Private key
import TurnkeyHttp
import TurnkeyCrypto
import TurnkeySwift
let (targetPublicKey, _, _) = TurnkeyCrypto.generateP256KeyPair()
guard
let client = TurnkeyContext.shared.client,
let orgId = TurnkeyContext.shared.session?.organizationId
else { return }
let resp = try await client.exportPrivateKey(TExportPrivateKeyBody(
organizationId: orgId,
privateKeyId: "<private_key_id>",
targetPublicKey: targetPublicKey
))
let exportBundle = resp.exportBundle
Importing
Wallet
Imports a wallet from a mnemonic and automatically refreshes local state.
import TurnkeySwift
let accounts: [WalletAccountParams] = [
WalletAccountParams(
addressFormat: .address_format_ethereum,
curve: .curve_secp256k1,
path: "m/44'/60'/0'/0/0",
pathFormat: .path_format_bip32
)
]
let walletId = try await turnkey.importWallet(
walletName: "Imported Wallet",
mnemonic: "<mnemonic>",
accounts: accounts
)
Private key
Imports a private key from plaintext key material and automatically refreshes local state.
import TurnkeyHttp
import TurnkeySwift
guard
let client = TurnkeyContext.shared.client,
let orgId = TurnkeyContext.shared.session?.organizationId
else { return }
let resp = try await client.importPrivateKey(TImportPrivateKeyBody(
organizationId: orgId,
privateKey: "<hex-or-base58-key>",
privateKeyName: "My Key",
addressFormats: [.address_format_ethereum]
))
let privateKeyId = resp.privateKeyId
Deleting
If a wallet, wallet account, or private key has not been exported, you must
either export it first or pass the deleteWithoutExport: true flag in the
delete request.
Wallet
import TurnkeyHttp
import TurnkeyTypes
import TurnkeySwift
guard
let client = TurnkeyContext.shared.client,
let orgId = TurnkeyContext.shared.session?.organizationId
else { return }
let deleteResp = try await client.deleteWallets(TDeleteWalletsBody(
organizationId: orgId,
deleteWithoutExport: true, // set to true if the wallet hasn't been exported
walletIds: ["<wallet_id_1>", "<wallet_id_2>"]
))
let removedWalletIds = deleteResp.walletIds
Wallet accounts
import TurnkeyHttp
import TurnkeyTypes
import TurnkeySwift
guard
let client = TurnkeyContext.shared.client,
let orgId = TurnkeyContext.shared.session?.organizationId
else { return }
let deleteResp = try await client.deleteWalletAccounts(TDeleteWalletAccountsBody(
organizationId: orgId,
deleteWithoutExport: true, // set to true if the accounts haven't been exported
walletAccountIds: ["<wallet_account_id_1>", "<wallet_account_id_2>"]
))
let removedAccountIds = deleteResp.walletAccountIds
Private keys
import TurnkeyHttp
import TurnkeyTypes
import TurnkeySwift
guard
let client = TurnkeyContext.shared.client,
let orgId = TurnkeyContext.shared.session?.organizationId
else { return }
let deleteResp = try await client.deletePrivateKeys(TDeletePrivateKeysBody(
organizationId: orgId,
deleteWithoutExport: true, // set to true if the keys haven't been exported
privateKeyIds: ["<private_key_id_1>", "<private_key_id_2>"]
))
let removedKeyIds = deleteResp.privateKeyIds