# Create API Keys Source: https://docs.turnkey.com/api-reference/activities/create-api-keys Add api keys to an existing User export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_API_KEYS_V2` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

A list of API Keys.

Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last.
Unique identifier for a given User.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createApiKeysIntent object A list of API Keys. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. Unique identifier for a given User. The result of the activity The createApiKeysResult object A list of API Key IDs. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_api_keys \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_API_KEYS_V2", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "userId": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_API_KEYS_V2", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createApiKeysIntent": { "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "userId": "" } }, "result": { "createApiKeysResult": { "apiKeyIds": [ "" ] } } } } } } ``` # Create Authenticators Source: https://docs.turnkey.com/api-reference/activities/create-authenticators Create Authenticators to authenticate requests to Turnkey export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_AUTHENTICATORS_V2` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

A list of Authenticators.

Human-readable name for an Authenticator. Challenge presented for authentication purposes.

attestation field

The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID`
Unique identifier for a given User.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createAuthenticatorsIntent object A list of Authenticators. Human-readable name for an Authenticator. Unique identifier for a given User. attestation field id field type field Enum options: `public-key` rawId field authenticatorAttachment field Enum options: `cross-platform`, `platform` response field clientDataJson field attestationObject field transports field item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` authenticatorAttachment field Enum options: `cross-platform`, `platform` clientExtensionResults field appid field appidExclude field credProps field rk field Challenge presented for authentication purposes. Unique identifier for a given User. The result of the activity The createAuthenticatorsResult object A list of Authenticator IDs. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_authenticators \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_AUTHENTICATORS_V2", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "userId": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_AUTHENTICATORS_V2", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createAuthenticatorsIntent": { "authenticators": [ { "authenticatorName": "", "userId": "", "attestation": { "id": "", "type": "", "rawId": "", "authenticatorAttachment": "", "response": { "clientDataJson": "", "attestationObject": "", "transports": [ "" ], "authenticatorAttachment": "" }, "clientExtensionResults": { "appid": true, "appidExclude": true, "credProps": { "rk": true } } }, "challenge": "" } ], "userId": "" } }, "result": { "createAuthenticatorsResult": { "authenticatorIds": [ "" ] } } } } } } ``` # Create Invitations Source: https://docs.turnkey.com/api-reference/activities/create-invitations Create Invitations to join an existing Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_INVITATIONS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

A list of Invitations.

The name of the intended Invitation recipient. The email address of the intended Invitation recipient.

A list of tags assigned to the Invitation recipient. This field, if not needed, should be an empty array in your request body.

Array item type: string

item field

Enum options: `ACCESS_TYPE_WEB`, `ACCESS_TYPE_API`, `ACCESS_TYPE_ALL` Unique identifier for the Sender of an Invitation.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createInvitationsIntent object A list of Invitations. The name of the intended Invitation recipient. The email address of the intended Invitation recipient. A list of tags assigned to the Invitation recipient. This field, if not needed, should be an empty array in your request body. item field accessType field Enum options: `ACCESS_TYPE_WEB`, `ACCESS_TYPE_API`, `ACCESS_TYPE_ALL` Unique identifier for the Sender of an Invitation. The result of the activity The createInvitationsResult object A list of Invitation IDs item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_invitations \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_INVITATIONS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "invitations": [ { "receiverUserName": "", "receiverUserEmail": "", "receiverUserTags": [ "" ], "accessType": "", "senderUserId": "" } ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_INVITATIONS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createInvitationsIntent": { "invitations": [ { "receiverUserName": "", "receiverUserEmail": "", "receiverUserTags": [ "" ], "accessType": "", "senderUserId": "" } ] } }, "result": { "createInvitationsResult": { "invitationIds": [ "" ] } } } } } } ``` # Create Oauth Providers Source: https://docs.turnkey.com/api-reference/activities/create-oauth-providers Creates Oauth providers for a specified user - BETA export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_OAUTH_PROVIDERS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

The ID of the User to add an Oauth provider to

A list of Oauth providers.

Human-readable name to identify a Provider. Base64 encoded OIDC token
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createOauthProvidersIntent object The ID of the User to add an Oauth provider to A list of Oauth providers. Human-readable name to identify a Provider. Base64 encoded OIDC token The result of the activity The createOauthProvidersResult object A list of unique identifiers for Oauth Providers item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_oauth_providers \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_OAUTH_PROVIDERS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userId": "", "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_OAUTH_PROVIDERS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createOauthProvidersIntent": { "userId": "", "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] } }, "result": { "createOauthProvidersResult": { "providerIds": [ "" ] } } } } } } ``` # Create Policies Source: https://docs.turnkey.com/api-reference/activities/create-policies Create new Policies export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_POLICIES` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

An array of policy intents to be created.

Human-readable name for a Policy. Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect The consensus expression that triggers the Effect notes field
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createPoliciesIntent object An array of policy intents to be created. Human-readable name for a Policy. effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect The consensus expression that triggers the Effect notes field The result of the activity The createPoliciesResult object A list of unique identifiers for the created policies. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_policies \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_POLICIES", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "policies": [ { "policyName": "", "effect": "", "condition": "", "consensus": "", "notes": "" } ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_POLICIES", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createPoliciesIntent": { "policies": [ { "policyName": "", "effect": "", "condition": "", "consensus": "", "notes": "" } ] } }, "result": { "createPoliciesResult": { "policyIds": [ "" ] } } } } } } ``` # Create Policy Source: https://docs.turnkey.com/api-reference/activities/create-policy Create a new Policy export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_POLICY_V3` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Human-readable name for a Policy. Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect The consensus expression that triggers the Effect notes field
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createPolicyIntent object Human-readable name for a Policy. A list of simple functions each including a subject, target and boolean. See Policy Engine Language section for additional details. subject field operator field Enum options: `OPERATOR_EQUAL`, `OPERATOR_MORE_THAN`, `OPERATOR_MORE_THAN_OR_EQUAL`, `OPERATOR_LESS_THAN`, `OPERATOR_LESS_THAN_OR_EQUAL`, `OPERATOR_CONTAINS`, `OPERATOR_NOT_EQUAL`, `OPERATOR_IN`, `OPERATOR_NOT_IN`, `OPERATOR_CONTAINS_ONE`, `OPERATOR_CONTAINS_ALL` target field effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` notes field The result of the activity The createPolicyResult object Unique identifier for a given Policy. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_policy \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_POLICY_V3", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "policyName": "", "effect": "", "condition": "", "consensus": "", "notes": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_POLICY_V3", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createPolicyIntent": { "policyName": "", "selectors": [ { "subject": "", "operator": "", "target": "" } ], "effect": "", "notes": "" } }, "result": { "createPolicyResult": { "policyId": "" } } } } } } ``` # Create Private Key Tag Source: https://docs.turnkey.com/api-reference/activities/create-private-key-tag Create a private key tag and add it to private keys. export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_PRIVATE_KEY_TAG` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Human-readable name for a Private Key Tag.

A list of Private Key IDs.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createPrivateKeyTagIntent object Human-readable name for a Private Key Tag. A list of Private Key IDs. item field The result of the activity The createPrivateKeyTagResult object Unique identifier for a given Private Key Tag. A list of Private Key IDs. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_private_key_tag \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_PRIVATE_KEY_TAG", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "privateKeyTagName": "", "privateKeyIds": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_PRIVATE_KEY_TAG", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createPrivateKeyTagIntent": { "privateKeyTagName": "", "privateKeyIds": [ "" ] } }, "result": { "createPrivateKeyTagResult": { "privateKeyTagId": "", "privateKeyIds": [ "" ] } } } } } } ``` # Create Private Keys Source: https://docs.turnkey.com/api-reference/activities/create-private-keys Create new Private Keys export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

A list of Private Keys.

Human-readable name for a Private Key. Enum options: `CURVE_SECP256K1`, `CURVE_ED25519`

A list of Private Key Tag IDs. This field, if not needed, should be an empty array in your request body.

Array item type: string

item field

Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP`
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createPrivateKeysIntentV2 object A list of Private Keys. Human-readable name for a Private Key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` A list of Private Key Tag IDs. This field, if not needed, should be an empty array in your request body. item field Cryptocurrency-specific formats for a derived address (e.g., Ethereum). item field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` The result of the activity The createPrivateKeysResultV2 object A list of Private Key IDs and addresses. privateKeyId field addresses field format field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` address field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_private_keys \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "privateKeys": [ { "privateKeyName": "", "curve": "", "privateKeyTags": [ "" ], "addressFormats": [ "" ] } ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createPrivateKeysIntentV2": { "privateKeys": [ { "privateKeyName": "", "curve": "", "privateKeyTags": [ "" ], "addressFormats": [ "" ] } ] } }, "result": { "createPrivateKeysResultV2": { "privateKeys": [ { "privateKeyId": "", "addresses": [ { "format": "", "address": "" } ] } ] } } } } } } ``` # Create Read Only Session Source: https://docs.turnkey.com/api-reference/activities/create-read-only-session Create a read only session for a user (valid for 1 hour) export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_READ_ONLY_SESSION` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization. parameters field A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createReadOnlySessionIntent object The result of the activity The createReadOnlySessionResult object Unique identifier for a given Organization. If the request is being made by a user and their Sub-Organization ID is unknown, this can be the Parent Organization ID. However, using the Sub-Organization ID is preferred due to performance reasons. Human-readable name for an Organization. Unique identifier for a given User. Human-readable name for a User. String representing a read only session UTC timestamp in seconds representing the expiry time for the read only session. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_read_only_session \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_READ_ONLY_SESSION", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": {} }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_READ_ONLY_SESSION", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createReadOnlySessionIntent": {} }, "result": { "createReadOnlySessionResult": { "organizationId": "", "organizationName": "", "userId": "", "username": "", "session": "", "sessionExpiry": "" } } } } } } ``` # Create Read Write Session Source: https://docs.turnkey.com/api-reference/activities/create-read-write-session Create a read write session for a user export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Client-side public key generated by the user, to which the read write session bundle (credentials) will be encrypted. Unique identifier for a given User. Optional human-readable name for an API Key. If none provided, default to Read Write Session - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated ReadWriteSession API keys
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createReadWriteSessionIntentV2 object Client-side public key generated by the user, to which the read write session bundle (credentials) will be encrypted. Unique identifier for a given User. Optional human-readable name for an API Key. If none provided, default to Read Write Session - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated ReadWriteSession API keys The result of the activity The createReadWriteSessionResultV2 object Unique identifier for a given Organization. If the request is being made by a user and their Sub-Organization ID is unknown, this can be the Parent Organization ID. However, using the Sub-Organization ID is preferred due to performance reasons. Human-readable name for an Organization. Unique identifier for a given User. Human-readable name for a User. Unique identifier for the created API key. HPKE encrypted credential bundle ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_read_write_session \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "targetPublicKey": "", "userId": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createReadWriteSessionIntentV2": { "targetPublicKey": "", "userId": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true } }, "result": { "createReadWriteSessionResultV2": { "organizationId": "", "organizationName": "", "userId": "", "username": "", "apiKeyId": "", "credentialBundle": "" } } } } } } ``` # Create Sub-Organization Source: https://docs.turnkey.com/api-reference/activities/create-sub-organization Create a new Sub-Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V7` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Name for this sub-organization

Root users to create within this sub-organization

Human-readable name for a User. The user's email address. The user's phone number in E.164 format e.g. +13214567890

A list of API Key parameters. This field, if not needed, should be an empty array in your request body.

Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last.

A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body.

Human-readable name for an Authenticator. Challenge presented for authentication purposes.

attestation field

The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID`

A list of Oauth providers. This field, if not needed, should be an empty array in your request body.

Human-readable name to identify a Provider. Base64 encoded OIDC token
The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users

wallet field

Human-readable name for a Wallet. Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24.
Disable email recovery for the sub-organization Disable email auth for the sub-organization Disable OTP SMS auth for the sub-organization Disable OTP email auth for the sub-organization
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createSubOrganizationIntentV7 object Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. The user's phone number in E.164 format e.g. +13214567890 A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. curveType field Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` A list of Oauth providers. This field, if not needed, should be an empty array in your request body. Human-readable name to identify a Provider. Base64 encoded OIDC token The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users wallet field Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. Disable email recovery for the sub-organization Disable email auth for the sub-organization Disable OTP SMS auth for the sub-organization Disable OTP email auth for the sub-organization The result of the activity The createSubOrganizationResultV7 object subOrganizationId field wallet field walletId field A list of account addresses. item field rootUserIds field item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_sub_organization \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V7", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "userPhoneNumber": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] } ], "rootQuorumThreshold": 123, "wallet": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "disableEmailRecovery": true, "disableEmailAuth": true, "disableSmsAuth": true, "disableOtpEmailAuth": true } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V7", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createSubOrganizationIntentV7": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "userPhoneNumber": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] } ], "rootQuorumThreshold": 123, "wallet": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "disableEmailRecovery": true, "disableEmailAuth": true, "disableSmsAuth": true, "disableOtpEmailAuth": true } }, "result": { "createSubOrganizationResultV7": { "subOrganizationId": "", "wallet": { "walletId": "", "addresses": [ "" ] }, "rootUserIds": [ "" ] } } } } } } ``` # Create User Tag Source: https://docs.turnkey.com/api-reference/activities/create-user-tag Create a user tag and add it to users. export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_USER_TAG` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Human-readable name for a User Tag.

A list of User IDs.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createUserTagIntent object Human-readable name for a User Tag. A list of User IDs. item field The result of the activity The createUserTagResult object Unique identifier for a given User Tag. A list of User IDs. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_user_tag \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_USER_TAG", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userTagName": "", "userIds": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_USER_TAG", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createUserTagIntent": { "userTagName": "", "userIds": [ "" ] } }, "result": { "createUserTagResult": { "userTagId": "", "userIds": [ "" ] } } } } } } ``` # Create Users Source: https://docs.turnkey.com/api-reference/activities/create-users Create Users in an existing Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_USERS_V3` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

A list of Users.

Human-readable name for a User. The user's email address. The user's phone number in E.164 format e.g. +13214567890

A list of API Key parameters. This field, if not needed, should be an empty array in your request body.

Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last.

A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body.

Human-readable name for an Authenticator. Challenge presented for authentication purposes.

attestation field

The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID`

A list of Oauth providers. This field, if not needed, should be an empty array in your request body.

Human-readable name to identify a Provider. Base64 encoded OIDC token

A list of User Tag IDs. This field, if not needed, should be an empty array in your request body.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createUsersIntent object A list of Users. Human-readable name for a User. The user's email address. accessType field Enum options: `ACCESS_TYPE_WEB`, `ACCESS_TYPE_API`, `ACCESS_TYPE_ALL` A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Unique identifier for a given User. attestation field id field type field Enum options: `public-key` rawId field authenticatorAttachment field Enum options: `cross-platform`, `platform` response field clientDataJson field attestationObject field transports field item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` authenticatorAttachment field Enum options: `cross-platform`, `platform` clientExtensionResults field appid field appidExclude field credProps field rk field Challenge presented for authentication purposes. A list of User Tag IDs. This field, if not needed, should be an empty array in your request body. item field The result of the activity The createUsersResult object A list of User IDs. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_users \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_USERS_V3", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "users": [ { "userName": "", "userEmail": "", "userPhoneNumber": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "oauthProviders": [ { "providerName": "", "oidcToken": "" } ], "userTags": [ "" ] } ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_USERS_V3", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createUsersIntent": { "users": [ { "userName": "", "userEmail": "", "accessType": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "userId": "", "attestation": { "id": "", "type": "", "rawId": "", "authenticatorAttachment": "", "response": { "clientDataJson": "", "attestationObject": "", "transports": [ "" ], "authenticatorAttachment": "" }, "clientExtensionResults": { "appid": true, "appidExclude": true, "credProps": { "rk": true } } }, "challenge": "" } ], "userTags": [ "" ] } ] } }, "result": { "createUsersResult": { "userIds": [ "" ] } } } } } } ``` # Create Wallet Source: https://docs.turnkey.com/api-reference/activities/create-wallet Create a Wallet and derive addresses export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_WALLET` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Human-readable name for a Wallet. Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createWalletIntent object Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. The result of the activity The createWalletResult object Unique identifier for a Wallet. A list of account addresses. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_wallet \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_WALLET", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_WALLET", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createWalletIntent": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 } }, "result": { "createWalletResult": { "walletId": "", "addresses": [ "" ] } } } } } } ``` # Create Wallet Accounts Source: https://docs.turnkey.com/api-reference/activities/create-wallet-accounts Derive additional addresses using an existing wallet export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_CREATE_WALLET_ACCOUNTS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given Wallet. Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP`
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The createWalletAccountsIntent object Unique identifier for a given Wallet. A list of wallet Accounts. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` The result of the activity The createWalletAccountsResult object A list of derived addresses. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/create_wallet_accounts \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_CREATE_WALLET_ACCOUNTS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "walletId": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_CREATE_WALLET_ACCOUNTS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "createWalletAccountsIntent": { "walletId": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ] } }, "result": { "createWalletAccountsResult": { "addresses": [ "" ] } } } } } } ``` # Delete API Keys Source: https://docs.turnkey.com/api-reference/activities/delete-api-keys Remove api keys from a User export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_DELETE_API_KEYS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given User.

A list of API Key IDs.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The deleteApiKeysIntent object Unique identifier for a given User. A list of API Key IDs. item field The result of the activity The deleteApiKeysResult object A list of API Key IDs. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/delete_api_keys \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_DELETE_API_KEYS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userId": "", "apiKeyIds": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_DELETE_API_KEYS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "deleteApiKeysIntent": { "userId": "", "apiKeyIds": [ "" ] } }, "result": { "deleteApiKeysResult": { "apiKeyIds": [ "" ] } } } } } } ``` # Delete Authenticators Source: https://docs.turnkey.com/api-reference/activities/delete-authenticators Remove authenticators from a User export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_DELETE_AUTHENTICATORS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given User.

A list of Authenticator IDs.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The deleteAuthenticatorsIntent object Unique identifier for a given User. A list of Authenticator IDs. item field The result of the activity The deleteAuthenticatorsResult object Unique identifier for a given Authenticator. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/delete_authenticators \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_DELETE_AUTHENTICATORS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userId": "", "authenticatorIds": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_DELETE_AUTHENTICATORS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "deleteAuthenticatorsIntent": { "userId": "", "authenticatorIds": [ "" ] } }, "result": { "deleteAuthenticatorsResult": { "authenticatorIds": [ "" ] } } } } } } ``` # Delete Invitation Source: https://docs.turnkey.com/api-reference/activities/delete-invitation Delete an existing Invitation export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_DELETE_INVITATION` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given Invitation object.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The deleteInvitationIntent object Unique identifier for a given Invitation object. The result of the activity The deleteInvitationResult object Unique identifier for a given Invitation. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/delete_invitation \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_DELETE_INVITATION", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "invitationId": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_DELETE_INVITATION", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "deleteInvitationIntent": { "invitationId": "" } }, "result": { "deleteInvitationResult": { "invitationId": "" } } } } } } ``` # Delete Oauth Providers Source: https://docs.turnkey.com/api-reference/activities/delete-oauth-providers Removes Oauth providers for a specified user - BETA export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_DELETE_OAUTH_PROVIDERS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

The ID of the User to remove an Oauth provider from

Unique identifier for a given Provider.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The deleteOauthProvidersIntent object The ID of the User to remove an Oauth provider from Unique identifier for a given Provider. item field The result of the activity The deleteOauthProvidersResult object A list of unique identifiers for Oauth Providers item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/delete_oauth_providers \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_DELETE_OAUTH_PROVIDERS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userId": "", "providerIds": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_DELETE_OAUTH_PROVIDERS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "deleteOauthProvidersIntent": { "userId": "", "providerIds": [ "" ] } }, "result": { "deleteOauthProvidersResult": { "providerIds": [ "" ] } } } } } } ``` # Delete Policy Source: https://docs.turnkey.com/api-reference/activities/delete-policy Delete an existing Policy export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_DELETE_POLICY` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given Policy.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The deletePolicyIntent object Unique identifier for a given Policy. The result of the activity The deletePolicyResult object Unique identifier for a given Policy. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/delete_policy \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_DELETE_POLICY", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "policyId": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_DELETE_POLICY", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "deletePolicyIntent": { "policyId": "" } }, "result": { "deletePolicyResult": { "policyId": "" } } } } } } ``` # Delete Private Key Tags Source: https://docs.turnkey.com/api-reference/activities/delete-private-key-tags Delete Private Key Tags within an Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_DELETE_PRIVATE_KEY_TAGS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

A list of Private Key Tag IDs.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The deletePrivateKeyTagsIntent object A list of Private Key Tag IDs. item field The result of the activity The deletePrivateKeyTagsResult object A list of Private Key Tag IDs. item field A list of Private Key IDs. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/delete_private_key_tags \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_DELETE_PRIVATE_KEY_TAGS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "privateKeyTagIds": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_DELETE_PRIVATE_KEY_TAGS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "deletePrivateKeyTagsIntent": { "privateKeyTagIds": [ "" ] } }, "result": { "deletePrivateKeyTagsResult": { "privateKeyTagIds": [ "" ], "privateKeyIds": [ "" ] } } } } } } ``` # Delete Private Keys Source: https://docs.turnkey.com/api-reference/activities/delete-private-keys Deletes private keys for an organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_DELETE_PRIVATE_KEYS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

List of unique identifiers for private keys within an organization

Array item type: string

item field

Optional parameter for deleting the private keys, even if any have not been previously exported. If they have been exported, this field is ignored.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The deletePrivateKeysIntent object List of unique identifiers for private keys within an organization item field Optional parameter for deleting the private keys, even if any have not been previously exported. If they have been exported, this field is ignored. The result of the activity The deletePrivateKeysResult object A list of private key unique identifiers that were removed item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/delete_private_keys \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_DELETE_PRIVATE_KEYS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "privateKeyIds": [ "" ], "deleteWithoutExport": true } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_DELETE_PRIVATE_KEYS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "deletePrivateKeysIntent": { "privateKeyIds": [ "" ], "deleteWithoutExport": true } }, "result": { "deletePrivateKeysResult": { "privateKeyIds": [ "" ] } } } } } } ``` # Delete Sub Organization Source: https://docs.turnkey.com/api-reference/activities/delete-sub-organization Deletes a sub organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_DELETE_SUB_ORGANIZATION` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Sub-organization deletion, by default, requires associated wallets and private keys to be exported for security reasons. Set this boolean to true to force sub-organization deletion even if some wallets or private keys within it have not been exported yet. Default: false.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The deleteSubOrganizationIntent object Sub-organization deletion, by default, requires associated wallets and private keys to be exported for security reasons. Set this boolean to true to force sub-organization deletion even if some wallets or private keys within it have not been exported yet. Default: false. The result of the activity The deleteSubOrganizationResult object Unique identifier of the sub organization that was removed ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/delete_sub_organization \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_DELETE_SUB_ORGANIZATION", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "deleteWithoutExport": true } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_DELETE_SUB_ORGANIZATION", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "deleteSubOrganizationIntent": { "deleteWithoutExport": true } }, "result": { "deleteSubOrganizationResult": { "subOrganizationUuid": "" } } } } } } ``` # Delete User Tags Source: https://docs.turnkey.com/api-reference/activities/delete-user-tags Delete User Tags within an Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_DELETE_USER_TAGS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

A list of User Tag IDs.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The deleteUserTagsIntent object A list of User Tag IDs. item field The result of the activity The deleteUserTagsResult object A list of User Tag IDs. item field A list of User IDs. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/delete_user_tags \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_DELETE_USER_TAGS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userTagIds": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_DELETE_USER_TAGS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "deleteUserTagsIntent": { "userTagIds": [ "" ] } }, "result": { "deleteUserTagsResult": { "userTagIds": [ "" ], "userIds": [ "" ] } } } } } } ``` # Delete Users Source: https://docs.turnkey.com/api-reference/activities/delete-users Delete Users within an Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_DELETE_USERS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

A list of User IDs.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The deleteUsersIntent object A list of User IDs. item field The result of the activity The deleteUsersResult object A list of User IDs. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/delete_users \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_DELETE_USERS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userIds": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_DELETE_USERS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "deleteUsersIntent": { "userIds": [ "" ] } }, "result": { "deleteUsersResult": { "userIds": [ "" ] } } } } } } ``` # Delete Wallets Source: https://docs.turnkey.com/api-reference/activities/delete-wallets Deletes wallets for an organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_DELETE_WALLETS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

List of unique identifiers for wallets within an organization

Array item type: string

item field

Optional parameter for deleting the wallets, even if any have not been previously exported. If they have been exported, this field is ignored.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The deleteWalletsIntent object List of unique identifiers for wallets within an organization item field Optional parameter for deleting the wallets, even if any have not been previously exported. If they have been exported, this field is ignored. The result of the activity The deleteWalletsResult object A list of wallet unique identifiers that were removed item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/delete_wallets \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_DELETE_WALLETS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "walletIds": [ "" ], "deleteWithoutExport": true } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_DELETE_WALLETS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "deleteWalletsIntent": { "walletIds": [ "" ], "deleteWithoutExport": true } }, "result": { "deleteWalletsResult": { "walletIds": [ "" ] } } } } } } ``` # Export Private Key Source: https://docs.turnkey.com/api-reference/activities/export-private-key Exports a Private Key export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_EXPORT_PRIVATE_KEY` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given Private Key. Client-side public key generated by the user, to which the export bundle will be encrypted.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The exportPrivateKeyIntent object Unique identifier for a given Private Key. Client-side public key generated by the user, to which the export bundle will be encrypted. The result of the activity The exportPrivateKeyResult object Unique identifier for a given Private Key. Export bundle containing a private key encrypted to the client's target public key. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/export_private_key \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_EXPORT_PRIVATE_KEY", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "privateKeyId": "", "targetPublicKey": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_EXPORT_PRIVATE_KEY", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "exportPrivateKeyIntent": { "privateKeyId": "", "targetPublicKey": "" } }, "result": { "exportPrivateKeyResult": { "privateKeyId": "", "exportBundle": "" } } } } } } ``` # Export Wallet Source: https://docs.turnkey.com/api-reference/activities/export-wallet Exports a Wallet export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_EXPORT_WALLET` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given Wallet. Client-side public key generated by the user, to which the export bundle will be encrypted. Enum options: `MNEMONIC_LANGUAGE_ENGLISH`, `MNEMONIC_LANGUAGE_SIMPLIFIED_CHINESE`, `MNEMONIC_LANGUAGE_TRADITIONAL_CHINESE`, `MNEMONIC_LANGUAGE_CZECH`, `MNEMONIC_LANGUAGE_FRENCH`, `MNEMONIC_LANGUAGE_ITALIAN`, `MNEMONIC_LANGUAGE_JAPANESE`, `MNEMONIC_LANGUAGE_KOREAN`, `MNEMONIC_LANGUAGE_SPANISH`
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The exportWalletIntent object Unique identifier for a given Wallet. Client-side public key generated by the user, to which the export bundle will be encrypted. language field Enum options: `MNEMONIC_LANGUAGE_ENGLISH`, `MNEMONIC_LANGUAGE_SIMPLIFIED_CHINESE`, `MNEMONIC_LANGUAGE_TRADITIONAL_CHINESE`, `MNEMONIC_LANGUAGE_CZECH`, `MNEMONIC_LANGUAGE_FRENCH`, `MNEMONIC_LANGUAGE_ITALIAN`, `MNEMONIC_LANGUAGE_JAPANESE`, `MNEMONIC_LANGUAGE_KOREAN`, `MNEMONIC_LANGUAGE_SPANISH` The result of the activity The exportWalletResult object Unique identifier for a given Wallet. Export bundle containing a wallet mnemonic + optional newline passphrase encrypted by the client's target public key. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/export_wallet \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_EXPORT_WALLET", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "walletId": "", "targetPublicKey": "", "language": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_EXPORT_WALLET", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "exportWalletIntent": { "walletId": "", "targetPublicKey": "", "language": "" } }, "result": { "exportWalletResult": { "walletId": "", "exportBundle": "" } } } } } } ``` # Export Wallet Account Source: https://docs.turnkey.com/api-reference/activities/export-wallet-account Exports a Wallet Account export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_EXPORT_WALLET_ACCOUNT` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Address to identify Wallet Account. Client-side public key generated by the user, to which the export bundle will be encrypted.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The exportWalletAccountIntent object Address to identify Wallet Account. Client-side public key generated by the user, to which the export bundle will be encrypted. The result of the activity The exportWalletAccountResult object Address to identify Wallet Account. Export bundle containing a private key encrypted by the client's target public key. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/export_wallet_account \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_EXPORT_WALLET_ACCOUNT", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "address": "", "targetPublicKey": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_EXPORT_WALLET_ACCOUNT", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "exportWalletAccountIntent": { "address": "", "targetPublicKey": "" } }, "result": { "exportWalletAccountResult": { "address": "", "exportBundle": "" } } } } } } ``` # Import Private Key Source: https://docs.turnkey.com/api-reference/activities/import-private-key Imports a private key export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_IMPORT_PRIVATE_KEY` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

The ID of the User importing a Private Key. Human-readable name for a Private Key. Bundle containing a raw private key encrypted to the enclave's target public key. Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP`
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The importPrivateKeyIntent object The ID of the User importing a Private Key. Human-readable name for a Private Key. Bundle containing a raw private key encrypted to the enclave's target public key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Cryptocurrency-specific formats for a derived address (e.g., Ethereum). item field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` The result of the activity The importPrivateKeyResult object Unique identifier for a Private Key. A list of addresses. format field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` address field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/import_private_key \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_IMPORT_PRIVATE_KEY", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userId": "", "privateKeyName": "", "encryptedBundle": "", "curve": "", "addressFormats": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_IMPORT_PRIVATE_KEY", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "importPrivateKeyIntent": { "userId": "", "privateKeyName": "", "encryptedBundle": "", "curve": "", "addressFormats": [ "" ] } }, "result": { "importPrivateKeyResult": { "privateKeyId": "", "addresses": [ { "format": "", "address": "" } ] } } } } } } ``` # Import Wallet Source: https://docs.turnkey.com/api-reference/activities/import-wallet Imports a wallet export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_IMPORT_WALLET` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

The ID of the User importing a Wallet. Human-readable name for a Wallet. Bundle containing a wallet mnemonic encrypted to the enclave's target public key. Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP`
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The importWalletIntent object The ID of the User importing a Wallet. Human-readable name for a Wallet. Bundle containing a wallet mnemonic encrypted to the enclave's target public key. A list of wallet Accounts. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` The result of the activity The importWalletResult object Unique identifier for a Wallet. A list of account addresses. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/import_wallet \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_IMPORT_WALLET", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userId": "", "walletName": "", "encryptedBundle": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_IMPORT_WALLET", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "importWalletIntent": { "userId": "", "walletName": "", "encryptedBundle": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ] } }, "result": { "importWalletResult": { "walletId": "", "addresses": [ "" ] } } } } } } ``` # Init Email Recovery Source: https://docs.turnkey.com/api-reference/activities/init-email-recovery Initializes a new email recovery export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_INIT_USER_EMAIL_RECOVERY` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Email of the user starting recovery Client-side public key generated by the user, to which the recovery bundle will be encrypted. Expiration window (in seconds) indicating how long the recovery credential is valid for. If not provided, a default of 15 minutes will be used.

emailCustomization field

The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The initUserEmailRecoveryIntent object Email of the user starting recovery Client-side public key generated by the user, to which the recovery bundle will be encrypted. Expiration window (in seconds) indicating how long the recovery credential is valid for. If not provided, a default of 15 minutes will be used. emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. The result of the activity The initUserEmailRecoveryResult object Unique identifier for the user being recovered. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/init_user_email_recovery \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_INIT_USER_EMAIL_RECOVERY", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "email": "", "targetPublicKey": "", "expirationSeconds": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" } } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_INIT_USER_EMAIL_RECOVERY", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "initUserEmailRecoveryIntent": { "email": "", "targetPublicKey": "", "expirationSeconds": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" } } }, "result": { "initUserEmailRecoveryResult": { "userId": "" } } } } } } ``` # Init Generic OTP Source: https://docs.turnkey.com/api-reference/activities/init-generic-otp Initiate a Generic OTP activity export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_INIT_OTP` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Whether to send OTP via SMS or email. Possible values: OTP\_TYPE\_SMS, OTP\_TYPE\_EMAIL Email or phone number to send the OTP code to Optional length of the OTP code. Default = 9

emailCustomization field

The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template.

smsCustomization field

Template containing references to .OtpCode i.e Your OTP is \{\{.OtpCode}}
Optional client-generated user identifier to enable per-user rate limiting for SMS auth. We recommend using a hash of the client-side IP address. Optional custom email address from which to send the OTP email Optional flag to specify if the OTP code should be alphanumeric (Crockford’s Base32). Default = true Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Expiration window (in seconds) indicating how long the OTP is valid for. If not provided, a default of 5 minutes will be used. Maximum value is 600 seconds (10 minutes) Optional custom email address to use as reply-to
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The initOtpIntent object Whether to send OTP via SMS or email. Possible values: OTP\_TYPE\_SMS, OTP\_TYPE\_EMAIL Email or phone number to send the OTP code to Optional length of the OTP code. Default = 9 emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. smsCustomization field Template containing references to .OtpCode i.e Your OTP is \{\{.OtpCode}} Optional client-generated user identifier to enable per-user rate limiting for SMS auth. We recommend using a hash of the client-side IP address. Optional custom email address from which to send the OTP email Optional flag to specify if the OTP code should be alphanumeric (Crockford’s Base32). Default = true Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Expiration window (in seconds) indicating how long the OTP is valid for. If not provided, a default of 5 minutes will be used. Maximum value is 600 seconds (10 minutes) Optional custom email address to use as reply-to The result of the activity The initOtpResult object Unique identifier for an OTP authentication ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/init_otp \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_INIT_OTP", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "otpType": "", "contact": "", "otpLength": 123, "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "smsCustomization": { "template": "" }, "userIdentifier": "", "sendFromEmailAddress": "", "alphanumeric": true, "sendFromEmailSenderName": "", "expirationSeconds": "", "replyToEmailAddress": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_INIT_OTP", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "initOtpIntent": { "otpType": "", "contact": "", "otpLength": 123, "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "smsCustomization": { "template": "" }, "userIdentifier": "", "sendFromEmailAddress": "", "alphanumeric": true, "sendFromEmailSenderName": "", "expirationSeconds": "", "replyToEmailAddress": "" } }, "result": { "initOtpResult": { "otpId": "" } } } } } } ``` # Init Import Private Key Source: https://docs.turnkey.com/api-reference/activities/init-import-private-key Initializes a new private key import export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_INIT_IMPORT_PRIVATE_KEY` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

The ID of the User importing a Private Key.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The initImportPrivateKeyIntent object The ID of the User importing a Private Key. The result of the activity The initImportPrivateKeyResult object Import bundle containing a public key and signature to use for importing client data. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/init_import_private_key \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_INIT_IMPORT_PRIVATE_KEY", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userId": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_INIT_IMPORT_PRIVATE_KEY", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "initImportPrivateKeyIntent": { "userId": "" } }, "result": { "initImportPrivateKeyResult": { "importBundle": "" } } } } } } ``` # Init Import Wallet Source: https://docs.turnkey.com/api-reference/activities/init-import-wallet Initializes a new wallet import export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_INIT_IMPORT_WALLET` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

The ID of the User importing a Wallet.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The initImportWalletIntent object The ID of the User importing a Wallet. The result of the activity The initImportWalletResult object Import bundle containing a public key and signature to use for importing client data. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/init_import_wallet \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_INIT_IMPORT_WALLET", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userId": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_INIT_IMPORT_WALLET", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "initImportWalletIntent": { "userId": "" } }, "result": { "initImportWalletResult": { "importBundle": "" } } } } } } ``` # Init OTP auth Source: https://docs.turnkey.com/api-reference/activities/init-otp-auth Initiate an OTP auth activity export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_INIT_OTP_AUTH_V2` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Enum to specifiy whether to send OTP via SMS or email Email or phone number to send the OTP code to Optional length of the OTP code. Default = 9

emailCustomization field

The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template.

smsCustomization field

Template containing references to .OtpCode i.e Your OTP is \{\{.OtpCode}}
Optional client-generated user identifier to enable per-user rate limiting for SMS auth. We recommend using a hash of the client-side IP address. Optional custom email address from which to send the OTP email Optional flag to specify if the OTP code should be alphanumeric (Crockford’s Base32). Default = true Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The initOtpAuthIntentV2 object Enum to specifiy whether to send OTP via SMS or email Email or phone number to send the OTP code to Optional length of the OTP code. Default = 9 emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. smsCustomization field Template containing references to .OtpCode i.e Your OTP is \{\{.OtpCode}} Optional client-generated user identifier to enable per-user rate limiting for SMS auth. We recommend using a hash of the client-side IP address. Optional custom email address from which to send the OTP email Optional flag to specify if the OTP code should be alphanumeric (Crockford’s Base32). Default = true Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to The result of the activity The initOtpAuthResultV2 object Unique identifier for an OTP authentication ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/init_otp_auth \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_INIT_OTP_AUTH_V2", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "otpType": "", "contact": "", "otpLength": 123, "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "smsCustomization": { "template": "" }, "userIdentifier": "", "sendFromEmailAddress": "", "alphanumeric": true, "sendFromEmailSenderName": "", "replyToEmailAddress": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_INIT_OTP_AUTH_V2", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "initOtpAuthIntentV2": { "otpType": "", "contact": "", "otpLength": 123, "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "smsCustomization": { "template": "" }, "userIdentifier": "", "sendFromEmailAddress": "", "alphanumeric": true, "sendFromEmailSenderName": "", "replyToEmailAddress": "" } }, "result": { "initOtpAuthResultV2": { "otpId": "" } } } } } } ``` # Login with a Stamp Source: https://docs.turnkey.com/api-reference/activities/login-with-a-stamp Create a session for a user through stamping client side (api key, wallet client, or passkey client) export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_STAMP_LOGIN` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Client-side public key generated by the user, which will be conditionally added to org data based on the passkey stamp associated with this request Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The stampLoginIntent object Client-side public key generated by the user, which will be conditionally added to org data based on the passkey stamp associated with this request Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys The result of the activity The stampLoginResult object Signed JWT containing an expiry, public key, session type, user id, and organization id ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/stamp_login \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_STAMP_LOGIN", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "publicKey": "", "expirationSeconds": "", "invalidateExisting": true } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_STAMP_LOGIN", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "stampLoginIntent": { "publicKey": "", "expirationSeconds": "", "invalidateExisting": true } }, "result": { "stampLoginResult": { "session": "" } } } } } } ``` # Login with Oauth Source: https://docs.turnkey.com/api-reference/activities/login-with-oauth Create an Oauth session for a user export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_OAUTH_LOGIN` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Base64 encoded OIDC token Client-side public key generated by the user, which will be conditionally added to org data based on the validity of the oidc token associated with this request Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The oauthLoginIntent object Base64 encoded OIDC token Client-side public key generated by the user, which will be conditionally added to org data based on the validity of the oidc token associated with this request Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys The result of the activity The oauthLoginResult object Signed JWT containing an expiry, public key, session type, user id, and organization id ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/oauth_login \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_OAUTH_LOGIN", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "oidcToken": "", "publicKey": "", "expirationSeconds": "", "invalidateExisting": true } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_OAUTH_LOGIN", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "oauthLoginIntent": { "oidcToken": "", "publicKey": "", "expirationSeconds": "", "invalidateExisting": true } }, "result": { "oauthLoginResult": { "session": "" } } } } } } ``` # Login with OTP Source: https://docs.turnkey.com/api-reference/activities/login-with-otp Create an OTP session for a user export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_OTP_LOGIN` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Signed JWT containing a unique id, expiry, verification type, contact Client-side public key generated by the user, which will be conditionally added to org data based on the validity of the verification token Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The otpLoginIntent object Signed JWT containing a unique id, expiry, verification type, contact Client-side public key generated by the user, which will be conditionally added to org data based on the validity of the verification token Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys The result of the activity The otpLoginResult object Signed JWT containing an expiry, public key, session type, user id, and organization id ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/otp_login \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_OTP_LOGIN", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "verificationToken": "", "publicKey": "", "expirationSeconds": "", "invalidateExisting": true } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_OTP_LOGIN", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "otpLoginIntent": { "verificationToken": "", "publicKey": "", "expirationSeconds": "", "invalidateExisting": true } }, "result": { "otpLoginResult": { "session": "" } } } } } } ``` # Oauth Source: https://docs.turnkey.com/api-reference/activities/oauth Authenticate a user with an Oidc token (Oauth) - BETA export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_OAUTH` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Base64 encoded OIDC token Client-side public key generated by the user, to which the oauth bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to Oauth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Oauth API keys
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The oauthIntent object Base64 encoded OIDC token Client-side public key generated by the user, to which the oauth bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to Oauth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Oauth API keys The result of the activity The oauthResult object Unique identifier for the authenticating User. Unique identifier for the created API key. HPKE encrypted credential bundle ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/oauth \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_OAUTH", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "oidcToken": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_OAUTH", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "oauthIntent": { "oidcToken": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true } }, "result": { "oauthResult": { "userId": "", "apiKeyId": "", "credentialBundle": "" } } } } } } ``` # OTP auth Source: https://docs.turnkey.com/api-reference/activities/otp-auth Authenticate a user with an OTP code sent via email or SMS export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_OTP_AUTH` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

ID representing the result of an init OTP activity. OTP sent out to a user's contact (email or SMS) Client-side public key generated by the user, to which the OTP bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to OTP Auth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated OTP Auth API keys
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The otpAuthIntent object ID representing the result of an init OTP activity. OTP sent out to a user's contact (email or SMS) Client-side public key generated by the user, to which the OTP bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to OTP Auth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated OTP Auth API keys The result of the activity The otpAuthResult object Unique identifier for the authenticating User. Unique identifier for the created API key. HPKE encrypted credential bundle ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/otp_auth \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_OTP_AUTH", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "otpId": "", "otpCode": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_OTP_AUTH", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "otpAuthIntent": { "otpId": "", "otpCode": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true } }, "result": { "otpAuthResult": { "userId": "", "apiKeyId": "", "credentialBundle": "" } } } } } } ``` # Activities Source: https://docs.turnkey.com/api-reference/activities/overview Activities are requests to securely execute a workload in Turnkey. # What Are Activities? Activities (also called [submissions](/developer-reference/api-overview/submissions)) are requests to create, modify, or use resources within Turnkey. Submission endpoints are always prefixed with `/public/v1/submit`. * **Policy Enforcement:** Activities are subject to consensus or condition enforcement via the policy engine. * **Optimistic Execution:** Activities are executed optimistically synchronous—if possible, the request completes synchronously; otherwise, it falls back to asynchronous processing. * **Activity Status:** * `COMPLETED`: The activity was successful and the `result` field is populated. * `FAILED`: The activity failed and the `failure` field contains the reason. * `CONSENSUS_NEEDED`: More signatures are required to process the request. * `PENDING`: The request is processing asynchronously. * **Status Updates:** You can get updates by re-submitting the request (idempotent) or polling `get_activity` with the activity ID. * **Idempotency:** The API is idempotent—identical requests (same POST body) return the same activity. To generate a new activity, change the `timestampMs` value in your request. # Perform Email Auth Source: https://docs.turnkey.com/api-reference/activities/perform-email-auth Authenticate a user via Email export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_EMAIL_AUTH_V2` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Email of the authenticating user. Client-side public key generated by the user, to which the email auth bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to Email Auth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used.

emailCustomization field

The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template.
Invalidate all other previously generated Email Auth API keys Optional custom email address from which to send the email Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The emailAuthIntent object Email of the authenticating user. Client-side public key generated by the user, to which the email auth bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to Email Auth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. Invalidate all other previously generated Email Auth API keys Optional custom email address from which to send the email Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to The result of the activity The emailAuthResult object Unique identifier for the authenticating User. Unique identifier for the created API key. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/email_auth \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_EMAIL_AUTH_V2", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "email": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "invalidateExisting": true, "sendFromEmailAddress": "", "sendFromEmailSenderName": "", "replyToEmailAddress": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_EMAIL_AUTH_V2", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "emailAuthIntent": { "email": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "invalidateExisting": true, "sendFromEmailAddress": "", "sendFromEmailSenderName": "", "replyToEmailAddress": "" } }, "result": { "emailAuthResult": { "userId": "", "apiKeyId": "" } } } } } } ``` # Recover a user Source: https://docs.turnkey.com/api-reference/activities/recover-a-user Completes the process of recovering a user by adding an authenticator export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_RECOVER_USER` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

authenticator field

Human-readable name for an Authenticator. Challenge presented for authentication purposes.

attestation field

The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID`
Unique identifier for the user performing recovery.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The recoverUserIntent object authenticator field Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` Unique identifier for the user performing recovery. The result of the activity The recoverUserResult object ID of the authenticator created. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/recover_user \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_RECOVER_USER", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "authenticator": { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } }, "userId": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_RECOVER_USER", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "recoverUserIntent": { "authenticator": { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } }, "userId": "" } }, "result": { "recoverUserResult": { "authenticatorId": [ "" ] } } } } } } ``` # Remove Organization Feature Source: https://docs.turnkey.com/api-reference/activities/remove-organization-feature Removes an organization feature. This activity must be approved by the current root quorum. export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH`
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The removeOrganizationFeatureIntent object name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` The result of the activity The removeOrganizationFeatureResult object Resulting list of organization features. name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` value field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/remove_organization_feature \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "name": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "removeOrganizationFeatureIntent": { "name": "" } }, "result": { "removeOrganizationFeatureResult": { "features": [ { "name": "", "value": "" } ] } } } } } } ``` # Set Organization Feature Source: https://docs.turnkey.com/api-reference/activities/set-organization-feature Sets an organization feature. This activity must be approved by the current root quorum. export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` Optional value for the feature. Will override existing values if feature is already set.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The setOrganizationFeatureIntent object name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` Optional value for the feature. Will override existing values if feature is already set. The result of the activity The setOrganizationFeatureResult object Resulting list of organization features. name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` value field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/set_organization_feature \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "name": "", "value": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "setOrganizationFeatureIntent": { "name": "", "value": "" } }, "result": { "setOrganizationFeatureResult": { "features": [ { "name": "", "value": "" } ] } } } } } } ``` # Sign Raw Payload Source: https://docs.turnkey.com/api-reference/activities/sign-raw-payload Sign a raw payload export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

A Wallet account address, Private Key address, or Private Key identifier. Raw unsigned payload to be signed. Enum options: `PAYLOAD_ENCODING_HEXADECIMAL`, `PAYLOAD_ENCODING_TEXT_UTF8` Enum options: `HASH_FUNCTION_NO_OP`, `HASH_FUNCTION_SHA256`, `HASH_FUNCTION_KECCAK256`, `HASH_FUNCTION_NOT_APPLICABLE`
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The signRawPayloadIntent object Unique identifier for a given Private Key. Raw unsigned payload to be signed. encoding field Enum options: `PAYLOAD_ENCODING_HEXADECIMAL`, `PAYLOAD_ENCODING_TEXT_UTF8` hashFunction field Enum options: `HASH_FUNCTION_NO_OP`, `HASH_FUNCTION_SHA256`, `HASH_FUNCTION_KECCAK256`, `HASH_FUNCTION_NOT_APPLICABLE` The result of the activity The signRawPayloadResult object Component of an ECSDA signature. Component of an ECSDA signature. Component of an ECSDA signature. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/sign_raw_payload \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "signWith": "", "payload": "", "encoding": "", "hashFunction": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "signRawPayloadIntent": { "privateKeyId": "", "payload": "", "encoding": "", "hashFunction": "" } }, "result": { "signRawPayloadResult": { "r": "", "s": "", "v": "" } } } } } } ``` # Sign Raw Payloads Source: https://docs.turnkey.com/api-reference/activities/sign-raw-payloads Sign multiple raw payloads with the same signing parameters export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_SIGN_RAW_PAYLOADS` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

A Wallet account address, Private Key address, or Private Key identifier.

An array of raw unsigned payloads to be signed.

Array item type: string

item field

Enum options: `PAYLOAD_ENCODING_HEXADECIMAL`, `PAYLOAD_ENCODING_TEXT_UTF8` Enum options: `HASH_FUNCTION_NO_OP`, `HASH_FUNCTION_SHA256`, `HASH_FUNCTION_KECCAK256`, `HASH_FUNCTION_NOT_APPLICABLE`
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The signRawPayloadsIntent object A Wallet account address, Private Key address, or Private Key identifier. An array of raw unsigned payloads to be signed. item field encoding field Enum options: `PAYLOAD_ENCODING_HEXADECIMAL`, `PAYLOAD_ENCODING_TEXT_UTF8` hashFunction field Enum options: `HASH_FUNCTION_NO_OP`, `HASH_FUNCTION_SHA256`, `HASH_FUNCTION_KECCAK256`, `HASH_FUNCTION_NOT_APPLICABLE` The result of the activity The signRawPayloadsResult object signatures field Component of an ECSDA signature. Component of an ECSDA signature. Component of an ECSDA signature. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/sign_raw_payloads \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_SIGN_RAW_PAYLOADS", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "signWith": "", "payloads": [ "" ], "encoding": "", "hashFunction": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_SIGN_RAW_PAYLOADS", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "signRawPayloadsIntent": { "signWith": "", "payloads": [ "" ], "encoding": "", "hashFunction": "" } }, "result": { "signRawPayloadsResult": { "signatures": [ { "r": "", "s": "", "v": "" } ] } } } } } } ``` # Sign Transaction Source: https://docs.turnkey.com/api-reference/activities/sign-transaction Sign a transaction export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_SIGN_TRANSACTION_V2` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

A Wallet account address, Private Key address, or Private Key identifier. Raw unsigned transaction to be signed Enum options: `TRANSACTION_TYPE_ETHEREUM`, `TRANSACTION_TYPE_SOLANA`, `TRANSACTION_TYPE_TRON`
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The signTransactionIntent object Unique identifier for a given Private Key. Raw unsigned transaction to be signed by a particular Private Key. type field Enum options: `TRANSACTION_TYPE_ETHEREUM`, `TRANSACTION_TYPE_SOLANA`, `TRANSACTION_TYPE_TRON` The result of the activity The signTransactionResult object signedTransaction field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/sign_transaction \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_SIGN_TRANSACTION_V2", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "signWith": "", "unsignedTransaction": "", "type": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_SIGN_TRANSACTION_V2", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "signTransactionIntent": { "privateKeyId": "", "unsignedTransaction": "", "type": "" } }, "result": { "signTransactionResult": { "signedTransaction": "" } } } } } } ``` # Update Policy Source: https://docs.turnkey.com/api-reference/activities/update-policy Update an existing Policy export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_UPDATE_POLICY_V2` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given Policy. Human-readable name for a Policy. Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect (optional). The consensus expression that triggers the Effect (optional). Accompanying notes for a Policy (optional).
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The updatePolicyIntentV2 object Unique identifier for a given Policy. Human-readable name for a Policy. policyEffect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect (optional). The consensus expression that triggers the Effect (optional). Accompanying notes for a Policy (optional). The result of the activity The updatePolicyResultV2 object Unique identifier for a given Policy. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/update_policy \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_UPDATE_POLICY_V2", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "policyId": "", "policyName": "", "policyEffect": "", "policyCondition": "", "policyConsensus": "", "policyNotes": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UPDATE_POLICY_V2", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "updatePolicyIntentV2": { "policyId": "", "policyName": "", "policyEffect": "", "policyCondition": "", "policyConsensus": "", "policyNotes": "" } }, "result": { "updatePolicyResultV2": { "policyId": "" } } } } } } ``` # Update Private Key Tag Source: https://docs.turnkey.com/api-reference/activities/update-private-key-tag Update human-readable name or associated private keys. Note that this activity is atomic: all of the updates will succeed at once, or all of them will fail. export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_UPDATE_PRIVATE_KEY_TAG` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given Private Key Tag. The new, human-readable name for the tag with the given ID.

A list of Private Keys IDs to add this tag to.

Array item type: string

item field

A list of Private Key IDs to remove this tag from.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The updatePrivateKeyTagIntent object Unique identifier for a given Private Key Tag. The new, human-readable name for the tag with the given ID. A list of Private Keys IDs to add this tag to. item field A list of Private Key IDs to remove this tag from. item field The result of the activity The updatePrivateKeyTagResult object Unique identifier for a given Private Key Tag. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/update_private_key_tag \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_UPDATE_PRIVATE_KEY_TAG", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "privateKeyTagId": "", "newPrivateKeyTagName": "", "addPrivateKeyIds": [ "" ], "removePrivateKeyIds": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UPDATE_PRIVATE_KEY_TAG", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "updatePrivateKeyTagIntent": { "privateKeyTagId": "", "newPrivateKeyTagName": "", "addPrivateKeyIds": [ "" ], "removePrivateKeyIds": [ "" ] } }, "result": { "updatePrivateKeyTagResult": { "privateKeyTagId": "" } } } } } } ``` # Update Root Quorum Source: https://docs.turnkey.com/api-reference/activities/update-root-quorum Set the threshold and members of the root quorum. This activity must be approved by the current root quorum. export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_UPDATE_ROOT_QUORUM` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

The threshold of unique approvals to reach quorum.

The unique identifiers of users who comprise the quorum set.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The updateRootQuorumIntent object The threshold of unique approvals to reach quorum. The unique identifiers of users who comprise the quorum set. item field The result of the activity The updateRootQuorumResult object ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/update_root_quorum \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_UPDATE_ROOT_QUORUM", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "threshold": 123, "userIds": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UPDATE_ROOT_QUORUM", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "updateRootQuorumIntent": { "threshold": 123, "userIds": [ "" ] } }, "result": { "updateRootQuorumResult": {} } } } } } ``` # Update User Source: https://docs.turnkey.com/api-reference/activities/update-user Update a User in an existing Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_UPDATE_USER` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given User. Human-readable name for a User. The user's email address.

An updated list of User Tags to apply to this User. This field, if not needed, should be an empty array in your request body.

Array item type: string

item field

The user's phone number in E.164 format e.g. +13214567890
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The updateUserIntent object Unique identifier for a given User. Human-readable name for a User. The user's email address. An updated list of User Tags to apply to this User. This field, if not needed, should be an empty array in your request body. item field The user's phone number in E.164 format e.g. +13214567890 The result of the activity The updateUserResult object A User ID. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/update_user \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_UPDATE_USER", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userId": "", "userName": "", "userEmail": "", "userTagIds": [ "" ], "userPhoneNumber": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UPDATE_USER", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "updateUserIntent": { "userId": "", "userName": "", "userEmail": "", "userTagIds": [ "" ], "userPhoneNumber": "" } }, "result": { "updateUserResult": { "userId": "" } } } } } } ``` # Update User Tag Source: https://docs.turnkey.com/api-reference/activities/update-user-tag Update human-readable name or associated users. Note that this activity is atomic: all of the updates will succeed at once, or all of them will fail. export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_UPDATE_USER_TAG` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given User Tag. The new, human-readable name for the tag with the given ID.

A list of User IDs to add this tag to.

Array item type: string

item field

A list of User IDs to remove this tag from.

Array item type: string

item field

A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The updateUserTagIntent object Unique identifier for a given User Tag. The new, human-readable name for the tag with the given ID. A list of User IDs to add this tag to. item field A list of User IDs to remove this tag from. item field The result of the activity The updateUserTagResult object Unique identifier for a given User Tag. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/update_user_tag \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_UPDATE_USER_TAG", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "userTagId": "", "newUserTagName": "", "addUserIds": [ "" ], "removeUserIds": [ "" ] } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UPDATE_USER_TAG", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "updateUserTagIntent": { "userTagId": "", "newUserTagName": "", "addUserIds": [ "" ], "removeUserIds": [ "" ] } }, "result": { "updateUserTagResult": { "userTagId": "" } } } } } } ``` # Update Wallet Source: https://docs.turnkey.com/api-reference/activities/update-wallet Update a wallet for an organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_UPDATE_WALLET` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

Unique identifier for a given Wallet. Human-readable name for a Wallet.
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The updateWalletIntent object Unique identifier for a given Wallet. Human-readable name for a Wallet. The result of the activity The updateWalletResult object A Wallet ID. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/update_wallet \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_UPDATE_WALLET", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "walletId": "", "walletName": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UPDATE_WALLET", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "updateWalletIntent": { "walletId": "", "walletName": "" } }, "result": { "updateWalletResult": { "walletId": "" } } } } } } ``` # Verify Generic OTP Source: https://docs.turnkey.com/api-reference/activities/verify-generic-otp Verify a Generic OTP export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Enum options: `ACTIVITY_TYPE_VERIFY_OTP` Timestamp (in milliseconds) of the request, used to verify liveness of user requests. Unique identifier for a given Organization.

parameters field

ID representing the result of an init OTP activity. OTP sent out to a user's contact (email or SMS) Expiration window (in seconds) indicating how long the verification token is valid for. If not provided, a default of 1 hour will be used. Maximum value is 86400 seconds (24 hours)
A successful response returns the following fields: The activity object containing type, intent, and result The activity type The intent of the activity The verifyOtpIntent object ID representing the result of an init OTP activity. OTP sent out to a user's contact (email or SMS) Expiration window (in seconds) indicating how long the verification token is valid for. If not provided, a default of 1 hour will be used. Maximum value is 86400 seconds (24 hours) The result of the activity The verifyOtpResult object Signed JWT containing a unique id, expiry, verification type, contact ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/submit/verify_otp \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "type": "ACTIVITY_TYPE_VERIFY_OTP", "timestampMs": " (e.g. 1746736509954)", "organizationId": " (Your Organization ID)", "parameters": { "otpId": "", "otpCode": "", "expirationSeconds": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_VERIFY_OTP", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "type": "", "intent": { "verifyOtpIntent": { "otpId": "", "otpCode": "", "expirationSeconds": "" } }, "result": { "verifyOtpResult": { "verificationToken": "" } } } } } } ``` # API Reference Source: https://docs.turnkey.com/api-reference/overview Review our [API Introduction](/developer-reference/api-overview/intro) to get started. export const tags = [{ "id": "activities", "label": "Activities" }, { "id": "api-keys", "label": "API Keys" }, { "id": "authenticators", "label": "Authenticators" }, { "id": "user-auth", "label": "User Auth" }, { "id": "organizations", "label": "Organizations" }, { "id": "policies", "label": "Policies" }, { "id": "private-keys", "label": "Private Keys" }, { "id": "users", "label": "Users" }, { "id": "wallets", "label": "Wallets" }, { "id": "private-key-tags", "label": "Private Key Tags" }, { "id": "user-tags", "label": "User Tags" }, { "id": "sessions", "label": "Sessions" }, { "id": "invitations", "label": "Invitations" }, { "id": "user-recovery", "label": "User Recovery" }, { "id": "features", "label": "Features" }, { "id": "signing", "label": "Signing" }]; export const endpoints = [{ "name": "Get Activity", "id": "get-activity", "type": "query", "tags": [{ "id": "activities", "label": "Activities" }] }, { "name": "Get API key", "id": "get-api-key", "type": "query", "tags": [{ "id": "api-keys", "label": "API keys" }] }, { "name": "Get API keys", "id": "get-api-keys", "type": "query", "tags": [{ "id": "api-keys", "label": "API keys" }] }, { "name": "Get Authenticator", "id": "get-authenticator", "type": "query", "tags": [{ "id": "authenticators", "label": "Authenticators" }] }, { "name": "Get Authenticators", "id": "get-authenticators", "type": "query", "tags": [{ "id": "authenticators", "label": "Authenticators" }] }, { "name": "Get Oauth providers", "id": "get-oauth-providers", "type": "query", "tags": [{ "id": "user-auth", "label": "User Auth" }] }, { "name": "Get Configs", "id": "get-configs", "type": "query", "tags": [{ "id": "organizations", "label": "Organizations" }] }, { "name": "Get Policy", "id": "get-policy", "type": "query", "tags": [{ "id": "policies", "label": "Policies" }] }, { "name": "Get Private Key", "id": "get-private-key", "type": "query", "tags": [{ "id": "private-keys", "label": "Private Keys" }] }, { "name": "Get User", "id": "get-user", "type": "query", "tags": [{ "id": "users", "label": "Users" }] }, { "name": "Get Wallet", "id": "get-wallet", "type": "query", "tags": [{ "id": "wallets", "label": "Wallets" }] }, { "name": "Get Wallet Account", "id": "get-wallet-account", "type": "query", "tags": [{ "id": "wallets", "label": "Wallets" }] }, { "name": "List Activities", "id": "list-activities", "type": "query", "tags": [{ "id": "activities", "label": "Activities" }] }, { "name": "List Policies", "id": "list-policies", "type": "query", "tags": [{ "id": "policies", "label": "Policies" }] }, { "name": "List Private Key Tags", "id": "list-private-key-tags", "type": "query", "tags": [{ "id": "private-key-tags", "label": "Private Key Tags" }] }, { "name": "List Private Keys", "id": "list-private-keys", "type": "query", "tags": [{ "id": "private-keys", "label": "Private Keys" }] }, { "name": "Get Suborgs", "id": "get-suborgs", "type": "query", "tags": [{ "id": "organizations", "label": "Organizations" }] }, { "name": "List User Tags", "id": "list-user-tags", "type": "query", "tags": [{ "id": "user-tags", "label": "User Tags" }] }, { "name": "List Users", "id": "list-users", "type": "query", "tags": [{ "id": "users", "label": "Users" }] }, { "name": "Get Verified Suborgs", "id": "get-verified-suborgs", "type": "query", "tags": [{ "id": "organizations", "label": "Organizations" }] }, { "name": "List Wallets Accounts", "id": "list-wallets-accounts", "type": "query", "tags": [{ "id": "wallets", "label": "Wallets" }] }, { "name": "List Wallets", "id": "list-wallets", "type": "query", "tags": [{ "id": "wallets", "label": "Wallets" }] }, { "name": "Who am I", "id": "who-am-i", "type": "query", "tags": [{ "id": "sessions", "label": "Sessions" }] }, { "name": "Create API Keys", "id": "create-api-keys", "type": "activity", "tags": [{ "id": "api-keys", "label": "API Keys" }] }, { "name": "Create Authenticators", "id": "create-authenticators", "type": "activity", "tags": [{ "id": "authenticators", "label": "Authenticators" }] }, { "name": "Create Invitations", "id": "create-invitations", "type": "activity", "tags": [{ "id": "invitations", "label": "Invitations" }] }, { "name": "Create Oauth Providers", "id": "create-oauth-providers", "type": "activity", "tags": [{ "id": "user-auth", "label": "User Auth" }] }, { "name": "Create Policies", "id": "create-policies", "type": "activity", "tags": [{ "id": "policies", "label": "Policies" }] }, { "name": "Create Policy", "id": "create-policy", "type": "activity", "tags": [{ "id": "policies", "label": "Policies" }] }, { "name": "Create Private Key Tag", "id": "create-private-key-tag", "type": "activity", "tags": [{ "id": "private-key-tags", "label": "Private Key Tags" }] }, { "name": "Create Private Keys", "id": "create-private-keys", "type": "activity", "tags": [{ "id": "private-keys", "label": "Private Keys" }] }, { "name": "Create Read Only Session", "id": "create-read-only-session", "type": "activity", "tags": [{ "id": "sessions", "label": "Sessions" }] }, { "name": "Create Read Write Session", "id": "create-read-write-session", "type": "activity", "tags": [{ "id": "sessions", "label": "Sessions" }] }, { "name": "Create Sub-Organization", "id": "create-sub-organization", "type": "activity", "tags": [{ "id": "organizations", "label": "Organizations" }] }, { "name": "Create User Tag", "id": "create-user-tag", "type": "activity", "tags": [{ "id": "user-tags", "label": "User Tags" }] }, { "name": "Create Users", "id": "create-users", "type": "activity", "tags": [{ "id": "users", "label": "Users" }] }, { "name": "Create Wallet", "id": "create-wallet", "type": "activity", "tags": [{ "id": "wallets", "label": "Wallets" }] }, { "name": "Create Wallet Accounts", "id": "create-wallet-accounts", "type": "activity", "tags": [{ "id": "wallets", "label": "Wallets" }] }, { "name": "Delete API Keys", "id": "delete-api-keys", "type": "activity", "tags": [{ "id": "api-keys", "label": "API Keys" }] }, { "name": "Delete Authenticators", "id": "delete-authenticators", "type": "activity", "tags": [{ "id": "authenticators", "label": "Authenticators" }] }, { "name": "Delete Invitation", "id": "delete-invitation", "type": "activity", "tags": [{ "id": "invitations", "label": "Invitations" }] }, { "name": "Delete Oauth Providers", "id": "delete-oauth-providers", "type": "activity", "tags": [{ "id": "user-auth", "label": "User Auth" }] }, { "name": "Delete Policy", "id": "delete-policy", "type": "activity", "tags": [{ "id": "policies", "label": "Policies" }] }, { "name": "Delete Private Key Tags", "id": "delete-private-key-tags", "type": "activity", "tags": [{ "id": "private-key-tags", "label": "Private Key Tags" }] }, { "name": "Delete Private Keys", "id": "delete-private-keys", "type": "activity", "tags": [{ "id": "private-keys", "label": "Private Keys" }] }, { "name": "Delete Sub Organization", "id": "delete-sub-organization", "type": "activity", "tags": [{ "id": "organizations", "label": "Organizations" }] }, { "name": "Delete User Tags", "id": "delete-user-tags", "type": "activity", "tags": [{ "id": "user-tags", "label": "User Tags" }] }, { "name": "Delete Users", "id": "delete-users", "type": "activity", "tags": [{ "id": "users", "label": "Users" }] }, { "name": "Delete Wallets", "id": "delete-wallets", "type": "activity", "tags": [{ "id": "wallets", "label": "Wallets" }] }, { "name": "Perform Email Auth", "id": "perform-email-auth", "type": "activity", "tags": [{ "id": "user-auth", "label": "User Auth" }] }, { "name": "Export Private Key", "id": "export-private-key", "type": "activity", "tags": [{ "id": "private-keys", "label": "Private Keys" }] }, { "name": "Export Wallet", "id": "export-wallet", "type": "activity", "tags": [{ "id": "wallets", "label": "Wallets" }] }, { "name": "Export Wallet Account", "id": "export-wallet-account", "type": "activity", "tags": [{ "id": "wallets", "label": "Wallets" }] }, { "name": "Import Private Key", "id": "import-private-key", "type": "activity", "tags": [{ "id": "private-keys", "label": "Private Keys" }] }, { "name": "Import Wallet", "id": "import-wallet", "type": "activity", "tags": [{ "id": "wallets", "label": "Wallets" }] }, { "name": "Init Import Private Key", "id": "init-import-private-key", "type": "activity", "tags": [{ "id": "private-keys", "label": "Private Keys" }] }, { "name": "Init Import Wallet", "id": "init-import-wallet", "type": "activity", "tags": [{ "id": "wallets", "label": "Wallets" }] }, { "name": "Init OTP auth", "id": "init-otp-auth", "type": "activity", "tags": [{ "id": "user-auth", "label": "User Auth" }] }, { "name": "Init Email Recovery", "id": "init-email-recovery", "type": "activity", "tags": [{ "id": "user-recovery", "label": "User Recovery" }] }, { "name": "Oauth", "id": "oauth", "type": "activity", "tags": [{ "id": "user-auth", "label": "User Auth" }] }, { "name": "OTP auth", "id": "otp-auth", "type": "activity", "tags": [{ "id": "user-auth", "label": "User Auth" }] }, { "name": "Recover a user", "id": "recover-a-user", "type": "activity", "tags": [{ "id": "user-recovery", "label": "User Recovery" }] }, { "name": "Remove Organization Feature", "id": "remove-organization-feature", "type": "activity", "tags": [{ "id": "features", "label": "Features" }] }, { "name": "Set Organization Feature", "id": "set-organization-feature", "type": "activity", "tags": [{ "id": "features", "label": "Features" }] }, { "name": "Sign Raw Payload", "id": "sign-raw-payload", "type": "activity", "tags": [{ "id": "signing", "label": "Signing" }] }, { "name": "Sign Raw Payloads", "id": "sign-raw-payloads", "type": "activity", "tags": [{ "id": "signing", "label": "Signing" }] }, { "name": "Sign Transaction", "id": "sign-transaction", "type": "activity", "tags": [{ "id": "signing", "label": "Signing" }] }, { "name": "Update Policy", "id": "update-policy", "type": "activity", "tags": [{ "id": "policies", "label": "Policies" }] }, { "name": "Update Private Key Tag", "id": "update-private-key-tag", "type": "activity", "tags": [{ "id": "private-key-tags", "label": "Private Key Tags" }] }, { "name": "Update Root Quorum", "id": "update-root-quorum", "type": "activity", "tags": [{ "id": "organizations", "label": "Organizations" }] }, { "name": "Update User", "id": "update-user", "type": "activity", "tags": [{ "id": "users", "label": "Users" }] }, { "name": "Update User Tag", "id": "update-user-tag", "type": "activity", "tags": [{ "id": "user-tags", "label": "User Tags" }] }, { "name": "Update Wallet", "id": "update-wallet", "type": "activity", "tags": [{ "id": "wallets", "label": "Wallets" }] }]; export const EndpointFilter = ({endpoints, tags}) => { const filterId = `endpoint-filter-${Math.random().toString(36).slice(2, 9)}`; const handleTagClick = value => { const rootEl = document.getElementById(filterId); if (!rootEl) return; const filterTags = rootEl.getAttribute('data-filter-tags') || ''; const filterTagsArray = filterTags.split(',').filter(Boolean); const isType = ["all", "query", "activity"].includes(value); if (isType) { rootEl.setAttribute('data-filter-type', value); } else { if (filterTagsArray.includes(value)) { filterTagsArray.splice(filterTagsArray.indexOf(value), 1); } else { filterTagsArray.push(value); } rootEl.setAttribute('data-filter-tags', filterTagsArray.join(',')); } const rows = rootEl.querySelectorAll('.endpoint-row'); rows.forEach(r => { const tagsAttr = r.getAttribute('data-tags') || ''; const tags = tagsAttr.split(',').filter(Boolean); const matchesTags = filterTagsArray.length === 0 || filterTagsArray.some(f => tags.includes(f)); const rowType = r.getAttribute('data-endpoint-type') || 'all'; const currentType = rootEl.getAttribute('data-filter-type'); const matchesType = currentType === 'all' || rowType === currentType; r.style.display = matchesTags && matchesType ? 'block' : 'none'; }); const pills = rootEl.querySelectorAll('.endpoint-tag'); pills.forEach(p => { if (p.hasAttribute('data-endpoint-type')) { const type = p.getAttribute('data-endpoint-type'); if (type === rootEl.getAttribute('data-filter-type')) { p.style.backgroundColor = 'rgb(var(--primary-light))'; p.style.color = 'white'; } else { p.style.removeProperty('background-color'); p.style.removeProperty('color'); } } else { const tagId = p.getAttribute('data-tag'); if (filterTagsArray.includes(tagId)) { p.style.backgroundColor = 'rgb(var(--primary-light))'; p.style.color = 'white'; } else { p.style.removeProperty('background-color'); p.style.removeProperty('color'); } } }); }; return
{tags.map(tag => handleTagClick(tag.id)} className="endpoint-tag select-none h-8 text-xs px-2 cursor-pointer bg-gray-100/50 dark:bg-white/10 inline-flex items-center justify-center rounded-full text-gray-600 dark:text-gray-200 font-medium"> {tag.label} )}
{endpoints.map(endpoint =>
t.id).join(",")} data-endpoint-type={endpoint.type}> { window.location.href = `${endpoint.type === "query" ? "queries" : "activities"}/${endpoint.id}`; }} className="cursor-pointer py-2 font-normal border-b border-gray-100 dark:border-gray-700 group flex flex-row justify-between items-start md:items-center">
{endpoint.name}
{endpoint.tags.map(tag => {tag.label} )}
)}
; }; # Get Activity Source: https://docs.turnkey.com/api-reference/queries/get-activity Get details about an Activity export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given Activity object. A successful response returns the following fields: activity field Unique identifier for a given Activity object. Unique identifier for a given Organization. status field Enum options: `ACTIVITY_STATUS_CREATED`, `ACTIVITY_STATUS_PENDING`, `ACTIVITY_STATUS_COMPLETED`, `ACTIVITY_STATUS_FAILED`, `ACTIVITY_STATUS_CONSENSUS_NEEDED`, `ACTIVITY_STATUS_REJECTED` type field Enum options: `ACTIVITY_TYPE_CREATE_API_KEYS`, `ACTIVITY_TYPE_CREATE_USERS`, `ACTIVITY_TYPE_CREATE_PRIVATE_KEYS`, `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD`, `ACTIVITY_TYPE_CREATE_INVITATIONS`, `ACTIVITY_TYPE_ACCEPT_INVITATION`, `ACTIVITY_TYPE_CREATE_POLICY`, `ACTIVITY_TYPE_DISABLE_PRIVATE_KEY`, `ACTIVITY_TYPE_DELETE_USERS`, `ACTIVITY_TYPE_DELETE_API_KEYS`, `ACTIVITY_TYPE_DELETE_INVITATION`, `ACTIVITY_TYPE_DELETE_ORGANIZATION`, `ACTIVITY_TYPE_DELETE_POLICY`, `ACTIVITY_TYPE_CREATE_USER_TAG`, `ACTIVITY_TYPE_DELETE_USER_TAGS`, `ACTIVITY_TYPE_CREATE_ORGANIZATION`, `ACTIVITY_TYPE_SIGN_TRANSACTION`, `ACTIVITY_TYPE_APPROVE_ACTIVITY`, `ACTIVITY_TYPE_REJECT_ACTIVITY`, `ACTIVITY_TYPE_DELETE_AUTHENTICATORS`, `ACTIVITY_TYPE_CREATE_AUTHENTICATORS`, `ACTIVITY_TYPE_CREATE_PRIVATE_KEY_TAG`, `ACTIVITY_TYPE_DELETE_PRIVATE_KEY_TAGS`, `ACTIVITY_TYPE_SET_PAYMENT_METHOD`, `ACTIVITY_TYPE_ACTIVATE_BILLING_TIER`, `ACTIVITY_TYPE_DELETE_PAYMENT_METHOD`, `ACTIVITY_TYPE_CREATE_POLICY_V2`, `ACTIVITY_TYPE_CREATE_POLICY_V3`, `ACTIVITY_TYPE_CREATE_API_ONLY_USERS`, `ACTIVITY_TYPE_UPDATE_ROOT_QUORUM`, `ACTIVITY_TYPE_UPDATE_USER_TAG`, `ACTIVITY_TYPE_UPDATE_PRIVATE_KEY_TAG`, `ACTIVITY_TYPE_CREATE_AUTHENTICATORS_V2`, `ACTIVITY_TYPE_CREATE_ORGANIZATION_V2`, `ACTIVITY_TYPE_CREATE_USERS_V2`, `ACTIVITY_TYPE_ACCEPT_INVITATION_V2`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V2`, `ACTIVITY_TYPE_UPDATE_ALLOWED_ORIGINS`, `ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2`, `ACTIVITY_TYPE_UPDATE_USER`, `ACTIVITY_TYPE_UPDATE_POLICY`, `ACTIVITY_TYPE_SET_PAYMENT_METHOD_V2`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V3`, `ACTIVITY_TYPE_CREATE_WALLET`, `ACTIVITY_TYPE_CREATE_WALLET_ACCOUNTS`, `ACTIVITY_TYPE_INIT_USER_EMAIL_RECOVERY`, `ACTIVITY_TYPE_RECOVER_USER`, `ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE`, `ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE`, `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2`, `ACTIVITY_TYPE_SIGN_TRANSACTION_V2`, `ACTIVITY_TYPE_EXPORT_PRIVATE_KEY`, `ACTIVITY_TYPE_EXPORT_WALLET`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V4`, `ACTIVITY_TYPE_EMAIL_AUTH`, `ACTIVITY_TYPE_EXPORT_WALLET_ACCOUNT`, `ACTIVITY_TYPE_INIT_IMPORT_WALLET`, `ACTIVITY_TYPE_IMPORT_WALLET`, `ACTIVITY_TYPE_INIT_IMPORT_PRIVATE_KEY`, `ACTIVITY_TYPE_IMPORT_PRIVATE_KEY`, `ACTIVITY_TYPE_CREATE_POLICIES`, `ACTIVITY_TYPE_SIGN_RAW_PAYLOADS`, `ACTIVITY_TYPE_CREATE_READ_ONLY_SESSION`, `ACTIVITY_TYPE_CREATE_OAUTH_PROVIDERS`, `ACTIVITY_TYPE_DELETE_OAUTH_PROVIDERS`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V5`, `ACTIVITY_TYPE_OAUTH`, `ACTIVITY_TYPE_CREATE_API_KEYS_V2`, `ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION`, `ACTIVITY_TYPE_EMAIL_AUTH_V2`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V6`, `ACTIVITY_TYPE_DELETE_PRIVATE_KEYS`, `ACTIVITY_TYPE_DELETE_WALLETS`, `ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2`, `ACTIVITY_TYPE_DELETE_SUB_ORGANIZATION`, `ACTIVITY_TYPE_INIT_OTP_AUTH`, `ACTIVITY_TYPE_OTP_AUTH`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V7`, `ACTIVITY_TYPE_UPDATE_WALLET`, `ACTIVITY_TYPE_UPDATE_POLICY_V2`, `ACTIVITY_TYPE_CREATE_USERS_V3`, `ACTIVITY_TYPE_INIT_OTP_AUTH_V2`, `ACTIVITY_TYPE_INIT_OTP`, `ACTIVITY_TYPE_VERIFY_OTP`, `ACTIVITY_TYPE_OTP_LOGIN`, `ACTIVITY_TYPE_STAMP_LOGIN`, `ACTIVITY_TYPE_OAUTH_LOGIN` intent field createOrganizationIntent field Human-readable name for an Organization. The root user's email address. rootAuthenticator field Human-readable name for an Authenticator. Unique identifier for a given User. attestation field id field type field Enum options: `public-key` rawId field authenticatorAttachment field Enum options: `cross-platform`, `platform` response field clientDataJson field attestationObject field transports field item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` authenticatorAttachment field Enum options: `cross-platform`, `platform` clientExtensionResults field appid field appidExclude field credProps field rk field Challenge presented for authentication purposes. Unique identifier for the root user object. createAuthenticatorsIntent field A list of Authenticators. Human-readable name for an Authenticator. Unique identifier for a given User. attestation field id field type field Enum options: `public-key` rawId field authenticatorAttachment field Enum options: `cross-platform`, `platform` response field clientDataJson field attestationObject field transports field item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` authenticatorAttachment field Enum options: `cross-platform`, `platform` clientExtensionResults field appid field appidExclude field credProps field rk field Challenge presented for authentication purposes. Unique identifier for a given User. createUsersIntent field A list of Users. Human-readable name for a User. The user's email address. accessType field Enum options: `ACCESS_TYPE_WEB`, `ACCESS_TYPE_API`, `ACCESS_TYPE_ALL` A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Unique identifier for a given User. attestation field id field type field Enum options: `public-key` rawId field authenticatorAttachment field Enum options: `cross-platform`, `platform` response field clientDataJson field attestationObject field transports field item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` authenticatorAttachment field Enum options: `cross-platform`, `platform` clientExtensionResults field appid field appidExclude field credProps field rk field Challenge presented for authentication purposes. A list of User Tag IDs. This field, if not needed, should be an empty array in your request body. item field createPrivateKeysIntent field A list of Private Keys. Human-readable name for a Private Key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` A list of Private Key Tag IDs. This field, if not needed, should be an empty array in your request body. item field Cryptocurrency-specific formats for a derived address (e.g., Ethereum). item field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` signRawPayloadIntent field Unique identifier for a given Private Key. Raw unsigned payload to be signed. encoding field Enum options: `PAYLOAD_ENCODING_HEXADECIMAL`, `PAYLOAD_ENCODING_TEXT_UTF8` hashFunction field Enum options: `HASH_FUNCTION_NO_OP`, `HASH_FUNCTION_SHA256`, `HASH_FUNCTION_KECCAK256`, `HASH_FUNCTION_NOT_APPLICABLE` createInvitationsIntent field A list of Invitations. The name of the intended Invitation recipient. The email address of the intended Invitation recipient. A list of tags assigned to the Invitation recipient. This field, if not needed, should be an empty array in your request body. item field accessType field Enum options: `ACCESS_TYPE_WEB`, `ACCESS_TYPE_API`, `ACCESS_TYPE_ALL` Unique identifier for the Sender of an Invitation. acceptInvitationIntent field Unique identifier for a given Invitation object. Unique identifier for a given User. authenticator field Human-readable name for an Authenticator. Unique identifier for a given User. attestation field id field type field Enum options: `public-key` rawId field authenticatorAttachment field Enum options: `cross-platform`, `platform` response field clientDataJson field attestationObject field transports field item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` authenticatorAttachment field Enum options: `cross-platform`, `platform` clientExtensionResults field appid field appidExclude field credProps field rk field Challenge presented for authentication purposes. createPolicyIntent field Human-readable name for a Policy. A list of simple functions each including a subject, target and boolean. See Policy Engine Language section for additional details. subject field operator field Enum options: `OPERATOR_EQUAL`, `OPERATOR_MORE_THAN`, `OPERATOR_MORE_THAN_OR_EQUAL`, `OPERATOR_LESS_THAN`, `OPERATOR_LESS_THAN_OR_EQUAL`, `OPERATOR_CONTAINS`, `OPERATOR_NOT_EQUAL`, `OPERATOR_IN`, `OPERATOR_NOT_IN`, `OPERATOR_CONTAINS_ONE`, `OPERATOR_CONTAINS_ALL` target field effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` notes field disablePrivateKeyIntent field Unique identifier for a given Private Key. deleteUsersIntent field A list of User IDs. item field deleteAuthenticatorsIntent field Unique identifier for a given User. A list of Authenticator IDs. item field deleteInvitationIntent field Unique identifier for a given Invitation object. deleteOrganizationIntent field Unique identifier for a given Organization. deletePolicyIntent field Unique identifier for a given Policy. createUserTagIntent field Human-readable name for a User Tag. A list of User IDs. item field deleteUserTagsIntent field A list of User Tag IDs. item field signTransactionIntent field Unique identifier for a given Private Key. Raw unsigned transaction to be signed by a particular Private Key. type field Enum options: `TRANSACTION_TYPE_ETHEREUM`, `TRANSACTION_TYPE_SOLANA`, `TRANSACTION_TYPE_TRON` createApiKeysIntent field A list of API Keys. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. Unique identifier for a given User. deleteApiKeysIntent field Unique identifier for a given User. A list of API Key IDs. item field approveActivityIntent field An artifact verifying a User's action. rejectActivityIntent field An artifact verifying a User's action. createPrivateKeyTagIntent field Human-readable name for a Private Key Tag. A list of Private Key IDs. item field deletePrivateKeyTagsIntent field A list of Private Key Tag IDs. item field createPolicyIntentV2 field Human-readable name for a Policy. A list of simple functions each including a subject, target and boolean. See Policy Engine Language section for additional details. subject field operator field Enum options: `OPERATOR_EQUAL`, `OPERATOR_MORE_THAN`, `OPERATOR_MORE_THAN_OR_EQUAL`, `OPERATOR_LESS_THAN`, `OPERATOR_LESS_THAN_OR_EQUAL`, `OPERATOR_CONTAINS`, `OPERATOR_NOT_EQUAL`, `OPERATOR_IN`, `OPERATOR_NOT_IN`, `OPERATOR_CONTAINS_ONE`, `OPERATOR_CONTAINS_ALL` targets field item field effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` notes field setPaymentMethodIntent field The account number of the customer's credit card. The verification digits of the customer's credit card. The month that the credit card expires. The year that the credit card expires. The email that will receive invoices for the credit card. The name associated with the credit card. activateBillingTierIntent field The product that the customer wants to subscribe to. deletePaymentMethodIntent field The payment method that the customer wants to remove. createPolicyIntentV3 field Human-readable name for a Policy. effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect The consensus expression that triggers the Effect notes field createApiOnlyUsersIntent field A list of API-only Users to create. The name of the new API-only User. The email address for this API-only User (optional). A list of tags assigned to the new API-only User. This field, if not needed, should be an empty array in your request body. item field A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. updateRootQuorumIntent field The threshold of unique approvals to reach quorum. The unique identifiers of users who comprise the quorum set. item field updateUserTagIntent field Unique identifier for a given User Tag. The new, human-readable name for the tag with the given ID. A list of User IDs to add this tag to. item field A list of User IDs to remove this tag from. item field updatePrivateKeyTagIntent field Unique identifier for a given Private Key Tag. The new, human-readable name for the tag with the given ID. A list of Private Keys IDs to add this tag to. item field A list of Private Key IDs to remove this tag from. item field createAuthenticatorsIntentV2 field A list of Authenticators. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` Unique identifier for a given User. acceptInvitationIntentV2 field Unique identifier for a given Invitation object. Unique identifier for a given User. authenticator field Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` createOrganizationIntentV2 field Human-readable name for an Organization. The root user's email address. rootAuthenticator field Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` Unique identifier for the root user object. createUsersIntentV2 field A list of Users. Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` A list of User Tag IDs. This field, if not needed, should be an empty array in your request body. item field createSubOrganizationIntent field Name for this sub-organization rootAuthenticator field Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` createSubOrganizationIntentV2 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users updateAllowedOriginsIntent field Additional origins requests are allowed from besides Turnkey origins item field createPrivateKeysIntentV2 field A list of Private Keys. Human-readable name for a Private Key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` A list of Private Key Tag IDs. This field, if not needed, should be an empty array in your request body. item field Cryptocurrency-specific formats for a derived address (e.g., Ethereum). item field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` updateUserIntent field Unique identifier for a given User. Human-readable name for a User. The user's email address. An updated list of User Tags to apply to this User. This field, if not needed, should be an empty array in your request body. item field The user's phone number in E.164 format e.g. +13214567890 updatePolicyIntent field Unique identifier for a given Policy. Human-readable name for a Policy. policyEffect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect (optional). The consensus expression that triggers the Effect (optional). Accompanying notes for a Policy (optional). setPaymentMethodIntentV2 field The id of the payment method that was created clientside. The email that will receive invoices for the credit card. The name associated with the credit card. createSubOrganizationIntentV3 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users A list of Private Keys. Human-readable name for a Private Key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` A list of Private Key Tag IDs. This field, if not needed, should be an empty array in your request body. item field Cryptocurrency-specific formats for a derived address (e.g., Ethereum). item field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` createWalletIntent field Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. createWalletAccountsIntent field Unique identifier for a given Wallet. A list of wallet Accounts. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` initUserEmailRecoveryIntent field Email of the user starting recovery Client-side public key generated by the user, to which the recovery bundle will be encrypted. Expiration window (in seconds) indicating how long the recovery credential is valid for. If not provided, a default of 15 minutes will be used. emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. recoverUserIntent field authenticator field Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` Unique identifier for the user performing recovery. setOrganizationFeatureIntent field name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` Optional value for the feature. Will override existing values if feature is already set. removeOrganizationFeatureIntent field name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` signRawPayloadIntentV2 field A Wallet account address, Private Key address, or Private Key identifier. Raw unsigned payload to be signed. encoding field Enum options: `PAYLOAD_ENCODING_HEXADECIMAL`, `PAYLOAD_ENCODING_TEXT_UTF8` hashFunction field Enum options: `HASH_FUNCTION_NO_OP`, `HASH_FUNCTION_SHA256`, `HASH_FUNCTION_KECCAK256`, `HASH_FUNCTION_NOT_APPLICABLE` signTransactionIntentV2 field A Wallet account address, Private Key address, or Private Key identifier. Raw unsigned transaction to be signed type field Enum options: `TRANSACTION_TYPE_ETHEREUM`, `TRANSACTION_TYPE_SOLANA`, `TRANSACTION_TYPE_TRON` exportPrivateKeyIntent field Unique identifier for a given Private Key. Client-side public key generated by the user, to which the export bundle will be encrypted. exportWalletIntent field Unique identifier for a given Wallet. Client-side public key generated by the user, to which the export bundle will be encrypted. language field Enum options: `MNEMONIC_LANGUAGE_ENGLISH`, `MNEMONIC_LANGUAGE_SIMPLIFIED_CHINESE`, `MNEMONIC_LANGUAGE_TRADITIONAL_CHINESE`, `MNEMONIC_LANGUAGE_CZECH`, `MNEMONIC_LANGUAGE_FRENCH`, `MNEMONIC_LANGUAGE_ITALIAN`, `MNEMONIC_LANGUAGE_JAPANESE`, `MNEMONIC_LANGUAGE_KOREAN`, `MNEMONIC_LANGUAGE_SPANISH` createSubOrganizationIntentV4 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users wallet field Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. Disable email recovery for the sub-organization Disable email auth for the sub-organization emailAuthIntent field Email of the authenticating user. Client-side public key generated by the user, to which the email auth bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to Email Auth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. Invalidate all other previously generated Email Auth API keys Optional custom email address from which to send the email Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to exportWalletAccountIntent field Address to identify Wallet Account. Client-side public key generated by the user, to which the export bundle will be encrypted. initImportWalletIntent field The ID of the User importing a Wallet. importWalletIntent field The ID of the User importing a Wallet. Human-readable name for a Wallet. Bundle containing a wallet mnemonic encrypted to the enclave's target public key. A list of wallet Accounts. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` initImportPrivateKeyIntent field The ID of the User importing a Private Key. importPrivateKeyIntent field The ID of the User importing a Private Key. Human-readable name for a Private Key. Bundle containing a raw private key encrypted to the enclave's target public key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Cryptocurrency-specific formats for a derived address (e.g., Ethereum). item field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` createPoliciesIntent field An array of policy intents to be created. Human-readable name for a Policy. effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect The consensus expression that triggers the Effect notes field signRawPayloadsIntent field A Wallet account address, Private Key address, or Private Key identifier. An array of raw unsigned payloads to be signed. item field encoding field Enum options: `PAYLOAD_ENCODING_HEXADECIMAL`, `PAYLOAD_ENCODING_TEXT_UTF8` hashFunction field Enum options: `HASH_FUNCTION_NO_OP`, `HASH_FUNCTION_SHA256`, `HASH_FUNCTION_KECCAK256`, `HASH_FUNCTION_NOT_APPLICABLE` createReadOnlySessionIntent field createOauthProvidersIntent field The ID of the User to add an Oauth provider to A list of Oauth providers. Human-readable name to identify a Provider. Base64 encoded OIDC token deleteOauthProvidersIntent field The ID of the User to remove an Oauth provider from Unique identifier for a given Provider. item field createSubOrganizationIntentV5 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` A list of Oauth providers. This field, if not needed, should be an empty array in your request body. Human-readable name to identify a Provider. Base64 encoded OIDC token The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users wallet field Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. Disable email recovery for the sub-organization Disable email auth for the sub-organization oauthIntent field Base64 encoded OIDC token Client-side public key generated by the user, to which the oauth bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to Oauth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Oauth API keys createApiKeysIntentV2 field A list of API Keys. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. curveType field Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last. Unique identifier for a given User. createReadWriteSessionIntent field Client-side public key generated by the user, to which the read write session bundle (credentials) will be encrypted. Email of the user to create a read write session for Optional human-readable name for an API Key. If none provided, default to Read Write Session - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. emailAuthIntentV2 field Email of the authenticating user. Client-side public key generated by the user, to which the email auth bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to Email Auth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. Invalidate all other previously generated Email Auth API keys Optional custom email address from which to send the email Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to createSubOrganizationIntentV6 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. curveType field Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` A list of Oauth providers. This field, if not needed, should be an empty array in your request body. Human-readable name to identify a Provider. Base64 encoded OIDC token The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users wallet field Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. Disable email recovery for the sub-organization Disable email auth for the sub-organization deletePrivateKeysIntent field List of unique identifiers for private keys within an organization item field Optional parameter for deleting the private keys, even if any have not been previously exported. If they have been exported, this field is ignored. deleteWalletsIntent field List of unique identifiers for wallets within an organization item field Optional parameter for deleting the wallets, even if any have not been previously exported. If they have been exported, this field is ignored. createReadWriteSessionIntentV2 field Client-side public key generated by the user, to which the read write session bundle (credentials) will be encrypted. Unique identifier for a given User. Optional human-readable name for an API Key. If none provided, default to Read Write Session - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated ReadWriteSession API keys deleteSubOrganizationIntent field Sub-organization deletion, by default, requires associated wallets and private keys to be exported for security reasons. Set this boolean to true to force sub-organization deletion even if some wallets or private keys within it have not been exported yet. Default: false. initOtpAuthIntent field Enum to specifiy whether to send OTP via SMS or email Email or phone number to send the OTP code to emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. smsCustomization field Template containing references to .OtpCode i.e Your OTP is \{\{.OtpCode}} Optional client-generated user identifier to enable per-user rate limiting for SMS auth. We recommend using a hash of the client-side IP address. Optional custom email address from which to send the OTP email Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to otpAuthIntent field ID representing the result of an init OTP activity. OTP sent out to a user's contact (email or SMS) Client-side public key generated by the user, to which the OTP bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to OTP Auth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated OTP Auth API keys createSubOrganizationIntentV7 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. The user's phone number in E.164 format e.g. +13214567890 A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. curveType field Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` A list of Oauth providers. This field, if not needed, should be an empty array in your request body. Human-readable name to identify a Provider. Base64 encoded OIDC token The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users wallet field Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. Disable email recovery for the sub-organization Disable email auth for the sub-organization Disable OTP SMS auth for the sub-organization Disable OTP email auth for the sub-organization updateWalletIntent field Unique identifier for a given Wallet. Human-readable name for a Wallet. updatePolicyIntentV2 field Unique identifier for a given Policy. Human-readable name for a Policy. policyEffect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect (optional). The consensus expression that triggers the Effect (optional). Accompanying notes for a Policy (optional). createUsersIntentV3 field A list of Users. Human-readable name for a User. The user's email address. The user's phone number in E.164 format e.g. +13214567890 A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. curveType field Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` A list of Oauth providers. This field, if not needed, should be an empty array in your request body. Human-readable name to identify a Provider. Base64 encoded OIDC token A list of User Tag IDs. This field, if not needed, should be an empty array in your request body. item field initOtpAuthIntentV2 field Enum to specifiy whether to send OTP via SMS or email Email or phone number to send the OTP code to Optional length of the OTP code. Default = 9 emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. smsCustomization field Template containing references to .OtpCode i.e Your OTP is \{\{.OtpCode}} Optional client-generated user identifier to enable per-user rate limiting for SMS auth. We recommend using a hash of the client-side IP address. Optional custom email address from which to send the OTP email Optional flag to specify if the OTP code should be alphanumeric (Crockford’s Base32). Default = true Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to initOtpIntent field Whether to send OTP via SMS or email. Possible values: OTP\_TYPE\_SMS, OTP\_TYPE\_EMAIL Email or phone number to send the OTP code to Optional length of the OTP code. Default = 9 emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. smsCustomization field Template containing references to .OtpCode i.e Your OTP is \{\{.OtpCode}} Optional client-generated user identifier to enable per-user rate limiting for SMS auth. We recommend using a hash of the client-side IP address. Optional custom email address from which to send the OTP email Optional flag to specify if the OTP code should be alphanumeric (Crockford’s Base32). Default = true Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Expiration window (in seconds) indicating how long the OTP is valid for. If not provided, a default of 5 minutes will be used. Maximum value is 600 seconds (10 minutes) Optional custom email address to use as reply-to verifyOtpIntent field ID representing the result of an init OTP activity. OTP sent out to a user's contact (email or SMS) Expiration window (in seconds) indicating how long the verification token is valid for. If not provided, a default of 1 hour will be used. Maximum value is 86400 seconds (24 hours) otpLoginIntent field Signed JWT containing a unique id, expiry, verification type, contact Client-side public key generated by the user, which will be conditionally added to org data based on the validity of the verification token Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys stampLoginIntent field Client-side public key generated by the user, which will be conditionally added to org data based on the passkey stamp associated with this request Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys oauthLoginIntent field Base64 encoded OIDC token Client-side public key generated by the user, which will be conditionally added to org data based on the validity of the oidc token associated with this request Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys result field createOrganizationResult field Unique identifier for a given Organization. createAuthenticatorsResult field A list of Authenticator IDs. item field createUsersResult field A list of User IDs. item field createPrivateKeysResult field A list of Private Key IDs. item field createInvitationsResult field A list of Invitation IDs item field acceptInvitationResult field Unique identifier for a given Invitation. Unique identifier for a given User. signRawPayloadResult field Component of an ECSDA signature. Component of an ECSDA signature. Component of an ECSDA signature. createPolicyResult field Unique identifier for a given Policy. disablePrivateKeyResult field Unique identifier for a given Private Key. deleteUsersResult field A list of User IDs. item field deleteAuthenticatorsResult field Unique identifier for a given Authenticator. item field deleteInvitationResult field Unique identifier for a given Invitation. deleteOrganizationResult field Unique identifier for a given Organization. deletePolicyResult field Unique identifier for a given Policy. createUserTagResult field Unique identifier for a given User Tag. A list of User IDs. item field deleteUserTagsResult field A list of User Tag IDs. item field A list of User IDs. item field signTransactionResult field signedTransaction field deleteApiKeysResult field A list of API Key IDs. item field createApiKeysResult field A list of API Key IDs. item field createPrivateKeyTagResult field Unique identifier for a given Private Key Tag. A list of Private Key IDs. item field deletePrivateKeyTagsResult field A list of Private Key Tag IDs. item field A list of Private Key IDs. item field setPaymentMethodResult field The last four digits of the credit card added. The name associated with the payment method. The email address associated with the payment method. activateBillingTierResult field The id of the product being subscribed to. deletePaymentMethodResult field The payment method that was removed. createApiOnlyUsersResult field A list of API-only User IDs. item field updateRootQuorumResult field updateUserTagResult field Unique identifier for a given User Tag. updatePrivateKeyTagResult field Unique identifier for a given Private Key Tag. createSubOrganizationResult field subOrganizationId field rootUserIds field item field updateAllowedOriginsResult field createPrivateKeysResultV2 field A list of Private Key IDs and addresses. privateKeyId field addresses field format field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` address field updateUserResult field A User ID. updatePolicyResult field Unique identifier for a given Policy. createSubOrganizationResultV3 field subOrganizationId field A list of Private Key IDs and addresses. privateKeyId field addresses field format field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` address field rootUserIds field item field createWalletResult field Unique identifier for a Wallet. A list of account addresses. item field createWalletAccountsResult field A list of derived addresses. item field initUserEmailRecoveryResult field Unique identifier for the user being recovered. recoverUserResult field ID of the authenticator created. item field setOrganizationFeatureResult field Resulting list of organization features. name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` value field removeOrganizationFeatureResult field Resulting list of organization features. name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` value field exportPrivateKeyResult field Unique identifier for a given Private Key. Export bundle containing a private key encrypted to the client's target public key. exportWalletResult field Unique identifier for a given Wallet. Export bundle containing a wallet mnemonic + optional newline passphrase encrypted by the client's target public key. createSubOrganizationResultV4 field subOrganizationId field wallet field walletId field A list of account addresses. item field rootUserIds field item field emailAuthResult field Unique identifier for the authenticating User. Unique identifier for the created API key. exportWalletAccountResult field Address to identify Wallet Account. Export bundle containing a private key encrypted by the client's target public key. initImportWalletResult field Import bundle containing a public key and signature to use for importing client data. importWalletResult field Unique identifier for a Wallet. A list of account addresses. item field initImportPrivateKeyResult field Import bundle containing a public key and signature to use for importing client data. importPrivateKeyResult field Unique identifier for a Private Key. A list of addresses. format field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` address field createPoliciesResult field A list of unique identifiers for the created policies. item field signRawPayloadsResult field signatures field Component of an ECSDA signature. Component of an ECSDA signature. Component of an ECSDA signature. createReadOnlySessionResult field Unique identifier for a given Organization. If the request is being made by a user and their Sub-Organization ID is unknown, this can be the Parent Organization ID. However, using the Sub-Organization ID is preferred due to performance reasons. Human-readable name for an Organization. Unique identifier for a given User. Human-readable name for a User. String representing a read only session UTC timestamp in seconds representing the expiry time for the read only session. createOauthProvidersResult field A list of unique identifiers for Oauth Providers item field deleteOauthProvidersResult field A list of unique identifiers for Oauth Providers item field createSubOrganizationResultV5 field subOrganizationId field wallet field walletId field A list of account addresses. item field rootUserIds field item field oauthResult field Unique identifier for the authenticating User. Unique identifier for the created API key. HPKE encrypted credential bundle createReadWriteSessionResult field Unique identifier for a given Organization. If the request is being made by a user and their Sub-Organization ID is unknown, this can be the Parent Organization ID. However, using the Sub-Organization ID is preferred due to performance reasons. Human-readable name for an Organization. Unique identifier for a given User. Human-readable name for a User. Unique identifier for the created API key. HPKE encrypted credential bundle createSubOrganizationResultV6 field subOrganizationId field wallet field walletId field A list of account addresses. item field rootUserIds field item field deletePrivateKeysResult field A list of private key unique identifiers that were removed item field deleteWalletsResult field A list of wallet unique identifiers that were removed item field createReadWriteSessionResultV2 field Unique identifier for a given Organization. If the request is being made by a user and their Sub-Organization ID is unknown, this can be the Parent Organization ID. However, using the Sub-Organization ID is preferred due to performance reasons. Human-readable name for an Organization. Unique identifier for a given User. Human-readable name for a User. Unique identifier for the created API key. HPKE encrypted credential bundle deleteSubOrganizationResult field Unique identifier of the sub organization that was removed initOtpAuthResult field Unique identifier for an OTP authentication otpAuthResult field Unique identifier for the authenticating User. Unique identifier for the created API key. HPKE encrypted credential bundle createSubOrganizationResultV7 field subOrganizationId field wallet field walletId field A list of account addresses. item field rootUserIds field item field updateWalletResult field A Wallet ID. updatePolicyResultV2 field Unique identifier for a given Policy. initOtpAuthResultV2 field Unique identifier for an OTP authentication initOtpResult field Unique identifier for an OTP authentication verifyOtpResult field Signed JWT containing a unique id, expiry, verification type, contact otpLoginResult field Signed JWT containing an expiry, public key, session type, user id, and organization id stampLoginResult field Signed JWT containing an expiry, public key, session type, user id, and organization id oauthLoginResult field Signed JWT containing an expiry, public key, session type, user id, and organization id A list of objects representing a particular User's approval or rejection of a Consensus request, including all relevant metadata. Unique identifier for a given Vote object. Unique identifier for a given User. user field Unique identifier for a given User. Human-readable name for a User. The user's email address. The user's phone number in E.164 format e.g. +13214567890 A list of Authenticator parameters. Types of transports that may be used by an Authenticator (e.g., USB, NFC, BLE). item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` attestationType field Identifier indicating the type of the Security Key. Unique identifier for a WebAuthn credential. The type of Authenticator device. credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given Authenticator. Human-readable name for an Authenticator. createdAt field seconds field nanos field updatedAt field seconds field nanos field A list of API Key parameters. This field, if not needed, should be an empty array in your request body. credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given API Key. Human-readable name for an API Key. createdAt field seconds field nanos field updatedAt field seconds field nanos field Optional window (in seconds) indicating how long the API Key should last. A list of User Tag IDs. item field A list of Oauth Providers. Unique identifier for an OAuth Provider Human-readable name to identify a Provider. The issuer of the token, typically a URL indicating the authentication server, e.g [https://accounts.google.com](https://accounts.google.com) Expected audience ('aud' attribute of the signed token) which represents the app ID Expected subject ('sub' attribute of the signed token) which represents the user ID createdAt field seconds field nanos field updatedAt field seconds field nanos field createdAt field seconds field nanos field updatedAt field seconds field nanos field Unique identifier for a given Activity object. selection field Enum options: `VOTE_SELECTION_APPROVED`, `VOTE_SELECTION_REJECTED` The raw message being signed within a Vote. The public component of a cryptographic key pair used to sign messages and transactions. The signature applied to a particular vote. Method used to produce a signature. createdAt field seconds field nanos field An artifact verifying a User's action. canApprove field canReject field createdAt field seconds field nanos field updatedAt field seconds field nanos field failure field code field message field details field @type field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_activity \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "activityId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activity": { "id": "", "organizationId": "", "status": "", "type": "", "intent": { "createOrganizationIntent": { "organizationName": "", "rootEmail": "", "rootAuthenticator": { "authenticatorName": "", "userId": "", "attestation": { "id": "", "type": "", "rawId": "", "authenticatorAttachment": "", "response": { "clientDataJson": "", "attestationObject": "", "transports": [ "" ], "authenticatorAttachment": "" }, "clientExtensionResults": { "appid": true, "appidExclude": true, "credProps": { "rk": true } } }, "challenge": "" }, "rootUserId": "" }, "createAuthenticatorsIntent": { "authenticators": [ { "authenticatorName": "", "userId": "", "attestation": { "id": "", "type": "", "rawId": "", "authenticatorAttachment": "", "response": { "clientDataJson": "", "attestationObject": "", "transports": [ "" ], "authenticatorAttachment": "" }, "clientExtensionResults": { "appid": true, "appidExclude": true, "credProps": { "rk": true } } }, "challenge": "" } ], "userId": "" }, "createUsersIntent": { "users": [ { "userName": "", "userEmail": "", "accessType": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "userId": "", "attestation": { "id": "", "type": "", "rawId": "", "authenticatorAttachment": "", "response": { "clientDataJson": "", "attestationObject": "", "transports": [ "" ], "authenticatorAttachment": "" }, "clientExtensionResults": { "appid": true, "appidExclude": true, "credProps": { "rk": true } } }, "challenge": "" } ], "userTags": [ "" ] } ] }, "createPrivateKeysIntent": { "privateKeys": [ { "privateKeyName": "", "curve": "", "privateKeyTags": [ "" ], "addressFormats": [ "" ] } ] }, "signRawPayloadIntent": { "privateKeyId": "", "payload": "", "encoding": "", "hashFunction": "" }, "createInvitationsIntent": { "invitations": [ { "receiverUserName": "", "receiverUserEmail": "", "receiverUserTags": [ "" ], "accessType": "", "senderUserId": "" } ] }, "acceptInvitationIntent": { "invitationId": "", "userId": "", "authenticator": { "authenticatorName": "", "userId": "", "attestation": { "id": "", "type": "", "rawId": "", "authenticatorAttachment": "", "response": { "clientDataJson": "", "attestationObject": "", "transports": [ "" ], "authenticatorAttachment": "" }, "clientExtensionResults": { "appid": true, "appidExclude": true, "credProps": { "rk": true } } }, "challenge": "" } }, "createPolicyIntent": { "policyName": "", "selectors": [ { "subject": "", "operator": "", "target": "" } ], "effect": "", "notes": "" }, "disablePrivateKeyIntent": { "privateKeyId": "" }, "deleteUsersIntent": { "userIds": [ "" ] }, "deleteAuthenticatorsIntent": { "userId": "", "authenticatorIds": [ "" ] }, "deleteInvitationIntent": { "invitationId": "" }, "deleteOrganizationIntent": { "organizationId": "" }, "deletePolicyIntent": { "policyId": "" }, "createUserTagIntent": { "userTagName": "", "userIds": [ "" ] }, "deleteUserTagsIntent": { "userTagIds": [ "" ] }, "signTransactionIntent": { "privateKeyId": "", "unsignedTransaction": "", "type": "" }, "createApiKeysIntent": { "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "userId": "" }, "deleteApiKeysIntent": { "userId": "", "apiKeyIds": [ "" ] }, "approveActivityIntent": { "fingerprint": "" }, "rejectActivityIntent": { "fingerprint": "" }, "createPrivateKeyTagIntent": { "privateKeyTagName": "", "privateKeyIds": [ "" ] }, "deletePrivateKeyTagsIntent": { "privateKeyTagIds": [ "" ] }, "createPolicyIntentV2": { "policyName": "", "selectors": [ { "subject": "", "operator": "", "targets": [ "" ] } ], "effect": "", "notes": "" }, "setPaymentMethodIntent": { "number": "", "cvv": "", "expiryMonth": "", "expiryYear": "", "cardHolderEmail": "", "cardHolderName": "" }, "activateBillingTierIntent": { "productId": "" }, "deletePaymentMethodIntent": { "paymentMethodId": "" }, "createPolicyIntentV3": { "policyName": "", "effect": "", "condition": "", "consensus": "", "notes": "" }, "createApiOnlyUsersIntent": { "apiOnlyUsers": [ { "userName": "", "userEmail": "", "userTags": [ "" ], "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ] } ] }, "updateRootQuorumIntent": { "threshold": 123, "userIds": [ "" ] }, "updateUserTagIntent": { "userTagId": "", "newUserTagName": "", "addUserIds": [ "" ], "removeUserIds": [ "" ] }, "updatePrivateKeyTagIntent": { "privateKeyTagId": "", "newPrivateKeyTagName": "", "addPrivateKeyIds": [ "" ], "removePrivateKeyIds": [ "" ] }, "createAuthenticatorsIntentV2": { "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "userId": "" }, "acceptInvitationIntentV2": { "invitationId": "", "userId": "", "authenticator": { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } }, "createOrganizationIntentV2": { "organizationName": "", "rootEmail": "", "rootAuthenticator": { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } }, "rootUserId": "" }, "createUsersIntentV2": { "users": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "userTags": [ "" ] } ] }, "createSubOrganizationIntent": { "name": "", "rootAuthenticator": { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } }, "createSubOrganizationIntentV2": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ] } ], "rootQuorumThreshold": 123 }, "updateAllowedOriginsIntent": { "allowedOrigins": [ "" ] }, "createPrivateKeysIntentV2": { "privateKeys": [ { "privateKeyName": "", "curve": "", "privateKeyTags": [ "" ], "addressFormats": [ "" ] } ] }, "updateUserIntent": { "userId": "", "userName": "", "userEmail": "", "userTagIds": [ "" ], "userPhoneNumber": "" }, "updatePolicyIntent": { "policyId": "", "policyName": "", "policyEffect": "", "policyCondition": "", "policyConsensus": "", "policyNotes": "" }, "setPaymentMethodIntentV2": { "paymentMethodId": "", "cardHolderEmail": "", "cardHolderName": "" }, "createSubOrganizationIntentV3": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ] } ], "rootQuorumThreshold": 123, "privateKeys": [ { "privateKeyName": "", "curve": "", "privateKeyTags": [ "" ], "addressFormats": [ "" ] } ] }, "createWalletIntent": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "createWalletAccountsIntent": { "walletId": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ] }, "initUserEmailRecoveryIntent": { "email": "", "targetPublicKey": "", "expirationSeconds": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" } }, "recoverUserIntent": { "authenticator": { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } }, "userId": "" }, "setOrganizationFeatureIntent": { "name": "", "value": "" }, "removeOrganizationFeatureIntent": { "name": "" }, "signRawPayloadIntentV2": { "signWith": "", "payload": "", "encoding": "", "hashFunction": "" }, "signTransactionIntentV2": { "signWith": "", "unsignedTransaction": "", "type": "" }, "exportPrivateKeyIntent": { "privateKeyId": "", "targetPublicKey": "" }, "exportWalletIntent": { "walletId": "", "targetPublicKey": "", "language": "" }, "createSubOrganizationIntentV4": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ] } ], "rootQuorumThreshold": 123, "wallet": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "disableEmailRecovery": true, "disableEmailAuth": true }, "emailAuthIntent": { "email": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "invalidateExisting": true, "sendFromEmailAddress": "", "sendFromEmailSenderName": "", "replyToEmailAddress": "" }, "exportWalletAccountIntent": { "address": "", "targetPublicKey": "" }, "initImportWalletIntent": { "userId": "" }, "importWalletIntent": { "userId": "", "walletName": "", "encryptedBundle": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ] }, "initImportPrivateKeyIntent": { "userId": "" }, "importPrivateKeyIntent": { "userId": "", "privateKeyName": "", "encryptedBundle": "", "curve": "", "addressFormats": [ "" ] }, "createPoliciesIntent": { "policies": [ { "policyName": "", "effect": "", "condition": "", "consensus": "", "notes": "" } ] }, "signRawPayloadsIntent": { "signWith": "", "payloads": [ "" ], "encoding": "", "hashFunction": "" }, "createReadOnlySessionIntent": "", "createOauthProvidersIntent": { "userId": "", "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] }, "deleteOauthProvidersIntent": { "userId": "", "providerIds": [ "" ] }, "createSubOrganizationIntentV5": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] } ], "rootQuorumThreshold": 123, "wallet": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "disableEmailRecovery": true, "disableEmailAuth": true }, "oauthIntent": { "oidcToken": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true }, "createApiKeysIntentV2": { "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "userId": "" }, "createReadWriteSessionIntent": { "targetPublicKey": "", "email": "", "apiKeyName": "", "expirationSeconds": "" }, "emailAuthIntentV2": { "email": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "invalidateExisting": true, "sendFromEmailAddress": "", "sendFromEmailSenderName": "", "replyToEmailAddress": "" }, "createSubOrganizationIntentV6": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] } ], "rootQuorumThreshold": 123, "wallet": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "disableEmailRecovery": true, "disableEmailAuth": true }, "deletePrivateKeysIntent": { "privateKeyIds": [ "" ], "deleteWithoutExport": true }, "deleteWalletsIntent": { "walletIds": [ "" ], "deleteWithoutExport": true }, "createReadWriteSessionIntentV2": { "targetPublicKey": "", "userId": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true }, "deleteSubOrganizationIntent": { "deleteWithoutExport": true }, "initOtpAuthIntent": { "otpType": "", "contact": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "smsCustomization": { "template": "" }, "userIdentifier": "", "sendFromEmailAddress": "", "sendFromEmailSenderName": "", "replyToEmailAddress": "" }, "otpAuthIntent": { "otpId": "", "otpCode": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true }, "createSubOrganizationIntentV7": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "userPhoneNumber": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] } ], "rootQuorumThreshold": 123, "wallet": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "disableEmailRecovery": true, "disableEmailAuth": true, "disableSmsAuth": true, "disableOtpEmailAuth": true }, "updateWalletIntent": { "walletId": "", "walletName": "" }, "updatePolicyIntentV2": { "policyId": "", "policyName": "", "policyEffect": "", "policyCondition": "", "policyConsensus": "", "policyNotes": "" }, "createUsersIntentV3": { "users": [ { "userName": "", "userEmail": "", "userPhoneNumber": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "oauthProviders": [ { "providerName": "", "oidcToken": "" } ], "userTags": [ "" ] } ] }, "initOtpAuthIntentV2": { "otpType": "", "contact": "", "otpLength": 123, "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "smsCustomization": { "template": "" }, "userIdentifier": "", "sendFromEmailAddress": "", "alphanumeric": true, "sendFromEmailSenderName": "", "replyToEmailAddress": "" }, "initOtpIntent": { "otpType": "", "contact": "", "otpLength": 123, "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "smsCustomization": { "template": "" }, "userIdentifier": "", "sendFromEmailAddress": "", "alphanumeric": true, "sendFromEmailSenderName": "", "expirationSeconds": "", "replyToEmailAddress": "" }, "verifyOtpIntent": { "otpId": "", "otpCode": "", "expirationSeconds": "" }, "otpLoginIntent": { "verificationToken": "", "publicKey": "", "expirationSeconds": "", "invalidateExisting": true }, "stampLoginIntent": { "publicKey": "", "expirationSeconds": "", "invalidateExisting": true }, "oauthLoginIntent": { "oidcToken": "", "publicKey": "", "expirationSeconds": "", "invalidateExisting": true } }, "result": { "createOrganizationResult": { "organizationId": "" }, "createAuthenticatorsResult": { "authenticatorIds": [ "" ] }, "createUsersResult": { "userIds": [ "" ] }, "createPrivateKeysResult": { "privateKeyIds": [ "" ] }, "createInvitationsResult": { "invitationIds": [ "" ] }, "acceptInvitationResult": { "invitationId": "", "userId": "" }, "signRawPayloadResult": { "r": "", "s": "", "v": "" }, "createPolicyResult": { "policyId": "" }, "disablePrivateKeyResult": { "privateKeyId": "" }, "deleteUsersResult": { "userIds": [ "" ] }, "deleteAuthenticatorsResult": { "authenticatorIds": [ "" ] }, "deleteInvitationResult": { "invitationId": "" }, "deleteOrganizationResult": { "organizationId": "" }, "deletePolicyResult": { "policyId": "" }, "createUserTagResult": { "userTagId": "", "userIds": [ "" ] }, "deleteUserTagsResult": { "userTagIds": [ "" ], "userIds": [ "" ] }, "signTransactionResult": { "signedTransaction": "" }, "deleteApiKeysResult": { "apiKeyIds": [ "" ] }, "createApiKeysResult": { "apiKeyIds": [ "" ] }, "createPrivateKeyTagResult": { "privateKeyTagId": "", "privateKeyIds": [ "" ] }, "deletePrivateKeyTagsResult": { "privateKeyTagIds": [ "" ], "privateKeyIds": [ "" ] }, "setPaymentMethodResult": { "lastFour": "", "cardHolderName": "", "cardHolderEmail": "" }, "activateBillingTierResult": { "productId": "" }, "deletePaymentMethodResult": { "paymentMethodId": "" }, "createApiOnlyUsersResult": { "userIds": [ "" ] }, "updateRootQuorumResult": "", "updateUserTagResult": { "userTagId": "" }, "updatePrivateKeyTagResult": { "privateKeyTagId": "" }, "createSubOrganizationResult": { "subOrganizationId": "", "rootUserIds": [ "" ] }, "updateAllowedOriginsResult": "", "createPrivateKeysResultV2": { "privateKeys": [ { "privateKeyId": "", "addresses": [ { "format": "", "address": "" } ] } ] }, "updateUserResult": { "userId": "" }, "updatePolicyResult": { "policyId": "" }, "createSubOrganizationResultV3": { "subOrganizationId": "", "privateKeys": [ { "privateKeyId": "", "addresses": [ { "format": "", "address": "" } ] } ], "rootUserIds": [ "" ] }, "createWalletResult": { "walletId": "", "addresses": [ "" ] }, "createWalletAccountsResult": { "addresses": [ "" ] }, "initUserEmailRecoveryResult": { "userId": "" }, "recoverUserResult": { "authenticatorId": [ "" ] }, "setOrganizationFeatureResult": { "features": [ { "name": "", "value": "" } ] }, "removeOrganizationFeatureResult": { "features": [ { "name": "", "value": "" } ] }, "exportPrivateKeyResult": { "privateKeyId": "", "exportBundle": "" }, "exportWalletResult": { "walletId": "", "exportBundle": "" }, "createSubOrganizationResultV4": { "subOrganizationId": "", "wallet": { "walletId": "", "addresses": [ "" ] }, "rootUserIds": [ "" ] }, "emailAuthResult": { "userId": "", "apiKeyId": "" }, "exportWalletAccountResult": { "address": "", "exportBundle": "" }, "initImportWalletResult": { "importBundle": "" }, "importWalletResult": { "walletId": "", "addresses": [ "" ] }, "initImportPrivateKeyResult": { "importBundle": "" }, "importPrivateKeyResult": { "privateKeyId": "", "addresses": [ { "format": "", "address": "" } ] }, "createPoliciesResult": { "policyIds": [ "" ] }, "signRawPayloadsResult": { "signatures": [ { "r": "", "s": "", "v": "" } ] }, "createReadOnlySessionResult": { "organizationId": "", "organizationName": "", "userId": "", "username": "", "session": "", "sessionExpiry": "" }, "createOauthProvidersResult": { "providerIds": [ "" ] }, "deleteOauthProvidersResult": { "providerIds": [ "" ] }, "createSubOrganizationResultV5": { "subOrganizationId": "", "wallet": { "walletId": "", "addresses": [ "" ] }, "rootUserIds": [ "" ] }, "oauthResult": { "userId": "", "apiKeyId": "", "credentialBundle": "" }, "createReadWriteSessionResult": { "organizationId": "", "organizationName": "", "userId": "", "username": "", "apiKeyId": "", "credentialBundle": "" }, "createSubOrganizationResultV6": { "subOrganizationId": "", "wallet": { "walletId": "", "addresses": [ "" ] }, "rootUserIds": [ "" ] }, "deletePrivateKeysResult": { "privateKeyIds": [ "" ] }, "deleteWalletsResult": { "walletIds": [ "" ] }, "createReadWriteSessionResultV2": { "organizationId": "", "organizationName": "", "userId": "", "username": "", "apiKeyId": "", "credentialBundle": "" }, "deleteSubOrganizationResult": { "subOrganizationUuid": "" }, "initOtpAuthResult": { "otpId": "" }, "otpAuthResult": { "userId": "", "apiKeyId": "", "credentialBundle": "" }, "createSubOrganizationResultV7": { "subOrganizationId": "", "wallet": { "walletId": "", "addresses": [ "" ] }, "rootUserIds": [ "" ] }, "updateWalletResult": { "walletId": "" }, "updatePolicyResultV2": { "policyId": "" }, "initOtpAuthResultV2": { "otpId": "" }, "initOtpResult": { "otpId": "" }, "verifyOtpResult": { "verificationToken": "" }, "otpLoginResult": { "session": "" }, "stampLoginResult": { "session": "" }, "oauthLoginResult": { "session": "" } }, "votes": [ { "id": "", "userId": "", "user": { "userId": "", "userName": "", "userEmail": "", "userPhoneNumber": "", "authenticators": [ { "transports": [ "" ], "attestationType": "", "aaguid": "", "credentialId": "", "model": "", "credential": { "publicKey": "", "type": "" }, "authenticatorId": "", "authenticatorName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ], "apiKeys": [ { "credential": { "publicKey": "", "type": "" }, "apiKeyId": "", "apiKeyName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "expirationSeconds": "" } ], "userTags": [ "" ], "oauthProviders": [ { "providerId": "", "providerName": "", "issuer": "", "audience": "", "subject": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ], "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } }, "activityId": "", "selection": "", "message": "", "publicKey": "", "signature": "", "scheme": "", "createdAt": { "seconds": "", "nanos": "" } } ], "fingerprint": "", "canApprove": true, "canReject": true, "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "failure": { "code": 123, "message": "", "details": [ { "@type": "" } ] } } } } } ``` # Get API key Source: https://docs.turnkey.com/api-reference/queries/get-api-key Get details about an API key export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given API key. A successful response returns the following fields: apiKey field credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given API Key. Human-readable name for an API Key. createdAt field seconds field nanos field updatedAt field seconds field nanos field Optional window (in seconds) indicating how long the API Key should last. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_api_key \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "apiKeyId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "apiKey": { "credential": { "publicKey": "", "type": "" }, "apiKeyId": "", "apiKeyName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "expirationSeconds": "" } } } } ``` # Get API keys Source: https://docs.turnkey.com/api-reference/queries/get-api-keys Get details about API keys for a user export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given User. A successful response returns the following fields: A list of API keys. credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given API Key. Human-readable name for an API Key. createdAt field seconds field nanos field updatedAt field seconds field nanos field Optional window (in seconds) indicating how long the API Key should last. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_api_keys \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "userId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "apiKeys": [ { "credential": { "publicKey": "", "type": "" }, "apiKeyId": "", "apiKeyName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "expirationSeconds": "" } ] } } } ``` # Get Authenticator Source: https://docs.turnkey.com/api-reference/queries/get-authenticator Get details about an authenticator export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given Authenticator. A successful response returns the following fields: authenticator field Types of transports that may be used by an Authenticator (e.g., USB, NFC, BLE). item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` attestationType field Identifier indicating the type of the Security Key. Unique identifier for a WebAuthn credential. The type of Authenticator device. credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given Authenticator. Human-readable name for an Authenticator. createdAt field seconds field nanos field updatedAt field seconds field nanos field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_authenticator \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "authenticatorId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "authenticator": { "transports": [ "" ], "attestationType": "", "aaguid": "", "credentialId": "", "model": "", "credential": { "publicKey": "", "type": "" }, "authenticatorId": "", "authenticatorName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } } } } ``` # Get Authenticators Source: https://docs.turnkey.com/api-reference/queries/get-authenticators Get details about authenticators for a user export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given User. A successful response returns the following fields: A list of authenticators. Types of transports that may be used by an Authenticator (e.g., USB, NFC, BLE). item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` attestationType field Identifier indicating the type of the Security Key. Unique identifier for a WebAuthn credential. The type of Authenticator device. credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given Authenticator. Human-readable name for an Authenticator. createdAt field seconds field nanos field updatedAt field seconds field nanos field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_authenticators \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "userId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "authenticators": [ { "transports": [ "" ], "attestationType": "", "aaguid": "", "credentialId": "", "model": "", "credential": { "publicKey": "", "type": "" }, "authenticatorId": "", "authenticatorName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ] } } } ``` # Get Configs Source: https://docs.turnkey.com/api-reference/queries/get-configs Get quorum settings and features for an organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. A successful response returns the following fields: configs field features field name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` value field quorum field Count of unique approvals required to meet quorum. Unique identifiers of quorum set members. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_organization_configs \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "configs": { "features": [ { "name": "", "value": "" } ], "quorum": { "threshold": 123, "userIds": [ "" ] } } } } } ``` # Get Oauth providers Source: https://docs.turnkey.com/api-reference/queries/get-oauth-providers Get details about Oauth providers for a user export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given User. A successful response returns the following fields: A list of Oauth Providers Unique identifier for an OAuth Provider Human-readable name to identify a Provider. The issuer of the token, typically a URL indicating the authentication server, e.g [https://accounts.google.com](https://accounts.google.com) Expected audience ('aud' attribute of the signed token) which represents the app ID Expected subject ('sub' attribute of the signed token) which represents the user ID createdAt field seconds field nanos field updatedAt field seconds field nanos field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_oauth_providers \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "userId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "oauthProviders": [ { "providerId": "", "providerName": "", "issuer": "", "audience": "", "subject": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ] } } } ``` # Get Policy Source: https://docs.turnkey.com/api-reference/queries/get-policy Get details about a Policy export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given Policy. A successful response returns the following fields: policy field Unique identifier for a given Policy. Human-readable name for a Policy. effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` createdAt field seconds field nanos field updatedAt field seconds field nanos field Human-readable notes added by a User to describe a particular policy. A consensus expression that evalutes to true or false. A condition expression that evalutes to true or false. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_policy \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "policyId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "policy": { "policyId": "", "policyName": "", "effect": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "notes": "", "consensus": "", "condition": "" } } } } ``` # Get Private Key Source: https://docs.turnkey.com/api-reference/queries/get-private-key Get details about a Private Key export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given Private Key. A successful response returns the following fields: privateKey field Unique identifier for a given Private Key. The public component of a cryptographic key pair used to sign messages and transactions. Human-readable name for a Private Key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Derived cryptocurrency addresses for a given Private Key. format field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` address field A list of Private Key Tag IDs. item field createdAt field seconds field nanos field updatedAt field seconds field nanos field True when a given Private Key is exported, false otherwise. True when a given Private Key is imported, false otherwise. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_private_key \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "privateKeyId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "privateKey": { "privateKeyId": "", "publicKey": "", "privateKeyName": "", "curve": "", "addresses": [ { "format": "", "address": "" } ], "privateKeyTags": [ "" ], "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "exported": true, "imported": true } } } } ``` # Get Suborgs Source: https://docs.turnkey.com/api-reference/queries/get-suborgs Get all suborg IDs associated given a parent org ID and an optional filter. export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for the parent Organization. This is used to find sub-organizations within it. Specifies the type of filter to apply, i.e 'CREDENTIAL\_ID', 'NAME', 'USERNAME', 'EMAIL', 'PHONE\_NUMBER', 'OIDC\_TOKEN' or 'PUBLIC\_KEY' The value of the filter to apply for the specified type. For example, a specific email or name string.

paginationOptions field

A limit of the number of object to be returned, between 1 and 100. Defaults to 10. A pagination cursor. This is an object ID that enables you to fetch all objects before this ID. A pagination cursor. This is an object ID that enables you to fetch all objects after this ID.
A successful response returns the following fields: List of unique identifiers for the matching sub-organizations. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/list_suborgs \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "filterType": "", "filterValue": "", "paginationOptions": { "limit": "", "before": "", "after": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "organizationIds": [ "" ] } } } ``` # Get User Source: https://docs.turnkey.com/api-reference/queries/get-user Get details about a User export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given User. A successful response returns the following fields: user field Unique identifier for a given User. Human-readable name for a User. The user's email address. The user's phone number in E.164 format e.g. +13214567890 A list of Authenticator parameters. Types of transports that may be used by an Authenticator (e.g., USB, NFC, BLE). item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` attestationType field Identifier indicating the type of the Security Key. Unique identifier for a WebAuthn credential. The type of Authenticator device. credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given Authenticator. Human-readable name for an Authenticator. createdAt field seconds field nanos field updatedAt field seconds field nanos field A list of API Key parameters. This field, if not needed, should be an empty array in your request body. credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given API Key. Human-readable name for an API Key. createdAt field seconds field nanos field updatedAt field seconds field nanos field Optional window (in seconds) indicating how long the API Key should last. A list of User Tag IDs. item field A list of Oauth Providers. Unique identifier for an OAuth Provider Human-readable name to identify a Provider. The issuer of the token, typically a URL indicating the authentication server, e.g [https://accounts.google.com](https://accounts.google.com) Expected audience ('aud' attribute of the signed token) which represents the app ID Expected subject ('sub' attribute of the signed token) which represents the user ID createdAt field seconds field nanos field updatedAt field seconds field nanos field createdAt field seconds field nanos field updatedAt field seconds field nanos field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_user \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "userId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "user": { "userId": "", "userName": "", "userEmail": "", "userPhoneNumber": "", "authenticators": [ { "transports": [ "" ], "attestationType": "", "aaguid": "", "credentialId": "", "model": "", "credential": { "publicKey": "", "type": "" }, "authenticatorId": "", "authenticatorName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ], "apiKeys": [ { "credential": { "publicKey": "", "type": "" }, "apiKeyId": "", "apiKeyName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "expirationSeconds": "" } ], "userTags": [ "" ], "oauthProviders": [ { "providerId": "", "providerName": "", "issuer": "", "audience": "", "subject": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ], "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } } } } ``` # Get Verified Suborgs Source: https://docs.turnkey.com/api-reference/queries/get-verified-suborgs Get all email or phone verified suborg IDs associated given a parent org ID. export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for the parent Organization. This is used to find sub-organizations within it. Specifies the type of filter to apply, i.e 'EMAIL', 'PHONE\_NUMBER' The value of the filter to apply for the specified type. For example, a specific email or phone number string.

paginationOptions field

A limit of the number of object to be returned, between 1 and 100. Defaults to 10. A pagination cursor. This is an object ID that enables you to fetch all objects before this ID. A pagination cursor. This is an object ID that enables you to fetch all objects after this ID.
A successful response returns the following fields: List of unique identifiers for the matching sub-organizations. item field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/list_verified_suborgs \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "filterType": "", "filterValue": "", "paginationOptions": { "limit": "", "before": "", "after": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "organizationIds": [ "" ] } } } ``` # Get Wallet Source: https://docs.turnkey.com/api-reference/queries/get-wallet Get details about a Wallet export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given Wallet. A successful response returns the following fields: wallet field Unique identifier for a given Wallet. Human-readable name for a Wallet. createdAt field seconds field nanos field updatedAt field seconds field nanos field True when a given Wallet is exported, false otherwise. True when a given Wallet is imported, false otherwise. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_wallet \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "walletId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "wallet": { "walletId": "", "walletName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "exported": true, "imported": true } } } } ``` # Get Wallet Account Source: https://docs.turnkey.com/api-reference/queries/get-wallet-account Get a single wallet account export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given Wallet. Address corresponding to a Wallet Account. Path corresponding to a Wallet Account. A successful response returns the following fields: account field Unique identifier for a given Wallet Account. The Organization the Account belongs to. The Wallet the Account was derived from. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate the Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Address generated using the Wallet seed and Account parameters. createdAt field seconds field nanos field updatedAt field seconds field nanos field The public component of this wallet account's underlying cryptographic key pair. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/get_wallet_account \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "walletId": "", "address": "", "path": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "account": { "walletAccountId": "", "organizationId": "", "walletId": "", "curve": "", "pathFormat": "", "path": "", "addressFormat": "", "address": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "publicKey": "" } } } } ``` # List Activities Source: https://docs.turnkey.com/api-reference/queries/list-activities List all Activities within an Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Enum options: `ACTIVITY_STATUS_CREATED`, `ACTIVITY_STATUS_PENDING`, `ACTIVITY_STATUS_COMPLETED`, `ACTIVITY_STATUS_FAILED`, `ACTIVITY_STATUS_CONSENSUS_NEEDED`, `ACTIVITY_STATUS_REJECTED`

paginationOptions field

A limit of the number of object to be returned, between 1 and 100. Defaults to 10. A pagination cursor. This is an object ID that enables you to fetch all objects before this ID. A pagination cursor. This is an object ID that enables you to fetch all objects after this ID.
Enum options: `ACTIVITY_TYPE_CREATE_API_KEYS`, `ACTIVITY_TYPE_CREATE_USERS`, `ACTIVITY_TYPE_CREATE_PRIVATE_KEYS`, `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD`, `ACTIVITY_TYPE_CREATE_INVITATIONS`, `ACTIVITY_TYPE_ACCEPT_INVITATION`, `ACTIVITY_TYPE_CREATE_POLICY`, `ACTIVITY_TYPE_DISABLE_PRIVATE_KEY`, `ACTIVITY_TYPE_DELETE_USERS`, `ACTIVITY_TYPE_DELETE_API_KEYS`, `ACTIVITY_TYPE_DELETE_INVITATION`, `ACTIVITY_TYPE_DELETE_ORGANIZATION`, `ACTIVITY_TYPE_DELETE_POLICY`, `ACTIVITY_TYPE_CREATE_USER_TAG`, `ACTIVITY_TYPE_DELETE_USER_TAGS`, `ACTIVITY_TYPE_CREATE_ORGANIZATION`, `ACTIVITY_TYPE_SIGN_TRANSACTION`, `ACTIVITY_TYPE_APPROVE_ACTIVITY`, `ACTIVITY_TYPE_REJECT_ACTIVITY`, `ACTIVITY_TYPE_DELETE_AUTHENTICATORS`, `ACTIVITY_TYPE_CREATE_AUTHENTICATORS`, `ACTIVITY_TYPE_CREATE_PRIVATE_KEY_TAG`, `ACTIVITY_TYPE_DELETE_PRIVATE_KEY_TAGS`, `ACTIVITY_TYPE_SET_PAYMENT_METHOD`, `ACTIVITY_TYPE_ACTIVATE_BILLING_TIER`, `ACTIVITY_TYPE_DELETE_PAYMENT_METHOD`, `ACTIVITY_TYPE_CREATE_POLICY_V2`, `ACTIVITY_TYPE_CREATE_POLICY_V3`, `ACTIVITY_TYPE_CREATE_API_ONLY_USERS`, `ACTIVITY_TYPE_UPDATE_ROOT_QUORUM`, `ACTIVITY_TYPE_UPDATE_USER_TAG`, `ACTIVITY_TYPE_UPDATE_PRIVATE_KEY_TAG`, `ACTIVITY_TYPE_CREATE_AUTHENTICATORS_V2`, `ACTIVITY_TYPE_CREATE_ORGANIZATION_V2`, `ACTIVITY_TYPE_CREATE_USERS_V2`, `ACTIVITY_TYPE_ACCEPT_INVITATION_V2`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V2`, `ACTIVITY_TYPE_UPDATE_ALLOWED_ORIGINS`, `ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2`, `ACTIVITY_TYPE_UPDATE_USER`, `ACTIVITY_TYPE_UPDATE_POLICY`, `ACTIVITY_TYPE_SET_PAYMENT_METHOD_V2`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V3`, `ACTIVITY_TYPE_CREATE_WALLET`, `ACTIVITY_TYPE_CREATE_WALLET_ACCOUNTS`, `ACTIVITY_TYPE_INIT_USER_EMAIL_RECOVERY`, `ACTIVITY_TYPE_RECOVER_USER`, `ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE`, `ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE`, `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2`, `ACTIVITY_TYPE_SIGN_TRANSACTION_V2`, `ACTIVITY_TYPE_EXPORT_PRIVATE_KEY`, `ACTIVITY_TYPE_EXPORT_WALLET`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V4`, `ACTIVITY_TYPE_EMAIL_AUTH`, `ACTIVITY_TYPE_EXPORT_WALLET_ACCOUNT`, `ACTIVITY_TYPE_INIT_IMPORT_WALLET`, `ACTIVITY_TYPE_IMPORT_WALLET`, `ACTIVITY_TYPE_INIT_IMPORT_PRIVATE_KEY`, `ACTIVITY_TYPE_IMPORT_PRIVATE_KEY`, `ACTIVITY_TYPE_CREATE_POLICIES`, `ACTIVITY_TYPE_SIGN_RAW_PAYLOADS`, `ACTIVITY_TYPE_CREATE_READ_ONLY_SESSION`, `ACTIVITY_TYPE_CREATE_OAUTH_PROVIDERS`, `ACTIVITY_TYPE_DELETE_OAUTH_PROVIDERS`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V5`, `ACTIVITY_TYPE_OAUTH`, `ACTIVITY_TYPE_CREATE_API_KEYS_V2`, `ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION`, `ACTIVITY_TYPE_EMAIL_AUTH_V2`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V6`, `ACTIVITY_TYPE_DELETE_PRIVATE_KEYS`, `ACTIVITY_TYPE_DELETE_WALLETS`, `ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2`, `ACTIVITY_TYPE_DELETE_SUB_ORGANIZATION`, `ACTIVITY_TYPE_INIT_OTP_AUTH`, `ACTIVITY_TYPE_OTP_AUTH`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V7`, `ACTIVITY_TYPE_UPDATE_WALLET`, `ACTIVITY_TYPE_UPDATE_POLICY_V2`, `ACTIVITY_TYPE_CREATE_USERS_V3`, `ACTIVITY_TYPE_INIT_OTP_AUTH_V2`, `ACTIVITY_TYPE_INIT_OTP`, `ACTIVITY_TYPE_VERIFY_OTP`, `ACTIVITY_TYPE_OTP_LOGIN`, `ACTIVITY_TYPE_STAMP_LOGIN`, `ACTIVITY_TYPE_OAUTH_LOGIN` A successful response returns the following fields: A list of Activities. Unique identifier for a given Activity object. Unique identifier for a given Organization. status field Enum options: `ACTIVITY_STATUS_CREATED`, `ACTIVITY_STATUS_PENDING`, `ACTIVITY_STATUS_COMPLETED`, `ACTIVITY_STATUS_FAILED`, `ACTIVITY_STATUS_CONSENSUS_NEEDED`, `ACTIVITY_STATUS_REJECTED` type field Enum options: `ACTIVITY_TYPE_CREATE_API_KEYS`, `ACTIVITY_TYPE_CREATE_USERS`, `ACTIVITY_TYPE_CREATE_PRIVATE_KEYS`, `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD`, `ACTIVITY_TYPE_CREATE_INVITATIONS`, `ACTIVITY_TYPE_ACCEPT_INVITATION`, `ACTIVITY_TYPE_CREATE_POLICY`, `ACTIVITY_TYPE_DISABLE_PRIVATE_KEY`, `ACTIVITY_TYPE_DELETE_USERS`, `ACTIVITY_TYPE_DELETE_API_KEYS`, `ACTIVITY_TYPE_DELETE_INVITATION`, `ACTIVITY_TYPE_DELETE_ORGANIZATION`, `ACTIVITY_TYPE_DELETE_POLICY`, `ACTIVITY_TYPE_CREATE_USER_TAG`, `ACTIVITY_TYPE_DELETE_USER_TAGS`, `ACTIVITY_TYPE_CREATE_ORGANIZATION`, `ACTIVITY_TYPE_SIGN_TRANSACTION`, `ACTIVITY_TYPE_APPROVE_ACTIVITY`, `ACTIVITY_TYPE_REJECT_ACTIVITY`, `ACTIVITY_TYPE_DELETE_AUTHENTICATORS`, `ACTIVITY_TYPE_CREATE_AUTHENTICATORS`, `ACTIVITY_TYPE_CREATE_PRIVATE_KEY_TAG`, `ACTIVITY_TYPE_DELETE_PRIVATE_KEY_TAGS`, `ACTIVITY_TYPE_SET_PAYMENT_METHOD`, `ACTIVITY_TYPE_ACTIVATE_BILLING_TIER`, `ACTIVITY_TYPE_DELETE_PAYMENT_METHOD`, `ACTIVITY_TYPE_CREATE_POLICY_V2`, `ACTIVITY_TYPE_CREATE_POLICY_V3`, `ACTIVITY_TYPE_CREATE_API_ONLY_USERS`, `ACTIVITY_TYPE_UPDATE_ROOT_QUORUM`, `ACTIVITY_TYPE_UPDATE_USER_TAG`, `ACTIVITY_TYPE_UPDATE_PRIVATE_KEY_TAG`, `ACTIVITY_TYPE_CREATE_AUTHENTICATORS_V2`, `ACTIVITY_TYPE_CREATE_ORGANIZATION_V2`, `ACTIVITY_TYPE_CREATE_USERS_V2`, `ACTIVITY_TYPE_ACCEPT_INVITATION_V2`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V2`, `ACTIVITY_TYPE_UPDATE_ALLOWED_ORIGINS`, `ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2`, `ACTIVITY_TYPE_UPDATE_USER`, `ACTIVITY_TYPE_UPDATE_POLICY`, `ACTIVITY_TYPE_SET_PAYMENT_METHOD_V2`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V3`, `ACTIVITY_TYPE_CREATE_WALLET`, `ACTIVITY_TYPE_CREATE_WALLET_ACCOUNTS`, `ACTIVITY_TYPE_INIT_USER_EMAIL_RECOVERY`, `ACTIVITY_TYPE_RECOVER_USER`, `ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE`, `ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE`, `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2`, `ACTIVITY_TYPE_SIGN_TRANSACTION_V2`, `ACTIVITY_TYPE_EXPORT_PRIVATE_KEY`, `ACTIVITY_TYPE_EXPORT_WALLET`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V4`, `ACTIVITY_TYPE_EMAIL_AUTH`, `ACTIVITY_TYPE_EXPORT_WALLET_ACCOUNT`, `ACTIVITY_TYPE_INIT_IMPORT_WALLET`, `ACTIVITY_TYPE_IMPORT_WALLET`, `ACTIVITY_TYPE_INIT_IMPORT_PRIVATE_KEY`, `ACTIVITY_TYPE_IMPORT_PRIVATE_KEY`, `ACTIVITY_TYPE_CREATE_POLICIES`, `ACTIVITY_TYPE_SIGN_RAW_PAYLOADS`, `ACTIVITY_TYPE_CREATE_READ_ONLY_SESSION`, `ACTIVITY_TYPE_CREATE_OAUTH_PROVIDERS`, `ACTIVITY_TYPE_DELETE_OAUTH_PROVIDERS`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V5`, `ACTIVITY_TYPE_OAUTH`, `ACTIVITY_TYPE_CREATE_API_KEYS_V2`, `ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION`, `ACTIVITY_TYPE_EMAIL_AUTH_V2`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V6`, `ACTIVITY_TYPE_DELETE_PRIVATE_KEYS`, `ACTIVITY_TYPE_DELETE_WALLETS`, `ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2`, `ACTIVITY_TYPE_DELETE_SUB_ORGANIZATION`, `ACTIVITY_TYPE_INIT_OTP_AUTH`, `ACTIVITY_TYPE_OTP_AUTH`, `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V7`, `ACTIVITY_TYPE_UPDATE_WALLET`, `ACTIVITY_TYPE_UPDATE_POLICY_V2`, `ACTIVITY_TYPE_CREATE_USERS_V3`, `ACTIVITY_TYPE_INIT_OTP_AUTH_V2`, `ACTIVITY_TYPE_INIT_OTP`, `ACTIVITY_TYPE_VERIFY_OTP`, `ACTIVITY_TYPE_OTP_LOGIN`, `ACTIVITY_TYPE_STAMP_LOGIN`, `ACTIVITY_TYPE_OAUTH_LOGIN` intent field createOrganizationIntent field Human-readable name for an Organization. The root user's email address. rootAuthenticator field Human-readable name for an Authenticator. Unique identifier for a given User. attestation field id field type field Enum options: `public-key` rawId field authenticatorAttachment field Enum options: `cross-platform`, `platform` response field clientDataJson field attestationObject field transports field item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` authenticatorAttachment field Enum options: `cross-platform`, `platform` clientExtensionResults field appid field appidExclude field credProps field rk field Challenge presented for authentication purposes. Unique identifier for the root user object. createAuthenticatorsIntent field A list of Authenticators. Human-readable name for an Authenticator. Unique identifier for a given User. attestation field id field type field Enum options: `public-key` rawId field authenticatorAttachment field Enum options: `cross-platform`, `platform` response field clientDataJson field attestationObject field transports field item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` authenticatorAttachment field Enum options: `cross-platform`, `platform` clientExtensionResults field appid field appidExclude field credProps field rk field Challenge presented for authentication purposes. Unique identifier for a given User. createUsersIntent field A list of Users. Human-readable name for a User. The user's email address. accessType field Enum options: `ACCESS_TYPE_WEB`, `ACCESS_TYPE_API`, `ACCESS_TYPE_ALL` A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Unique identifier for a given User. attestation field id field type field Enum options: `public-key` rawId field authenticatorAttachment field Enum options: `cross-platform`, `platform` response field clientDataJson field attestationObject field transports field item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` authenticatorAttachment field Enum options: `cross-platform`, `platform` clientExtensionResults field appid field appidExclude field credProps field rk field Challenge presented for authentication purposes. A list of User Tag IDs. This field, if not needed, should be an empty array in your request body. item field createPrivateKeysIntent field A list of Private Keys. Human-readable name for a Private Key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` A list of Private Key Tag IDs. This field, if not needed, should be an empty array in your request body. item field Cryptocurrency-specific formats for a derived address (e.g., Ethereum). item field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` signRawPayloadIntent field Unique identifier for a given Private Key. Raw unsigned payload to be signed. encoding field Enum options: `PAYLOAD_ENCODING_HEXADECIMAL`, `PAYLOAD_ENCODING_TEXT_UTF8` hashFunction field Enum options: `HASH_FUNCTION_NO_OP`, `HASH_FUNCTION_SHA256`, `HASH_FUNCTION_KECCAK256`, `HASH_FUNCTION_NOT_APPLICABLE` createInvitationsIntent field A list of Invitations. The name of the intended Invitation recipient. The email address of the intended Invitation recipient. A list of tags assigned to the Invitation recipient. This field, if not needed, should be an empty array in your request body. item field accessType field Enum options: `ACCESS_TYPE_WEB`, `ACCESS_TYPE_API`, `ACCESS_TYPE_ALL` Unique identifier for the Sender of an Invitation. acceptInvitationIntent field Unique identifier for a given Invitation object. Unique identifier for a given User. authenticator field Human-readable name for an Authenticator. Unique identifier for a given User. attestation field id field type field Enum options: `public-key` rawId field authenticatorAttachment field Enum options: `cross-platform`, `platform` response field clientDataJson field attestationObject field transports field item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` authenticatorAttachment field Enum options: `cross-platform`, `platform` clientExtensionResults field appid field appidExclude field credProps field rk field Challenge presented for authentication purposes. createPolicyIntent field Human-readable name for a Policy. A list of simple functions each including a subject, target and boolean. See Policy Engine Language section for additional details. subject field operator field Enum options: `OPERATOR_EQUAL`, `OPERATOR_MORE_THAN`, `OPERATOR_MORE_THAN_OR_EQUAL`, `OPERATOR_LESS_THAN`, `OPERATOR_LESS_THAN_OR_EQUAL`, `OPERATOR_CONTAINS`, `OPERATOR_NOT_EQUAL`, `OPERATOR_IN`, `OPERATOR_NOT_IN`, `OPERATOR_CONTAINS_ONE`, `OPERATOR_CONTAINS_ALL` target field effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` notes field disablePrivateKeyIntent field Unique identifier for a given Private Key. deleteUsersIntent field A list of User IDs. item field deleteAuthenticatorsIntent field Unique identifier for a given User. A list of Authenticator IDs. item field deleteInvitationIntent field Unique identifier for a given Invitation object. deleteOrganizationIntent field Unique identifier for a given Organization. deletePolicyIntent field Unique identifier for a given Policy. createUserTagIntent field Human-readable name for a User Tag. A list of User IDs. item field deleteUserTagsIntent field A list of User Tag IDs. item field signTransactionIntent field Unique identifier for a given Private Key. Raw unsigned transaction to be signed by a particular Private Key. type field Enum options: `TRANSACTION_TYPE_ETHEREUM`, `TRANSACTION_TYPE_SOLANA`, `TRANSACTION_TYPE_TRON` createApiKeysIntent field A list of API Keys. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. Unique identifier for a given User. deleteApiKeysIntent field Unique identifier for a given User. A list of API Key IDs. item field approveActivityIntent field An artifact verifying a User's action. rejectActivityIntent field An artifact verifying a User's action. createPrivateKeyTagIntent field Human-readable name for a Private Key Tag. A list of Private Key IDs. item field deletePrivateKeyTagsIntent field A list of Private Key Tag IDs. item field createPolicyIntentV2 field Human-readable name for a Policy. A list of simple functions each including a subject, target and boolean. See Policy Engine Language section for additional details. subject field operator field Enum options: `OPERATOR_EQUAL`, `OPERATOR_MORE_THAN`, `OPERATOR_MORE_THAN_OR_EQUAL`, `OPERATOR_LESS_THAN`, `OPERATOR_LESS_THAN_OR_EQUAL`, `OPERATOR_CONTAINS`, `OPERATOR_NOT_EQUAL`, `OPERATOR_IN`, `OPERATOR_NOT_IN`, `OPERATOR_CONTAINS_ONE`, `OPERATOR_CONTAINS_ALL` targets field item field effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` notes field setPaymentMethodIntent field The account number of the customer's credit card. The verification digits of the customer's credit card. The month that the credit card expires. The year that the credit card expires. The email that will receive invoices for the credit card. The name associated with the credit card. activateBillingTierIntent field The product that the customer wants to subscribe to. deletePaymentMethodIntent field The payment method that the customer wants to remove. createPolicyIntentV3 field Human-readable name for a Policy. effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect The consensus expression that triggers the Effect notes field createApiOnlyUsersIntent field A list of API-only Users to create. The name of the new API-only User. The email address for this API-only User (optional). A list of tags assigned to the new API-only User. This field, if not needed, should be an empty array in your request body. item field A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. updateRootQuorumIntent field The threshold of unique approvals to reach quorum. The unique identifiers of users who comprise the quorum set. item field updateUserTagIntent field Unique identifier for a given User Tag. The new, human-readable name for the tag with the given ID. A list of User IDs to add this tag to. item field A list of User IDs to remove this tag from. item field updatePrivateKeyTagIntent field Unique identifier for a given Private Key Tag. The new, human-readable name for the tag with the given ID. A list of Private Keys IDs to add this tag to. item field A list of Private Key IDs to remove this tag from. item field createAuthenticatorsIntentV2 field A list of Authenticators. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` Unique identifier for a given User. acceptInvitationIntentV2 field Unique identifier for a given Invitation object. Unique identifier for a given User. authenticator field Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` createOrganizationIntentV2 field Human-readable name for an Organization. The root user's email address. rootAuthenticator field Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` Unique identifier for the root user object. createUsersIntentV2 field A list of Users. Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` A list of User Tag IDs. This field, if not needed, should be an empty array in your request body. item field createSubOrganizationIntent field Name for this sub-organization rootAuthenticator field Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` createSubOrganizationIntentV2 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users updateAllowedOriginsIntent field Additional origins requests are allowed from besides Turnkey origins item field createPrivateKeysIntentV2 field A list of Private Keys. Human-readable name for a Private Key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` A list of Private Key Tag IDs. This field, if not needed, should be an empty array in your request body. item field Cryptocurrency-specific formats for a derived address (e.g., Ethereum). item field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` updateUserIntent field Unique identifier for a given User. Human-readable name for a User. The user's email address. An updated list of User Tags to apply to this User. This field, if not needed, should be an empty array in your request body. item field The user's phone number in E.164 format e.g. +13214567890 updatePolicyIntent field Unique identifier for a given Policy. Human-readable name for a Policy. policyEffect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect (optional). The consensus expression that triggers the Effect (optional). Accompanying notes for a Policy (optional). setPaymentMethodIntentV2 field The id of the payment method that was created clientside. The email that will receive invoices for the credit card. The name associated with the credit card. createSubOrganizationIntentV3 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users A list of Private Keys. Human-readable name for a Private Key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` A list of Private Key Tag IDs. This field, if not needed, should be an empty array in your request body. item field Cryptocurrency-specific formats for a derived address (e.g., Ethereum). item field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` createWalletIntent field Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. createWalletAccountsIntent field Unique identifier for a given Wallet. A list of wallet Accounts. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` initUserEmailRecoveryIntent field Email of the user starting recovery Client-side public key generated by the user, to which the recovery bundle will be encrypted. Expiration window (in seconds) indicating how long the recovery credential is valid for. If not provided, a default of 15 minutes will be used. emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. recoverUserIntent field authenticator field Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` Unique identifier for the user performing recovery. setOrganizationFeatureIntent field name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` Optional value for the feature. Will override existing values if feature is already set. removeOrganizationFeatureIntent field name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` signRawPayloadIntentV2 field A Wallet account address, Private Key address, or Private Key identifier. Raw unsigned payload to be signed. encoding field Enum options: `PAYLOAD_ENCODING_HEXADECIMAL`, `PAYLOAD_ENCODING_TEXT_UTF8` hashFunction field Enum options: `HASH_FUNCTION_NO_OP`, `HASH_FUNCTION_SHA256`, `HASH_FUNCTION_KECCAK256`, `HASH_FUNCTION_NOT_APPLICABLE` signTransactionIntentV2 field A Wallet account address, Private Key address, or Private Key identifier. Raw unsigned transaction to be signed type field Enum options: `TRANSACTION_TYPE_ETHEREUM`, `TRANSACTION_TYPE_SOLANA`, `TRANSACTION_TYPE_TRON` exportPrivateKeyIntent field Unique identifier for a given Private Key. Client-side public key generated by the user, to which the export bundle will be encrypted. exportWalletIntent field Unique identifier for a given Wallet. Client-side public key generated by the user, to which the export bundle will be encrypted. language field Enum options: `MNEMONIC_LANGUAGE_ENGLISH`, `MNEMONIC_LANGUAGE_SIMPLIFIED_CHINESE`, `MNEMONIC_LANGUAGE_TRADITIONAL_CHINESE`, `MNEMONIC_LANGUAGE_CZECH`, `MNEMONIC_LANGUAGE_FRENCH`, `MNEMONIC_LANGUAGE_ITALIAN`, `MNEMONIC_LANGUAGE_JAPANESE`, `MNEMONIC_LANGUAGE_KOREAN`, `MNEMONIC_LANGUAGE_SPANISH` createSubOrganizationIntentV4 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users wallet field Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. Disable email recovery for the sub-organization Disable email auth for the sub-organization emailAuthIntent field Email of the authenticating user. Client-side public key generated by the user, to which the email auth bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to Email Auth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. Invalidate all other previously generated Email Auth API keys Optional custom email address from which to send the email Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to exportWalletAccountIntent field Address to identify Wallet Account. Client-side public key generated by the user, to which the export bundle will be encrypted. initImportWalletIntent field The ID of the User importing a Wallet. importWalletIntent field The ID of the User importing a Wallet. Human-readable name for a Wallet. Bundle containing a wallet mnemonic encrypted to the enclave's target public key. A list of wallet Accounts. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` initImportPrivateKeyIntent field The ID of the User importing a Private Key. importPrivateKeyIntent field The ID of the User importing a Private Key. Human-readable name for a Private Key. Bundle containing a raw private key encrypted to the enclave's target public key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Cryptocurrency-specific formats for a derived address (e.g., Ethereum). item field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` createPoliciesIntent field An array of policy intents to be created. Human-readable name for a Policy. effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect The consensus expression that triggers the Effect notes field signRawPayloadsIntent field A Wallet account address, Private Key address, or Private Key identifier. An array of raw unsigned payloads to be signed. item field encoding field Enum options: `PAYLOAD_ENCODING_HEXADECIMAL`, `PAYLOAD_ENCODING_TEXT_UTF8` hashFunction field Enum options: `HASH_FUNCTION_NO_OP`, `HASH_FUNCTION_SHA256`, `HASH_FUNCTION_KECCAK256`, `HASH_FUNCTION_NOT_APPLICABLE` createReadOnlySessionIntent field createOauthProvidersIntent field The ID of the User to add an Oauth provider to A list of Oauth providers. Human-readable name to identify a Provider. Base64 encoded OIDC token deleteOauthProvidersIntent field The ID of the User to remove an Oauth provider from Unique identifier for a given Provider. item field createSubOrganizationIntentV5 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` A list of Oauth providers. This field, if not needed, should be an empty array in your request body. Human-readable name to identify a Provider. Base64 encoded OIDC token The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users wallet field Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. Disable email recovery for the sub-organization Disable email auth for the sub-organization oauthIntent field Base64 encoded OIDC token Client-side public key generated by the user, to which the oauth bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to Oauth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Oauth API keys createApiKeysIntentV2 field A list of API Keys. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. curveType field Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last. Unique identifier for a given User. createReadWriteSessionIntent field Client-side public key generated by the user, to which the read write session bundle (credentials) will be encrypted. Email of the user to create a read write session for Optional human-readable name for an API Key. If none provided, default to Read Write Session - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. emailAuthIntentV2 field Email of the authenticating user. Client-side public key generated by the user, to which the email auth bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to Email Auth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. Invalidate all other previously generated Email Auth API keys Optional custom email address from which to send the email Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to createSubOrganizationIntentV6 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. curveType field Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` A list of Oauth providers. This field, if not needed, should be an empty array in your request body. Human-readable name to identify a Provider. Base64 encoded OIDC token The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users wallet field Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. Disable email recovery for the sub-organization Disable email auth for the sub-organization deletePrivateKeysIntent field List of unique identifiers for private keys within an organization item field Optional parameter for deleting the private keys, even if any have not been previously exported. If they have been exported, this field is ignored. deleteWalletsIntent field List of unique identifiers for wallets within an organization item field Optional parameter for deleting the wallets, even if any have not been previously exported. If they have been exported, this field is ignored. createReadWriteSessionIntentV2 field Client-side public key generated by the user, to which the read write session bundle (credentials) will be encrypted. Unique identifier for a given User. Optional human-readable name for an API Key. If none provided, default to Read Write Session - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated ReadWriteSession API keys deleteSubOrganizationIntent field Sub-organization deletion, by default, requires associated wallets and private keys to be exported for security reasons. Set this boolean to true to force sub-organization deletion even if some wallets or private keys within it have not been exported yet. Default: false. initOtpAuthIntent field Enum to specifiy whether to send OTP via SMS or email Email or phone number to send the OTP code to emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. smsCustomization field Template containing references to .OtpCode i.e Your OTP is \{\{.OtpCode}} Optional client-generated user identifier to enable per-user rate limiting for SMS auth. We recommend using a hash of the client-side IP address. Optional custom email address from which to send the OTP email Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to otpAuthIntent field ID representing the result of an init OTP activity. OTP sent out to a user's contact (email or SMS) Client-side public key generated by the user, to which the OTP bundle (credentials) will be encrypted. Optional human-readable name for an API Key. If none provided, default to OTP Auth - \ Expiration window (in seconds) indicating how long the API key is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated OTP Auth API keys createSubOrganizationIntentV7 field Name for this sub-organization Root users to create within this sub-organization Human-readable name for a User. The user's email address. The user's phone number in E.164 format e.g. +13214567890 A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. curveType field Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` A list of Oauth providers. This field, if not needed, should be an empty array in your request body. Human-readable name to identify a Provider. Base64 encoded OIDC token The threshold of unique approvals to reach root quorum. This value must be less than or equal to the number of root users wallet field Human-readable name for a Wallet. A list of wallet Accounts. This field, if not needed, should be an empty array in your request body. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate a wallet Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Length of mnemonic to generate the Wallet seed. Defaults to 12. Accepted values: 12, 15, 18, 21, 24. Disable email recovery for the sub-organization Disable email auth for the sub-organization Disable OTP SMS auth for the sub-organization Disable OTP email auth for the sub-organization updateWalletIntent field Unique identifier for a given Wallet. Human-readable name for a Wallet. updatePolicyIntentV2 field Unique identifier for a given Policy. Human-readable name for a Policy. policyEffect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` The condition expression that triggers the Effect (optional). The consensus expression that triggers the Effect (optional). Accompanying notes for a Policy (optional). createUsersIntentV3 field A list of Users. Human-readable name for a User. The user's email address. The user's phone number in E.164 format e.g. +13214567890 A list of API Key parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an API Key. The public component of a cryptographic key pair used to sign messages and transactions. curveType field Enum options: `API_KEY_CURVE_P256`, `API_KEY_CURVE_SECP256K1`, `API_KEY_CURVE_ED25519` Optional window (in seconds) indicating how long the API Key should last. A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. Human-readable name for an Authenticator. Challenge presented for authentication purposes. attestation field The cbor encoded then base64 url encoded id of the credential. A base64 url encoded payload containing metadata about the signing context and the challenge. A base64 url encoded payload containing authenticator data and any attestation the webauthn provider chooses. The type of authenticator transports. item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` A list of Oauth providers. This field, if not needed, should be an empty array in your request body. Human-readable name to identify a Provider. Base64 encoded OIDC token A list of User Tag IDs. This field, if not needed, should be an empty array in your request body. item field initOtpAuthIntentV2 field Enum to specifiy whether to send OTP via SMS or email Email or phone number to send the OTP code to Optional length of the OTP code. Default = 9 emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. smsCustomization field Template containing references to .OtpCode i.e Your OTP is \{\{.OtpCode}} Optional client-generated user identifier to enable per-user rate limiting for SMS auth. We recommend using a hash of the client-side IP address. Optional custom email address from which to send the OTP email Optional flag to specify if the OTP code should be alphanumeric (Crockford’s Base32). Default = true Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Optional custom email address to use as reply-to initOtpIntent field Whether to send OTP via SMS or email. Possible values: OTP\_TYPE\_SMS, OTP\_TYPE\_EMAIL Email or phone number to send the OTP code to Optional length of the OTP code. Default = 9 emailCustomization field The name of the application. A URL pointing to a logo in PNG format. Note this logo will be resized to fit into 340px x 124px. A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. JSON object containing key/value pairs to be used with custom templates. Unique identifier for a given Email Template. If not specified, the default is the most recent Email Template. smsCustomization field Template containing references to .OtpCode i.e Your OTP is \{\{.OtpCode}} Optional client-generated user identifier to enable per-user rate limiting for SMS auth. We recommend using a hash of the client-side IP address. Optional custom email address from which to send the OTP email Optional flag to specify if the OTP code should be alphanumeric (Crockford’s Base32). Default = true Optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications' Expiration window (in seconds) indicating how long the OTP is valid for. If not provided, a default of 5 minutes will be used. Maximum value is 600 seconds (10 minutes) Optional custom email address to use as reply-to verifyOtpIntent field ID representing the result of an init OTP activity. OTP sent out to a user's contact (email or SMS) Expiration window (in seconds) indicating how long the verification token is valid for. If not provided, a default of 1 hour will be used. Maximum value is 86400 seconds (24 hours) otpLoginIntent field Signed JWT containing a unique id, expiry, verification type, contact Client-side public key generated by the user, which will be conditionally added to org data based on the validity of the verification token Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys stampLoginIntent field Client-side public key generated by the user, which will be conditionally added to org data based on the passkey stamp associated with this request Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys oauthLoginIntent field Base64 encoded OIDC token Client-side public key generated by the user, which will be conditionally added to org data based on the validity of the oidc token associated with this request Expiration window (in seconds) indicating how long the Session is valid for. If not provided, a default of 15 minutes will be used. Invalidate all other previously generated Login API keys result field createOrganizationResult field Unique identifier for a given Organization. createAuthenticatorsResult field A list of Authenticator IDs. item field createUsersResult field A list of User IDs. item field createPrivateKeysResult field A list of Private Key IDs. item field createInvitationsResult field A list of Invitation IDs item field acceptInvitationResult field Unique identifier for a given Invitation. Unique identifier for a given User. signRawPayloadResult field Component of an ECSDA signature. Component of an ECSDA signature. Component of an ECSDA signature. createPolicyResult field Unique identifier for a given Policy. disablePrivateKeyResult field Unique identifier for a given Private Key. deleteUsersResult field A list of User IDs. item field deleteAuthenticatorsResult field Unique identifier for a given Authenticator. item field deleteInvitationResult field Unique identifier for a given Invitation. deleteOrganizationResult field Unique identifier for a given Organization. deletePolicyResult field Unique identifier for a given Policy. createUserTagResult field Unique identifier for a given User Tag. A list of User IDs. item field deleteUserTagsResult field A list of User Tag IDs. item field A list of User IDs. item field signTransactionResult field signedTransaction field deleteApiKeysResult field A list of API Key IDs. item field createApiKeysResult field A list of API Key IDs. item field createPrivateKeyTagResult field Unique identifier for a given Private Key Tag. A list of Private Key IDs. item field deletePrivateKeyTagsResult field A list of Private Key Tag IDs. item field A list of Private Key IDs. item field setPaymentMethodResult field The last four digits of the credit card added. The name associated with the payment method. The email address associated with the payment method. activateBillingTierResult field The id of the product being subscribed to. deletePaymentMethodResult field The payment method that was removed. createApiOnlyUsersResult field A list of API-only User IDs. item field updateRootQuorumResult field updateUserTagResult field Unique identifier for a given User Tag. updatePrivateKeyTagResult field Unique identifier for a given Private Key Tag. createSubOrganizationResult field subOrganizationId field rootUserIds field item field updateAllowedOriginsResult field createPrivateKeysResultV2 field A list of Private Key IDs and addresses. privateKeyId field addresses field format field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` address field updateUserResult field A User ID. updatePolicyResult field Unique identifier for a given Policy. createSubOrganizationResultV3 field subOrganizationId field A list of Private Key IDs and addresses. privateKeyId field addresses field format field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` address field rootUserIds field item field createWalletResult field Unique identifier for a Wallet. A list of account addresses. item field createWalletAccountsResult field A list of derived addresses. item field initUserEmailRecoveryResult field Unique identifier for the user being recovered. recoverUserResult field ID of the authenticator created. item field setOrganizationFeatureResult field Resulting list of organization features. name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` value field removeOrganizationFeatureResult field Resulting list of organization features. name field Enum options: `FEATURE_NAME_ROOT_USER_EMAIL_RECOVERY`, `FEATURE_NAME_WEBAUTHN_ORIGINS`, `FEATURE_NAME_EMAIL_AUTH`, `FEATURE_NAME_EMAIL_RECOVERY`, `FEATURE_NAME_WEBHOOK`, `FEATURE_NAME_SMS_AUTH`, `FEATURE_NAME_OTP_EMAIL_AUTH` value field exportPrivateKeyResult field Unique identifier for a given Private Key. Export bundle containing a private key encrypted to the client's target public key. exportWalletResult field Unique identifier for a given Wallet. Export bundle containing a wallet mnemonic + optional newline passphrase encrypted by the client's target public key. createSubOrganizationResultV4 field subOrganizationId field wallet field walletId field A list of account addresses. item field rootUserIds field item field emailAuthResult field Unique identifier for the authenticating User. Unique identifier for the created API key. exportWalletAccountResult field Address to identify Wallet Account. Export bundle containing a private key encrypted by the client's target public key. initImportWalletResult field Import bundle containing a public key and signature to use for importing client data. importWalletResult field Unique identifier for a Wallet. A list of account addresses. item field initImportPrivateKeyResult field Import bundle containing a public key and signature to use for importing client data. importPrivateKeyResult field Unique identifier for a Private Key. A list of addresses. format field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` address field createPoliciesResult field A list of unique identifiers for the created policies. item field signRawPayloadsResult field signatures field Component of an ECSDA signature. Component of an ECSDA signature. Component of an ECSDA signature. createReadOnlySessionResult field Unique identifier for a given Organization. If the request is being made by a user and their Sub-Organization ID is unknown, this can be the Parent Organization ID. However, using the Sub-Organization ID is preferred due to performance reasons. Human-readable name for an Organization. Unique identifier for a given User. Human-readable name for a User. String representing a read only session UTC timestamp in seconds representing the expiry time for the read only session. createOauthProvidersResult field A list of unique identifiers for Oauth Providers item field deleteOauthProvidersResult field A list of unique identifiers for Oauth Providers item field createSubOrganizationResultV5 field subOrganizationId field wallet field walletId field A list of account addresses. item field rootUserIds field item field oauthResult field Unique identifier for the authenticating User. Unique identifier for the created API key. HPKE encrypted credential bundle createReadWriteSessionResult field Unique identifier for a given Organization. If the request is being made by a user and their Sub-Organization ID is unknown, this can be the Parent Organization ID. However, using the Sub-Organization ID is preferred due to performance reasons. Human-readable name for an Organization. Unique identifier for a given User. Human-readable name for a User. Unique identifier for the created API key. HPKE encrypted credential bundle createSubOrganizationResultV6 field subOrganizationId field wallet field walletId field A list of account addresses. item field rootUserIds field item field deletePrivateKeysResult field A list of private key unique identifiers that were removed item field deleteWalletsResult field A list of wallet unique identifiers that were removed item field createReadWriteSessionResultV2 field Unique identifier for a given Organization. If the request is being made by a user and their Sub-Organization ID is unknown, this can be the Parent Organization ID. However, using the Sub-Organization ID is preferred due to performance reasons. Human-readable name for an Organization. Unique identifier for a given User. Human-readable name for a User. Unique identifier for the created API key. HPKE encrypted credential bundle deleteSubOrganizationResult field Unique identifier of the sub organization that was removed initOtpAuthResult field Unique identifier for an OTP authentication otpAuthResult field Unique identifier for the authenticating User. Unique identifier for the created API key. HPKE encrypted credential bundle createSubOrganizationResultV7 field subOrganizationId field wallet field walletId field A list of account addresses. item field rootUserIds field item field updateWalletResult field A Wallet ID. updatePolicyResultV2 field Unique identifier for a given Policy. initOtpAuthResultV2 field Unique identifier for an OTP authentication initOtpResult field Unique identifier for an OTP authentication verifyOtpResult field Signed JWT containing a unique id, expiry, verification type, contact otpLoginResult field Signed JWT containing an expiry, public key, session type, user id, and organization id stampLoginResult field Signed JWT containing an expiry, public key, session type, user id, and organization id oauthLoginResult field Signed JWT containing an expiry, public key, session type, user id, and organization id A list of objects representing a particular User's approval or rejection of a Consensus request, including all relevant metadata. Unique identifier for a given Vote object. Unique identifier for a given User. user field Unique identifier for a given User. Human-readable name for a User. The user's email address. The user's phone number in E.164 format e.g. +13214567890 A list of Authenticator parameters. Types of transports that may be used by an Authenticator (e.g., USB, NFC, BLE). item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` attestationType field Identifier indicating the type of the Security Key. Unique identifier for a WebAuthn credential. The type of Authenticator device. credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given Authenticator. Human-readable name for an Authenticator. createdAt field seconds field nanos field updatedAt field seconds field nanos field A list of API Key parameters. This field, if not needed, should be an empty array in your request body. credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given API Key. Human-readable name for an API Key. createdAt field seconds field nanos field updatedAt field seconds field nanos field Optional window (in seconds) indicating how long the API Key should last. A list of User Tag IDs. item field A list of Oauth Providers. Unique identifier for an OAuth Provider Human-readable name to identify a Provider. The issuer of the token, typically a URL indicating the authentication server, e.g [https://accounts.google.com](https://accounts.google.com) Expected audience ('aud' attribute of the signed token) which represents the app ID Expected subject ('sub' attribute of the signed token) which represents the user ID createdAt field seconds field nanos field updatedAt field seconds field nanos field createdAt field seconds field nanos field updatedAt field seconds field nanos field Unique identifier for a given Activity object. selection field Enum options: `VOTE_SELECTION_APPROVED`, `VOTE_SELECTION_REJECTED` The raw message being signed within a Vote. The public component of a cryptographic key pair used to sign messages and transactions. The signature applied to a particular vote. Method used to produce a signature. createdAt field seconds field nanos field An artifact verifying a User's action. canApprove field canReject field createdAt field seconds field nanos field updatedAt field seconds field nanos field failure field code field message field details field @type field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/list_activities \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "filterByStatus": [ "" ], "paginationOptions": { "limit": "", "before": "", "after": "" }, "filterByType": [ "" ] }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "activities": [ { "id": "", "organizationId": "", "status": "", "type": "", "intent": { "createOrganizationIntent": { "organizationName": "", "rootEmail": "", "rootAuthenticator": { "authenticatorName": "", "userId": "", "attestation": { "id": "", "type": "", "rawId": "", "authenticatorAttachment": "", "response": { "clientDataJson": "", "attestationObject": "", "transports": [ "" ], "authenticatorAttachment": "" }, "clientExtensionResults": { "appid": true, "appidExclude": true, "credProps": { "rk": true } } }, "challenge": "" }, "rootUserId": "" }, "createAuthenticatorsIntent": { "authenticators": [ { "authenticatorName": "", "userId": "", "attestation": { "id": "", "type": "", "rawId": "", "authenticatorAttachment": "", "response": { "clientDataJson": "", "attestationObject": "", "transports": [ "" ], "authenticatorAttachment": "" }, "clientExtensionResults": { "appid": true, "appidExclude": true, "credProps": { "rk": true } } }, "challenge": "" } ], "userId": "" }, "createUsersIntent": { "users": [ { "userName": "", "userEmail": "", "accessType": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "userId": "", "attestation": { "id": "", "type": "", "rawId": "", "authenticatorAttachment": "", "response": { "clientDataJson": "", "attestationObject": "", "transports": [ "" ], "authenticatorAttachment": "" }, "clientExtensionResults": { "appid": true, "appidExclude": true, "credProps": { "rk": true } } }, "challenge": "" } ], "userTags": [ "" ] } ] }, "createPrivateKeysIntent": { "privateKeys": [ { "privateKeyName": "", "curve": "", "privateKeyTags": [ "" ], "addressFormats": [ "" ] } ] }, "signRawPayloadIntent": { "privateKeyId": "", "payload": "", "encoding": "", "hashFunction": "" }, "createInvitationsIntent": { "invitations": [ { "receiverUserName": "", "receiverUserEmail": "", "receiverUserTags": [ "" ], "accessType": "", "senderUserId": "" } ] }, "acceptInvitationIntent": { "invitationId": "", "userId": "", "authenticator": { "authenticatorName": "", "userId": "", "attestation": { "id": "", "type": "", "rawId": "", "authenticatorAttachment": "", "response": { "clientDataJson": "", "attestationObject": "", "transports": [ "" ], "authenticatorAttachment": "" }, "clientExtensionResults": { "appid": true, "appidExclude": true, "credProps": { "rk": true } } }, "challenge": "" } }, "createPolicyIntent": { "policyName": "", "selectors": [ { "subject": "", "operator": "", "target": "" } ], "effect": "", "notes": "" }, "disablePrivateKeyIntent": { "privateKeyId": "" }, "deleteUsersIntent": { "userIds": [ "" ] }, "deleteAuthenticatorsIntent": { "userId": "", "authenticatorIds": [ "" ] }, "deleteInvitationIntent": { "invitationId": "" }, "deleteOrganizationIntent": { "organizationId": "" }, "deletePolicyIntent": { "policyId": "" }, "createUserTagIntent": { "userTagName": "", "userIds": [ "" ] }, "deleteUserTagsIntent": { "userTagIds": [ "" ] }, "signTransactionIntent": { "privateKeyId": "", "unsignedTransaction": "", "type": "" }, "createApiKeysIntent": { "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "userId": "" }, "deleteApiKeysIntent": { "userId": "", "apiKeyIds": [ "" ] }, "approveActivityIntent": { "fingerprint": "" }, "rejectActivityIntent": { "fingerprint": "" }, "createPrivateKeyTagIntent": { "privateKeyTagName": "", "privateKeyIds": [ "" ] }, "deletePrivateKeyTagsIntent": { "privateKeyTagIds": [ "" ] }, "createPolicyIntentV2": { "policyName": "", "selectors": [ { "subject": "", "operator": "", "targets": [ "" ] } ], "effect": "", "notes": "" }, "setPaymentMethodIntent": { "number": "", "cvv": "", "expiryMonth": "", "expiryYear": "", "cardHolderEmail": "", "cardHolderName": "" }, "activateBillingTierIntent": { "productId": "" }, "deletePaymentMethodIntent": { "paymentMethodId": "" }, "createPolicyIntentV3": { "policyName": "", "effect": "", "condition": "", "consensus": "", "notes": "" }, "createApiOnlyUsersIntent": { "apiOnlyUsers": [ { "userName": "", "userEmail": "", "userTags": [ "" ], "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ] } ] }, "updateRootQuorumIntent": { "threshold": 123, "userIds": [ "" ] }, "updateUserTagIntent": { "userTagId": "", "newUserTagName": "", "addUserIds": [ "" ], "removeUserIds": [ "" ] }, "updatePrivateKeyTagIntent": { "privateKeyTagId": "", "newPrivateKeyTagName": "", "addPrivateKeyIds": [ "" ], "removePrivateKeyIds": [ "" ] }, "createAuthenticatorsIntentV2": { "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "userId": "" }, "acceptInvitationIntentV2": { "invitationId": "", "userId": "", "authenticator": { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } }, "createOrganizationIntentV2": { "organizationName": "", "rootEmail": "", "rootAuthenticator": { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } }, "rootUserId": "" }, "createUsersIntentV2": { "users": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "userTags": [ "" ] } ] }, "createSubOrganizationIntent": { "name": "", "rootAuthenticator": { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } }, "createSubOrganizationIntentV2": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ] } ], "rootQuorumThreshold": 123 }, "updateAllowedOriginsIntent": { "allowedOrigins": [ "" ] }, "createPrivateKeysIntentV2": { "privateKeys": [ { "privateKeyName": "", "curve": "", "privateKeyTags": [ "" ], "addressFormats": [ "" ] } ] }, "updateUserIntent": { "userId": "", "userName": "", "userEmail": "", "userTagIds": [ "" ], "userPhoneNumber": "" }, "updatePolicyIntent": { "policyId": "", "policyName": "", "policyEffect": "", "policyCondition": "", "policyConsensus": "", "policyNotes": "" }, "setPaymentMethodIntentV2": { "paymentMethodId": "", "cardHolderEmail": "", "cardHolderName": "" }, "createSubOrganizationIntentV3": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ] } ], "rootQuorumThreshold": 123, "privateKeys": [ { "privateKeyName": "", "curve": "", "privateKeyTags": [ "" ], "addressFormats": [ "" ] } ] }, "createWalletIntent": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "createWalletAccountsIntent": { "walletId": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ] }, "initUserEmailRecoveryIntent": { "email": "", "targetPublicKey": "", "expirationSeconds": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" } }, "recoverUserIntent": { "authenticator": { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } }, "userId": "" }, "setOrganizationFeatureIntent": { "name": "", "value": "" }, "removeOrganizationFeatureIntent": { "name": "" }, "signRawPayloadIntentV2": { "signWith": "", "payload": "", "encoding": "", "hashFunction": "" }, "signTransactionIntentV2": { "signWith": "", "unsignedTransaction": "", "type": "" }, "exportPrivateKeyIntent": { "privateKeyId": "", "targetPublicKey": "" }, "exportWalletIntent": { "walletId": "", "targetPublicKey": "", "language": "" }, "createSubOrganizationIntentV4": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ] } ], "rootQuorumThreshold": 123, "wallet": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "disableEmailRecovery": true, "disableEmailAuth": true }, "emailAuthIntent": { "email": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "invalidateExisting": true, "sendFromEmailAddress": "", "sendFromEmailSenderName": "", "replyToEmailAddress": "" }, "exportWalletAccountIntent": { "address": "", "targetPublicKey": "" }, "initImportWalletIntent": { "userId": "" }, "importWalletIntent": { "userId": "", "walletName": "", "encryptedBundle": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ] }, "initImportPrivateKeyIntent": { "userId": "" }, "importPrivateKeyIntent": { "userId": "", "privateKeyName": "", "encryptedBundle": "", "curve": "", "addressFormats": [ "" ] }, "createPoliciesIntent": { "policies": [ { "policyName": "", "effect": "", "condition": "", "consensus": "", "notes": "" } ] }, "signRawPayloadsIntent": { "signWith": "", "payloads": [ "" ], "encoding": "", "hashFunction": "" }, "createReadOnlySessionIntent": "", "createOauthProvidersIntent": { "userId": "", "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] }, "deleteOauthProvidersIntent": { "userId": "", "providerIds": [ "" ] }, "createSubOrganizationIntentV5": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] } ], "rootQuorumThreshold": 123, "wallet": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "disableEmailRecovery": true, "disableEmailAuth": true }, "oauthIntent": { "oidcToken": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true }, "createApiKeysIntentV2": { "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "userId": "" }, "createReadWriteSessionIntent": { "targetPublicKey": "", "email": "", "apiKeyName": "", "expirationSeconds": "" }, "emailAuthIntentV2": { "email": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "invalidateExisting": true, "sendFromEmailAddress": "", "sendFromEmailSenderName": "", "replyToEmailAddress": "" }, "createSubOrganizationIntentV6": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] } ], "rootQuorumThreshold": 123, "wallet": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "disableEmailRecovery": true, "disableEmailAuth": true }, "deletePrivateKeysIntent": { "privateKeyIds": [ "" ], "deleteWithoutExport": true }, "deleteWalletsIntent": { "walletIds": [ "" ], "deleteWithoutExport": true }, "createReadWriteSessionIntentV2": { "targetPublicKey": "", "userId": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true }, "deleteSubOrganizationIntent": { "deleteWithoutExport": true }, "initOtpAuthIntent": { "otpType": "", "contact": "", "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "smsCustomization": { "template": "" }, "userIdentifier": "", "sendFromEmailAddress": "", "sendFromEmailSenderName": "", "replyToEmailAddress": "" }, "otpAuthIntent": { "otpId": "", "otpCode": "", "targetPublicKey": "", "apiKeyName": "", "expirationSeconds": "", "invalidateExisting": true }, "createSubOrganizationIntentV7": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "", "userPhoneNumber": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "oauthProviders": [ { "providerName": "", "oidcToken": "" } ] } ], "rootQuorumThreshold": 123, "wallet": { "walletName": "", "accounts": [ { "curve": "", "pathFormat": "", "path": "", "addressFormat": "" } ], "mnemonicLength": 123 }, "disableEmailRecovery": true, "disableEmailAuth": true, "disableSmsAuth": true, "disableOtpEmailAuth": true }, "updateWalletIntent": { "walletId": "", "walletName": "" }, "updatePolicyIntentV2": { "policyId": "", "policyName": "", "policyEffect": "", "policyCondition": "", "policyConsensus": "", "policyNotes": "" }, "createUsersIntentV3": { "users": [ { "userName": "", "userEmail": "", "userPhoneNumber": "", "apiKeys": [ { "apiKeyName": "", "publicKey": "", "curveType": "", "expirationSeconds": "" } ], "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": [ "" ] } } ], "oauthProviders": [ { "providerName": "", "oidcToken": "" } ], "userTags": [ "" ] } ] }, "initOtpAuthIntentV2": { "otpType": "", "contact": "", "otpLength": 123, "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "smsCustomization": { "template": "" }, "userIdentifier": "", "sendFromEmailAddress": "", "alphanumeric": true, "sendFromEmailSenderName": "", "replyToEmailAddress": "" }, "initOtpIntent": { "otpType": "", "contact": "", "otpLength": 123, "emailCustomization": { "appName": "", "logoUrl": "", "magicLinkTemplate": "", "templateVariables": "", "templateId": "" }, "smsCustomization": { "template": "" }, "userIdentifier": "", "sendFromEmailAddress": "", "alphanumeric": true, "sendFromEmailSenderName": "", "expirationSeconds": "", "replyToEmailAddress": "" }, "verifyOtpIntent": { "otpId": "", "otpCode": "", "expirationSeconds": "" }, "otpLoginIntent": { "verificationToken": "", "publicKey": "", "expirationSeconds": "", "invalidateExisting": true }, "stampLoginIntent": { "publicKey": "", "expirationSeconds": "", "invalidateExisting": true }, "oauthLoginIntent": { "oidcToken": "", "publicKey": "", "expirationSeconds": "", "invalidateExisting": true } }, "result": { "createOrganizationResult": { "organizationId": "" }, "createAuthenticatorsResult": { "authenticatorIds": [ "" ] }, "createUsersResult": { "userIds": [ "" ] }, "createPrivateKeysResult": { "privateKeyIds": [ "" ] }, "createInvitationsResult": { "invitationIds": [ "" ] }, "acceptInvitationResult": { "invitationId": "", "userId": "" }, "signRawPayloadResult": { "r": "", "s": "", "v": "" }, "createPolicyResult": { "policyId": "" }, "disablePrivateKeyResult": { "privateKeyId": "" }, "deleteUsersResult": { "userIds": [ "" ] }, "deleteAuthenticatorsResult": { "authenticatorIds": [ "" ] }, "deleteInvitationResult": { "invitationId": "" }, "deleteOrganizationResult": { "organizationId": "" }, "deletePolicyResult": { "policyId": "" }, "createUserTagResult": { "userTagId": "", "userIds": [ "" ] }, "deleteUserTagsResult": { "userTagIds": [ "" ], "userIds": [ "" ] }, "signTransactionResult": { "signedTransaction": "" }, "deleteApiKeysResult": { "apiKeyIds": [ "" ] }, "createApiKeysResult": { "apiKeyIds": [ "" ] }, "createPrivateKeyTagResult": { "privateKeyTagId": "", "privateKeyIds": [ "" ] }, "deletePrivateKeyTagsResult": { "privateKeyTagIds": [ "" ], "privateKeyIds": [ "" ] }, "setPaymentMethodResult": { "lastFour": "", "cardHolderName": "", "cardHolderEmail": "" }, "activateBillingTierResult": { "productId": "" }, "deletePaymentMethodResult": { "paymentMethodId": "" }, "createApiOnlyUsersResult": { "userIds": [ "" ] }, "updateRootQuorumResult": "", "updateUserTagResult": { "userTagId": "" }, "updatePrivateKeyTagResult": { "privateKeyTagId": "" }, "createSubOrganizationResult": { "subOrganizationId": "", "rootUserIds": [ "" ] }, "updateAllowedOriginsResult": "", "createPrivateKeysResultV2": { "privateKeys": [ { "privateKeyId": "", "addresses": [ { "format": "", "address": "" } ] } ] }, "updateUserResult": { "userId": "" }, "updatePolicyResult": { "policyId": "" }, "createSubOrganizationResultV3": { "subOrganizationId": "", "privateKeys": [ { "privateKeyId": "", "addresses": [ { "format": "", "address": "" } ] } ], "rootUserIds": [ "" ] }, "createWalletResult": { "walletId": "", "addresses": [ "" ] }, "createWalletAccountsResult": { "addresses": [ "" ] }, "initUserEmailRecoveryResult": { "userId": "" }, "recoverUserResult": { "authenticatorId": [ "" ] }, "setOrganizationFeatureResult": { "features": [ { "name": "", "value": "" } ] }, "removeOrganizationFeatureResult": { "features": [ { "name": "", "value": "" } ] }, "exportPrivateKeyResult": { "privateKeyId": "", "exportBundle": "" }, "exportWalletResult": { "walletId": "", "exportBundle": "" }, "createSubOrganizationResultV4": { "subOrganizationId": "", "wallet": { "walletId": "", "addresses": [ "" ] }, "rootUserIds": [ "" ] }, "emailAuthResult": { "userId": "", "apiKeyId": "" }, "exportWalletAccountResult": { "address": "", "exportBundle": "" }, "initImportWalletResult": { "importBundle": "" }, "importWalletResult": { "walletId": "", "addresses": [ "" ] }, "initImportPrivateKeyResult": { "importBundle": "" }, "importPrivateKeyResult": { "privateKeyId": "", "addresses": [ { "format": "", "address": "" } ] }, "createPoliciesResult": { "policyIds": [ "" ] }, "signRawPayloadsResult": { "signatures": [ { "r": "", "s": "", "v": "" } ] }, "createReadOnlySessionResult": { "organizationId": "", "organizationName": "", "userId": "", "username": "", "session": "", "sessionExpiry": "" }, "createOauthProvidersResult": { "providerIds": [ "" ] }, "deleteOauthProvidersResult": { "providerIds": [ "" ] }, "createSubOrganizationResultV5": { "subOrganizationId": "", "wallet": { "walletId": "", "addresses": [ "" ] }, "rootUserIds": [ "" ] }, "oauthResult": { "userId": "", "apiKeyId": "", "credentialBundle": "" }, "createReadWriteSessionResult": { "organizationId": "", "organizationName": "", "userId": "", "username": "", "apiKeyId": "", "credentialBundle": "" }, "createSubOrganizationResultV6": { "subOrganizationId": "", "wallet": { "walletId": "", "addresses": [ "" ] }, "rootUserIds": [ "" ] }, "deletePrivateKeysResult": { "privateKeyIds": [ "" ] }, "deleteWalletsResult": { "walletIds": [ "" ] }, "createReadWriteSessionResultV2": { "organizationId": "", "organizationName": "", "userId": "", "username": "", "apiKeyId": "", "credentialBundle": "" }, "deleteSubOrganizationResult": { "subOrganizationUuid": "" }, "initOtpAuthResult": { "otpId": "" }, "otpAuthResult": { "userId": "", "apiKeyId": "", "credentialBundle": "" }, "createSubOrganizationResultV7": { "subOrganizationId": "", "wallet": { "walletId": "", "addresses": [ "" ] }, "rootUserIds": [ "" ] }, "updateWalletResult": { "walletId": "" }, "updatePolicyResultV2": { "policyId": "" }, "initOtpAuthResultV2": { "otpId": "" }, "initOtpResult": { "otpId": "" }, "verifyOtpResult": { "verificationToken": "" }, "otpLoginResult": { "session": "" }, "stampLoginResult": { "session": "" }, "oauthLoginResult": { "session": "" } }, "votes": [ { "id": "", "userId": "", "user": { "userId": "", "userName": "", "userEmail": "", "userPhoneNumber": "", "authenticators": [ { "transports": [ "" ], "attestationType": "", "aaguid": "", "credentialId": "", "model": "", "credential": { "publicKey": "", "type": "" }, "authenticatorId": "", "authenticatorName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ], "apiKeys": [ { "credential": { "publicKey": "", "type": "" }, "apiKeyId": "", "apiKeyName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "expirationSeconds": "" } ], "userTags": [ "" ], "oauthProviders": [ { "providerId": "", "providerName": "", "issuer": "", "audience": "", "subject": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ], "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } }, "activityId": "", "selection": "", "message": "", "publicKey": "", "signature": "", "scheme": "", "createdAt": { "seconds": "", "nanos": "" } } ], "fingerprint": "", "canApprove": true, "canReject": true, "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "failure": { "code": 123, "message": "", "details": [ { "@type": "" } ] } } ] } } } ``` # List Policies Source: https://docs.turnkey.com/api-reference/queries/list-policies List all Policies within an Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. A successful response returns the following fields: A list of Policies. Unique identifier for a given Policy. Human-readable name for a Policy. effect field Enum options: `EFFECT_ALLOW`, `EFFECT_DENY` createdAt field seconds field nanos field updatedAt field seconds field nanos field Human-readable notes added by a User to describe a particular policy. A consensus expression that evalutes to true or false. A condition expression that evalutes to true or false. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/list_policies \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "policies": [ { "policyId": "", "policyName": "", "effect": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "notes": "", "consensus": "", "condition": "" } ] } } } ``` # List Private Key Tags Source: https://docs.turnkey.com/api-reference/queries/list-private-key-tags List all Private Key Tags within an Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. A successful response returns the following fields: A list of Private Key Tags Unique identifier for a given Tag. Human-readable name for a Tag. tagType field Enum options: `TAG_TYPE_USER`, `TAG_TYPE_PRIVATE_KEY` createdAt field seconds field nanos field updatedAt field seconds field nanos field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/list_private_key_tags \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "privateKeyTags": [ { "tagId": "", "tagName": "", "tagType": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ] } } } ``` # List Private Keys Source: https://docs.turnkey.com/api-reference/queries/list-private-keys List all Private Keys within an Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. A successful response returns the following fields: A list of Private Keys. Unique identifier for a given Private Key. The public component of a cryptographic key pair used to sign messages and transactions. Human-readable name for a Private Key. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` Derived cryptocurrency addresses for a given Private Key. format field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` address field A list of Private Key Tag IDs. item field createdAt field seconds field nanos field updatedAt field seconds field nanos field True when a given Private Key is exported, false otherwise. True when a given Private Key is imported, false otherwise. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/list_private_keys \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "privateKeys": [ { "privateKeyId": "", "publicKey": "", "privateKeyName": "", "curve": "", "addresses": [ { "format": "", "address": "" } ], "privateKeyTags": [ "" ], "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "exported": true, "imported": true } ] } } } ``` # List User Tags Source: https://docs.turnkey.com/api-reference/queries/list-user-tags List all User Tags within an Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. A successful response returns the following fields: A list of User Tags Unique identifier for a given Tag. Human-readable name for a Tag. tagType field Enum options: `TAG_TYPE_USER`, `TAG_TYPE_PRIVATE_KEY` createdAt field seconds field nanos field updatedAt field seconds field nanos field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/list_user_tags \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "userTags": [ { "tagId": "", "tagName": "", "tagType": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ] } } } ``` # List Users Source: https://docs.turnkey.com/api-reference/queries/list-users List all Users within an Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. A successful response returns the following fields: A list of Users. Unique identifier for a given User. Human-readable name for a User. The user's email address. The user's phone number in E.164 format e.g. +13214567890 A list of Authenticator parameters. Types of transports that may be used by an Authenticator (e.g., USB, NFC, BLE). item field Enum options: `AUTHENTICATOR_TRANSPORT_BLE`, `AUTHENTICATOR_TRANSPORT_INTERNAL`, `AUTHENTICATOR_TRANSPORT_NFC`, `AUTHENTICATOR_TRANSPORT_USB`, `AUTHENTICATOR_TRANSPORT_HYBRID` attestationType field Identifier indicating the type of the Security Key. Unique identifier for a WebAuthn credential. The type of Authenticator device. credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given Authenticator. Human-readable name for an Authenticator. createdAt field seconds field nanos field updatedAt field seconds field nanos field A list of API Key parameters. This field, if not needed, should be an empty array in your request body. credential field The public component of a cryptographic key pair used to sign messages and transactions. type field Enum options: `CREDENTIAL_TYPE_WEBAUTHN_AUTHENTICATOR`, `CREDENTIAL_TYPE_API_KEY_P256`, `CREDENTIAL_TYPE_RECOVER_USER_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_SECP256K1`, `CREDENTIAL_TYPE_EMAIL_AUTH_KEY_P256`, `CREDENTIAL_TYPE_API_KEY_ED25519`, `CREDENTIAL_TYPE_OTP_AUTH_KEY_P256`, `CREDENTIAL_TYPE_READ_WRITE_SESSION_KEY_P256`, `CREDENTIAL_TYPE_OAUTH_KEY_P256`, `CREDENTIAL_TYPE_LOGIN` Unique identifier for a given API Key. Human-readable name for an API Key. createdAt field seconds field nanos field updatedAt field seconds field nanos field Optional window (in seconds) indicating how long the API Key should last. A list of User Tag IDs. item field A list of Oauth Providers. Unique identifier for an OAuth Provider Human-readable name to identify a Provider. The issuer of the token, typically a URL indicating the authentication server, e.g [https://accounts.google.com](https://accounts.google.com) Expected audience ('aud' attribute of the signed token) which represents the app ID Expected subject ('sub' attribute of the signed token) which represents the user ID createdAt field seconds field nanos field updatedAt field seconds field nanos field createdAt field seconds field nanos field updatedAt field seconds field nanos field ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/list_users \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "users": [ { "userId": "", "userName": "", "userEmail": "", "userPhoneNumber": "", "authenticators": [ { "transports": [ "" ], "attestationType": "", "aaguid": "", "credentialId": "", "model": "", "credential": { "publicKey": "", "type": "" }, "authenticatorId": "", "authenticatorName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ], "apiKeys": [ { "credential": { "publicKey": "", "type": "" }, "apiKeyId": "", "apiKeyName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "expirationSeconds": "" } ], "userTags": [ "" ], "oauthProviders": [ { "providerId": "", "providerName": "", "issuer": "", "audience": "", "subject": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ], "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" } } ] } } } ``` # List Wallets Source: https://docs.turnkey.com/api-reference/queries/list-wallets List all Wallets within an Organization export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. A successful response returns the following fields: A list of Wallets. Unique identifier for a given Wallet. Human-readable name for a Wallet. createdAt field seconds field nanos field updatedAt field seconds field nanos field True when a given Wallet is exported, false otherwise. True when a given Wallet is imported, false otherwise. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/list_wallets \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "wallets": [ { "walletId": "", "walletName": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "exported": true, "imported": true } ] } } } ``` # List Wallets Accounts Source: https://docs.turnkey.com/api-reference/queries/list-wallets-accounts List all Accounts within a Wallet export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. Unique identifier for a given Wallet.

paginationOptions field

A limit of the number of object to be returned, between 1 and 100. Defaults to 10. A pagination cursor. This is an object ID that enables you to fetch all objects before this ID. A pagination cursor. This is an object ID that enables you to fetch all objects after this ID.
A successful response returns the following fields: A list of Accounts generated from a Wallet that share a common seed. Unique identifier for a given Wallet Account. The Organization the Account belongs to. The Wallet the Account was derived from. curve field Enum options: `CURVE_SECP256K1`, `CURVE_ED25519` pathFormat field Enum options: `PATH_FORMAT_BIP32` Path used to generate the Account. addressFormat field Enum options: `ADDRESS_FORMAT_UNCOMPRESSED`, `ADDRESS_FORMAT_COMPRESSED`, `ADDRESS_FORMAT_ETHEREUM`, `ADDRESS_FORMAT_SOLANA`, `ADDRESS_FORMAT_COSMOS`, `ADDRESS_FORMAT_TRON`, `ADDRESS_FORMAT_SUI`, `ADDRESS_FORMAT_APTOS`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_MAINNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_TESTNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2PKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2SH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2WSH`, `ADDRESS_FORMAT_BITCOIN_SIGNET_P2TR`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2PKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2SH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WPKH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2WSH`, `ADDRESS_FORMAT_BITCOIN_REGTEST_P2TR`, `ADDRESS_FORMAT_SEI`, `ADDRESS_FORMAT_XLM`, `ADDRESS_FORMAT_DOGE_MAINNET`, `ADDRESS_FORMAT_DOGE_TESTNET`, `ADDRESS_FORMAT_TON_V3R2`, `ADDRESS_FORMAT_TON_V4R2`, `ADDRESS_FORMAT_XRP` Address generated using the Wallet seed and Account parameters. createdAt field seconds field nanos field updatedAt field seconds field nanos field The public component of this wallet account's underlying cryptographic key pair. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/list_wallet_accounts \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "", "walletId": "", "paginationOptions": { "limit": "", "before": "", "after": "" } }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "accounts": [ { "walletAccountId": "", "organizationId": "", "walletId": "", "curve": "", "pathFormat": "", "path": "", "addressFormat": "", "address": "", "createdAt": { "seconds": "", "nanos": "" }, "updatedAt": { "seconds": "", "nanos": "" }, "publicKey": "" } ] } } } ``` # Queries Source: https://docs.turnkey.com/api-reference/queries/overview Queries are read requests to Turnkey's API. They allow you to retrieve data about your organization and its resources. # What Are Queries? Queries are read-only operations that let you fetch information from Turnkey's API without modifying any resources. Query endpoints are always prefixed with `/public/v1/query`. * **No Policy Enforcement:** Queries are not subject to the policy engine, so any authenticated user in your organization can perform them. * **Organization-wide Access:** All users within an organization can read any data within the organization. Parent organizations can also query data for all of their sub-organizations. * **Use Cases:** Common use cases include listing users, retrieving organization details, and fetching activity logs. # Who am I? Source: https://docs.turnkey.com/api-reference/queries/who-am-i Get basic information about your current API or WebAuthN user and their organization. Affords Sub-Organization look ups via Parent Organization for WebAuthN or API key users. export const EndpointPath = ({type, path}) => { return
POST
/
public
/
v1
/
{type}
/
{path}
; }; export const NestedParam = ({parentKey, childKey, type, required, description, children}) => { const fullKey = `${parentKey}.${childKey}`; const anchorId = `body-${fullKey.replace(/\./g, '-')}`; return
{parentKey}. {childKey}
{type}
{required && required }
{children &&
{children}
}
; }; export const H3Bordered = ({text}) =>

{text}

; export const Authorizations = () => { return

Authorizations

X-Stamp
string
header
required
X-Stamp-Webauthn
string
header
required
; }; Unique identifier for a given Organization. If the request is being made by a WebAuthN user and their Sub-Organization ID is unknown, this can be the Parent Organization ID; using the Sub-Organization ID when possible is preferred due to performance reasons. A successful response returns the following fields: Unique identifier for a given Organization. Human-readable name for an Organization. Unique identifier for a given User. Human-readable name for a User. ```bash cURL curl --request POST \ --url https://api.turnkey.com/public/v1/query/whoami \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header "X-Stamp: " \ --data '{ "organizationId": "" }' ``` ```json 200 { "activity": { "id": "", "status": "ACTIVITY_STATUS_COMPLETED", "type": "ACTIVITY_TYPE_UNKNOWN_V1", "organizationId": "", "timestampMs": " (e.g. 1746736509954)", "result": { "organizationId": "", "organizationName": "", "userId": "", "username": "" } } } ``` # Backend Authentication Source: https://docs.turnkey.com/authentication/backend-setup Guide for setting up a secure backend proxy with Turnkey authentication, focusing on JWT implementation and user data management. ## Introduction When integrating Turnkey into an application with an existing authentication system, you'll need to establish a secure communication pattern between your frontend, backend, and the Turnkey API. This guide explains how to implement a backend proxy pattern that leverages your existing user authentication while enabling Turnkey operations. ## Why Use a Backend Proxy? There are several benefits to proxying Turnkey requests through your own backend: 1. **User data**: Store and retrieve user data associated with Turnkey sub-organizations 2. **Metrics and monitoring**: Add custom validations, rate limiting, and logging 3. **Co-signing capabilities**: Enable 2/2 signing patterns where your application is a co-signer ## JWT Authentication Flow JSON Web Tokens (JWTs) provide a secure, stateless way to authenticate requests between your frontend and backend. Here's how to implement a JWT-based flow with Turnkey: ### Architecture Overview ```mermaid sequenceDiagram participant User participant Frontend participant Backend participant Turnkey %% Login/Signup Flow User->>Frontend: Login/Signup Action Frontend->>Frontend: Create signed Turnkey request Frontend->>Backend: Send signed request Backend->>Turnkey: Forward request Turnkey->>Backend: Authenticate & return response Backend->>Backend: Generate JWT Backend->>Frontend: Return JWT + response Frontend->>Frontend: Store JWT %% Subsequent Request Flow User->>Frontend: Action requiring Turnkey Frontend->>Frontend: Create signed request Frontend->>Backend: Send request with JWT Backend->>Backend: Validate JWT Backend->>Turnkey: Forward validated request Turnkey->>Backend: Process & return response Backend->>Frontend: Return response Frontend->>User: Update UI ``` ### Login and Sign Up Flows The first step in integrating Turnkey with JWT authentication is handling user login and signup. Both processes follow similar patterns but differ in how they establish the user's identity with Turnkey. #### Getting the User's Sub-organization ID Before you can authenticate a user with Turnkey, you need their sub-organization ID. There are multiple ways to obtain this: 1. **Database Lookup**: Query your database using the user's email or ID ```typescript const user = await db.users.findUnique({ where: { email: userEmail }, select: { turnkeySubOrgId: true }, }); ``` 2. **Turnkey API Lookup (Alternative)** If you don't have the sub-organization ID stored alongside your user record, you can query Turnkey using the user's email to find associated sub-organization IDs. ```typescript const { organizationIds } = await turnkeyServer.getSubOrgIds({ organizationId: process.env.TURNKEY_ORGANIZATION_ID, filterType: "EMAIL", filterValue: userEmail, }); // NB: This assumes the user has exactly one sub-org. See notes below! const subOrgId = organizationIds[0]; // First matching sub-org ``` The example above (`const subOrgId = organizationIds[0];`) simply takes the first ID found. **This approach might not be suitable for all applications.** * **Crucial Verification Step:** Retrieving a `subOrgId` via email lookup is only the first step and **does not grant access**. Your application *must* authenticate the user (e.g., via passkey) *after* the lookup. Only then should you verify if the authenticated user is authorized for that `subOrgId`, typically by checking your user database. Blindly trusting the lookup result is insecure. * **Handling No Results:** If `organizationIds` is empty, it might indicate the user doesn't have an existing sub-organization. Your application should handle this, potentially by initiating a signup flow or failing the login. * **Handling Multiple Results:** If multiple IDs are returned, your application must decide how to proceed. You could: * Prompt the user to select the intended sub-organization. * Enforce a business rule that an email can only map to one sub-organization and treat multiple results as an error state. * Use other contextual information (if available) to disambiguate. 3. **JWT Cookie**: Extract the user ID from an existing JWT in cookies (for returning users) If a user has previously logged in, their JWT might be stored in a cookie. You can verify this token and extract the user ID to confirm their identity. ```typescript // Example: Extracting User ID from JWT Cookie async function getUserIdFromCookie(req) { const token = req.cookies.authToken; if (!token) return null; try { const decoded = jwt.verify(token, JWT_SECRET); return decoded.userId; } catch (error) { // Invalid or expired token return null; } } // If you need the subOrgId associated with this userId, // perform a database lookup after verifying the JWT: // const user = await db.users.findUnique({ // where: { id: userId }, // select: { turnkeySubOrgId: true } // }); // const subOrgId = user?.turnkeySubOrgId; ``` #### Login Flow Generate a signed Turnkey request ```typescript app.ts import { turnkeyClient } from "./turnkey"; // This will require passkey authentication from the user const signedWhoamiRequest = await turnkeyClient.stampGetWhoami({ organizationId: subOrgId, }); ``` ```typescript turnkey.ts import { Turnkey } from "@turnkey/sdk-browser"; export const turnkeyClient = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: subOrgId, // From previous step }); ``` Forward the signed request ```typescript const response = await fetch("/api/auth/login", { method: "POST", body: JSON.stringify({ signedRequest: signedWhoamiRequest }), headers: { "Content-Type": "application/json" }, }); ``` Process the request and issue JWT ```typescript app.ts [expandable] import { turnkeyServer } from "./turnkey"; import jwt from "jsonwebtoken"; app.post("/api/auth/login", async (req, res) => { const { signedRequest } = req.body; try { // Forward to Turnkey - the request is already signed by the user's passkey const { url, body, stamp } = signedRequest; // Forward to Turnkey const response = await fetch(url, { method: 'POST', body, headers: { [stamp.stampHeaderName]: stamp.stampHeaderValue, }, }); const turnkeyResponse = await response.json(); // If we get here without error, the authentication succeeded if (turnkeyResponse.organizationId) { // Lookup or create user in your database const user = await findOrCreateUser(turnkeyResponse.organizationId); // Generate JWT containing only the application's user ID // The subOrgId is stored in the database, associated with the userId const token = jwt.sign( { userId: user.id, }, JWT_SECRET, { expiresIn: "1h" } ); // Set JWT as cookie or return in response res.cookie("authToken", token, { httpOnly: true, secure: true }); return res.status(200).json({ success: true }); } } catch (error) { return res.status(401).json({ error: "Authentication failed" }); } }); ``` ```typescript turnkey.ts import { Turnkey } from "@turnkey/sdk-server"; // Initialize server-side client export const turnkeyServer = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY, apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }).apiClient(); ``` #### Sign Up Flow For new users, the flow is similar but involves creating a new sub-organization: Collect user information ```typescript app.ts import { turnkeyClient } from "./turnkey"; const email = "user@example.com"; const { encodedChallenge, attestation } = (await turnkeyClient?.createUserPasskey({ publicKey: { user: { name: 'Popup Wallet Demo', displayName: 'Popup Wallet Demo', }, }, })) || {}; // Send to backend const response = await fetch("/api/auth/signup", { method: "POST", body: JSON.stringify({ email, challenge: encodedChallenge, attestation, }), headers: { "Content-Type": "application/json" }, }); ``` ```typescript turnkey.ts import { Turnkey } from "@turnkey/sdk-browser"; const turnkey = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, // Set this to your domain for production rpId: "localhost", }); export const turnkeyClient = turnkey.passkeyClient(); ``` Create sub-organization and issue JWT ```typescript app.ts [expandable] import { turnkeyServer } from "./turnkey"; import jwt from "jsonwebtoken"; import { DEFAULT_ETHEREUM_ACCOUNTS } from "@turnkey/sdk-browser"; const JWT_SECRET = process.env.JWT_SECRET; app.post("/api/auth/signup", async (req, res) => { const { email, challenge, attestation } = req.body; try { // Create the sub-organization const createSubOrgResponse = await turnkeyServer.createSubOrganization({ subOrganizationName: `${email} - Organization`, rootUsers: [ { userName: email, userEmail: email, apiKeys: [], authenticators: [ { authenticatorName: "Default Passkey", challenge, attestation, }, ], }, ], rootQuorumThreshold: 1, wallet: { walletName: "Default Wallet", accounts: DEFAULT_ETHEREUM_ACCOUNTS, }, }); if (createSubOrgResponse.organizationId) { // Store user in your database const user = await createUser(createSubOrgResponse.organizationId, email); // Generate JWT containing only the application's user ID const token = jwt.sign( { userId: user.id, }, JWT_SECRET, { expiresIn: "1h" } ); res.cookie("authToken", token, { httpOnly: true, secure: true }); return res.status(200).json({ success: true, message: "Signup successful, user created, and logged in." }); } } catch (error) { // Handle specific errors (e.g., email already exists) console.error("Signup Error:", error); return res.status(500).json({ error: "Signup failed" }); } }); ``` ```typescript turnkey.ts import { Turnkey } from "@turnkey/sdk-server"; // Initialize server-side client export const turnkeyServer = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY, apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }).apiClient(); ``` ### Email OTP Authentication Flow Turnkey allows users to authenticate via email using a secure One-Time Passcode (OTP). Your backend initiates this by calling `sendOtp`. Turnkey emails the code to the user. The user enters the code in the frontend, which sends it (along with identifiers) to your backend. Your backend then calls `verifyOtp`. Upon successful Turnkey verification, your backend issues its own application JWT to manage the proxied session. **Note:** This flow generally assumes the user and their associated Turnkey Sub-Organization already exist, as it's primarily for authentication rather than initial signup. #### Architecture Overview ```mermaid sequenceDiagram participant User participant Frontend participant Backend participant Turnkey %% OTP Request Phase User->>Frontend: Enters email address Frontend->>Frontend: Get iframe targetPublicKey Frontend->>Backend: Request OTP (email, targetPublicKey) Backend->>Backend: Lookup user/subOrgId by email alt User/SubOrg Found Backend->>Turnkey: call sendOtp(subOrgId, email, targetPublicKey) Turnkey->>Backend: Return otpId Turnkey->>User: Sends OTP Email Backend->>Frontend: Return otpId else User/SubOrg Not Found Backend->>Frontend: Return error (user needs signup/different flow) end %% OTP Verification & Login Phase User->>Frontend: Enters received OTP code Frontend->>Frontend: Get iframe targetPublicKey (for encryption) Frontend->>Backend: Submit verification (email, otpCode, otpId, targetPublicKey) Backend->>Backend: Lookup user/subOrgId by email Backend->>Turnkey: call verifyOtp(subOrgId, otpId, otpCode, targetPublicKey) alt Turnkey Verification Success Turnkey->>Backend: Success, returns **authSession** (contains token) Backend->>Backend: User is authenticated by Turnkey Backend->>Backend: Generate Backend Application JWT (with userId) Backend->>Frontend: Return Success + Set JWT Cookie + **Return authSession** Frontend->>Frontend: **call authIframeClient.loginWithSession(authSession)** Frontend->>Frontend: Store JWT, User logged in to application else Turnkey Verification Failure Turnkey->>Backend: Failure response Backend->>Frontend: Return error response end ``` #### Implementation Steps The user provides their email. The frontend gets the Turnkey iframe's public key (referred to as `targetPublicKey`) and sends both to the backend. The backend finds the user's sub-organization and asks Turnkey to send the OTP email by calling `sendOtp`, passing the iframe's public key as the `targetPublicKey` parameter (used by Turnkey for credential encryption upon successful verification). ```typescript frontend.ts [expandable] import { useTurnkey } from "@turnkey/sdk-react"; // Or however you access the client // User enters email and clicks 'Send OTP' const handleRequestOtp = async (email: string) => { const { authIframeClient } = useTurnkey(); if (!authIframeClient) { console.error("Turnkey iframe client not available"); // Handle error: Inform user or disable button return; } try { // Get the public key associated with the Turnkey iframe client instance. // This is sent to the backend for the sendOtp request. const targetPublicKey = await authIframeClient.getPublicKey(); const response = await fetch("/api/auth/otp/request", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, targetPublicKey }), }); const data = await response.json(); if (response.ok) { // Store otpId returned from backend for the verification step const otpId = data.otpId; console.log("OTP requested successfully, otpId:", otpId); // Show UI for OTP input, store otpId for the next step // e.g., setOtpIdState(otpId); } else { console.error("Failed to request OTP:", data.error); // Show error message to the user } } catch (error) { console.error("Error requesting OTP:", error); // Show error message to the user } }; ``` ```typescript backend-otp-request.ts [expandable] import { turnkeyServer } from "./turnkey"; // Import initialized Turnkey server client import { findUserByEmail } from "./dbUtils"; // Assume DB utility for finding user/subOrgId app.post("/api/auth/otp/request", async (req, res) => { const { email, targetPublicKey } = req.body; if (!email || !targetPublicKey) { return res.status(400).json({ error: "Email and targetPublicKey (iframe public key) are required", }); } try { // Find the user and their associated sub-organization in your database const user = await findUserByEmail(email); if (!user || !user.turnkeySubOrgId) { // Handle case where user/sub-org is not found appropriately return res.status(404).json({ error: "User or associated sub-organization not found for this email.", }); } const subOrgId = user.turnkeySubOrgId; // Call Turnkey to initiate the OTP flow via email const otpResponse = await turnkeyServer.sendOtp({ suborgID: subOrgId, otpType: "EMAIL", contact: email, targetPublicKey: targetPublicKey, // Pass the iframe public key as targetPublicKey }); if (otpResponse?.otpId) { // Return the otpId to the frontend; it's needed for verification console.log( `Turnkey sendOtp successful for ${email}, otpId: ${otpResponse.otpId}` ); return res .status(200) .json({ message: "OTP sent successfully", otpId: otpResponse.otpId }); } else { throw new Error("Turnkey sendOtp did not return an otpId."); } } catch (error) { console.error("Error requesting Turnkey OTP:", error); // Avoid leaking internal Turnkey errors; log them and return a generic error return res.status(500).json({ error: "Failed to send OTP" }); } }); ``` The user submits the received OTP code. The frontend gets the iframe's public key again (as `targetPublicKey` for encryption) and sends the code, email, original `otpId`, and `targetPublicKey` to the backend. The backend asks Turnkey to verify the code using `verifyOtp`. If successful, the backend generates and sets its own application session JWT cookie **and** returns the `authSession` object from Turnkey to the frontend. The frontend then uses this `authSession` to establish the Turnkey session within the iframe via `loginWithSession`. ```typescript frontend.ts [expandable] import { useTurnkey } from "@turnkey/sdk-react"; // User enters OTP and clicks 'Verify' // Assumes 'otpId' was stored in state from the previous step const handleVerifyOtp = async ( email: string, otpCode: string, otpId: string ) => { const { authIframeClient } = useTurnkey(); if (!authIframeClient) { console.error("Turnkey iframe client not available"); return; } try { // Get the public key again, this time as the target for credential encryption const targetPublicKey = await authIframeClient.getPublicKey(); const response = await fetch("/api/auth/otp/verify", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, otpCode, otpId, targetPublicKey }), }); if (response.ok) { // Backend successfully verified OTP with Turnkey and issued its JWT (in cookie) console.log("OTP verification successful, backend session established."); // Get the authSession from the backend response const data = await response.json(); const authSession = data.authSession; if (!authSession?.token) { console.error("Backend did not return a valid Turnkey authSession."); // Handle error: inform user authentication might be incomplete return; } // Use the session token from the backend to log in the Turnkey iframe console.log("Establishing Turnkey iframe session..."); await authIframeClient.loginWithSession(authSession); console.log("Turnkey iframe session established."); // Now both backend app session (cookie) and Turnkey iframe session are active. // Redirect user or update UI state (e.g., router.push('/dashboard')) } else { const data = await response.json(); console.error("OTP verification failed:", data.error); // Show error message to the user } } catch (error) { console.error("Error verifying OTP:", error); // Show error message to the user } }; ``` ```typescript backend-otp-verify.ts [expandable] import { turnkeyServer } from "./turnkey"; // Import initialized Turnkey server client import { findUserByEmail } from "./dbUtils"; // Assume DB utility import jwt from "jsonwebtoken"; const JWT_SECRET = process.env.JWT_SECRET; app.post("/api/auth/otp/verify", async (req, res) => { const { email, otpCode, otpId, targetPublicKey } = req.body; if (!email || !otpCode || !otpId || !targetPublicKey) { return res.status(400).json({ error: "Email, OTP code, OTP ID, and targetPublicKey are required", }); } try { // Find the user again to get their subOrgId and application userId const user = await findUserByEmail(email); if (!user || !user.turnkeySubOrgId) { return res .status(404) .json({ error: "User not found for this email during verification." }); } const subOrgId = user.turnkeySubOrgId; const applicationUserId = user.id; // Your application's internal user ID // Call Turnkey to verify the OTP code // If successful, Turnkey generates credentials encrypted for the targetPublicKey. // The backend doesn't necessarily need the returned session details, // but success confirms the user validated via OTP. const verifyResult = await turnkeyServer.verifyOtp({ suborgID: subOrgId, otpId: otpId, otpCode: otpCode, targetPubKey: targetPublicKey, // Encrypt credentials for the iframe client }); // If verifyOtp doesn't throw, verification was successful with Turnkey. console.log( `Turnkey OTP verified successfully for ${email}. Issuing backend JWT.` ); // console.log('Turnkey verifyOtp result:', verifyResult); // Optional: log result if needed // Generate the application's session JWT const token = jwt.sign({ userId: applicationUserId }, JWT_SECRET, { expiresIn: "1h", // Or your desired session duration }); // Set JWT as secure, httpOnly cookie for the application session res.cookie("authToken", token, { httpOnly: true, secure: true, // Set to true in production (requires HTTPS) sameSite: "lax", // Or 'strict' }); return res.status(200).json({ success: true, message: "Authentication successful", userId: applicationUserId, authSession: verifyResult, // Return the session object to the frontend }); } catch (error: any) { // Handle specific Turnkey errors if possible, otherwise return generic error console.error("Error verifying Turnkey OTP:", error); let errorMessage = "Failed to verify OTP."; if (error.message?.includes("invalid code")) { errorMessage = "Invalid or expired OTP code."; return res.status(401).json({ error: errorMessage }); // 401 Unauthorized } // Add more specific error handling based on Turnkey error codes/messages if needed return res.status(500).json({ error: errorMessage }); } }); ``` This provides a secure authentication flow using Turnkey's Email OTP service, integrated with your backend's JWT-based session management **and** Turnkey's frontend iframe session management. ### Subsequent Authenticated Requests Once the user is logged in (via passkey, OTP, or other methods) and has a valid JWT, subsequent requests from the frontend to your backend should include this JWT. **Crucial Security Note on Proxied Requests (Read and Write):** When proxying requests to Turnkey through your backend, it's **critical** to ensure that the authenticated user (identified by `userId` from the JWT) is actually authorized to perform the requested action on the *target* Turnkey sub-organization (`subOrgId`). This applies to **both write operations (like signing transactions) and read operations (like fetching balances or activities)**. Simply verifying the JWT authenticates the user, but it doesn't authorize them for a specific sub-organization. Your backend **must**: 1. Verify the JWT to get the authenticated `userId`. 2. Look up the `subOrgId`(s) associated with that `userId` in your application's database. 3. Compare the `subOrgId` from the incoming request against the one associated with the authenticated user in your database. 4. **Only proceed** if the requested `subOrgId` matches the one(s) associated with the authenticated user. Failure to perform this check, especially on read operations, could allow a user to potentially access information from sub-organizations they do not belong to. 1. **Client-side**: Include JWT in requests to your backend ```typescript const signedTurnkeyRequest = await turnkeyClient.stampSignRequest({ organizationId: subOrgId, signWith: "private-key-id", // ID of the private key to use for signing type: "TRANSACTION_TYPE_ETHEREUM", // Type of transaction unsignedTransaction: "0x...", // Hex-encoded unsigned transaction }); const response = await fetch("/api/proxy/turnkey/sign-transaction", { method: "POST", body: JSON.stringify({ signedTurnkeyRequest }), headers: { "Content-Type": "application/json", // JWT automatically included in cookies if httpOnly // Or explicitly: 'Authorization': `Bearer ${jwt}` }, credentials: "include", // Include cookies }); ``` 2. **Backend Verification**: Your backend verifies the JWT and processes the request ```typescript [expandable] // Example: JWT middleware const verifyJwt = (req, res, next) => { const token = req.cookies.authToken || req.headers.authorization?.split(" ")[1]; if (!token) { return res.status(401).json({ error: "Unauthorized" }); } try { const decoded = jwt.verify(token, JWT_SECRET); // Attach only userId to the request object req.user = { userId: decoded.userId }; next(); } catch (err) { return res.status(401).json({ error: "Invalid token" }); } }; // Protected route app.post( "/api/proxy/turnkey/sign-transaction", verifyJwt, async (req, res) => { const { signedRequest } = req.body; // Extract userId from the request object populated by middleware const { userId } = req.user; // --- Database Lookup Required for Authorization --- // Fetch the user's subOrgId from your database. // This lookup is ESSENTIAL for authorizing the user for the target sub-org, // regardless of whether the operation is a read or a write. const user = await db.users.findUnique({ where: { id: userId }, select: { turnkeySubOrgId: true }, }); const subOrgId = user?.turnkeySubOrgId; if (!subOrgId) { // User exists (JWT verified) but isn't linked to a sub-org in our DB return res.status(403).json({ error: "Forbidden: User not associated with a Turnkey sub-organization.", }); } // --- End DB Lookup --- // Validate the request is for the correct sub-organization // Compare the subOrgId from the incoming request against the one // associated with the authenticated user in our database. if (signedRequest.organizationId !== subOrgId) { return res .status(403) .json({ error: "Forbidden: Sub-organization ID mismatch" }); } // Forward to Turnkey const { url, body, stamp } = signedRequest; const response = await fetch(url, { method: "POST", body, headers: { [stamp.stampHeaderName]: stamp.stampHeaderValue, }, }); const turnkeyResponse = await response.json(); // Return the response return res.status(200).json(turnkeyResponse); } ); ``` ### JWT Implementation When implementing JWT authentication: ```typescript [expandable] import jwt from "jsonwebtoken"; // Get this from a secure environment variable const JWT_SECRET = process.env.JWT_SECRET; // Generate a JWT after successful authentication function generateToken(user) { return jwt.sign( { userId: user.id, }, JWT_SECRET, { expiresIn: "1h", // Token expires in 1 hour } ); } // Verify a JWT function verifyToken(token) { try { return jwt.verify(token, JWT_SECRET); } catch (error) { // Handle various JWT verification errors return null; } } ``` #### JWT Best Practices * Keep token expiration times short (15-60 minutes) * Include only necessary claims in the payload * Use HTTPS for all communications * Store tokens securely (use HTTP-only cookies rather than localStorage) * Implement token refresh mechanisms for long-lived sessions * Consider using JWTs with signatures (JWS) for enhanced security ## User Data Storage and Retrieval Many applications need to store additional user data and associate it with their Turnkey activities. Here's how to implement this: ### User-Turnkey Association Model Store a mapping between your application's user IDs and their corresponding Turnkey organization IDs: ```typescript // Prisma schema example model User { id String @id @default(uuid()) email String @unique name String? turnkeySubOrgId String @unique createdAt DateTime @default(now()) lastLoginAt DateTime @updatedAt } ``` ### Storing User Data When a user first authenticates with Turnkey (either by creating a new sub-organization or linking to an existing one): 1. Save the Turnkey organization ID in your user database 2. Optionally store additional metadata (creation time, recovery options, etc.) 3. Set up any necessary hooks or listeners for Turnkey activities ### Retrieving User Data When processing a proxied Turnkey request: 1. Extract the user ID from the authenticated JWT 2. Look up the associated Turnkey organization ID 3. Use this organization ID when forwarding requests to Turnkey ## Implementation Examples ### Next.js Server Actions Next.js Server Actions provide a convenient way to implement secure backend operations: ```typescript actions.ts [expandable] "use server"; import { cookies } from "next/headers"; import jwt from "jsonwebtoken"; import { db } from "@/lib/db"; // Assuming db setup import { turnkeyServer } from "./turnkey"; // Import the initialized client // Proxy a signing request to Turnkey export async function proxySignTransaction(signedRequest) { const token = cookies().get("authToken")?.value; if (!token) { throw new Error("Unauthorized: No token provided"); } let userId; try { const decoded = jwt.verify(token, process.env.JWT_SECRET); userId = decoded.userId; } catch (err) { throw new Error("Unauthorized: Invalid token"); } // --- Database Lookup Required for Authorization --- const user = await db.user.findUnique({ where: { id: userId }, select: { turnkeySubOrgId: true }, }); const subOrgId = user?.turnkeySubOrgId; if (!subOrgId) { throw new Error( "Forbidden: User not associated with a Turnkey sub-organization." ); } // --- End DB Lookup --- // Validate the request is for the correct sub-organization if (signedRequest.organizationId !== subOrgId) { throw new Error("Forbidden: Sub-organization ID mismatch"); } try { // Forward to Turnkey const { url, body, stamp } = signedRequest; const response = await fetch(url, { method: "POST", body, headers: { [stamp.stampHeaderName]: stamp.stampHeaderValue, }, }); const turnkeyResponse = await response.json(); return turnkeyResponse; } catch (error) { console.error("Error proxying to Turnkey:", error); throw new Error("Failed to proxy request to Turnkey"); } } ``` ```typescript turnkey.ts import { Turnkey } from "@turnkey/sdk-server"; // Initialize the server-side Turnkey client export const turnkeyServer = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY, apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }).apiClient(); ``` ### Express.js Example For standard Node.js applications using Express: ```typescript [expandable] import express from "express"; import cookieParser from "cookie-parser"; import jwt from "jsonwebtoken"; import { Turnkey } from "@turnkey/sdk-server"; const app = express(); app.use(express.json()); app.use(cookieParser()); // Initialize the server-side Turnkey client const turnkeyServer = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY, apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }).apiClient(); // JWT middleware const verifyJwt = (req, res, next) => { const token = req.cookies.authToken || req.headers.authorization?.split(" ")[1]; if (!token) { return res.status(401).json({ error: "Unauthorized" }); } try { const decoded = jwt.verify(token, process.env.JWT_SECRET); // Attach only userId to the request object req.user = { userId: decoded.userId }; next(); } catch (err) { return res.status(401).json({ error: "Invalid token" }); } }; // Proxy endpoint for Turnkey transaction signing app.post("/api/proxy/turnkey/sign-transaction", verifyJwt, async (req, res) => { const { signedRequest } = req.body; // Extract userId from the request object populated by middleware const { userId } = req.user; // --- Database Lookup Required for Authorization --- // Fetch the user's subOrgId from your database const user = await db.users.findUnique({ where: { id: userId }, select: { turnkeySubOrgId: true }, }); const subOrgId = user?.turnkeySubOrgId; if (!subOrgId) { // User exists (JWT verified) but isn't linked to a sub-org in our DB return res.status(403).json({ error: "Forbidden: User not associated with a Turnkey sub-organization.", }); } // --- End DB Lookup --- // Validate the request is for the correct sub-organization // Compare against the subOrgId retrieved from the database if (signedRequest.organizationId !== subOrgId) { return res .status(403) .json({ error: "Forbidden: Sub-organization ID mismatch" }); } try { // Forward to Turnkey const { url, body, stamp } = signedRequest; const response = await fetch(url, { method: "POST", body, headers: { [stamp.stampHeaderName]: stamp.stampHeaderValue, }, }); const turnkeyResponse = await response.json(); // Return the response return res.status(200).json(turnkeyResponse); } catch (error) { console.error("Error signing transaction:", error); return res.status(500).json({ error: "Failed to sign transaction", message: error.message, }); } }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); }); ``` ## Security Considerations When implementing this pattern, keep these security considerations in mind: 1. **API Key Security**: Never expose your backend Turnkey API keys to the frontend 2. **JWT Validation**: Thoroughly validate JWTs (signature, expiration, audience, etc.) 3. **Input Validation**: Sanitize and validate all input received from the frontend 4. **Rate Limiting**: Implement rate limiting to prevent abuse 5. **Monitoring**: Set up logging and monitoring for suspicious activities 6. **Error Handling**: Return appropriate error messages without exposing sensitive details ## Advanced Topics Learn about advanced patterns like multi-signature setups requiring approvals from both the user and the backend. # Email Auth & Recovery Source: https://docs.turnkey.com/authentication/email Email Authentication enables users to authenticate and recover their Turnkey accounts using email-based verification. There are two methods of email authentication: **One-Time Password** * Uses a 6-9 digit or bech32 alphanumeric one-time password sent via email * Simple, and familiar user experience **Credential Bundle** * Sends an encrypted API key credential directly via email * Alternative method for specific use cases * More secure, but requires copying the full credential to the client Both methods provide users with an expiring API key for authentication or account recovery. ## Core Mechanism Email Authentication is built with expiring API keys as the foundation. The two delivery mechanisms are: ### OTP-based Method The authentication process happens in two steps: A 6-9 digit or alphanumeric OTP code is sent to the user's verified email address Upon verification of the correct code, an API key credential is generated and encrypted for the client ### Credential Bundle Method The API key credential is encrypted and delivered directly through email to the user. In both cases, once the credential is live on the client side (within the context of an iframe), it is readily available to stamp (authenticate) requests. See the [enclave to end-user secure channel](/security/enclave-secure-channels) for more info on how we achieve secure delivery. ## Prerequisites Make sure you have set up your primary Turnkey organization with at least one API user that can programmatically initiate email auth on behalf of suborgs. Check out our [Quickstart guide](/getting-started/quickstart) if you need help getting started. To allow an API user to initiate email auth, you'll need the following policy in your main organization: ```json { "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "activity.resource == 'AUTH' && activity.action == 'CREATE'" } ``` ## User Experience ### OTP-based Authentication Flow The flow begins with a new activity of type `ACTIVITY_TYPE_INIT_OTP_AUTH` with these parameters: * `otpType`: specify `"OTP_TYPE_EMAIL"` * `contact`: user's email address (must match their registered email) * `emailCustomization`: optional parameters for customizing emails * `userIdentifier`: optional parameter for rate limiting SMS OTP requests per user. We recommend generating this server-side based on the user's IP address or public key. See the [OTP Rate Limits](#otp-rate-limits) section below for more details. * `alphanumeric`: optional parameter for making this code bech32 alphanumeric or not. default: true * `otpLength`: optional parameter for selecting the length of the OTP. default: 9 After receiving the OTP, users complete authentication with `ACTIVITY_TYPE_OTP_AUTH`: * `otpId`: ID from the init activity * `otpCode`: the 6-9 digit or alphanumeric code received via email * `targetPublicKey`: public key for credential encryption * `apiKeyName`: optional name (defaults to `OTP Auth - `) * `expirationSeconds`: optional validity window (defaults to 15 minutes) * `invalidateExisting`: optional boolean to invalidate previous OTP Auth API keys auth otp email ### OTP Rate Limits In order to safeguard users, Turnkey enforces rate limits for OTP auth activities. If a `userIdentifier` parameter is provided, the following limits are enforced: * 3 requests per 3 minutes per unique `userIdentifier` * 3 retries max per code, after which point that code will be locked * 3 active codes per user, each with a 5 minute TTL ### Credential Bundle Authentication Flow This alternative method uses `ACTIVITY_TYPE_EMAIL_AUTH` with these parameters: * `email`: user's email address (must match their registered email) * `targetPublicKey`: public key for credential encryption * `apiKeyName`: optional name (defaults to `Email Auth - `) * `expirationSeconds`: optional validity window (defaults to 15 minutes) * `emailCustomization`: optional parameters for customizing emails * `invalidateExisting`: optional boolean to invalidate previous Email Auth API keys auth email ### Recovery Flow For account recovery scenarios, users can initiate a recovery-specific flow using the `ACTIVITY_TYPE_INIT_USER_EMAIL_RECOVERY` activity type, which requires: * `email`: the email of the user needing recovery (must match their registered email) * `targetPublicKey`: the public key for recovery credential encryption The recovery process consists of two phases: 1. **Initiation**: Generates a temporary recovery credential and sends it via email 2. **Finalization**: User decrypts the recovery credential and uses it to sign an `ACTIVITY_TYPE_RECOVER_USER` activity, which can add new authenticators to regain account access auth email ## Email Customization We offer customization for the following: * `appName`: the name of the application. This will be used in the email's subject, e.g. `Sign in to ${appName}` * `logoUrl`: a link to a PNG with a max width of 340px and max height of 124px * `magicLinkTemplate`: a template for the URL to be used in the magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s` ```js // Sign and submits the EMAIL_AUTH activity const response = await client.emailAuth({ type: "ACTIVITY_TYPE_EMAIL_AUTH", timestampMs: String(Date.now()), organizationId: , parameters: { email: , targetPublicKey: , apiKeyName: , expirationSeconds: , emailCustomization: { appName: , logoUrl: , magicLinkTemplate: } }, }); ``` ### Email Templates We also support custom HTML email templates for [Enterprise](https://www.turnkey.com/pricing) clients on the **Scale** tier. This allows you to inject arbitrary data from a JSON string containing key-value pairs. In this case, the `emailCustomization` variable may look like: ```js ... emailCustomization: { templateId: , templateVariables: "{\"username\": \"alice and bob\"}" } ... ``` In this specific example, the value `alice and bob` can be interpolated into the email template using the key `username`. The use of such template variables is purely optional. Here's an example of a custom HTML email containing an email auth bundle: ![dynamic email auth example](https://mintlify.s3.us-west-1.amazonaws.com/turnkey-0e7c1f5b/images/embedded-wallets/img/email-auth-example-dynamic.png) If you are interested in implementing bespoke, fully-customized email templates, please reach out to [hello@turnkey.com](mailto:hello@turnkey.com). ## Authorization Authorization is managed through our [policy engine](/concepts/policies/overview): ### Authentication Both OTP-based and credential bundle authentication activities: * Can be performed by [root users](/concepts/overview#users) and users with proper policy authorization * Require the respective feature to be enabled in the organization and sub-organization * Can target any user in the organization or sub-organizations Specifically: * For OTP-based auth: `ACTIVITY_TYPE_INIT_OTP_AUTH` and `ACTIVITY_TYPE_OTP_AUTH` * For credential bundle auth: `ACTIVITY_TYPE_EMAIL_AUTH` ### Recovery * `ACTIVITY_TYPE_INIT_USER_EMAIL_RECOVERY`: * Initiates the recovery process * Requires proper authorization via policies * Can target any user in the organization or sub-organizations * `ACTIVITY_TYPE_RECOVER_USER`: * Must be signed by the recovery credential received via email * Users can add credentials to their own user when authenticated * Recovery credentials expire after 15 minutes * Only the most recent recovery credential remains valid * Users can add new authenticators to regain account access when authenticated with a recovery credential email auth authorization ## Implementation in Sub-organizations Both authentication methods and recovery work seamlessly with [sub-organizations](/concepts/sub-organizations). ### Example Implementations * [OTP Auth Example](https://github.com/tkhq/sdk/tree/main/examples/otp-auth) * [Email Auth Example](https://github.com/tkhq/sdk/tree/main/examples/email-auth) * [Email Recovery Example](https://github.com/tkhq/sdk/tree/main/examples/email-recovery) * [Demo Embedded Wallet](https://wallet.tx.xyz) ([code](https://github.com/tkhq/demo-embedded-wallet)) For implementation details: ## Implementation in Organizations For organizations accessed via dashboard: 1. Ensure the required features are enabled: * `FEATURE_NAME_OTP_EMAIL_AUTH` for OTP-based authentication * `FEATURE_NAME_EMAIL_AUTH` for credential bundle authentication * Recovery features if needed 2. Users initiating the request must have appropriate permissions ## Opting Out Organizations can disable email-based features if their security model requires it: Use `ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE` to disable: * `FEATURE_NAME_OTP_EMAIL_AUTH` for OTP-based authentication * `FEATURE_NAME_EMAIL_AUTH` for credential bundle authentication * `FEATURE_NAME_EMAIL_RECOVERY` for recovery When creating sub-organizations, use: * `disableOtpEmailAuth` parameter for OTP-based authentication * `disableEmailAuth` parameter for credential bundle authentication * `disableEmailRecovery` parameter for recovery ## Implementation Notes[​](#implementation-notes "Direct link to Implementation Notes") * Users are limited to: * 10 long-lived API keys * 10 expiring API keys (oldest are discarded when limit is reached) ### For Top-level Organizations * Both authentication methods are disabled by default * Must be enabled via `ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE` ### For Sub-organizations * Both authentication methods are enabled by default * Can be disabled during creation using `CreateSubOrganizationIntentV7` activity parameters Example of enabling OTP-based Email Auth: ```bash turnkey request --host api.turnkey.com --path /public/v1/submit/set_organization_feature --body '{ "timestampMs": "'"$(date +%s)"'000", "type": "ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE", "organizationId": "", "parameters": { "name": "FEATURE_NAME_OTP_EMAIL_AUTH" } }' --organization ``` Example of enabling credential bundle Email Auth: ```bash turnkey request --host api.turnkey.com --path /public/v1/submit/set_organization_feature --body '{ "timestampMs": "'"$(date +%s)"'000", "type": "ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE", "organizationId": "", "parameters": { "name": "FEATURE_NAME_EMAIL_AUTH" } }' --organization ``` # Overview Source: https://docs.turnkey.com/authentication/overview Learn about supported authentication methods for Turnkey, how to add them, and usage details. Turnkey's wallet system supports granular controls on who can access wallets and what actions different users can perform. To enforce these controls, Turnkey's API must verify the identity of the party requesting a wallet action, ensuring that only authorized actions are executed by the system. This process is known as **authentication**. Turnkey supports both **API authentication** and **user authentication** for authenticating access to wallets. ## API authentication With **API authentication**, Turnkey authenticates a request from your server directly using an **API secret**. This ensures that Turnkey only executes requests sent by your servers alone, and no other party. In addition to the API secret, you can also configure **authorization policies** that control specific wallets, private keys, and other resources. Any requests to use or update these resources require approval according to the corresponding policy. This allows you to enforce granular controls on all Turnkey resources. For backend implementation details, see our [Backend Setup](/authentication/backend-setup) guide. **API Reference**: [Create API Keys](/api-reference/api-keys/create-api-keys), [Get API Keys](/api-reference/api-keys/get-api-key) ## User authentication Turnkey is a powerful toolkit for progressive authentication of users. With fine-grained control over onboarding flows and wallet connections, you can improve conversion and craft better UX. Using any of Turnkey's client-side SDKs, your app can authenticate users across web2 and web3 accounts, including: * **WebAuthN/Passkeys**: Biometric or passkey-based login based on the WebAuthn standard. [Learn more](/authentication/passkeys/introduction) * **Email or SMS**: Passwordless login via a one-time passcode sent to a user's email address or phone number. [Learn more](/authentication/email) | [SMS Authentication](/authentication/sms) * **OAuth and social logins**: Social login with Google, Apple, Twitter, Discord, GitHub, LinkedIn, and more. [Learn more](/authentication/social-logins) * **Wallets**: External wallet login via Sign-In With Ethereum and Sign-In With Solana. Your app can configure each of these authentication methods to be an upfront login method, or as an account that users link later. All of Turnkey's authentication methods create a common user object, where you can easily find a user's unique ID and all of the accounts they've linked to their profile. A user is a user, regardless of whether they've connected with a wallet, email or other account. Once a user successfully authenticates with Turnkey, Turnkey creates a session for that user that your app can use to represent an authenticated session or to make authenticated requests to your backend. For information about managing authenticated sessions, see our [Sessions](/authentication/sessions) documentation. ## Related Resources Biometric and hardware-based passwordless authentication using WebAuthn standard. Passwordless login via one-time codes sent to users' email addresses. User verification through one-time passwords sent via text message. OAuth authentication with popular social providers like Google, Apple, and Twitter. Manage authenticated user sessions and access tokens in your application. # Discoverable vs. Non-Discoverable Source: https://docs.turnkey.com/authentication/passkeys/discoverable-vs-non-discoverable Also known as "resident" vs. "non-resident" credentials. From [the spec](https://www.w3.org/TR/webauthn-2/) > Historically, client-side discoverable credentials have been known as resident credentials or resident keys. Due to the phrases ResidentKey and residentKey being widely used in both the WebAuthn API and also in the Authenticator Model (e.g., in dictionary member names, algorithm variable names, and operation parameters) the usage of resident within their names has not been changed for backwards compatibility purposes. Also, the term resident key is defined here as equivalent to a client-side discoverable credential. What does this mean exactly? * "resident" credentials and "discoverable" credentials are the same * "non-resident" credentials and "non-discoverable" credentials are the same. The spec authors made this rename for clarity. With terminology out of the way, what is a "discoverable" credential compared to a "non-discoverable" credential? And why does it matter? ## Discoverable credentials A discoverable credential is a self-contained key pair, stored on the end-user's device. Discoverable credentials are preferred because keys are self-contained, can easily be synced and can be used across devices independently. Crucially for UX, the end-user is able to list their passkeys and choose which device/passkey they'd like to use: device selection on Chrome passkey selection on Chrome With discoverable credentials you don't have to keep track of credential IDs. Your authentication flow can simply be: "prompt the user with passkey authentication", and let the browser or device native UX handle the rest! The downside is you lose some control over these prompts, because they will vary depending on your users' OS and browser. For a live example using discoverable credentials, see [wallet.tx.xyz](https://wallet.tx.xyz/). ## Non-Discoverable credentials A non-discoverable credential isn’t stored on the end-user's device fully: Turnkey must store the generated credential ID; otherwise the user won’t be able to sign. This is because the actual signing key is a combination of an “on-device” secret and the credential ID (see details [here](https://crypto.stackexchange.com/questions/105942/how-do-non-resident-keys-work-in-webauthn)). Why would you choose non-discoverable credentials? * Most hardware security keys have limited slots to store discoverable credentials, or will refuse to create new discoverable credentials on the hardware altogether. YubiKey 5 [advertises 25 slots](https://support.yubico.com/hc/en-us/articles/4404456942738-FAQ#h_01FFHQFVBW0995G2MKZGCKQVEJ), SoloKeys [support 50](https://github.com/solokeys/solo1/issues/156#issuecomment-477645573), NitroKeys 3 [support 10](https://github.com/Nitrokey/nitrokey-3-firmware/blob/0e23c75318e2016ac1cfb8345de9279e3ad2eaf9/components/apps/src/lib.rs#L390). Non-discoverable credentials aren't subject to these limits because they work off of a single hardware secret. * Security keys can only allow clearing of individual slots if they support [CTAP 2.1](https://fidoalliance.org/specs/fido-v2.1-rd-20201208/fido-client-to-authenticator-protocol-v2.1-rd-20201208.html). This is described in [this blog post](https://fy.blackhats.net.au/blog/2023-02-02-how-hype-will-turn-your-security-key-into-junk/). When security keys do not support CTAP 2.1, slots can only be freed up by resetting the hardware entirely, erasing all secrets at once. * Non-discoverable credentials take less space. This is important in some environments, but unlikely to be relevant if your users are storing passkeys in their Google or Apple accounts (plenty of space available there!) * Credential IDs have to be communicated during authentication (via the `allowCredentials` field). This allows browsers to offer better, more tailored prompts in some cases. For example: if the list contains a single authenticator with `"transports": ["AUTHENTICATOR_TRANSPORT_INTERNAL"]`, Chrome does “the right thing” by skipping the device selection popup: users go straight to the fingerprint popup, with no need to select “this device”! The downside to this is, of course, that you need to store credential IDs, and you need to make sure you can retrieve credentials for each user. This can be done with a table of credentials keyed by user email, for example. Or if you have your own authentication already, a list of credentials can be returned when the user logs in. For a live example using non-discoverable credentials, head to [app.turnkey.com](https://app.turnkey.com). That's right, Turnkey uses non-discoverable credentials because we need to offer broad support for security keys. We have some work ongoing to support both discoverable and non-discoverable credentials going forward. # Integrating Passkeys Source: https://docs.turnkey.com/authentication/passkeys/integration ## Passkey flow A typical passkey flow is composed of 4 main steps, depicted below: Passkey flow on Turnkey 1. Your app frontend triggers a passkey prompt. 2. Your end-user uses their device to produce a signature with their passkey, and a signed request is produced. 3. The signed request is forwarded to your backend. This step is optional, see ["To Proxy or not to proxy"](#proxying-signed-requests) below for more information. 4. The signed request is verified within a Turnkey secure enclave. This flow happens once for **registration** and for each subsequent **authentication** or signature request. The main difference is the browser APIs used to trigger the passkey prompt in step (1): * **Passkey registration** uses `navigator.credentials.create`(as described in [this guide](https://web.dev/passkey-registration/)). `navigator.credentials.create` triggers the creation of a **new** passkey. * **Passkey authentication** uses `navigator.credentials.get`. See [this guide](https://web.dev/passkey-form-autofill/) for more information. `navigator.credentials.get` triggers a signature prompt for an **existing** passkey. ## Our SDK can help Our SDK has integrated passkey functionality, and we've built examples to help you get started. * [`@turnkey/http`](https://www.npmjs.com/package/@turnkey/http) has a helper to trigger passkey registration (`getWebAuthnAttestation`). You can see it in action in our [`with-federated-passkeys`](https://github.com/tkhq/sdk/tree/main/examples/with-federated-passkeys) example: [direct code link](https://github.com/tkhq/sdk/blob/a2bfbf3cbd6040902bbe4c247900ac560be42925/examples/with-federated-passkeys/src/pages/index.tsx#L88) * [`@turnkey/webauthn-stamper`](https://www.npmjs.com/package/@turnkey/webauthn-stamper) is a passkey-compatible stamper which integrates seamlessly with `TurnkeyClient`: ```ts import { WebauthnStamper } from "@turnkey/webauthn-stamper"; import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; const stamper = new WebauthnStamper({ rpId: "your.app.xyz", }); // New HTTP client able to sign with passkeys const httpClient = new TurnkeyClient( { baseUrl: "https://api.turnkey.com" }, stamper ); // This will produce a signed request that can be POSTed from anywhere. // The `signedRequest` has a URL, a POST body, and a "stamp" (HTTP header name and value) const signedRequest = await httpClient.stampCreatePrivateKeys(...) // Alternatively, you can POST directly from your frontend. // Our HTTP client will use the webauthn stamper and the configured baseUrl automatically! const activityPoller = createActivityPoller({ client: client, requestFn: client.createPrivateKeys, }); // Contains the activity result; no backend proxy needed! const completedActivity = await activityPoller({ type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2", // (omitting the rest of this for brevity) }) ``` * [`@turnkey/viem`](https://www.npmjs.com/package/@turnkey/viem) is a package wrapping all of the above so that you work directly with Viem without worrying about passkeys. See [this demo](https://github.com/tkhq/sdk/tree/main/examples/with-viem-and-passkeys). Regardless of whether you use our helpers and abstractions, take a look at [our registration and authentication options guide](/authentication/passkeys/options). This will help you choose the right options for your passkey flow. If you have questions, feedback, or find yourself in need of an abstraction or integration that doesn't exist yet, please get in touch with us! You can * Create an [issue on our SDK repo](https://github.com/tkhq/sdk/issues) * Join our slack community [here](https://join.slack.com/t/clubturnkey/shared_invite/zt-31v4yhgw6-PwBzyNsWCCBTk2xft3EoHQ) * Contact us at [hello@turnkey.com](mailto:hello@turnkey.com) We're here to make this as easy as possible for you and your team! ## Passkey wallets with sub-organizations If you're wondering how to create independent, non-custodial wallets for your end-users, head to [Sub-Organizations](/concepts/sub-organizations). In short: you'll be able to pass the registered passkeys as part of a "create sub-organization" activity, making your end-users the sole owners of any resource created within the sub-organization (including private keys). Your organization will only have read permissions. # Introduction to Passkeys Source: https://docs.turnkey.com/authentication/passkeys/introduction Passkeys are born out of a new standard being pushed by major industry players: Apple and Google. Google has a great high-level introduction to passkeys at [https://developers.google.com/identity/passkeys](https://developers.google.com/identity/passkeys), and Apple has its own version here: [https://developer.apple.com/passkeys](https://developer.apple.com/passkeys) ## TLDR: what are passkeys? From a technical point of view, passkeys are cryptographic key pairs created on end-user devices. Apple and Google have done a great job making these key pairs usable: * Key generation happens in secure end-user hardware. * Using passkeys is easy thanks to native browser UIs and cross-device syncing. * Passkey recovery for users is supported natively by Apple via iCloud Keychain and Google via the Google Password Manager. Passkeys come with big security upgrades compared to traditional passwords: * Access to passkeys is gated with OS-level biometrics: faceID, touchID, lock screen patterns, and so on. * Passkeys are bound to the web domain that creates them. This is important to thwart phishing attacks, where an attacker hosts a similar-looking website to steal user credentials. This is doable with passwords; impossible with passkeys. * Because passkeys rely on public key cryptography, passkeys have two components: a public key and a private key. Private keys are never disclosed to websites or apps, making them a lot harder to steal. Only public keys are sent. To authenticate, passkeys sign messages (with their private keys) and provide signatures as proofs, similar to crypto wallets. ## Isn't this similar to Webauthn? If you know about Webauthn, congratulations: a lot of this will feel familiar. Passkeys rely on the [same web standard](https://www.w3.org/TR/webauthn-2/) and the same browser APIs: `navigator.credentials.create` and `navigator.credentials.get`. The difference? Passkeys are resident credentials and they can be synced between devices. As a result, they are **not** device-bound and can be used from any device. ## How do cross-device syncing and recovery work? Synchronization and recovery are both supported natively by Apple and Google: * With Apple, Passkeys created on one device are synced through [iCloud Keychain](https://support.apple.com/en-us/HT204085) as long as the user is logged in with their Apple ID. Apple covers both syncing and recovery in ["About the security of passkeys"](https://support.apple.com/en-us/102195). For some additional detail, see [this Q\&A with the passkey team](https://developer.apple.com/news/?id=21mnmxow). Apple's account recovery process is documented in [this support page](https://support.apple.com/en-us/HT204921). * With Google, [Google Password Manager](https://passwords.google/) syncs passkeys across devices seamlessly. Google has plans to support syncing more broadly across different operating systems, see [this support summary](https://developers.google.com/identity/passkeys/supported-environments#chrome-passkey-support-summary). Recovery is covered in [this FAQ ("What happens if a user loses their device?")](https://developers.google.com/identity/passkeys/faq#what_happens_if_a_user_loses_their_device): it relies on Google's overall [account recovery process](https://support.google.com/accounts/answer/7682439?hl=en) because passkeys are attached to Google accounts. ## OS and browser support Modern browsers have great support for passkeys. See [caniuse](https://caniuse.com/passkeys) for detailed information. Support also varies by operating system: [this matrix](https://passkeys.dev/device-support/#matrix) has detailed information about OS-level support. ## Betting on Webauthn and Passkeys We believe **it's time to move away from passwords** so we've built Turnkey without them. When you authenticate to Turnkey you'll be prompted to create a new passkey: Authenticator selection on Turnkey Passkey prompt on Turnkey Authentication to Turnkey requires a passkey signature. No password needed! Next up, learn about how you can integrate passkeys into your app, [here](/authentication/passkeys/integration). # Native Passkeys Source: https://docs.turnkey.com/authentication/passkeys/native If you're unfamiliar with passkeys broadly, head to for an overview. TL;DR: passkeys are cryptographic key pairs generated and stored on secure hardware. Typically this is your Mac's or iPhone's , your Android's , or an external security key plugged in via USB. * Registration ("sign up") creates a new key pair: this is your passkey * Authentication ("sign in") uses an existing passkey to sign a message, proving ownership of the associated private key stored on your device. ## Passkeys on the Web Creating and using passkeys on the web is straightforward: browsers offer APIs to do it! * `navigator.credentials.create` creates a passkey * `navigator.credentials.get` prompts the user to select a passkey to sign a message And this doesn't require a backend. Here's a demo proving it: [https://passkeyapp.tkhqlabs.xyz/](https://passkeyapp.tkhqlabs.xyz/) An important security feature of passkeys: they're **domain-bound** to prevent phishing. In other words: passkeys created on `passkeyapp.tkhqlabs.xyz` won't be usable on `turnkey.com` for example. Browsers prevent this. ## Native Platform APIs ### Android In the Android ecosystem the `CredentialManager` supports creating and using passkeys with `CreatePublicKeyCredentialRequest` and `GetCredentialRequest`. See [the associated documentation](https://developer.android.com/training/sign-in/passkeys#sign-in) for more information. ### iOS iOS APIs to create and use passkeys are available as well: * `ASAuthorizationPlatformPublicKeyCredentialProvider(…).createCredentialRegistrationRequest` for passkey creation * `ASAuthorizationPlatformPublicKeyCredentialProvider(…).createCredentialAssertionRequest` for passkey usage See [these docs](https://developer.apple.com/documentation/authenticationservices/asauthorizationplatformpublickeycredentialprovider) for more info. And [this app](https://github.com/r-n-o/shiny) for a mini demo. ### Beware: no native Turnkey SDK (yet) While the native APIs to interact with passkeys exists on both iOS and Android, Turnkey doesn't yet offer an SDK for Swift or Kotlin, which means you'd have to write code to sign activities and send HTTP requests to our API. Get in touch with us if this is something you're attempting to do, we'd love to support you and release this as a proper SDK maintained by Turnkey. ## Building with React Native (recommended) Turnkey has a fully-featured [TypeScript SDK](https://github.com/tkhq/sdk/). It provides a type-safe client to call the Turnkey API and abstracts activity request signing. [React Native](https://reactnative.dev/) lets you write your app in Typescript and compile it into native code for both iOS and Android automatically. To sign Turnkey requests with native passkeys in a React Native application we've released [`@turnkey/react-native-passkey-stamper`](https://www.npmjs.com/package/@turnkey/react-native-passkey-stamper), a package compatible with our TypeScript client to sign Turnkey requests with native passkeys. Under the hood this package wraps [`react-native-passkey`](https://github.com/f-23/react-native-passkey), which calls the right native APIs on [iOS](https://github.com/f-23/react-native-passkey/blob/17184a1b1f6f3ac61e07aa784c9b64efb28b570e/ios/Passkey.swift#L29) and [Android](https://github.com/f-23/react-native-passkey/blob/17184a1b1f6f3ac61e07aa784c9b64efb28b570e/android/src/main/java/com/reactnativepasskey/PasskeyModule.kt#L30C44-L30C76), and exports a unified interface that we leverage. Bottom-line: if you've used our [webauthn stamper](https://www.npmjs.com/package/@turnkey/webauthn-stamper) or [API key stamper](https://www.npmjs.com/package/@turnkey/api-key-stamper), using our React Native passkey stamper will feel familiar. Take a look at the ["Installation"](https://www.npmjs.com/package/@turnkey/react-native-passkey-stamper#installation) and ["Usage"](https://www.npmjs.com/package/@turnkey/react-native-passkey-stamper#usage) sections to get started with passkeys in your React Native application. If you're looking for a concrete example, head to [this repository](https://github.com/r-n-o/passkeyapp): it contains a sample application integrated with Turnkey, written with Expo, and tested on both Android and iOS. ## Linking apps and web domains Passkeys on native apps aren't app-bound, they're **domain** bound just like web passkeys. This may come as a surprise: you'll have to configure a web domain to use passkeys natively! Configuration is done separately per ecosystem, but the idea is the same: * iOS expects a JSON file at the domain root (`/.well-known /apple-app-site-association`) : [example](https://github.com/r-n-o/passkeyapp/blob/main/http/.well-known/apple-app-site-association) * Android expects a JSON file at the domain root (`/.well-known/assetlinks.json`): [example](https://github.com/r-n-o/passkeyapp/blob/main/http/.well-known/assetlinks.json) This unlocks interesting flows where users use their web-created passkeys in a "companion" native app, or vice-versa. For example: a native app linked to the wallet.tx.xyz domain would allow users to log into their account from a native mobile app *using their web-created passkey* as long as they're synced properly. Note that these associations are "many-to-many": a website can link multiple associated apps, and a single native application can choose to create passkeys for multiple domains, via a dropdown for example. However (as far as we know) a single passkey is always bound to a single web domain: it can't be bound to multiple web domains. # Passkey Options Source: https://docs.turnkey.com/authentication/passkeys/options Whether you use the raw browser APIs or one of our helpers you'll have flexibility to set your own registration and authentication options. This page provides an overview and some recommendations related to these options. ## Registration options Mozilla has good (but lengthy) documentation on each option: [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/create). Below we detail the most relevant options you'll want to think about. ### `challenge` This is the challenge signed by the end-user for registration. During registration this challenge isn't meaningful so we recommend picking a random challenge. It will not be visible to users. ### `timeout` Number of seconds before "giving up". The browser will simply show a timeout popup: Timeout popup This UI isn't very helpful, so we recommend making the timeout long (5 minutes). The less your users see this, the better. ### `rp` The `rp` options is an object with 2 fields: `id` and `name`. `rp.id` (aka RPID) should be your app top-level domain. For example, if your app is hosted on `https://your.app.xyz` the RPID should be `app.xyz` unless you have good reasons to do otherwise (see below). `rp.id`, or RPID, is a way to identify the website a passkey is associated with. Once set at registration time, it **determines the set of origins on which the passkey may be be used**. The [WebAuthn spec](https://www.w3.org/TR/webauthn-2/#relying-party-identifier) states that the RPID must be a “registrable domain suffix of, or equal to” the current domain. If the page creating a passkey is hosted at `https://your.app.xyz`, the RPID can thus be "your.app.xyz" or "app.xyz". A passkey with RPID "your.app.xyz" **cannot** be used on `https://www.app.xyz` or `https://foo.app.xyz`. However a passkey created with RPID "app.xyz" **will** be usable on all `https://*.app.xyz` sub-domains: `https://your.app.xyz`, `https://www.app.xyz`, `https://foo.app.xyz`, and so on. Hence our general recommendation above to set `app.xyz` (top-level domain) as the RPID to maximize flexibility. A reason why you might want to set the RPID to "your.app.xyz" instead of "app.xyz" like recommended above is extra security: if you are worried about user passkeys being usable across all your sub-domains, it makes sense to scope passkeys to the sub-domain they're meant to be used on, and only that sub-domain. If you scope passkeys to a specific sub-domain, be aware that migrating your app to a different sub-domain later will require a migration process where users have to re-enroll themselves by creating new passkeys on the new sub-domain. Passkeys cannot be transferred from one RPID to another. `rp.id` will show up in the initial registration popup: RPID in registration prompt `rp.name` doesn't show up in the popup so can be set to anything. We recommend setting it to the correctly capitalized name of your app, in case browsers start showing it in their native UIs in the future. ### `attestation` This option indicates whether an attestation is needed, to prove the authenticator authenticity. In general, Turnkey doesn't need attestations. Most passkeys do not produce meaningful attestations for privacy reasons. In the context of passkey integrations, you can omit this option: it will default to "none". ### `pubKeyCredParams` and `alg` The `pubKeyCredParams` is a list of supported algorithms. If you're relying on Turnkey to validate passkey signatures, this list should be: `[{alg: -7, type: "public-key"}, {alg: -257, type: "public-key"}]`. The integers `-7` and `-257` are algorithm identifiers for ES256 (aka P256) and RS256 (aka RSA), respectively. The full list of possible values is part of the [COSE standard, maintained by IANA](https://www.iana.org/assignments/cose/cose.xhtml#algorithms). Currently Turnkey only supports ES256 and RS256. ### `user` The `user` field has three sub-fields: * `id`: also known as "user handle", isn't visible to the end-user. We **strongly recommend setting this to a random value** (e.g. `const id = new Uint8Array(32); crypto.getRandomValues(id)`) to make sure a new passkey is created. Be aware: **if you accidentally set this value to an existing user handle, the corresponding passkey will be overridden!** [This section of spec](https://www.w3.org/TR/webauthn-2/#dictionary-user-credential-params) is clear on the matter: "the user handle ought not be a constant value across different accounts, even for non-discoverable credentials". * `name`: this will show up in the passkey list modal (see screenshot below). We recommend setting this to something the user will recognize: their email, the name of your app, or potentially leave this up to the user: User name and display name in passkey list * `displayName`: as far as we can tell this doesn't show up in current browser UIs. It might show up in future iterations so it's best to populate this with the same value as `name`. ### `authenticatorSelection` This option has lots of consequences for UX, and it has many sub-options, outlined below. #### `authenticatorAttachment` This option, if set, restricts the type of authenticators that can be registered. See the table below for the values this option can take and their effect on registration prompts (captured via Chrome on a MacBook Pro). | Empty (default) | `platform` | `cross-platform` | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | If you want broad compatibility, leave this option empty, and the browser UI will allow for both internal and external passkeys. | If set to `platform`, only internal authenticators (face ID, touch ID, and so on) can be registered. | If set to `cross-platform`, only passkeys from other devices or attached via USB are allowed. | | authenticatorAttachment unspecified | authenticatorAttachment set to platform | authenticatorAttachment set to cross-platform | #### `requireResidentKey` and `residentKey` These options allow you to specify whether you want your users to create discoverable or non-discoverable credentials. See [Discoverable vs. non-discoverable](/authentication/passkeys/discoverable-vs-non-discoverable) for more information. Default values: `residentKey` is `discouraged` and `requireResidentKey` is `false`. Important note: the default for `requireResidentKey` (`discouraged`) results in different outcomes based on OS: Android devices create non-discoverable credentials whereas iOS devices create discoverable credentials. If you want to create discoverable credentials whenever possible, set `requireResidentKey` to `false` and `residentKey` to `preferred`, which work across Android and iOS devices. #### `userVerification` "User verification" refers to mechanisms on the authenticators themselves such as PIN codes or biometric/fingerprint readers. This flag can be set to: * `discouraged`: yubikey PINs won't be required even if the device technically supports it. We've found that for TouchID/FaceID, authentication will still be required however. * `preferred`: yubikey PINs and other authentication mechanisms will be required if supported, but devices without them will be accepted. * `required`: authenticators without user verification support won't be accepted. To maximize compatibility we recommend setting `userVerification` to "discouraged" or "preferred" because some authenticators do not support user verification. Due to poor yubikey PIN UX in browsers, setting `userVerification` to "discouraged" is best unless you operate with a strict security threat model where user verification makes a big difference. "preferred" is the default value if you don't specify this option. ## Authentication options Mozilla's documentation on authentication options can be found here: [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get). Luckily there are fewer authentication options than registration. ### `challenge` This is the challenge to sign with the passkey. If you're integrating with Turnkey, the challenge should be the POST body of the request to be signed. Our SDK and helpers set this automatically for you already. ### `rpId` Must match the `rp.id` option during passkey registration. Passkeys are domain bound, so it's not possible to use a passkey registered with `rp.id` set to "foo.com" and use it on "bar.com". This is a core anti-phishing counter-measure. ### `allowCredentials` List of objects restricting which credentials can be used during authentication. This is crucial to specify if you're using [non-discoverable credentials](/authentication/passkeys/discoverable-vs-non-discoverable#non-discoverable-credentials) or if you want to tailor browser prompts to the right type of transport. Each object in this list has an ID (the credential ID) and a list of transports (e.g. "hybrid", "internal", "usb", etc). The `transports` list is **optional** but results in better, more targeted prompts. For example, here are screenshot of targeted prompts captured on Chrome, on a MacBook laptop: | `transports: ["internal"]` | `transports: ["usb"]` | `transports: ["hybrid"]` | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | authentication prompt with transports: internal | authentication prompt with transports: usb | authentication prompt with transport: hybrid | The credential ID needs to be passed as a buffer but is returned from registration as a base64-encoded value: make sure to decode it (in JavaScript: `Buffer.from(storedCredentialId, "base64")`) to avoid issues. If the wrong credential ID is specified, `transports: ["internal"]` is set, browsers error right away because they can enumerate internal credentials. Chrome, for example, displays the following error: Chrome error when no matching passkey has been found for the provided Credential ID However, if the wrong credential ID is specified without `transports` set (or with other-than-internal `transports` set), browsers won't error right away because they can't enumerate external credentials. They will display an error once the user has pressed their security key or gone through the cross-device passkey flow: Chrome error when the credential ID used by the user is not in the allowCredentials list ### `attestation` See [`attestation`](#attestation) above. ### `timeout` See [`timeout`](#timeout) above. ### `UserVerification` See [`UserVerification`](#userverification) above. # Proxying signed requests Source: https://docs.turnkey.com/authentication/proxying-signed-requests Turnkey has an open CORS policy for its public API. This means your frontend can choose to POST sign requests straight to `https://api.turnkey.com`. Your frontend can also choose to forward the requests via a backend server (which POSTs the signed request to Turnkey). How should you decide what to do? Here are some considerations: * A backend proxy can be useful if you need to inspect and persist activity results. For example: if your users are creating wallets, you might want to persist the addresses. If your users are signing transactions, you might want to broadcast on their behalf. * Another reason why a backend server could be beneficial is monitoring, feature toggles, and validation: with a proxy you're able to control which requests are proxied and which aren't. You can also perform additional validation before signed requests are forwarded to Turnkey. * POSTing signed requests directly from your app frontend to Turnkey saves you the burden of running a proxy server, and takes you out of the loop so that your end-users interact directly with Turnkey. This is a "hands-off" approach that can work well if you want to give your end-users maximum flexibility and ownership over their sub-organization. # Sessions Source: https://docs.turnkey.com/authentication/sessions Turnkey sessions allow a user to take multiple, contiguous actions in a defined period of time. ## What is a session? Such actions can be divided into two buckets: * Read operations: Retrieving data (e.g., viewing wallet balances) * Write operations: Modifying data or performing sensitive actions (e.g., signing transactions) ## How can I create a session? ### Read-only sessions In terms of end-user experience, a read-only session might make sense in low-touch applications where users are primarily reading data (think viewing wallets and their balances). As for implementation, there are a few ways a developer can achieve read-only access on behalf of a user. Note: an end-user (sub-organization) falls hierarchically under the developer (parent-organization). #### Parent organization access By default, a parent organization has read access to all of its sub-organizations’ data. This means you can set up a federated model where the client makes requests to a backend (containing the parent organization’s API key credentials), the backend populates the requested data, and returns it back to the client. From an implementation perspective, each read request (i.e. `get` or `list`) requires an `organizationId` parameter. Populate that field with the sub-organization’s ID in order to get its data. #### Client side access Separately, if you would like the client to have all read requests encapsulated (instead of reading data via a proxy like in the previous approach), the client can initiate a read-only session via a [CreateReadOnlySession activity](/api-reference/sessions/create-read-only-session). This activity returns a session string that, if passed into an HTTP request via `X-Session` header, gives permission to perform reads. Note that because this is an activity performed by an end-user, it requires authentication (e.g. via passkey). If you’d like to do this via our SDK abstractions, you can leverage the [login](https://github.com/tkhq/sdk/blob/6b3ea14d1184c5394449ecaad2b0f445e373823f/packages/sdk-browser/src/sdk-client.ts#L231-L255)1 method, which creates a `CreateReadOnlySession` activity under the hood. It stores the resulting session string in [Local Storage](https://github.com/tkhq/sdk/blob/6b3ea14d1184c5394449ecaad2b0f445e373823f/packages/sdk-browser/src/sdk-client.ts#L242-L252)2, and subsequent requests to fetch data from Turnkey injects the session stored here at [call time](https://github.com/tkhq/sdk/blob/6b3ea14d1184c5394449ecaad2b0f445e373823f/packages/sdk-browser/src/__generated__/sdk-client-base.ts#L45-L47)3 within `@turnkey/sdk-browser`. ### Read-write sessions In contrast to read-only sessions, a read-write session makes sense when a user would like to make several write requests in a window of time without having to manually authenticate each one via passkey. There are a few ways to achieve this: #### Creating a read-write session Developers can leverage the [CreateReadWriteSession](/api-reference/sessions/create-read-write-session) activity, which requires a target embedded key and returns a credential bundle. This is a pattern that many core, secure flows follow, including Email Auth, and OTP Auth. See [documentation](/authentication/email#mechanism-and-cryptographic-details) for more details. Read-write sessions As illustrated above, once you have a target embedded key in place on the client side, you can call `CreateReadWriteSession`, get the resulting credential bundle, and decrypt it on the client side using the “TEK”. Upon decryption, the result is a usable Turnkey API key that can be used to make both read and write requests. Our SDK contains an abstraction called [loginWithReadWriteSession](https://github.com/tkhq/sdk/blob/6b3ea14d1184c5394449ecaad2b0f445e373823f/packages/sdk-browser/src/sdk-client.ts#L257-L284). Crucially, it is able to infer the organization (or sub-organization) based on a stamp, and create a read-write session on behalf of that organization. From an end-user experience perspective, this means that a developer can request an end-user’s passkey approval once, and subsequently give that user a read-write session. Note that `loginWithReadWriteSession` stores the resulting credential bundle (returned by Turnkey) in Local Storage. We store this credential bundle in Local Storage as it can be used across various React components and pages – as long as both the target embedded key and credential bundle exist, they can be used as a credential to create Turnkey requests. For details on the shape of this stored artifact, see [here](https://github.com/tkhq/sdk/blob/9e9943387123d077fa3b7f38ef3be007291a2c8a/packages/sdk-browser/src/storage.ts#L64-L117). ### Mechanisms Your next question might be: where can I get the target embedded key? There are two primary mechanisms we offer that provide such embedded keys: #### iframes: Turnkey hosts an iframe for use cases such as this one at [https://auth.turnkey.com](https://auth.turnkey.com) (see [here](https://github.com/tkhq/frames/tree/main/auth) for code implementation). It’s to be used in conjunction with our [@turnkey/iframe-stamper](/sdks/advanced/iframe-stamper), but note that some complexity can be abstracted away if using @turnkey/sdk-react. See this [code example](/embedded-wallets/code-examples/create-passkey-session) for more. The iframe is responsible for holding the “TEK” mentioned in the previous diagram. In addition to housing the TEK, it exposes some methods to be able to interact with (but not extract!) the TEK. The end result is that the iframe can safely and securely sign requests to Turnkey. If you would like to take a look at lower level implementation details, see [here](https://github.com/tkhq/sdk/blob/main/packages/iframe-stamper/src/index.ts). There are a few considerations to note when using sessions with iframes: * Sessions only last as long as the iframe is maintained on the browser * On desktop, this generally is as long as the user doesn’t completely quit the browser * On mobile, specifically iOS devices, this behavior is much more finicky as iOS is aggressive in clearing out data contained within iframes * In either case, sessions are indeed shared across different browser tabs and windows * May be more difficult to set up to use in conjunction with React Native or other frameworks #### Local Storage: Another potential host for a TEK is directly in Local Storage. We’ve created libraries to create a target embedded key (P-256 implementation [here](https://github.com/tkhq/sdk/blob/6b3ea14d1184c5394449ecaad2b0f445e373823f/packages/crypto/src/crypto.ts#L268-L284)). Mechanically, it operates much like the iframe. However, unlike the iframe approach, anyone with access to your application’s domain also has direct access to items stored in Local Storage. Here are some considerations for using Local Storage: * Generally more durable than using iframes in various contexts (i.e. web on both desktop and mobile) * Can be used in other settings such as React Native, Flutter, etc. * As mentioned, the developer has complete control over the target embedded key. As a result, it’s important to manage this credential with caution. For an example that leverages Local Storage with Email Auth, see [here](https://github.com/tkhq/sdk/tree/main/examples/email-auth-local-storage). #### API Key: Another option is to create an API key and store it directly within Local Storage. However, this is a riskier setup than via TEK (as mentioned in the above Local Storage section), as anyone who is able to access this client-side API key has full access to a User. ### Sessions FAQ Once a user has a valid session, it is trivial to use that session to create a new session. It is possible to reuse the same loginWithReadWriteSession abstraction, as this will create a brand new session and automatically store the resulting credential bundle in local storage. In order to delete a session, simply remove all user-related artifacts from Local Storage. See implementation in context [here](https://github.com/tkhq/sdk/blob/9e9943387123d077fa3b7f38ef3be007291a2c8a/packages/sdk-browser/src/sdk-client.ts#L242-L255). ```ts /** * Clears out all data pertaining to a user session. * * @returns {Promise} */ logoutUser = async (): Promise => { await removeStorageValue(StorageKeys.AuthBundle); // DEPRECATED await removeStorageValue(StorageKeys.CurrentUser); await removeStorageValue(StorageKeys.UserSession); await removeStorageValue(StorageKeys.ReadWriteSession); return true; }; ``` The expiration of session keys can be specified to any amount of time using the `expirationSeconds` parameter. The default length is 900 seconds (15 minutes). A user can have up to 10 expiring API keys at any given time. If you create an expiring API key that exceeds that limit, Turnkey automatically deletes one of your existing keys using the following priority: * Expired API keys are deleted first * If no expired keys exist, the oldest unexpired key is deleted If you are looking to invalidate existing sessions, you can use the `invalidateExisting` parameter for Email Auth and OTP Auth activities. This will clear all existing session keys. This is not recommended, because: * iOS Safari handles iframes differently. Specifically, it very aggressively evicts data stored within the iframe's local storage. * React Native doesn’t support iframes natively at all * Mobile browsers have different storage behaviors generally Instead, implement platform-specific session management using Local Storage for mobile. # SMS Authentication Source: https://docs.turnkey.com/authentication/sms SMS authentication enables users to authenticate their Turnkey account using their phone number via a 6-9 digit or bech32 alphanumeric one-time password (OTP). When authenticated, users receive an expiring API key stored in memory within an iframe, which functions like a session key to access their wallet. ## Access and Pricing SMS authentication is available to all Enterprise customers. To enable this feature, please reach out to the Turnkey team. SMS pricing is usage-based and varies depending on the country of the destination phone number. A downloadable price list for all supported countries is available here as a CSV. ## How It Works SMS authentication uses two activities: 1. `INIT_OTP_AUTH` - sends a 6-9 digit or bech32 alphanumeric OTP code to the specified phone number 2. `OTP_AUTH` - verifies the code and returns an encrypted API key credential ## Implementation ### Initiating SMS Authentication To start SMS authentication, create an activity with `ACTIVITY_TYPE_INIT_OTP_AUTH` and the following parameters: * `otpType`: must be set to `"OTP_TYPE_SMS"` * `contact`: user's phone number (must be previously approved and attached to the user's organization data) * `userIdentifier`: optional parameter for rate limiting SMS OTP requests per user. We recommend generating this server-side based on the user's IP address or public key. See the [OTP Rate Limits](#otp-rate-limits) section below for more details. * `smsCustomizationParams`: optional parameters for customizing sms. * `alphanumeric`: optional parameter for making this code bech32 alphanumeric or not. default: true * `otpLength`: optional parameter for selecting the length of the OTP. default: 9 ### Verifying the OTP Once the user receives their code, use `ACTIVITY_TYPE_OTP_AUTH` with these parameters: * `otpId`: ID from the `INIT_OTP_AUTH` response * `otpCode`: the 6-9 digit or bech32 alphanumeric code received via SMS * `targetPublicKey`: public key for credential encryption * `apiKeyName`: optional name for the API Key (defaults to `OTP Auth - `) * `expirationSeconds`: optional duration in seconds (defaults to 15 minutes) * `invalidateExisting`: optional boolean to invalidate previous OTP Auth API keys ## Authorization SMS authentication requires proper permissions through policies or parent organization status. Non-paying accounts are limited to **50 SMS messages** per month. ## Enabling/Disabling SMS Auth ### For Top-level Organizations SMS authentication is disabled by default. Enable it using `ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE`: ```bash turnkey request --host api.turnkey.com --path /public/v1/submit/set_organization_feature --body '{ "timestampMs": "'"$(date +%s)"'000", "type": "ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE", "organizationId": "", "parameters": { "name": "FEATURE_NAME_SMS_AUTH" } }' --organization ``` ### For Sub-organizations * SMS auth is enabled by default * Disable during creation using `disableSmsAuth: true` in the `CreateSubOrganizationIntentV7` activity * Disable after creation using `ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE` with feature name `FEATURE_NAME_SMS_AUTH` ## Implementation Notes * Users are limited to 10 long-lived API keys and 10 expiring API keys * When the expiring API key limit is reached, the oldest key is automatically discarded ## OTP Rate Limits In order to safeguard users, Turnkey enforces rate limits for OTP auth activities. If a `userIdentifier` parameter is provided, the following limits are enforced: * 3 requests per 3 minutes per unique `userIdentifier` * 3 retries max per code, after which point that code will be locked * 3 active codes per user, each with a 5 minute TTL # Social Logins Source: https://docs.turnkey.com/authentication/social-logins Social logins provide a familiar and convenient way for users to access applications using their existing accounts from popular platforms like Google, Apple, or Facebook. Under the hood, this functionality is powered by OAuth - a robust authentication protocol that enables secure user verification through OpenID Connect ([OIDC](https://openid.net/specs/openid-connect-core-1_0.html)) tokens. This feature is available exclusively for sub-organization users. Similar to [email auth](/authentication/email), social login authentication is ideal for users who prefer not to manage API keys or [passkeys](/authentication/passkeys/introduction) directly. This makes it particularly well-suited for onboarding users who are comfortable with traditional web2-style accounts but may be unfamiliar with cryptographic keys and credentials. An example implementing social login authentication for an organization can be found in our SDK repo [here](https://github.com/tkhq/sdk/tree/main/examples/oauth). ## Roles and responsibilities * **Turnkey**: runs verifiable infrastructure to create credentials and verify OIDC tokens * **Parent**: that's you! **For the rest of this guide we'll assume you, the reader, are a Turnkey customer**. We assume that you have: * an existing Turnkey organization (we'll refer to this organization as "the parent organization") * a web application frontend (we'll refer to this as just "app" or "web app") * a backend able to sign and POST Turnkey activities ("backend" or "parent backend") * **End-User**: the end-user is a user of your web app. They have an account with Google. * **OIDC Provider**: a provider able to authenticate your End-Users and provide OIDC tokens as proof. We'll use [Google](https://developers.google.com/identity/openid-connect/openid-connect) as an example. ## OAuth step-by-step ### Registration (signup) OAuth signup flow 1. **End-User** enters the signup flow on the app, gets redirected to Google for authentication. 2. Upon completion, the **Parent**'s backend receives the OIDC token authenticating **End-User**. 3. This token is used inside of a `CREATE_SUB_ORGANIZATION` activity to register Google as the Oauth provider under the root user. 4. **Turnkey** verifies the OIDC token and creates a new sub-organization. The user is now registered: a sub-organization under the parent organization has been created with a a root user, authenticated via an OAuth Provider. Concretely: * `issuer` is set to `https://accounts.google.com` * `audience` is set to `` (your Oauth app ID) * `subject` is set `` (the user ID of `End-User` on Google's side) ### Authentication (login) OAuth login flow 1. **End-User** enters the login flow on the app, gets redirected to Google for authentication. 2. Upon completion, `Parent backend` receives the OIDC token authenticating **End-User**. 3. This token is used inside of an `OAUTH` activity, signed by the **Parent**'s backend. 4. **Turnkey** verifies the OIDC token and encrypts an expiring API key credential to **End-User**. 5. **End-User** decrypts the credential. The user is now authenticated and able to perform Turnkey activities. ## OIDC token verification All OIDC tokens are verified inside of Turnkey's [secure enclaves](/security/secure-enclaves). We've designed a new secure enclave to fetch TLS content securely and bring [non-repudiation](https://en.wikipedia.org/wiki/Non-repudiation#In_digital_security) on top of TLS content: our TLS fetcher returns a URL and the fetched content, signed by the TLS fetcher's quorum key. By trusting the TLS fetcher quorum key, other Turnkey enclaves can bring TLS-fetched data into their computation safely. Verifying OIDC token is the first computation which requires this! To verify an OIDC token, other Turnkey enclaves receive the OIDC token as well as: * the signed content of the issuer's OpenId configuration. OpenId configuration **must** be hosted under `/.well-known/openid-configuration` for each domain. For Google for example, the issuer configuration is at [`accounts.google.com/.well-known/openid-configuration`](https://accounts.google.com/.well-known/openid-configuration). This JSON document contains, among other thing, a `jwksUri` key. The value for this key is a URL hosting the list of currently-valid OIDC token signers. * the signed content of the issuer's `jwksUri` (e.g., for Google, the `jwksUri` is [`googleapis.com/oauth2/v3/cert`](https://www.googleapis.com/oauth2/v3/certs)). This is a list of public keys against which the secure enclave can verify tokens. Note: **these public keys rotate periodically** (every \~6hrs), hence it's not possible to hardcode these public keys in our secure enclave code directly. We have to fetch them dynamically! With all of that, an enclave can independently verify an OIDC token without making outbound requests. Once the token is parsed and considered authentic, our enclaves match the `iss`, `aud` and `sub` attributes against the registered OAuth providers on the Turnkey sub-organization. We also check `exp` to make sure the OIDC token is not expired, and the `nonce` attribute (see next section). ## Nonce restrictions in OIDC tokens Our [`OAUTH`](/api-reference/user-auth/oauth) activity requires 2 parameters minimum: * `oidcToken`: the base64 OIDC token * `targetPublicKey`: the client-side public key generated by the user In order to prevent OIDC tokens from being used against multiple public keys, our enclaves parse the OIDC token and, as part of the validation logic, enforce that the `nonce` claim is set to `sha256(targetPublicKey)`. For example, if the iframe public key is `04bb76f9a8aaafbb0722fa184f66642ae425e2a032bde8ffa0479ff5a93157b204c7848701cf246d81fd58f6c4c47a437d9f81e6a183042f2f1aa2f6aa28e4ab65`, our enclaves expect the OIDC token nonce to be `1f9570d976946c0cb72f0e853eea0fb648b5e9e9a2266d25f971817e187c9b18`. This restriction only applies during **authentication** (`OAUTH` activity). Registration via `CREATE_OAUTH_PROVIDER` and `CREATE_SUB_ORGANIZATION` activities is not affected since these activities do not accept a `targetPublicKey` and do not return encrypted credentials as a result. If your OAuth provider does not allow you to customize `nonce` claims, Turnkey also accepts and validates `tknonce` claims. This is an alternative claim that will be considered. Only one of (`nonce`, `tknonce`) needs to be set to `sha256(targetPublicKey)`; not both. ## OAuth vs. OIDC [OAuth2.0](https://datatracker.ietf.org/doc/html/rfc6749) is a separate protocol from [OIDC](https://openid.net/specs/openid-connect-core-1_0.html), with distinct goals: * "OAuth2.0" is an authorization framework * "OIDC" is an authentication framework We chose to name this feature "OAuth" because of the term familiarity: most Turnkey customers will have to setup an "OAuth" app with Google, and the user experience is often referred to as "OAuth" flows regardless of the protocol underneath. ## Providers Below, some details and pointers about specific providers we've worked with before. If yours isn't listed below it does not mean it can't be supported: any OIDC provider should work with Turnkey's OAuth. ### Google This provider is extensively tested and supported. We've integrated it in our demo wallet (hosted at [https://wallet.tx.xyz](https://wallet.tx.xyz)), along with Apple and Facebook: OAuth demo wallet The code is open-source, feel free to [check it out](https://github.com/tkhq/demo-embedded-wallet) for reference. The exact line where the OAuth component is loaded is here: [ui/src/screens/LandingScreen.tsx](https://github.com/tkhq/demo-embedded-wallet/blob/d4ec308e9ce0bf0da7b64da2b39e1a80c077eb82/ui/src/screens/LandingScreen.tsx#L384). The main documentation for Google OIDC is available [here](https://github.com/tkhq/demo-embedded-wallet/blob/bf0e2292cbd2ee9cde6b241591b077fadf7ee71b/src/components/auth.tsx#L157). ### Apple Apple integration is also extensively tested and supported, and is integrated into our demo wallet (hosted at [https://wallet.tx.xyz](https://wallet.tx.xyz)). The code provides an [example component](https://github.com/tkhq/demo-embedded-wallet/blob/bf0e2292cbd2ee9cde6b241591b077fadf7ee71b/src/components/apple-auth.tsx) as well as an [example redirect handler](https://github.com/tkhq/demo-embedded-wallet/blob/bf0e2292cbd2ee9cde6b241591b077fadf7ee71b/src/app/\(landing\)/oauth-callback/apple/page.tsx). Documentation for Apple OIDC can be found [here](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/authenticating_users_with_sign_in_with_apple). ### Facebook Facebook OIDC requires a [manual flow with PFKE](https://developers.facebook.com/docs/facebook-login/guides/advanced/oidc-token/) (Proof for Key Exchange). This flow requires a few extra steps compared with Apple or Google. Specifically: * You will need to generate a **code verifier** that can either be recalled (e.g. from a database) or reassembled in a later request. * You will need to provide a **code challenge** as a parameter of the OAuth redirect that is either the code verifier itself or the hash of the code verifier. * Instead of receiving the OIDC token after the OAuth flow, you will receive an **auth code** that must be exchanged for an OIDC token in a subsequent request. The code verifier and your app's ID are also required in this exchange. In our example demo wallet, we opt to avoid using a database in the authentication process and instead generate our verification code serverside using the hash of a nonce and a secret salt value. The nonce is then passed to and returned from the Facebook API as a **state** parameter (see [the API spec](https://developers.facebook.com/docs/facebook-login/guides/advanced/oidc-token/) for details). Finally, the server reconstructs the verification code by re-hashing the nonce and the the salt. The full flow is displayed below: Facebook OAuth flow Code for the [redirect component](https://github.com/tkhq/demo-embedded-wallet/blob/bf0e2292cbd2ee9cde6b241591b077fadf7ee71b/src/components/facebook-auth.tsx), [OAuth callback](https://github.com/tkhq/demo-embedded-wallet/blob/bf0e2292cbd2ee9cde6b241591b077fadf7ee71b/src/app/\(landing\)/oauth-callback/facebook/page.tsx), and [code exchange](https://github.com/tkhq/demo-embedded-wallet/blob/bf0e2292cbd2ee9cde6b241591b077fadf7ee71b/src/actions/turnkey.ts#L54) are all available in the example wallet repo. If you prefer to use a database such as Redis instead of reassembling the verification code, you can store the verification code and retrieve it in the exchange stage using a lookup key either passed as **state** or stored in local browser storage. ### Auth0 This provider was tested successfully and offers a wide range of authentication factors and integration. For example, Auth0 can wrap Twitter's auth or any other ["Social Connection"](https://marketplace.auth0.com/features/social-connections). In the testing process we discovered that Auth0 admins can manage users freely. Be careful about who can and can't access your Auth0 account: Auth0's management APIs allow for account merging. Specifically, anyone with a `users:update` scope token can call [this endpoint](https://auth0.com/docs/api/management/v2/users/post-identities) to arbitrarily link an identity. For example, if a Google-authenticated user (OIDC token `sub` claim: `google-oauth2|118121659617646047510`) gets merged into a Twitter-authenticated user (OIDC token `sub` claim: `twitter|47169608`), the OIDC token obtained by logging in through Google post-merge will be `twitter|47169608`. This can be surprising and lead to account takeover if an Auth0 admin is malicious. This is documented in Auth0's own docs, [here](https://auth0.com/docs/manage-users/user-accounts/user-account-linking#precautions). ### AWS Cognito The main thing to call out is the inability to pass custom `nonce` claims easily. To pass the hash of the end-user's iframe public key, use a custom `tknonce` claim instead. ### Social linking Social linking is the concept of automatically linking an email address to a Turnkey user by authenticating with a social provider. This allows an end-user to authenticate with the social provider, or a matching email address. Currently, we only allow automatic linking for Google social logins. The cases are as follows: 1. The end-user authenticates with Google. Their email address is automatically linked to their authentication methods and considered “verified,” allowing them to log in with email OTP or email auth in the future. 2. The end-user authenticates with a Google email address (e.g., @gmail.com) via email OTP or email auth. If they later authenticate with Google, the Google OIDC provider will automatically be added as a valid login method, provided the email matches. 3. The end-user has existing non-Google authentication methods (e.g. phone number, passkeys, etc.) and later adds Google OIDC as a login method (via [CREATE\_OAUTH\_PROVIDERS](/api-reference/activities/create-oauth-providers#api-key)). The email address in the Google account will be automatically marked as "verified" and linked to the existing user. For more information on how to implement social linking, see the [social linking code example](/embedded-wallets/code-examples/social-linking). # Advanced Source: https://docs.turnkey.com/category/advanced Use Turnkey's low-level http libraries directly Detailed guide on installing and initializing the TurnkeyClient Guide on using the ApiKeyStamper Guide on using the WalletStamper Guide on using the WebauthnStamper Guide on using the IframeStamper Guide on using the IndexedDbStamper # Code Examples Source: https://docs.turnkey.com/category/code-examples Create a Sub-Org with a Passkey User Authenticate a User with a Passkey Credential Create a User Passkey Session Create a User with Email Only Authenticate a User with Email Recover a User with Email Add an Additional Passkey Authenticate a User with an Ethereum Wallet Signing Transactions Import Wallet or Private Key Export Wallet or Private Key Social Linking # Code Examples Source: https://docs.turnkey.com/category/code-examples-1 Signing Transactions # Security & Architecture Source: https://docs.turnkey.com/category/security Learn how Turnkey achieves innovative, cloud scale, no single point of failure security. Turnkey is the first verifiable key management system of its kind, securing millions of wallets and private keys for a wide variety of use cases. Turnkey's security architecture ensures that raw private keys are never exposed to Turnkey, your software, or your team. We provide end-to-end private key generation and access control within secure enclaves, with strong isolation guarantees and cryptographic attestation proving that only authorized code is running. Our custom-built operating system, QuorumOS, minimizes attack surface and enables reproducible, auditable deployments. From hardware-backed trust to multi-factor access controls, every layer of Turnkey's architecture is designed to be secure, verifiable, and developer-friendly by default. Our whitepaper covers our holistic security model in-depth, and speaks to our vision for building verifiable key management infrastructure. Learn more about our approach to security here. Learn about Turnkey's unique security framework Learn how Turnkey handles private keys Overview of secure enclaves and how we use them Learn how we deploy our secure applications Learn how we ensure an end-to-end audit trail Turnkey's disaster recovery process Learn about Turnkey's enclave to end-user secure channels Read about Turnkey's ambitious foundations with the Turnkey Whitepaper Overview of Turnkey's responsible disclosure program # Web3 Libraries Source: https://docs.turnkey.com/category/web3-libraries Turnkey Web3 Libraries Ethers Wrapper Viem Wrapper CosmJS Wrapper EIP 1193 Provider Solana Web3 Wrapper # API Key Stamper Source: https://docs.turnkey.com/changelogs/api-key-stamper/readme # @turnkey/api-key-stamper ## 0.4.4 ### Patch Changes * 2d5977b: Update error messaging around api key and target public key usage ## 0.4.3 ### Patch Changes * Updated dependencies \[e5c4fe9] * @turnkey/encoding\@0.4.0 ## 0.4.2 ### Patch Changes * Updated dependencies \[93666ff] * @turnkey/encoding\@0.3.0 ## 0.4.1 ### Patch Changes * Changes: Resolves bugs where byte arrays might not be sufficiently padded (32 bytes are expected for x, y, and d elements of a JWK) * Updated dependencies * @turnkey/encoding\@0.2.1 ## 0.4.0 ### Minor Changes * New PureJS implementation for \`@turnkey/api-key-stamper\`\` to support React Native * Introduce a dependency on `@turnkey/encoding` to consolidate utility functions ## 0.3.1 ### Patch Changes * Upgrade to Node v18 (#184) ## 0.3.0 ### Minor Changes * Use rollup to build ESM and CommonJS, fix ESM support (#174) ## 0.2.0 ### Minor Changes * Add ESM support (#154) ## 0.1.1 ### Patch Changes * Hint for web bundlers not to polyfill Node crypto ## 0.1.0 Initial release # Cosmjs Source: https://docs.turnkey.com/changelogs/cosmjs/readme # @turnkey/cosmjs ## 0.7.5 ### Patch Changes * Updated dependencies \[7b72769] * @turnkey/sdk-server\@3.0.1 ## 0.7.4 ### Patch Changes * Updated dependencies \[e501690] * Updated dependencies \[d1083bd] * Updated dependencies \[f94d36e] * @turnkey/sdk-browser\@4.0.0 * @turnkey/sdk-server\@3.0.0 * @turnkey/http\@3.0.0 ## 0.7.3 ### Patch Changes * Updated dependencies \[bf87774] * @turnkey/sdk-browser\@3.1.0 ## 0.7.2 ### Patch Changes * Updated dependencies \[5ec5187] * @turnkey/sdk-browser\@3.0.1 * @turnkey/sdk-server\@2.6.1 ## 0.7.1 ### Patch Changes * Updated dependencies \[0e4e959] * Updated dependencies \[856f449] * Updated dependencies \[c9ae537] * Updated dependencies \[d4ce5fa] * Updated dependencies \[ecdb29a] * Updated dependencies \[72890f5] * @turnkey/sdk-browser\@3.0.0 * @turnkey/sdk-server\@2.6.0 * @turnkey/http\@2.22.0 ## 0.7.0 ### Minor Changes * a7b5ce3: Update @cosmos/\* dependencies from v0.31.0 to v0.33.0 and cosmjs-types from v0.8.0 to v0.9.0 ### Patch Changes * Updated dependencies \[93540e7] * Updated dependencies \[fdb8bf0] * Updated dependencies \[9147962] * @turnkey/sdk-browser\@2.0.0 * @turnkey/sdk-server\@2.5.0 ## 0.6.14 ### Patch Changes * Updated dependencies \[233ae71] * Updated dependencies \[9317588] * @turnkey/sdk-browser\@1.16.0 * @turnkey/sdk-server\@2.4.0 ## 0.6.13 ### Patch Changes * Updated dependencies \[56a307e] * @turnkey/sdk-browser\@1.15.0 * @turnkey/sdk-server\@2.3.0 * @turnkey/http\@2.21.0 ## 0.6.12 ### Patch Changes * Updated dependencies \[3c44c4a] * Updated dependencies \[bfc833f] * @turnkey/sdk-browser\@1.14.0 * @turnkey/sdk-server\@2.2.0 * @turnkey/http\@2.20.0 ## 0.6.11 ### Patch Changes * Updated dependencies \[69d2571] * Updated dependencies \[57f9cb0] * @turnkey/sdk-browser\@1.13.0 * @turnkey/sdk-server\@2.1.0 * @turnkey/http\@2.19.0 ## 0.6.10 ### Patch Changes * Updated dependencies \[755833b] * @turnkey/sdk-browser\@1.12.1 * @turnkey/sdk-server\@2.0.1 ## 0.6.9 ### Patch Changes * Updated dependencies \[6695af2] * Updated dependencies \[1ebd4e2] * @turnkey/sdk-browser\@1.12.0 * @turnkey/sdk-server\@2.0.0 * @turnkey/http\@2.18.0 ## 0.6.8 ### Patch Changes * Updated dependencies \[053fbfb] * @turnkey/sdk-browser\@1.11.2 * @turnkey/sdk-server\@1.7.3 * @turnkey/http\@2.17.3 ## 0.6.7 ### Patch Changes * Updated dependencies \[328d6aa] * Updated dependencies \[b90947e] * Updated dependencies \[2d5977b] * Updated dependencies \[fad7c37] * @turnkey/sdk-browser\@1.11.1 * @turnkey/sdk-server\@1.7.2 * @turnkey/api-key-stamper\@0.4.4 * @turnkey/http\@2.17.2 ## 0.6.6 ### Patch Changes * Updated dependencies \[7988bc1] * Updated dependencies \[538d4fc] * Updated dependencies \[12d5aaa] * @turnkey/sdk-browser\@1.11.0 * @turnkey/sdk-server\@1.7.1 * @turnkey/http\@2.17.1 ## 0.6.5 ### Patch Changes * @turnkey/sdk-browser\@1.10.2 ## 0.6.4 ### Patch Changes * Updated dependencies \[78bc39c] * @turnkey/sdk-server\@1.7.0 * @turnkey/http\@2.17.0 * @turnkey/sdk-browser\@1.10.1 ## 0.6.3 ### Patch Changes * Updated dependencies \[8bea78f] * @turnkey/sdk-browser\@1.10.0 ## 0.6.2 ### Patch Changes * Updated dependencies \[3dd74ac] * Updated dependencies \[1e36edf] * Updated dependencies \[4df8914] * Updated dependencies \[11a9e2f] * @turnkey/sdk-browser\@1.9.0 * @turnkey/sdk-server\@1.6.0 * @turnkey/http\@2.16.0 ## 0.6.1 ### Patch Changes * Updated dependencies \[9ebd062] * @turnkey/sdk-browser\@1.8.0 * @turnkey/sdk-server\@1.5.0 * @turnkey/http\@2.15.0 ## 0.6.0 ### Minor Changes * 5e60923: Add compatibility with wallet accounts and @turnkey/sdk-browser and @turnkey/sdk-server ### Patch Changes * Updated dependencies \[abe7138] * Updated dependencies \[96d7f99] * @turnkey/sdk-server\@1.4.2 * @turnkey/sdk-browser\@1.7.1 * @turnkey/http\@2.14.2 * @turnkey/api-key-stamper\@0.4.3 ## 0.5.21 ### Patch Changes * Updated dependencies \[ff059d5] * @turnkey/http\@2.14.1 ## 0.5.20 ### Patch Changes * Updated dependencies \[848f8d3] * @turnkey/http\@2.14.0 ## 0.5.19 ### Patch Changes * Updated dependencies \[93dee46] * @turnkey/http\@2.13.0 ## 0.5.18 ### Patch Changes * Updated dependencies \[e2f2e0b] * @turnkey/http\@2.12.3 ## 0.5.17 ### Patch Changes * Updated dependencies * @turnkey/http\@2.12.2 ## 0.5.16 ### Patch Changes * Updated dependencies \[f17a229] * @turnkey/http\@2.12.1 ## 0.5.15 ### Patch Changes * Updated dependencies * @turnkey/http\@2.12.0 ## 0.5.14 ### Patch Changes * Updated dependencies * @turnkey/http\@2.11.0 ## 0.5.13 ### Patch Changes * Updated dependencies \[7a9ce7a] * @turnkey/http\@2.10.0 ## 0.5.12 ### Patch Changes * Updated dependencies * @turnkey/http\@2.9.1 ## 0.5.11 ### Patch Changes * Updated dependencies \[83b62b5] * @turnkey/http\@2.9.0 ## 0.5.10 ### Patch Changes * Updated dependencies \[46a7d90] * @turnkey/http\@2.8.0 ## 0.5.9 ### Patch Changes * Updated dependencies * @turnkey/http\@2.7.1 ## 0.5.8 ### Patch Changes * Updated dependencies \[d73725b] * @turnkey/http\@2.7.0 ## 0.5.7 ### Patch Changes * Updated dependencies \[f9d636c] * @turnkey/http\@2.6.2 ## 0.5.6 ### Patch Changes * Updated dependencies \[52e2389] * @turnkey/http\@2.6.1 ## 0.5.5 ### Patch Changes * Updated dependencies \[7a3c890] * @turnkey/http\@2.6.0 ## 0.5.4 ### Patch Changes * Upgrade to Node v18 (#184) * Updated dependencies * @turnkey/http\@2.5.1 ## 0.5.3 ### Patch Changes * Updated dependencies \[464ac0e] * @turnkey/http\@2.5.0 ## 0.5.2 ### Patch Changes * @turnkey/http\@2.4.2 ## 0.5.1 ### Patch Changes * Updated dependencies \[f87ced8] * @turnkey/http\@2.4.1 ## 0.5.0 ### Minor Changes * Use rollup to build ESM and CommonJS, fix ESM support (#174) ### Patch Changes * Updated dependencies \[fc5b291] * @turnkey/http\@2.4.0 ## 0.4.14 ### Patch Changes * @turnkey/http\@2.3.1 ## 0.4.13 ### Patch Changes * Updated dependencies \[f1bd68a] * @turnkey/http\@2.3.0 ## 0.4.12 ### Patch Changes * Updated dependencies \[ed50a0f] * Updated dependencies * @turnkey/http\@2.2.0 ## 0.4.11 ### Patch Changes * Updated dependencies \[bb6ea0b] * @turnkey/http\@2.1.0 ## 0.4.10 ### Patch Changes * Updated dependencies * @turnkey/http\@2.0.0 * Updated the shape of signing ## 0.4.9 ### Patch Changes * Updated dependencies * @turnkey/http\@1.3.0 ## 0.4.8 ### Patch Changes * Updated dependencies * @turnkey/http\@1.2.0 ## 0.4.7 ### Patch Changes * @turnkey/http\@1.1.1 ## 0.4.6 ### Patch Changes * Updated dependencies * @turnkey/http\@1.1.0 ## 0.4.5 ### Patch Changes * Updated dependencies \[8d1d0e8] * @turnkey/http\@1.0.1 ## 0.4.4 ### Patch Changes * 46473ec: This breaking change updates generated code to be shorter and more intuitive to read: * generated fetchers do not include the HTTP method in their name. For example `useGetGetActivity` is now `useGetActivity`, and `usePostSignTransaction` is `useSignTransaction`. * input types follow the same convention (no HTTP method in the name): `TPostCreatePrivateKeysInput` is now `TCreatePrivateKeysInput`. * the "federated" request helpers introduced in `0.18.0` are now named "signed" requests to better reflect what they are. `FederatedRequest` is now `SignedRequest`, and generated types follow. For example: `federatedPostCreatePrivateKeys` is now `signCreatePrivateKeys`, `federatedGetGetActivity` is now `signGetActivity`, and so on. The name updates should be automatically suggested if you use VSCode since the new names are simply shorter versions of the old one. * Updated dependencies \[46473ec] * Updated dependencies \[38b424f] * @turnkey/http\@1.0.0 ## 0.4.3 ### Patch Changes * Updated dependencies * @turnkey/http\@0.18.1 ## 0.4.2 ### Patch Changes * Updated dependencies * @turnkey/http\@0.18.0 ## 0.4.1 ### Patch Changes * Updated dependencies * @turnkey/http\@0.17.1 ## 0.4.0 ### Minor Changes * No public facing changes ### Patch Changes * Updated dependencies \[9317f51] * @turnkey/http\@0.17.0 ## 0.3.0 ### Minor Changes * No public facing changes ### Patch Changes * Updated dependencies * @turnkey/http\@0.16.0 * Fix `.postGetPrivateKey(...)`'s underlying path, while adding `@deprecated` `.postGetPrivateKeyBackwardsCompat(...)` for backward compatibility ## 0.2.1 ### Patch Changes * Updated dependencies * @turnkey/http\@0.15.0 ## 0.2.0 ### Minor Changes * Moved `sha256` hashing from local to remote ### Patch Changes * Updated dependencies * @turnkey/http\@0.14.0 ## 0.1.1 ### Patch Changes * New `TurnkeyRequestError` error class that contains rich error details * Updated dependencies * @turnkey/http\@0.13.2 ## 0.1.0 * Initial release # Crypto Source: https://docs.turnkey.com/changelogs/crypto/readme # @turnkey/crypto ## 2.3.1 ### Patch Changes * 2bc0046: Migrated from WebCrypto (crypto.subtle.verify) to Noble for ECDSA signature verification ## 2.3.0 ### Minor Changes * 668edfa: Add keyformat to decryptExportBundle for displaying Solana private keys ## 2.2.0 ### Minor Changes * Added `toDerSignature` function used to convert a raw ECDSA signature into DER-encoded format for compatibility with our backend, which requires DER signatures ## 2.1.0 ### Minor Changes * [https://github.com/tkhq/sdk/pull/384](https://github.com/tkhq/sdk/pull/384): Reorganize into two subparts: * `crypto.ts`: core cryptography utilities * `turnkey.ts`: Turnkey-specific cryptography utilities Add `verifyStampSignature` method: * See in-line code docs for more details + example of usage * This is useful for checking the validity of a stamp (signature) against the request body ### Patch Changes * d989d46: Remove unnecessary react/typsecript packages ## 2.0.0 ### Major Changes * \[BREAKING CHANGE] renamed `decryptBundle` to `decryptCredentialBundle` (for decrypting email auth/recovery and oauth credential bundles) in order to distinguish from the new `decryptExportBundle` (for decrypting bundles containing wallet mnemonics or private key material) ### Patch Changes * Updated dependencies \[e5c4fe9] * @turnkey/encoding\@0.4.0 ## 1.0.0 ### Major Changes * 93666ff: turnkey/crypto standard HPKE encryption, first major release. Allows for programmatic importing in environments like node. Moved some encoding helper functions to turnkey/encoding ### Patch Changes * Updated dependencies \[93666ff] * @turnkey/encoding\@0.3.0 ## 0.2.1 ### Patch Changes * Updated dependencies * @turnkey/encoding\@0.2.1 ## 0.2.0 ### Minor Changes * Add HPKE encryption ## 0.1.1 ### Patch Changes * d968e0b: Bugfix: return public key ## 0.1.0 Initial release # Dart Source: https://docs.turnkey.com/changelogs/dart/readme # Change Log All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. ## 2025-03-11 ### Changes *** Packages with breaking changes: * There are no breaking changes in this release. Packages with other changes: * [`turnkey_sdk_flutter` - `v0.1.0`](#turnkey_sdk_flutter---v010) *** #### `turnkey_sdk_flutter` - `v0.1.0` * Initial release. Client side abstracted functions for Turnkey-powered Flutter apps ## 2025-02-18 ### Changes *** Packages with breaking changes: * There are no breaking changes in this release. Packages with other changes: * [`turnkey_sessions` - `v0.1.2`](#turnkey_sessions---v012) *** #### `turnkey_sessions` - `v0.1.2` * **DOCS**: Added auto login / logout example to README. ## 2025-02-18 ### Changes *** Packages with breaking changes: * There are no breaking changes in this release. Packages with other changes: * [`turnkey_sessions` - `v0.1.1`](#turnkey_sessions---v011) *** #### `turnkey_sessions` - `v0.1.1` * **FEAT**: Listeners notified when session expires (turnkey\_sessions). ## 2025-02-11 ### Changes *** Packages with breaking changes: * There are no breaking changes in this release. Packages with other changes: * [`turnkey_sessions` - `v0.1.0`](#turnkey_sessions---v010) *** #### `turnkey_sessions` - `v0.1.0` ## 2025-02-11 ### Changes *** Packages with breaking changes: * There are no breaking changes in this release. Packages with other changes: * [`turnkey_crypto` - `v0.1.1`](#turnkey_crypto---v011) *** #### `turnkey_crypto` - `v0.1.1` * Exposed generateP256KeyPair function # Eip 1193 Provider Source: https://docs.turnkey.com/changelogs/eip-1193-provider/readme # @turnkey/eip-1193-provider ## 3.3.5 ### Patch Changes * 7a89040: Fix type resolution ## 3.3.4 ### Patch Changes * Updated dependencies \[e501690] * Updated dependencies \[d1083bd] * Updated dependencies \[f94d36e] * @turnkey/sdk-browser\@4.0.0 * @turnkey/http\@3.0.0 ## 3.3.3 ### Patch Changes * Updated dependencies \[bf87774] * @turnkey/sdk-browser\@3.1.0 ## 3.3.2 ### Patch Changes * Updated dependencies \[5ec5187] * @turnkey/sdk-browser\@3.0.1 ## 3.3.1 ### Patch Changes * Updated dependencies \[0e4e959] * Updated dependencies \[856f449] * Updated dependencies \[d4ce5fa] * Updated dependencies \[ecdb29a] * Updated dependencies \[72890f5] * @turnkey/sdk-browser\@3.0.0 * @turnkey/http\@2.22.0 ## 3.3.0 ### Minor Changes * 93540e7: ## Major Package Updates ### @turnkey/sdk-browser * create abstract `TurnkeyBaseClient` class which extends `TurnkeySDKClientBase` * `TurnkeyBrowserClient`, `TurnkeyIframeClient`, `TurnkeyPasskeyClient`, and `TurnkeyWalletClient` all extend `TurnkeyBaseClient` * TurnkeyBrowserClient * Session Management * `refreshSession` - attempts to refresh an existing, active session and will extend the session expiry using the `expirationSeconds` parameter * loginWithBundle - authenticate a user via a credential bundle and creates a read-write session * loginWithPasskey - attempts to authenticate a user via passkey and create a read-only or read-write session * loginWithSession - takes a `Session`, which can be either read-only or read-write, created via a server action and attempts to authenticate the user * TurnkeyPasskeyClient * Session Management * createPasskeySession - leverages passkey authentication to create a read-write session. Once authenticated, the user will not be prompted for additional passkey taps. ### @turnkey/sdk-react * update `TurnkeyContext` to use new `.getSession()` method to check if there is an active session * `OTPVerification` component no longer receives `authIframeClient` or `onValidateSuccess` props ## Minor Package Updates ### @turnkey/sdk-server * expose `sendCredential` server action * add `SessionType` enum * `READ_ONLY` & `READ_WRITE` ### @turnkey/eip-1193-provider * update dependencies in `package.json` * moved from `peerDependencies` to `dependencies` * `"@turnkey/http": "workspace:*"` * `"@turnkey/sdk-browser": "workspace:*"` * moved from `devDependencies` to `dependencies` * `"@turnkey/api-key-stamper": "workspace:*"` * specify TypeScript version ^5.1.5 ### Patch Changes * Updated dependencies \[93540e7] * Updated dependencies \[9147962] * @turnkey/sdk-browser\@2.0.0 ## 3.1.5 ### Patch Changes * Updated dependencies \[233ae71] * @turnkey/sdk-browser\@1.16.0 ## 3.1.4 ### Patch Changes * Updated dependencies \[56a307e] * @turnkey/sdk-browser\@1.15.0 * @turnkey/http\@2.21.0 ## 3.1.3 ### Patch Changes * Updated dependencies \[3c44c4a] * @turnkey/sdk-browser\@1.14.0 * @turnkey/http\@2.20.0 ## 3.1.2 ### Patch Changes * Updated dependencies \[69d2571] * Updated dependencies \[57f9cb0] * @turnkey/sdk-browser\@1.13.0 * @turnkey/http\@2.19.0 ## 3.1.1 ### Patch Changes * Updated dependencies \[755833b] * @turnkey/sdk-browser\@1.12.1 ## 3.1.0 ### Minor Changes * 4945c71: Add support for @turnkey/sdk-browser clients ### Patch Changes * Updated dependencies \[6695af2] * @turnkey/sdk-browser\@1.12.0 * @turnkey/http\@2.18.0 ## 3.0.5 ### Patch Changes * Updated dependencies \[053fbfb] * @turnkey/http\@2.17.3 ## 3.0.4 ### Patch Changes * @turnkey/http\@2.17.2 ## 3.0.3 ### Patch Changes * Updated dependencies \[538d4fc] * @turnkey/http\@2.17.1 ## 3.0.2 ### Patch Changes * Updated dependencies \[78bc39c] * @turnkey/http\@2.17.0 ## 3.0.1 ### Patch Changes * Updated dependencies \[4df8914] * @turnkey/http\@2.16.0 ## 3.0.0 ### Patch Changes * 9c056d0: fix: personal\_sign parameters * Updated dependencies \[9ebd062] * @turnkey/http\@2.15.0 ## 2.0.8 ### Patch Changes * Updated dependencies \[96d7f99] * @turnkey/http\@2.14.2 ## 2.0.7 ### Patch Changes * Updated dependencies \[ff059d5] * @turnkey/http\@2.14.1 ## 2.0.6 ### Patch Changes * Updated dependencies \[848f8d3] * @turnkey/http\@2.14.0 ## 2.0.5 ### Patch Changes * Updated dependencies \[93dee46] * @turnkey/http\@2.13.0 ## 2.0.4 ### Patch Changes * Updated dependencies \[e2f2e0b] * @turnkey/http\@2.12.3 ## 2.0.3 ### Patch Changes * Removes unused VERSION from constants. Fixes issue with using process in a browser environment. ## 2.0.2 ### Patch Changes * Updated dependencies * @turnkey/http\@2.12.2 ## 2.0.1 ### Patch Changes * Updated dependencies \[f17a229] * @turnkey/http\@2.12.1 ## 2.0.0 ### Patch Changes * Updated dependencies * @turnkey/http\@2.12.0 ## 1.0.0 ### Patch Changes * Updated dependencies * @turnkey/http\@2.11.0 ## 0.2.0 ### Minor Changes * 65f781b: Initial Release ## 0.1.0 Initial release! # Encoding Source: https://docs.turnkey.com/changelogs/encoding/readme # @turnkey/encoding ## 0.4.0 ### Minor Changes * added hexToAscii function, useful for converting a raw hex string to a (wallet) mnemonic ## 0.3.0 ### Minor Changes * 93666ff: turnkey/crypto standard HPKE encryption, first major release. Allows for programmatic importing in environments like node. Moved some encoding helper functions to turnkey/encoding ## 0.2.1 ### Patch Changes * 2d7e5a9: include additional utility functions ## 0.2.0 ### Minor Changes * fac7770: Add uint8ArrayFromHexstring and drop language saying this is an internal package ## 0.1.0 Initial release # Ethers Source: https://docs.turnkey.com/changelogs/ethers/readme # @turnkey/ethers ## 1.1.22 ### Patch Changes * Updated dependencies \[7b72769] * @turnkey/sdk-server\@3.0.1 ## 1.1.21 ### Patch Changes * Updated dependencies \[e501690] * Updated dependencies \[d1083bd] * Updated dependencies \[f94d36e] * @turnkey/sdk-browser\@4.0.0 * @turnkey/sdk-server\@3.0.0 * @turnkey/http\@3.0.0 ## 1.1.20 ### Patch Changes * Updated dependencies \[bf87774] * @turnkey/sdk-browser\@3.1.0 ## 1.1.19 ### Patch Changes * Updated dependencies \[5ec5187] * @turnkey/sdk-browser\@3.0.1 * @turnkey/sdk-server\@2.6.1 ## 1.1.18 ### Patch Changes * Updated dependencies \[0e4e959] * Updated dependencies \[856f449] * Updated dependencies \[c9ae537] * Updated dependencies \[d4ce5fa] * Updated dependencies \[ecdb29a] * Updated dependencies \[72890f5] * @turnkey/sdk-browser\@3.0.0 * @turnkey/sdk-server\@2.6.0 * @turnkey/http\@2.22.0 ## 1.1.17 ### Patch Changes * Updated dependencies \[93540e7] * Updated dependencies \[fdb8bf0] * Updated dependencies \[9147962] * @turnkey/sdk-browser\@2.0.0 * @turnkey/sdk-server\@2.5.0 ## 1.1.16 ### Patch Changes * Updated dependencies \[233ae71] * Updated dependencies \[9317588] * @turnkey/sdk-browser\@1.16.0 * @turnkey/sdk-server\@2.4.0 ## 1.1.15 ### Patch Changes * Updated dependencies \[56a307e] * @turnkey/sdk-browser\@1.15.0 * @turnkey/sdk-server\@2.3.0 * @turnkey/http\@2.21.0 ## 1.1.14 ### Patch Changes * Updated dependencies \[3c44c4a] * Updated dependencies \[bfc833f] * @turnkey/sdk-browser\@1.14.0 * @turnkey/sdk-server\@2.2.0 * @turnkey/http\@2.20.0 ## 1.1.13 ### Patch Changes * Updated dependencies \[69d2571] * Updated dependencies \[57f9cb0] * @turnkey/sdk-browser\@1.13.0 * @turnkey/sdk-server\@2.1.0 * @turnkey/http\@2.19.0 ## 1.1.12 ### Patch Changes * Updated dependencies \[755833b] * @turnkey/sdk-browser\@1.12.1 * @turnkey/sdk-server\@2.0.1 ## 1.1.11 ### Patch Changes * Updated dependencies \[6695af2] * Updated dependencies \[1ebd4e2] * @turnkey/sdk-browser\@1.12.0 * @turnkey/sdk-server\@2.0.0 * @turnkey/http\@2.18.0 ## 1.1.10 ### Patch Changes * Updated dependencies \[053fbfb] * @turnkey/sdk-browser\@1.11.2 * @turnkey/sdk-server\@1.7.3 * @turnkey/http\@2.17.3 ## 1.1.9 ### Patch Changes * Updated dependencies \[328d6aa] * Updated dependencies \[b90947e] * Updated dependencies \[2d5977b] * Updated dependencies \[fad7c37] * @turnkey/sdk-browser\@1.11.1 * @turnkey/sdk-server\@1.7.2 * @turnkey/api-key-stamper\@0.4.4 * @turnkey/http\@2.17.2 ## 1.1.8 ### Patch Changes * Updated dependencies \[7988bc1] * Updated dependencies \[538d4fc] * Updated dependencies \[12d5aaa] * @turnkey/sdk-browser\@1.11.0 * @turnkey/sdk-server\@1.7.1 * @turnkey/http\@2.17.1 ## 1.1.7 ### Patch Changes * @turnkey/sdk-browser\@1.10.2 ## 1.1.6 ### Patch Changes * Updated dependencies \[78bc39c] * @turnkey/sdk-server\@1.7.0 * @turnkey/http\@2.17.0 * @turnkey/sdk-browser\@1.10.1 ## 1.1.5 ### Patch Changes * Updated dependencies \[8bea78f] * @turnkey/sdk-browser\@1.10.0 ## 1.1.4 ### Patch Changes * Updated dependencies \[3dd74ac] * Updated dependencies \[1e36edf] * Updated dependencies \[4df8914] * Updated dependencies \[11a9e2f] * @turnkey/sdk-browser\@1.9.0 * @turnkey/sdk-server\@1.6.0 * @turnkey/http\@2.16.0 ## 1.1.3 ### Patch Changes * Updated dependencies \[9ebd062] * @turnkey/sdk-browser\@1.8.0 * @turnkey/sdk-server\@1.5.0 * @turnkey/http\@2.15.0 ## 1.1.2 ### Patch Changes * Updated dependencies \[abe7138] * Updated dependencies \[96d7f99] * @turnkey/sdk-server\@1.4.2 * @turnkey/sdk-browser\@1.7.1 * @turnkey/http\@2.14.2 * @turnkey/api-key-stamper\@0.4.3 ## 1.1.1 ### Patch Changes * Updated dependencies \[ff059d5] * Updated dependencies \[ff059d5] * @turnkey/sdk-browser\@1.7.0 * @turnkey/sdk-server\@1.4.1 * @turnkey/http\@2.14.1 * @turnkey/api-key-stamper\@0.4.2 ## 1.1.0 ### Minor Changes * bdded80: Support awaiting consensus * Add a few new helper functions: * `serializeSignature` serializes a raw signature ### Patch Changes * Updated dependencies \[c988ed0] * Updated dependencies \[848f8d3] * @turnkey/sdk-browser\@1.6.0 * @turnkey/sdk-server\@1.4.0 * @turnkey/http\@2.14.0 ## 1.0.21 ### Patch Changes * Updated dependencies \[1813ed5] * @turnkey/sdk-browser\@1.5.0 ## 1.0.20 ### Patch Changes * Updated dependencies \[bab5393] * Updated dependencies \[a16073c] * Updated dependencies \[7e7d209] * @turnkey/sdk-browser\@1.4.0 ## 1.0.19 ### Patch Changes * Updated dependencies \[93dee46] * @turnkey/http\@2.13.0 * @turnkey/sdk-browser\@1.3.0 * @turnkey/sdk-server\@1.3.0 ## 1.0.18 ### Patch Changes * Updated dependencies \[e2f2e0b] * @turnkey/sdk-browser\@1.2.4 * @turnkey/sdk-server\@1.2.4 * @turnkey/http\@2.12.3 ## 1.0.17 ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@1.2.3 * @turnkey/sdk-server\@1.2.3 ## 1.0.16 ### Patch Changes * Updated dependencies * @turnkey/api-key-stamper\@0.4.1 * @turnkey/http\@2.12.2 * @turnkey/sdk-browser\@1.2.2 * @turnkey/sdk-server\@1.2.2 ## 1.0.15 ### Patch Changes * Updated dependencies \[f17a229] * @turnkey/http\@2.12.1 * @turnkey/sdk-browser\@1.2.1 * @turnkey/sdk-server\@1.2.1 ## 1.0.14 ### Patch Changes * Updated dependencies * @turnkey/http\@2.12.0 * @turnkey/sdk-browser\@1.2.0 * @turnkey/sdk-server\@1.2.0 ## 1.0.13 ### Patch Changes * Updated dependencies * @turnkey/http\@2.11.0 * @turnkey/sdk-browser\@1.1.0 * @turnkey/sdk-server\@1.1.0 ## 1.0.12 ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@1.0.0 * @turnkey/sdk-server\@1.0.0 ## 1.0.11 ### Patch Changes * @turnkey/sdk-browser\@0.4.1 ## 1.0.10 ### Patch Changes * Updated dependencies \[e4b29da] * @turnkey/sdk-browser\@0.4.0 ## 1.0.9 ### Patch Changes * Updated dependencies \[d409d81] * @turnkey/sdk-browser\@0.3.0 ## 1.0.8 ### Patch Changes * @turnkey/sdk-browser\@0.2.1 ## 1.0.7 ### Patch Changes * Updated dependencies * Updated dependencies \[e4d2a84] * @turnkey/sdk-browser\@0.2.0 * @turnkey/sdk-server\@0.2.0 ## 1.0.6 ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@0.1.0 * @turnkey/sdk-server\@0.1.0 ## 1.0.5 ### Patch Changes * a6502e6: Add support for new Turnkey Client types ## 1.0.4 ### Patch Changes * Updated dependencies \[7a9ce7a] * @turnkey/http\@2.10.0 ## 1.0.3 ### Patch Changes * Updated dependencies * @turnkey/http\@2.9.1 ## 1.0.2 ### Patch Changes * Updated dependencies \[83b62b5] * @turnkey/http\@2.9.0 ## 1.0.1 ### Patch Changes * Updated dependencies \[46a7d90] * @turnkey/http\@2.8.0 ## 1.0.0 ### Major Changes Updates @turnkey/ethers package and examples to use ethers v6. Refer to [https://docs.ethers.org/v6/migrating](https://docs.ethers.org/v6/migrating) for full migration instructions. ✨Summary of Changes✨ `getBalance` is no longer a method on the signer. It must be obtained via the provider instance. Additionally, it requires an address to be passed in: ``` // before const balance = await connectedSigner.getBalance(); // after // first get the address const address = await connectedSigner.getAddress() // then pass it in const balance = await connectedSigner.provider?.getBalance(address) ``` `getChainId` is no longer a method on the signer. It must be obtained via the network object on the provider instance: ``` // before const chainId = await connectedSigner.getChainId(); // after const chainId = (await connectedSigner.provider?.getNetwork())?.chainId; ``` `getTransactionCount` is no longer a method on the signer. It must be obtained via the provider instance. Additionally, it requires an address to be passed in: ``` // before const transactionCount = await connectedSigner.getTransactionCount(); // after // first get the address const address = await connectedSigner.getAddress() // then pass it in const transactionCount = await connectedSigner.provider?.getTransactionCount(address); ``` `getFeeData` is no longer a method on the signer. It must be obtained via the provider instance: ``` // before const feeData = await connectedSigner.getFeeData(); // after const feeData = await connectedSigner.provider?.getFeeData(); ``` BigNumber -> bigint: numerical values such as, chainId, fee data, balance now use new ES6 primitive `bigint` instead of `BigNumber`. For example, when checking if the balance is `0`, `bigint` must now be used for comparison: ``` // before if (balance.isZero()) {...} // after if (balance === 0n) {...} ``` ## 0.19.9 ### Patch Changes * Updated dependencies * @turnkey/http\@2.7.1 ## 0.19.8 ### Patch Changes * Updated dependencies (\[c3b423b], \[d73725b]) * @turnkey/api-key-stamper\@0.4.0 * @turnkey/http\@2.7.0 ## 0.19.7 ### Patch Changes * Updated dependencies \[f9d636c] * @turnkey/http\@2.6.2 ## 0.19.6 ### Patch Changes * Updated dependencies \[52e2389] * @turnkey/http\@2.6.1 ## 0.19.5 ### Patch Changes * Updated dependencies \[7a3c890] * @turnkey/http\@2.6.0 ## 0.19.4 ### Patch Changes * Upgrade to Node v18 (#184) * Updated dependencies * @turnkey/api-key-stamper\@0.3.1 * @turnkey/http\@2.5.1 ## 0.19.3 ### Patch Changes * Updated dependencies \[464ac0e] * @turnkey/http\@2.5.0 ## 0.19.2 ### Patch Changes * @turnkey/http\@2.4.2 ## 0.19.1 ### Patch Changes * Updated dependencies \[f87ced8] * @turnkey/http\@2.4.1 ## 0.19.0 ### Minor Changes * Use rollup to build ESM and CommonJS, fix ESM support (#174) ### Patch Changes * Updated dependencies \[fc5b291] * @turnkey/api-key-stamper\@0.3.0 * @turnkey/http\@2.4.0 ## 0.18.3 ### Patch Changes * Updated dependencies * @turnkey/api-key-stamper\@0.3.0 * @turnkey/http\@2.3.1 ## 0.18.2 ### Patch Changes * Updated dependencies \[f1bd68a] * @turnkey/http\@2.3.0 ## 0.18.1 ### Patch Changes * Updated dependencies \[ed50a0f] * Updated dependencies * @turnkey/http\@2.2.0 ## 0.18.0 ### Minor Changes * cf8631a: Update interface to support `signWith` This change supports signing with wallet account addresses, private key addresses, or private key IDs. See below for an example: ```js const turnkeyClient = new TurnkeyClient( { baseUrl: "https://api.turnkey.com", }, // This uses API key credentials. // If you're using passkeys, use `@turnkey/webauthn-stamper` to collect webauthn signatures: // new WebauthnStamper({...options...}) new ApiKeyStamper({ apiPublicKey: "...", apiPrivateKey: "...", }), ); // Initialize a Turnkey Signer const turnkeySigner = new TurnkeySigner({ client: turnkeyClient, organizationId: "...", signWith: "...", }); ``` ## 0.17.4 ### Patch Changes * Updated dependencies \[bb6ea0b] * @turnkey/http\@2.1.0 ## 0.17.3 ### Patch Changes * Updated dependencies * @turnkey/http\@2.0.0 * Updated the shape of signing ## 0.17.2 ### Patch Changes * Updated dependencies * @turnkey/http\@1.3.0 ## 0.17.1 ### Patch Changes * Update documentation as follows: * ebf87a9: This breaking change adds support for stampers (@turnkey/api-key-stamper / @turnkey/webauthn-stamper) to integrate with API keys or passkeys, bringing it to parity with our [Viem](https://github.com/tkhq/sdk/tree/main/packages/viem) package. See the following examples for sample usage: * [with-ethers](https://github.com/tkhq/sdk/tree/main/examples/with-ethers): updated to use `@turnkey/api-key-stamper` * [with-ethers-and-passkeys](https://github.com/tkhq/sdk/tree/main/examples/with-ethers-and-passkeys): demonstrates usage of `@turnkey/webauthn-stamper` ## 0.17.0 ### Minor Changes * Add support for stampers (@turnkey/api-key-stamper / @turnkey/webauthn-stamper) to integrate with API keys or passkeys. ## 0.16.8 ### Patch Changes * Updated dependencies * @turnkey/http\@1.2.0 ## 0.16.7 ### Patch Changes * @turnkey/http\@1.1.1 ## 0.16.6 ### Patch Changes * Updated dependencies * @turnkey/http\@1.1.0 ## 0.16.5 ### Patch Changes * Updated dependencies \[8d1d0e8] * @turnkey/http\@1.0.1 ## 0.16.4 ### Patch Changes * 46473ec: This breaking change updates generated code to be shorter and more intuitive to read: * generated fetchers do not include the HTTP method in their name. For example `useGetGetActivity` is now `useGetActivity`, and `usePostSignTransaction` is `useSignTransaction`. * input types follow the same convention (no HTTP method in the name): `TPostCreatePrivateKeysInput` is now `TCreatePrivateKeysInput`. * the "federated" request helpers introduced in `0.18.0` are now named "signed" requests to better reflect what they are. `FederatedRequest` is now `SignedRequest`, and generated types follow. For example: `federatedPostCreatePrivateKeys` is now `signCreatePrivateKeys`, `federatedGetGetActivity` is now `signGetActivity`, and so on. The name updates should be automatically suggested if you use VSCode since the new names are simply shorter versions of the old one. * Updated dependencies \[46473ec] * Updated dependencies \[38b424f] * @turnkey/http\@1.0.0 ## 0.16.3 ### Patch Changes * Updated dependencies * @turnkey/http\@0.18.1 ## 0.16.2 ### Patch Changes * Updated dependencies * @turnkey/http\@0.18.0 ## 0.16.1 ### Patch Changes * Updated dependencies * @turnkey/http\@0.17.1 ## 0.16.0 ### Minor Changes * No public facing changes ### Patch Changes * Updated dependencies \[9317f51] * @turnkey/http\@0.17.0 ## 0.15.0 ### Minor Changes * No public facing changes ### Patch Changes * Updated dependencies * @turnkey/http\@0.16.0 * Fix `.postGetPrivateKey(...)`'s underlying path, while adding `@deprecated` `.postGetPrivateKeyBackwardsCompat(...)` for backward compatibility ## 0.14.1 ### Patch Changes * Updated dependencies * @turnkey/http\@0.15.0 ## 0.14.0 ### Minor Changes * `signTransaction(...)` now verifies and drops `tx.from` if present * This mimics the behavior of ethers' Wallet [implementation](https://github.com/ethers-io/ethers.js/blob/f97b92bbb1bde22fcc44100af78d7f31602863ab/packages/wallet/src.ts/index.ts#L117-L121) ### Patch Changes * Updated dependencies * @turnkey/http\@0.14.0 ## 0.13.2 ### Patch Changes * New `TurnkeyRequestError` error class that contains rich error details * Updated dependencies * @turnkey/http\@0.13.2 ## 0.13.1 ### Patch Changes * Error messages now contain Turnkey-specific error details * Updated dependencies * @turnkey/http\@0.13.1 ## 0.13.0 ### Minor Changes * No public facing changes ### Patch Changes * Updated dependencies * @turnkey/http\@0.13.0 ## 0.12.0 ### Minor Changes * Error messages now contain Turnkey-specific error code and message ### Patch Changes * Updated dependencies * @turnkey/http\@0.12.0 ## 0.11.0 ### Minor Changes * `TurnkeySigner` now conforms to ethers' `TypedDataSigner` interface ### Patch Changes * Updated dependencies * @turnkey/http\@0.11.0 ## 0.10.0 ### Minor Changes * Added EIP-712 support for signing typed data to Ethers. * Update Gnosis example to make use of new signing functionality. ### Patch Changes * Updated dependencies * @turnkey/http\@0.10.0 ## 0.9.0 ### Minor Changes * Improved support for React Native runtime ([https://github.com/tkhq/sdk/pull/37](https://github.com/tkhq/sdk/pull/37)) ### Patch Changes * Updated dependencies * @turnkey/http\@0.9.0 ## 0.8.1 ### Patch Changes * Switched from `undici` to `cross-fetch` to improve bundler compatibility * Updated dependencies * @turnkey/http\@0.8.1 ## 0.8.0 ### Minor Changes * Added browser runtime support — `@turnkey/ethers` is now a universal (isomorphic) package * Dropped support for Node.js v14; we recommend using Node v18+ ### Patch Changes * Updated dependencies * @turnkey/http\@0.8.0 ## 0.7.0 ### Minor Changes * No public facing changes ### Patch Changes * Updated dependencies * @turnkey/http\@0.7.0 ## 0.6.0 ### Minor Changes * `#signMessage(...)`: move encoding and hashing logic to client side, `eth_sign` style ### Patch Changes * Updated dependencies * @turnkey/http\@0.6.0 ## 0.5.0 ### Minor Changes * Arbitrary message signing ### Patch Changes * Updated dependencies * @turnkey/http\@0.5.0 ## 0.4.0 ### Minor Changes * `timestamp` -> `timestampMs` ### Patch Changes * Updated dependencies * @turnkey/http\@0.4.0 ## 0.3.1 ### Patch Changes * Fix outdated artifact * Updated dependencies * @turnkey/http\@0.3.1 ## 0.3.0 ### Minor Changes * `keyId` -> `privateKeyId` everywhere ### Patch Changes * Updated dependencies * @turnkey/http\@0.3.0 ## 0.2.0 ### Minor Changes * Change parameter from `keyId` to `privateKeyId` * Bump API version to latest Beta ### Patch Changes * Updated dependencies * @turnkey/http\@0.2.0 ## 0.1.3 ### Patch Changes * Support runtime config for credentials * Updated dependencies * @turnkey/http\@0.1.3 ## 0.1.2 ### Patch Changes * Drop internal dev dependency * Updated dependencies * @turnkey/http\@0.1.2 ## 0.1.1 ### Patch Changes * Initial release * Updated dependencies * @turnkey/http\@0.1.1 # Go Source: https://docs.turnkey.com/changelogs/golang/readme # CHANGELOG ## [v0.3.0](https://github.com/tkhq/go-sdk/compare/v0.2.0...v0.3.0) (2025-02-19) * Update per mono release v2025.2.1 * Introduces new `GetWalletAccount` query ## [v0.2.0](https://github.com/tkhq/go-sdk/compare/v0.1.0...v0.2.0) (2025-02-13) * Update per mono release v2025.1.11 * Update vulnerable go crypto package ## [v0.1.0](https://github.com/tkhq/go-sdk/compare/8c73e973e9a5e1e4cfabef7aaae24a8fad91478f...v0.1.0) (2025-01-17) * First "official" beta release! 🥳 * Because it's the first, this release version corresponds to the latest changes merged in `8c73e973e9a5e1e4cfabef7aaae24a8fad91478f` # Http Source: https://docs.turnkey.com/changelogs/http/readme # @turnkey/http ## 3.0.0 ### Major Changes * f94d36e: Remove deprecated TurnkeyApiService. TurnkeyApi should be used instead. ### Minor Changes * d1083bd: New activity `INIT_OTP_AUTH_V2` which allows alphanumeric boolean and otpLength (6-9) to be passed * This release introduces the `INIT_OTP_AUTH_V2` activity. The difference between it and `INIT_OTP_AUTH` is that it can now accept `alphanumeric` and `otpLength` for selecting crockford bech32 alphanumeric codes and the length of those codes. By default alphanumeric = true, otpLength = 9 * This release introduces `sendFromEmailSenderName` to `INIT_OTP_AUTH`, `INIT_OTP_AUTH_V2`, `EMAIL_AUTH` and `EMAIL_AUTH_V2`. This is an optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications'. ## 2.22.0 ### Minor Changes * ecdb29a: Update API as per mono v2025.3.2 * This release introduces the `CREATE_USERS_V3` activity. The difference between it and `CREATE_USERS_V2` is that it can now accept `userPhoneNumber` and `oauthProviders`. In total, it accepts the following parameters: ```javascript /** @description A list of Users. */ users: { /** @description Human-readable name for a User. */ userName: string; /** @description The user's email address. */ userEmail?: string; /** @description The user's phone number in E.164 format e.g. +13214567890 */ userPhoneNumber?: string; /** @description A list of API Key parameters. This field, if not needed, should be an empty array in your request body. */ apiKeys: definitions["v1ApiKeyParamsV2"][]; /** @description A list of Authenticator parameters. This field, if not needed, should be an empty array in your request body. */ authenticators: definitions["v1AuthenticatorParamsV2"][]; /** @description A list of Oauth providers. This field, if not needed, should be an empty array in your request body. */ oauthProviders: definitions["v1OauthProviderParams"][]; /** @description A list of User Tag IDs. This field, if not needed, should be an empty array in your request body. */ userTags: string[]; } ``` See [source code](https://github.com/tkhq/sdk/blob/60c0c03440785b841d1f6f393612046423dc665f/packages/http/src/__generated__/services/coordinator/public/v1/public_api.types.ts#L2894-L2909) to view details on the nested types. ## 2.21.0 ### Minor Changes * 56a307e: Update API to mono v2025.3.0 * This release introduces an `invalidateExisting` flag to the `CreateReadWriteSession` and `Oauth` activities. If enabled, this will invalidate existing read-write and oauth API keys. This is useful in scenarios where a user attempts to create numerous `ReadWrite` or `Oauth` sessions. Because our API caps the number of session keys associated with a user, this flag can clear all other existing session keys of that specific type (e.g. setting `invalidateExisting: true` for `CreateReadWriteSession` will invalidate all previously created read-write session keys) ## 2.20.0 ### Minor Changes * 3c44c4a: Updates per mono release v2025.2.2 ## 2.19.0 ### Minor Changes * 57f9cb0: Update endpoints - surface `GetWalletAccount`. This endpoint takes in the following args: ```javascript /** @description Unique identifier for a given Organization. */ organizationId: string; /** @description Unique identifier for a given Wallet. */ walletId: string; /** @description Address corresponding to a Wallet Account. */ address?: string; /** @description Path corresponding to a Wallet Account. */ path?: string; ``` ## 2.18.0 ### Minor Changes * 6695af2: Update per mono release v2025.1.11 ## 2.17.3 ### Patch Changes * 053fbfb: Update mono dependencies ## 2.17.2 ### Patch Changes * Updated dependencies \[2d5977b] * @turnkey/api-key-stamper\@0.4.4 ## 2.17.1 ### Patch Changes * 538d4fc: Update api endpoints - NEW: User verification, SMS customization params ## 2.17.0 ### Minor Changes * 78bc39c: Add default accounts for various address types * Add wallet account ID to list wallets endpoint ## 2.16.0 ### Minor Changes * 4df8914: Version bump corresponding to mono release v2024.10.10. * Improved error message for duplicate activity submission * Address derivation support for DOGE, TON, SEI, XLM * Fix server side error if sub\_org doesn’t have email and/or phone number ## 2.15.0 ### Minor Changes * 9ebd062: Release OTP functionality ## 2.14.2 ### Patch Changes * 96d7f99: Update dependencies * Updated dependencies \[e5c4fe9] * @turnkey/encoding\@0.4.0 * @turnkey/api-key-stamper\@0.4.3 ## 2.14.1 ### Patch Changes * ff059d5: Update dependencies * Updated dependencies \[93666ff] * @turnkey/encoding\@0.3.0 * @turnkey/api-key-stamper\@0.4.2 ## 2.14.0 ### Minor Changes * 848f8d3: Add new helpers and update types and errors * `getSignatureFromActivity` returns the signature corresponding to a completed activity * `getSignedTransactionFromActivity` returns the signed transaction corresponding to a completed activity * `assertActivityCompleted` checks the state of an activity and throws an error if the activity either requires consensus or is otherwise not yet completed * `TERMINAL_ACTIVITY_STATUSES` is a const containing all terminal activity statuses. Useful for checking on an activity * `TurnkeyActivityError` now uses `undefined` instead of `null` * Export some additional types: `TActivity`, `TActivityId`, `TActivityStatus`, `TActivityType` ## 2.13.0 ### Minor Changes * 93dee46: Add create read write session v2 which allows for user targeting directly from stamp or optional userId in intent ## 2.12.3 ### Patch Changes * e2f2e0b: Added two new endpoints for deleting private keys and deleting wallets ## 2.12.2 ### Patch Changes * 2d7e5a9: fix a (currently unused) return value * Updated dependencies * @turnkey/api-key-stamper\@0.4.1 * @turnkey/encoding\@0.2.1 ## 2.12.1 ### Patch Changes * f17a229: Update to oauth related endpoints to drop jwks uri from oauth providers ## 2.12.0 ### Minor Changes * Add Email Auth V2 - Optional invalidate exisiting Email Authentication API keys ## 2.11.0 ### Minor Changes * Update to use new endpoints. Including CREATE\_READ\_WRITE\_SESSION which allows one shot passkey sessions (returns org information and a credential bundle) and CREATE\_API\_KEYS\_V2 which allows a curve type to be passed (SECP256K1 or P256) ## 2.10.0 ### Minor Changes * 7a9ce7a: Sync 2024.3.16 ## 2.9.1 ### Patch Changes * Update generated files to latest release: optional pagination options were added to list sub-organization and list wallet account endpoints. ## 2.9.0 ### Minor Changes * 83b62b5: Sync types for latest release ## 2.8.0 ### Minor Changes * 46a7d90: Update to v2024.2.1 API: add activities to initialize wallet import, import wallet, delete users, delete private key tags, delete user tags, and list sub-organizations ## 2.7.1 ### Patch Changes * Update to v2024.2.0 API types: `mnemonicLength` is now a number instead of a string ## 2.7.0 ### Minor Changes * Introduce and reference `@turnkey/encoding` to consolidate utility functions * Updated dependencies (\[c3b423b], \[d73725b]) * @turnkey/webauthn-stamper\@0.5.0 * @turnkey/api-key-stamper\@0.4.0 * @turnkey/encoding\@0.1.0 ## 2.6.2 ### Patch Changes * b45a9ac: Include package version in request headers * f9d636c: Export VERSION from turnkey/http ## 2.6.1 ### Patch Changes * 52e2389: Revert version export (#186 and #187) ## 2.6.0 ### Minor Changes * 0794f41: Add VERSION constant * 7a3c890: Add key export support ### Patch Changes * 4517e3b: Update version string to include package name ## 2.5.1 ### Patch Changes * Upgrade to Node v18 (#184) * Updated dependencies * @turnkey/webauthn-stamper\@0.4.3 * @turnkey/api-key-stamper\@0.3.1 ## 2.5.0 ### Minor Changes * 464ac0e: Update protos for latest release, which includes: * Support optional expirations for API keys, configurable via the `expirationSeconds` parameter. * Support Email Auth. Details to follow ⚡️ ## 2.4.2 ### Patch Changes * Updated dependencies \[a03e385] * @turnkey/webauthn-stamper\@0.4.2 ## 2.4.1 ### Patch Changes * Fix universal files to stop using `require`. Use ES6 imports instead (#178) * Updated dependencies \[f87ced8] * @turnkey/webauthn-stamper\@0.4.1 ## 2.4.0 ### Minor Changes * Use rollup to build ESM and CommonJS, fix ESM support (#174) ### Patch Changes * Updated dependencies \[fc5b291] * @turnkey/api-key-stamper\@0.3.0 * @turnkey/webauthn-stamper\@0.4.0 ## 2.3.1 ### Patch Changes * Updated dependencies * @turnkey/api-key-stamper\@0.2.0 ## 2.3.0 ### Minor Changes * Sync protos from latest public endpoints ## 2.2.0 ### Minor Changes * Add ESM to package dist (#154) ### Patch Changes * ed50a0f: simplify types ## 2.1.0 ### Minor Changes * bb6ea0b: Update generated files * new query endpoints to retrieve wallets (`/public/v1/query/list_wallets`) * new query endpoint to retrieve wallet accounts (`/public/v1/query/list_wallet_accounts`) ## 2.0.0 ### Major Changes * Synced protos from mono ### Upgrade notes * `signRawPayload` and `signTransaction` now expect a `signWith` param instead of `privateKeyId` previously * `signRawPayload` and `signTransaction` have been updated to expect a new type: `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2` and `ACTIVITY_TYPE_SIGN_TRANSACTION_V2`, respectively * If you have policies authorizing `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD` or `ACTIVITY_TYPE_SIGN_TRANSACTION` specifically, they will need to be updated to authorize `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2` and `ACTIVITY_TYPE_SIGN_TRANSACTION_V2` (or better yet, update your policies to allow all signing actions categorically using policy resources and actions. See [https://docs.turnkey.com/managing-policies/examples](https://docs.turnkey.com/managing-policies/examples)) * `createSubOrganization` now uses `ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V4` under the hood, which utilizes wallets. The shape of the request has been updated to include the following parameter, `wallet`. Here's an example: ```js { ... wallet: { walletName: "Default Wallet", accounts: [ { curve: "CURVE_SECP256K1", pathFormat: "PATH_FORMAT_BIP32", path: "m/44'/60'/0'/0/0", addressFormat: "ADDRESS_FORMAT_ETHEREUM", }, ], }, } ``` See [https://docs.turnkey.com/concepts/sub-organizations](https://docs.turnkey.com/concepts/sub-organizations) for more details. ## 1.3.0 ### Minor Changes * Synced protos from mono * Adds base URL check during initialization (closes [https://github.com/tkhq/sdk/issues/124](https://github.com/tkhq/sdk/issues/124)) * The following are new features additions, fresh out the oven. Still getting them ready for primetime! Refreshed examples to come soon™️. Stay tuned and reach out to the Turnkey team if you have any questions. * Wallets: * 🟢 `ACTIVITY_TYPE_CREATE_WALLET` (via `/api/v1/submit/create_wallet`): create a HD wallet * 🟢 `ACTIVITY_TYPE_CREATE_WALLET_ACCOUNTS` (via `/api/v1/submit/create_wallet_accounts`): create a wallet account (address) * 🟢 `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2` (via `/api/v1/submit/sign_raw_payload_v2`): sign a payload with a specified private key or address * 🟢 `ACTIVITY_TYPE_SIGN_TRANSACTION_V2` (via `/api/v1/submit/sign_transaction_v2`): sign a transaction with a specified private key or address * Organization features: * 🟢 `ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE` (via `/api/v1/submit/set_organization_feature`): set an organization feature * 🟢 `ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE` (via `/api/v1/submit/remove_organization_feature`): remove an organization feature * Only one feature supported as of this time; additional documentation to follow. * Export private key: * 🟡 `ACTIVITY_TYPE_EXPORT_PRIVATE_KEY` (via `/api/v1/submit/export_private_key`): export a private key, encrypted to a target public key. We do not yet have CLI or front-end tooling to use this safely; stay tuned! * Email recovery: * 🟡 `ACTIVITY_TYPE_INIT_USER_EMAIL_RECOVERY` (via `/api/v1/submit/init_user_email_recovery`): initialize a new email recovery flow Note: * 🟢: good to go! * 🟡: these endpoints are safe to use, but still experimental/unstable. Check back for updates and guidance. ### Patch Changes * Updated dependencies * @turnkey/webauthn-stamper\@0.2.0 ## 1.2.0 ### Minor Changes * The `createSubOrganization` request has been updated under the hood: * Calling `.createSubOrganization` on our HTTP client will trigger an activity of type `CREATE_SUB_ORGANIZATION_V3` instead of `CREATE_SUB_ORGANIZATION_V2` previously. * If there are any policies referencing `CREATE_SUB_ORGANIZATION_V2` specifically, they will no longer work out of the box if creating sub-orgs via SDK. These policies will need to be updated to allow `CREATE_SUB_ORGANIZATION_V3`. See policy examples related to access control [here](https://docs.turnkey.com/managing-policies/examples#access-control) for additional methods of constructing policies. * `CREATE_SUB_ORGANIZATION_V3` supports everything `CREATE_SUB_ORGANIZATION_V2` supports, with the addition of a `privateKeys` field to atomically create a sub-org with private keys. If no private keys are desired, simply provide an empty array. * **NOTE**: when reading `createSubOrganization` results, SDK users will now need to look at `activity.result.createSubOrganizationResultV3` instead of the previously valid `activity.result.createSubOrganizationResult`. ## 1.1.1 ### Patch Changes * Updated dependencies * @turnkey/api-key-stamper\@0.1.1 ## 1.1.0 ### Minor Changes New exports: * new `TurnkeyClient`. This is now the preferred interface to make Turnkey requests, because it supports both API keys and webauthn-signed requests. It also doesn't rely on global initialization * new method to poll requests: `createActivityPoller` Deprecation notices: * deprecate `TurnkeyApi` (use `TurnkeyClient` instead), `init`, `browserInit` (no need for them anymore if you're using `TurnkeyClient`), and `withAsyncPolling` (use `createActivityPoller` instead) * deprecate `SignedRequest` in favor of `TSignedRequest`. Besides the more correct name, `TSignedRequest` differs in its `stamp` property. It now stores the stamper header name as well as value, so users do not have to hardcode Turnkey stamp header names (e.g. "X-Stamp-Webauthn"). Update our swagger and generated files to latest versions: * new endpoint to update users: `/public/v1/submit/update_user` * pagination `limit` option has been updated to `string` instead of number for consistency with other pagination options Signing is now performed through Turnkey stampers. New dependencies: * @turnkey/webauthn-stamper\@0.1.0 * @turnkey/api-key-stamper\@0.1.0 ## 1.0.1 ### Patch Changes * 8d1d0e8: Synced protos from mono ## 1.0.0 ### Major Changes * 46473ec: This breaking change updates generated code to be shorter and more intuitive to read: * generated fetchers do not include the HTTP method in their name. For example `useGetGetActivity` is now `useGetActivity`, and `usePostSignTransaction` is `useSignTransaction`. * input types follow the same convention (no HTTP method in the name): `TPostCreatePrivateKeysInput` is now `TCreatePrivateKeysInput`. * the "federated" request helpers introduced in `0.18.0` are now named "signed" requests to better reflect what they are. `FederatedRequest` is now `SignedRequest`, and generated types follow. For example: `federatedPostCreatePrivateKeys` is now `signCreatePrivateKeys`, `federatedGetGetActivity` is now `signGetActivity`, and so on. The name updates should be automatically suggested if you use VSCode since the new names are simply shorter versions of the old one. ### Patch Changes * 38b424f: Sync public api types ## 0.18.1 ### Patch Changes * Synced protos from mono ## 0.18.0 ### Minor Changes * Add support for federated requests (an example is included under `sdk/examples/with-federated-passkeys`) * Routine re-sync protos from mono ## 0.17.1 ### Patch Changes * Re-sync protos from mono. No public-facing changes. ## 0.17.0 ### Minor Changes * Added support for ed25519 * New endpoint to programmatically approve or reject activities (`/submit/approve_activity`, `/submit/reject_activity`) * New endpoint to programmatically create authenticators (`/submit/create_authenticators`) * New endpoints to update Private Key tags (`/submit/update_private_key_tag`) * New endpoints to update User tags (`/submit/update_user_tag`) * Simplified shape for `AuthenticatorParams` with a new `AuthenticatorParamsV2`. To take advantage of this new shape, use `ACTIVITY_TYPE_CREATE_USERS_V2` and the new `ACTIVITY_TYPE_CREATE_AUTHENTICATORS`. ## 0.16.0 ### Minor Changes * Fix `.postGetPrivateKey(...)`'s underlying path, while adding `@deprecated` `.postGetPrivateKeyBackwardsCompat(...)` for backward compatibility ## 0.15.0 ### Minor Changes * Export a new helper for offline request signing: `sealAndStampRequestBody(...)`. ## 0.14.0 ### Minor Changes * Updated the `addressFormats` enum field in `/submit/create_private_keys` ## 0.13.2 ### Patch Changes * New `TurnkeyRequestError` error class that contains rich error details ## 0.13.1 ### Patch Changes * Error messages now contain Turnkey-specific error details ## 0.13.0 ### Minor Changes * New `/submit/create_api_only_users` endpoint: `TurnkeyApi.postCreateApiOnlyUsers(...)` * Marked `TurnkeyApi.postCreateUsers(...)` as deprecated * Improved documentation on methods (via TSDoc) ## 0.12.0 ### Minor Changes * Error messages now contain Turnkey-specific error code and message ## 0.11.0 ### Minor Changes * New `/submit/create_users` endpoint: `TurnkeyApi.postCreateUsers(...)` ## 0.10.0 ### Minor Changes * No public-facing changes ## 0.9.0 ### Minor Changes * Improved support for React Native runtime ([https://github.com/tkhq/sdk/pull/37](https://github.com/tkhq/sdk/pull/37)) ## 0.8.1 ### Patch Changes * Switched from `undici` to `cross-fetch` to improve bundler compatibility ## 0.8.0 ### Minor Changes * Added browser runtime support — `@turnkey/http` is now a universal (isomorphic) package * The API fetchers are now exported as namespace `TurnkeyApi`. `PublicApiService` has been marked as deprecated, but will remain functional until we hit v1.0. * Dropped support for Node.js v14; we recommend using Node v18+ ## 0.7.0 ### Minor Changes * Improved documentation * Added `withAsyncPolling(...)` helper to provide built-in async polling support. Read more: * [https://github.com/tkhq/sdk/tree/main/packages/http#withasyncpolling-helper](https://github.com/tkhq/sdk/tree/main/packages/http#withasyncpolling-helper) ## 0.6.0 ### Minor Changes * Improved OpenAPI documentation ## 0.5.0 ### Minor Changes * Arbitrary message signing ## 0.4.0 ### Minor Changes * `timestamp` -> `timestampMs` ## 0.3.1 ### Patch Changes * Fix outdated artifact ## 0.3.0 ### Minor Changes * `keyId` -> `privateKeyId` everywhere ## 0.2.0 ### Minor Changes * Change parameter from `keyId` to `privateKeyId` * Bump API version to latest Beta ## 0.1.3 ### Patch Changes * Support runtime config for credentials ## 0.1.2 ### Patch Changes * Drop internal dev dependency ## 0.1.1 ### Patch Changes * Initial release * Updated dependencies * @turnkey/jest-config\@0.1.1 # Iframe Stamper Source: https://docs.turnkey.com/changelogs/iframe-stamper/readme # @turnkey/iframe-stamper ## 2.5.0 ### Minor Changes * e501690: Add new utility functions * Add `clearEmbeddedKey()` async function, which clears the embedded key within an iframe * Add `initEmbeddedKey()` async function, which reinitializes the embedded key within an iframe ## 2.4.0 ### Minor Changes * a833088: Add `getEmbeddedPublicKey()` async function to get the public key of the live embedded key within the iframe ## 2.3.0 ### Minor Changes * 9147962: Add `dangerouslyOverrideIframeKeyTtl` option to override iframe embedded key TTL (for longer lived read/write sessions) ## 2.2.0 ### Minor Changes * a216a47: Add `requestId` to iframe requests. This allows developers to send multiple requests at once to an iframe, and have the corresponding responses be handled correctly (in order) ## 2.1.0 ### Minor Changes * fad7c37: `@turnkey/iframe-stamper` - Implemented MessageChannel API for secure communication between the parent and iframe. @turnkey/sdk-browser - fixed spelling in package.json @turnkey/sdk-server - fixed spelling in package.json ## 2.0.0 ### Major Changes * 5d0bfde: Include `organizationId` and `userId` in injected import and export bundles. ### Minor Changes * 2f2d09a: Add implementation for `applySettings()` * This is a function to apply settings on allowed parameters in the iframe. * Ultimately, this is used to style the HTML element used for plaintext in wallet and private key import. ### Patch Changes * 976663e: Add `sandbox` attribute to iframe element ## 1.2.0 ### Minor Changes * 0281b88: Remove optional publicKey parameter from injectKeyExportBundle. * 0e3584a: Add optional keyFormat and publicKey parameters to injectKeyExportBundle. Add extractKeyEncryptedBundle. ## 1.1.0 ### Minor Changes * 46a7d90: Add injectImportBundle and extractWalletEncryptedBundle to support wallet import. ## 1.0.0 ### Major Changes * This breaking change uses an HTML element instead of an ID to reference the iframe's container. ## 0.4.1 ### Patch Changes * Upgrade to Node v18 (#184) ## 0.4.0 ### Minor Changes * c98c222: - Add support for auth (e.g. via email), and include recovery under it. Note that the preferred path is now to use `injectCredentialBundle`, as opposed to `injectRecoveryBundle` (deprecated). ## 0.3.0 ### Minor Changes * Use rollup to build ESM and CommonJS, fix ESM support (#174) ## 0.2.1 ### Patch Changes * Catch and bubble up errors in the underlying iframe by listening to `ERROR` events (#165) ## 0.2.0 ### Minor Changes * Support wallet and private key export ## 0.1.0 Initial release # React Native Passkey Stamper Source: https://docs.turnkey.com/changelogs/react-native-passkey-stamper/readme # @turnkey/react-native-passkey-stamper ## 1.0.10 ### Patch Changes * Updated dependencies \[d1083bd] * Updated dependencies \[f94d36e] * @turnkey/http\@3.0.0 ## 1.0.9 ### Patch Changes * Updated dependencies \[ecdb29a] * @turnkey/http\@2.22.0 ## 1.0.8 ### Patch Changes * Updated dependencies \[56a307e] * @turnkey/http\@2.21.0 ## 1.0.7 ### Patch Changes * Updated dependencies \[3c44c4a] * @turnkey/http\@2.20.0 ## 1.0.6 ### Patch Changes * Updated dependencies \[57f9cb0] * @turnkey/http\@2.19.0 ## 1.0.5 ### Patch Changes * Updated dependencies \[6695af2] * @turnkey/http\@2.18.0 ## 1.0.4 ### Patch Changes * Updated dependencies \[053fbfb] * @turnkey/http\@2.17.3 ## 1.0.3 ### Patch Changes * @turnkey/http\@2.17.2 ## 1.0.2 ### Patch Changes * Updated dependencies \[538d4fc] * @turnkey/http\@2.17.1 ## 1.0.1 ### Patch Changes * Updated dependencies \[78bc39c] * @turnkey/http\@2.17.0 ## 1.0.0 ### Major Changes Upgrade react-native-passkey to 3.0.0 (see [release notes](https://github.com/f-23/react-native-passkey/releases/tag/v3.0.0)). Among other things you can now specify `withSecurityKey` and `withPlatformKey` (new optional arguments to `createPasskey`) to target platform passkeys or security keys on iOS. The same options can be passed as configuration to `PasskeyStamper` to target these features at authentication time. This is a major change because the `transports` property, previously a string array (`Array`) is now an array of enums (`Array`). ## 0.2.16 ### Patch Changes * Updated dependencies \[4df8914] * @turnkey/http\@2.16.0 ## 0.2.15 ### Patch Changes * Updated dependencies \[9ebd062] * @turnkey/http\@2.15.0 ## 0.2.14 ### Patch Changes * Updated dependencies \[e5c4fe9] * Updated dependencies \[96d7f99] * @turnkey/encoding\@0.4.0 * @turnkey/http\@2.14.2 ## 0.2.13 ### Patch Changes * Updated dependencies \[ff059d5] * Updated dependencies \[93666ff] * @turnkey/http\@2.14.1 * @turnkey/encoding\@0.3.0 ## 0.2.12 ### Patch Changes * Updated dependencies \[848f8d3] * @turnkey/http\@2.14.0 ## 0.2.11 ### Patch Changes * Updated dependencies \[93dee46] * @turnkey/http\@2.13.0 ## 0.2.10 ### Patch Changes * Updated dependencies \[e2f2e0b] * @turnkey/http\@2.12.3 ## 0.2.9 ### Patch Changes * Updated dependencies * @turnkey/encoding\@0.2.1 * @turnkey/http\@2.12.2 ## 0.2.8 ### Patch Changes * Updated dependencies \[f17a229] * @turnkey/http\@2.12.1 ## 0.2.7 ### Patch Changes * Updated dependencies * @turnkey/http\@2.12.0 ## 0.2.6 ### Patch Changes * Updated dependencies * @turnkey/http\@2.11.0 ## 0.2.5 ### Patch Changes * Updated dependencies \[7a9ce7a] * @turnkey/http\@2.10.0 ## 0.2.4 ### Patch Changes * Updated dependencies * @turnkey/http\@2.9.1 ## 0.2.3 ### Patch Changes * Updated dependencies \[83b62b5] * @turnkey/http\@2.9.0 ## 0.2.2 ### Patch Changes * Updated dependencies \[46a7d90] * @turnkey/http\@2.8.0 ## 0.2.1 ### Patch Changes * Updated dependencies * @turnkey/http\@2.7.1 ## 0.2.0 ### Minor Changes * Introduce `@turnkey/encoding` to consolidate utility functions * Updated dependencies \[d73725b] * @turnkey/encoding\@0.1.0 * @turnkey/http\@2.7.0 ## 0.1.0 Initial release # SDK Browser Source: https://docs.turnkey.com/changelogs/sdk-browser/readme # @turnkey/sdk-browser ## 4.0.0 ### Major Changes * d1083bd: initOtpAuth now defaults to v2 (breaking) which allows alphanumeric boolean and otpLength (6-9) to be passed. More details below. * This release introduces the `INIT_OTP_AUTH_V2` activity. The difference between it and `INIT_OTP_AUTH` is that it can now accept `alphanumeric` and `otpLength` for selecting crockford bech32 alphanumeric codes and the length of those codes. By default alphanumeric = true, otpLength = 9 * This release introduces `sendFromEmailSenderName` to `INIT_OTP_AUTH`, `INIT_OTP_AUTH_V2`, `EMAIL_AUTH` and `EMAIL_AUTH_V2`. This is an optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications'. ### Minor Changes * e501690: Add new utility functions: * Add `clearEmbeddedKey()` async function, which clears the embedded key within an iframe * Add `initEmbeddedKey()` async function, which reinitializes the embedded key within an iframe These can be used in tandem to reset the embedded key within an iframe. See demo video in this PR's description: [https://github.com/tkhq/sdk/pull/571](https://github.com/tkhq/sdk/pull/571) Usage may look like the following: ```javascript import { Turnkey } from "@turnkey/sdk-browser"; ... // create an instance of TurnkeyBrowserSDK const turnkeyBrowserSDK = new Turnkey(config); // create an instance of TurnkeyIframeClient const iframeClient = await turnkeyBrowserSDK.iframeClient({ iframeContainer: document.getElementById( "turnkey-auth-iframe-container-id", ), iframeUrl: "https://auth.turnkey.com", iframeElementId: "turnkey-auth-iframe-element-id", }); ... // Clear the existing embedded key await iframeClient.clearEmbeddedKey(); const newPublicKey = await iframeClient.initEmbeddedKey(); ``` ### Patch Changes * Updated dependencies \[e501690] * Updated dependencies \[d1083bd] * Updated dependencies \[f94d36e] * @turnkey/iframe-stamper\@2.5.0 * @turnkey/http\@3.0.0 * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 3.1.0 ### Minor Changes * bf87774: Expose `getEmbeddedPublicKey()` via `TurnkeyIframeClient`. This can be used to fetch the live public key of the target embedded key living within an iframe. Usage may look like the following: ```javascript import { Turnkey } from "@turnkey/sdk-browser"; // create an instance of TurnkeyBrowserSDK const turnkeyBrowserSDK = new Turnkey(config); // create an instance of TurnkeyIframeClient const iframeClient = await turnkeyBrowserSDK.iframeClient({ iframeContainer: document.getElementById( "turnkey-auth-iframe-container-id", ), iframeUrl: "https://auth.turnkey.com", iframeElementId: "turnkey-auth-iframe-element-id", }); ... const publicKey = await iframeClient.getEmbeddedPublicKey(); ``` Functionally, this can be useful for scenarios where the developer would like to verify whether an iframe has a live embedded key within it. This contrasts from the static `iframeStamper.iframePublicKey` exposed by `@turnkey/iframe-stamper`'s `publicKey()` method. ### Patch Changes * Updated dependencies \[a833088] * @turnkey/iframe-stamper\@2.4.0 ## 3.0.1 ### Patch Changes * 5ec5187: Fix initOtpAuth bug with improper version result (to be updated to V2 following release r2025.3.8) ## 3.0.0 ### Major Changes * 72890f5: ### @turnkey/sdk-browser * Move all type definitions to [`./__types__/base.ts`](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts) * `TurnkeyBrowserClient` * `refereshSession()` now consumes a [RefreshSessionParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L213) parameter * `loginWithBundle()` now consumes a [LoginWithBundleParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L219) parameter * `loginWithPasskey()` now consumes a [LoginWithPasskeyParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L224) parameter * `loginWithWallet()` now consumes a [LoginWithWalletParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L231) parameter ### @turnkey/sdk-react * `Auth.tsx` * updated `passkeyClient?.loginWithPasskey()` to implement new method signature * updated `walletClient?.loginWithWallet()` to implement new method signature ### @turnkey/sdk-server * Move all type definitions to [`./__types__/base.ts`](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-server/src/__types__/base.ts) ### Minor Changes * ecdb29a: Update API as per mono v2025.3.2 - Add CREATE\_USERS\_V3 ### Patch Changes * 0e4e959: bump update policy activity to v2 * 856f449: update `TurnkeyBrowserClient.login()` to align with other functions like `loginWithPasskey()` and `loginWithWallet()` * d4ce5fa: fix unexpected error when using read-only session type when calling loginWithPasskey & loginWithWallet * Updated dependencies \[ecdb29a] * @turnkey/http\@2.22.0 * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 2.0.0 ### Major Changes * 93540e7: ## Major Package Updates ### @turnkey/sdk-browser * create abstract `TurnkeyBaseClient` class which extends `TurnkeySDKClientBase` * `TurnkeyBrowserClient`, `TurnkeyIframeClient`, `TurnkeyPasskeyClient`, and `TurnkeyWalletClient` all extend `TurnkeyBaseClient` * TurnkeyBrowserClient * Session Management * `refreshSession` - attempts to refresh an existing, active session and will extend the session expiry using the `expirationSeconds` parameter * loginWithBundle - authenticate a user via a credential bundle and creates a read-write session * loginWithPasskey - attempts to authenticate a user via passkey and create a read-only or read-write session * loginWithSession - takes a `Session`, which can be either read-only or read-write, created via a server action and attempts to authenticate the user * TurnkeyPasskeyClient * Session Management * createPasskeySession - leverages passkey authentication to create a read-write session. Once authenticated, the user will not be prompted for additional passkey taps. ### @turnkey/sdk-react * update `TurnkeyContext` to use new `.getSession()` method to check if there is an active session * `OTPVerification` component no longer receives `authIframeClient` or `onValidateSuccess` props ## Minor Package Updates ### @turnkey/sdk-server * expose `sendCredential` server action * add `SessionType` enum * `READ_ONLY` & `READ_WRITE` ### @turnkey/eip-1193-provider * update dependencies in `package.json` * moved from `peerDependencies` to `dependencies` * `"@turnkey/http": "workspace:*"` * `"@turnkey/sdk-browser": "workspace:*"` * moved from `devDependencies` to `dependencies` * `"@turnkey/api-key-stamper": "workspace:*"` * specify TypeScript version ^5.1.5 ### Minor Changes * 9147962: add dangerouslyOverrideIframeKeyTtl option to override iframe embedded key TTL (for longer lived read/write sessions) ### Patch Changes * Updated dependencies \[9147962] * @turnkey/iframe-stamper\@2.3.0 * @turnkey/crypto\@2.3.1 ## 1.16.0 ### Minor Changes * 233ae71: Add updateUserAuth, addUserAuth, deleteUserAuth helper functions ### Patch Changes * @turnkey/crypto\@2.3.1 ## 1.15.0 ### Minor Changes * 56a307e: Update api to mono v2025.3.0 ### Patch Changes * Updated dependencies \[56a307e] * @turnkey/http\@2.21.0 * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 1.14.0 ### Minor Changes * 3c44c4a: Updates per mono release v2025.2.2 ### Patch Changes * Updated dependencies \[3c44c4a] * @turnkey/http\@2.20.0 * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 1.13.0 ### Minor Changes * 57f9cb0: Update endpoints - surface GetWalletAccount ### Patch Changes * 69d2571: Upgrade elliptic * Updated dependencies \[57f9cb0] * @turnkey/http\@2.19.0 * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 1.12.1 ### Patch Changes * 755833b: refactor stamper out of config object and move it directly onto the client to match @turnkey/http * Updated dependencies \[2bc0046] * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 1.12.0 ### Minor Changes * 6695af2: Update per mono release v2025.1.11 ### Patch Changes * Updated dependencies \[6695af2] * @turnkey/http\@2.18.0 * @turnkey/crypto\@2.3.0 * @turnkey/wallet-stamper\@1.0.2 ## 1.11.2 ### Patch Changes * 053fbfb: Update mono dependencies * Updated dependencies \[053fbfb] * Updated dependencies \[a216a47] * @turnkey/http\@2.17.3 * @turnkey/iframe-stamper\@2.2.0 * @turnkey/crypto\@2.3.0 * @turnkey/wallet-stamper\@1.0.2 ## 1.11.1 ### Patch Changes * 328d6aa: Add defaultXrpAccountAtIndex helper * b90947e: Update default account exports, surface WalletAccount type * 2d5977b: Update error messaging around api key and target public key usage * fad7c37: @turnkey/iframe-stamper - Implemented MessageChannel API for secure communication between the parent and iframe. @turnkey/sdk-browser - fixed spelling in package.json @turnkey/sdk-server - fixed spelling in package.json * Updated dependencies \[2d5977b] * Updated dependencies \[fad7c37] * @turnkey/api-key-stamper\@0.4.4 * @turnkey/iframe-stamper\@2.1.0 * @turnkey/crypto\@2.3.0 * @turnkey/http\@2.17.2 * @turnkey/wallet-stamper\@1.0.2 ## 1.11.0 ### Minor Changes * 7988bc1: Fix readWrite session to use credentialBundle and add loginWithAuthBundle to create a session when you already have a credentialBundle ### Patch Changes * 538d4fc: Update api endpoints - NEW: User verification, SMS customization params * 12d5aaa: Update TurnkeySDKBrowserConfig type with an optional iframeUrl field. The TurnkeyContext provider will check for an iframeUrl otherwise it will fallback to the default. * Updated dependencies \[c895c8f] * Updated dependencies \[538d4fc] * @turnkey/wallet-stamper\@1.0.2 * @turnkey/http\@2.17.1 * @turnkey/crypto\@2.3.0 ## 1.10.2 ### Patch Changes * Updated dependencies \[668edfa] * @turnkey/crypto\@2.3.0 * @turnkey/wallet-stamper\@1.0.1 ## 1.10.1 ### Patch Changes * Updated dependencies \[78bc39c] * @turnkey/http\@2.17.0 * @turnkey/crypto\@2.2.0 * @turnkey/wallet-stamper\@1.0.0 ## 1.10.0 ### Minor Changes ##### `TurnkeyWalletClient` * Added new `TurnkeyWalletClient` to the `@turnkey/sdk-browser` **Reason**: Allows using the `WalletStamper` with the browser sdk * Added `getPublicKey` method to `TurnkeyWalletClient` **Reason**: Enables easy access to wallet public key for sub-organization creation and future authentication flows * Updated `TurnkeyWalletClient` to use new `WalletInterface` **Reason**: Ensures compatibility with the updated Wallet Stamper interfaces ##### `AuthClient` (new enum) * Introduced a new enum to track which client is authenticated (Passkey, Wallet, Iframe) ##### `TurnkeyBrowserClient`, `TurnkeyIframeClient`, `TurnkeyPasskeyClient`, `TurnkeyWalletClient` * Added a static `authClient` property to base `TurnkeyBrowserClient` to be used by the child classes to track which client was used for the initial authentication ##### `UserSession` interface * Added a new `UserSession` interface which is to be stored in local storage to track the authentication state of the user and to eliminate the need to store the write and read sessions separately. * Added `authClient` in the session object to store the authentication method used in the user's session data. Will be used in the `@turnkey/sdk-react` to determine which client to return. * Added new versioned `UserSession` key: `"@turnkey/session/v1"` ##### `login` and `loginWithReadWriteSession` methods * Updated to use the new `authClient` property to track and store the authentication method used during login ### Patch Changes * Updated dependencies \[8bea78f] * @turnkey/wallet-stamper\@2.0.0 * @turnkey/crypto\@2.2.0 ## 1.9.0 ### Minor Changes * 3dd74ac: Added functionality for constructing and returning stamped requests for all packages * 1e36edf: Support RS256 by default when invoking createUserPasskey * 4df8914: Version bump corresponding to mono release v2024.10.10. More detailed changelog to follow * 11a9e2f: Allow override of WebauthnStamper configuration ### Patch Changes * Updated dependencies \[33e8e03] * Updated dependencies \[d989d46] * Updated dependencies \[4df8914] * @turnkey/crypto\@2.1.0 * @turnkey/http\@2.16.0 ## 1.8.0 ### Minor Changes * 9ebd062: Release OTP functionality ### Patch Changes * Updated dependencies \[9ebd062] * @turnkey/http\@2.15.0 ## 1.7.1 ### Patch Changes * 96d7f99: Update dependencies * Updated dependencies \[e5c4fe9] * Updated dependencies \[96d7f99] * @turnkey/crypto\@2.0.0 * @turnkey/encoding\@0.4.0 * @turnkey/http\@2.14.2 * @turnkey/api-key-stamper\@0.4.3 ## 1.7.0 ### Minor Changes * ff059d5: Add ability to create a read + write session ### Patch Changes * Updated dependencies \[ff059d5] * Updated dependencies \[93666ff] * @turnkey/http\@2.14.1 * @turnkey/crypto\@1.0.0 * @turnkey/encoding\@0.3.0 * @turnkey/api-key-stamper\@0.4.2 ## 1.6.0 ### Minor Changes * c988ed0: Support activity polling (e.g. for awaiting consensus) * \[Breaking] Update the `activityPoller` parameter for configuring polling behavior * Polling continues until either a max number of retries is reached, or if the activity hits a terminal status The shape of the parameter has gone from: ``` { duration: number; timeout: number; } ``` to ``` { intervalMs: number; numRetries: number; } ``` ### Patch Changes * Updated dependencies \[848f8d3] * @turnkey/http\@2.14.0 ## 1.5.0 ### Minor Changes * 1813ed5: Allow `organizationId` override for `TurnkeyBrowserClient.login` with an extra `config` argument ## 1.4.0 ### Minor Changes * bab5393: Add keyformat to key export bundle injection ### Patch Changes * a16073c: Exposes storage APIs used by the sdk for managing users & sessions * 7e7d209: Add authenticatorAttachment option ## 1.3.0 ### Minor Changes * 93dee46: Add create read write session v2 which allows for user targeting directly from stamp or optional userId in intent ### Patch Changes * Updated dependencies \[93dee46] * @turnkey/http\@2.13.0 ## 1.2.4 ### Patch Changes * Updated dependencies \[e2f2e0b] * @turnkey/http\@2.12.3 ## 1.2.3 ### Patch Changes * Fix activity versioning for CREATE\_SUB\_ORGANIZATION (V5=>V6) ## 1.2.2 ### Patch Changes * f4b607f: Verify and pad uncompressed public keys while creating passkey sessions * Updated dependencies * @turnkey/api-key-stamper\@0.4.1 * @turnkey/encoding\@0.2.1 * @turnkey/http\@2.12.2 * @turnkey/crypto\@0.2.1 ## 1.2.1 ### Patch Changes * f17a229: Update to oauth related endpoints to drop jwks uri from oauth providers * Updated dependencies \[f17a229] * @turnkey/http\@2.12.1 ## 1.2.0 ### Minor Changes * Add Email Auth V2 - Optional invalidate exisiting Email Authentication API keys ### Patch Changes * Updated dependencies * @turnkey/http\@2.12.0 ## 1.1.0 ### Minor Changes * Update to use new endpoints. Including CREATE\_READ\_WRITE\_SESSION which allows one shot passkey sessions (returns org information and a credential bundle) and CREATE\_API\_KEYS\_V2 which allows a curve type to be passed (SECP256K1 or P256) ### Patch Changes * Updated dependencies * @turnkey/http\@2.11.0 ## 1.0.0 ### Major Changes * Stable Release: Add Oauth integration. New suborg creation version will now require an oauthProviders field under root users. ## 0.4.1 ### Patch Changes * Updated dependencies * @turnkey/crypto\@0.2.0 ## 0.4.0 ### Minor Changes * e4b29da: Deprecate the `getAuthBundle()` path for passkey sessions and replace it with `getReadWriteSession()` to store authBundles with their expirationTimestamps so applications can better manually manage active writing sessions ## 0.3.0 ### Minor Changes * d409d81: Add support for Passkey Sessions ## 0.2.1 ### Patch Changes * Updated dependencies \[5d0bfde] * Updated dependencies \[2f2d09a] * Updated dependencies \[976663e] * @turnkey/iframe-stamper\@2.0.0 ## 0.2.0 ### Minor Changes * updated syntax ### Patch Changes * Updated dependencies \[5d0bfde] * Updated dependencies \[2f2d09a] * Updated dependencies \[976663e] * @turnkey/iframe-stamper\@2.0.0 ## 0.1.0 ### Minor Changes * Ready for 0.1.0 ## 0.0.1 Initial (experimental) release! This is an alpha release and subject to change. # SDK React Native Source: https://docs.turnkey.com/changelogs/sdk-react-native/readme # @turnkey/sdk-react-native ## 1.0.4 ### Patch Changes * Updated dependencies \[d1083bd] * Updated dependencies \[f94d36e] * @turnkey/http\@3.0.0 * @turnkey/crypto\@2.3.1 ## 1.0.3 ### Minor Changes * a7e7de0: Fixed compatibility issue with `@turnkey/viem` ## 1.0.2 ### Patch Changes * Updated dependencies \[ecdb29a] * @turnkey/http\@2.22.0 * @turnkey/crypto\@2.3.1 ## 1.0.1 ### Patch Changes * Updated dependencies \[56a307e] * @turnkey/http\@2.21.0 * @turnkey/crypto\@2.3.1 ## 1.0.0 ### Major Changes * fcf9503: This breaking change adds support for multiple sessions: * The concept of a **selected session** has been introduced: * Users can switch between sessions using `setSelectedSession({ sessionKey: })`. * The selected session determines the active `client`, `user`, and `session` state. * API calls such as `updateUser`, `createWallet`, and `signRawPayload` now apply to the selected session. * A session limit of **15 active sessions** has been enforced: * If the limit is reached, users must remove an existing session before creating a new one. * Expired or invalid sessions are automatically cleaned up. ## 0.1.1 ### Patch Changes * Updated dependencies \[3c44c4a] * @turnkey/http\@2.20.0 * @turnkey/crypto\@2.3.1 # SDK React Source: https://docs.turnkey.com/changelogs/sdk-react/readme # @turnkey/sdk-react ## 4.2.2 ### Patch Changes * 7755413: Ensure that iframe has an embedded key ## 4.2.1 ### Patch Changes * Updated dependencies \[7b72769] * @turnkey/sdk-server\@3.0.1 ## 4.2.0 ### Minor Changes * de59993: Update default country codes to supported deliveries: USA, Canada, France, Czech Republic, Finland, Germany, Greece, Hungary, Iceland, Ireland, Italy, Latvia (with a 1 min delay), Lithuania, Luxembourg, Malta, Mexico, Moldova, Montenegro, Netherlands, Norway, Poland, Portugal, Romania, Serbia, Slovenia, Spain, Sweden, Switzerland. * d1083bd: Add `otpConfig` param to `Auth` component that allows you to pass in `alphanumeric` and `otpLength` default for the Auth component is still false, 6 respectively (non breaking) ### Patch Changes * Updated dependencies \[e501690] * Updated dependencies \[d1083bd] * @turnkey/sdk-browser\@4.0.0 * @turnkey/sdk-server\@3.0.0 * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 4.1.3 ### Patch Changes * Updated dependencies \[bf87774] * @turnkey/sdk-browser\@3.1.0 * Expose `getEmbeddedPublicKey()` via `TurnkeyIframeClient`. This can be used to fetch the live public key of the target embedded key living within an iframe. Usage may look like the following: ```javascript import { useTurnkey } from "@turnkey/sdk-react"; ... const { authIframeClient } = useTurnkey(); const publicKey = await authIframeClient!.getEmbeddedPublicKey(); ``` Functionally, this can be useful for scenarios where the developer would like to verify whether an iframe has a live embedded key within it. This contrasts from the static `iframeStamper.iframePublicKey` exposed by `@turnkey/iframe-stamper`'s `publicKey()` method. ## 4.1.2 ### Patch Changes * Updated dependencies \[5ec5187] * @turnkey/sdk-browser\@3.0.1 * @turnkey/sdk-server\@2.6.1 ## 4.1.1 ### Patch Changes * 2b8de45: Add passkeyConfig to EWK You can do this by passing optional `passkeyConfig` of interface `PasskeyConfig` to the `` component ``` export interface PasskeyConfig { displayName?: string; name?: string; } ``` ## 4.1.0 ### Minor Changes * 72890f5: ### @turnkey/sdk-browser * Move all type definitions to [`./__types__/base.ts`](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts) * `TurnkeyBrowserClient` * `refereshSession()` now consumes a [RefreshSessionParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L213) parameter * `loginWithBundle()` now consumes a [LoginWithBundleParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L219) parameter * `loginWithPasskey()` now consumes a [LoginWithPasskeyParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L224) parameter * `loginWithWallet()` now consumes a [LoginWithWalletParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L231) parameter ### @turnkey/sdk-react * `Auth.tsx` * updated `passkeyClient?.loginWithPasskey()` to implement new method signature * updated `walletClient?.loginWithWallet()` to implement new method signature ### @turnkey/sdk-server * Move all type definitions to [`./__types__/base.ts`](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-server/src/__types__/base.ts) ### Patch Changes * c9ae537: Update nextJs to >= 15.2.3 as per github advisory: [https://github.com/advisories/GHSA-f82v-jwr5-mffw](https://github.com/advisories/GHSA-f82v-jwr5-mffw) For Next.js 15.x, this issue is fixed in 15.2.3 For Next.js 14.x, this issue is fixed in 14.2.25 For Next.js 13.x, this issue is fixed in 13.5.9 For Next.js 12.x, this issue is fixed in 12.3.5 * Updated dependencies \[0e4e959] * Updated dependencies \[856f449] * Updated dependencies \[c9ae537] * Updated dependencies \[d4ce5fa] * Updated dependencies \[ecdb29a] * Updated dependencies \[72890f5] * @turnkey/sdk-browser\@3.0.0 * @turnkey/sdk-server\@2.6.0 * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 4.0.0 ### Major Changes * 93540e7: ## Major Package Updates ### @turnkey/sdk-browser * create abstract `TurnkeyBaseClient` class which extends `TurnkeySDKClientBase` * `TurnkeyBrowserClient`, `TurnkeyIframeClient`, `TurnkeyPasskeyClient`, and `TurnkeyWalletClient` all extend `TurnkeyBaseClient` * TurnkeyBrowserClient * Session Management * `refreshSession` - attempts to refresh an existing, active session and will extend the session expiry using the `expirationSeconds` parameter * loginWithBundle - authenticate a user via a credential bundle and creates a read-write session * loginWithPasskey - attempts to authenticate a user via passkey and create a read-only or read-write session * loginWithSession - takes a `Session`, which can be either read-only or read-write, created via a server action and attempts to authenticate the user * TurnkeyPasskeyClient * Session Management * createPasskeySession - leverages passkey authentication to create a read-write session. Once authenticated, the user will not be prompted for additional passkey taps. ### @turnkey/sdk-react * update `TurnkeyContext` to use new `.getSession()` method to check if there is an active session * `OTPVerification` component no longer receives `authIframeClient` or `onValidateSuccess` props ## Minor Package Updates ### @turnkey/sdk-server * expose `sendCredential` server action * add `SessionType` enum * `READ_ONLY` & `READ_WRITE` ### @turnkey/eip-1193-provider * update dependencies in `package.json` * moved from `peerDependencies` to `dependencies` * `"@turnkey/http": "workspace:*"` * `"@turnkey/sdk-browser": "workspace:*"` * moved from `devDependencies` to `dependencies` * `"@turnkey/api-key-stamper": "workspace:*"` * specify TypeScript version ^5.1.5 ### Minor Changes * 9147962: add dangerouslyOverrideIframeKeyTtl option to override iframe embedded key TTL (for longer lived read/write sessions) ### Patch Changes * fdb8bf0: Add loading indicators for EWK. Exposed email customization to EWK. * Updated dependencies \[93540e7] * Updated dependencies \[fdb8bf0] * Updated dependencies \[9147962] * @turnkey/sdk-browser\@2.0.0 * @turnkey/sdk-server\@2.5.0 * @turnkey/crypto\@2.3.1 ## 3.1.0 ### Minor Changes * 9317588: Adds wallet as an authentication option in the Embedded Wallet Kit components for sdk-react ### Patch Changes * Updated dependencies \[233ae71] * Updated dependencies \[9317588] * @turnkey/sdk-browser\@1.16.0 * @turnkey/sdk-server\@2.4.0 * @turnkey/crypto\@2.3.1 ## 3.0.6 ### Patch Changes * Updated dependencies \[56a307e] * @turnkey/sdk-browser\@1.15.0 * @turnkey/sdk-server\@2.3.0 * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 3.0.5 ### Patch Changes * cdf2e6e: Fix issue in EWK preventing sign up flow ## 3.0.4 ### Patch Changes * 9256e75: Fix apple login issue on mobile web browser * bfc833f: Add getOrCreateSuborg server action * Updated dependencies \[3c44c4a] * Updated dependencies \[bfc833f] * @turnkey/sdk-browser\@1.14.0 * @turnkey/sdk-server\@2.2.0 * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 3.0.3 ### Patch Changes * 5f6de98: Fix phone number validation issue causing issues with non +1 country codes * Updated dependencies \[69d2571] * Updated dependencies \[57f9cb0] * @turnkey/sdk-browser\@1.13.0 * @turnkey/sdk-server\@2.1.0 * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 3.0.2 ### Patch Changes * faa757c: Patch EWK custom session lengths - previously not working as intended (defaulted to 15 minute sessions only) and fix the following useLocalStorage issue when compiling: \[Error: useLocalStorage is a client-only hook] * a8bd73b: Fix issue with EWK where suborgs were being created on failed fetches ## 3.0.1 ### Patch Changes * cb8cf7e: Add all supported country codes to phone input field * 2eb2179: Fix bundling issue with sdk-react * Updated dependencies \[755833b] * Updated dependencies \[2bc0046] * @turnkey/sdk-browser\@1.12.1 * @turnkey/sdk-server\@2.0.1 * @turnkey/crypto\@2.3.1 * @turnkey/wallet-stamper\@1.0.3 ## 3.0.0 ### Major Changes * 1ebd4e2: Remove references to server actions and import from sdk-server ### Patch Changes * Updated dependencies \[6695af2] * Updated dependencies \[1ebd4e2] * @turnkey/sdk-browser\@1.12.0 * @turnkey/sdk-server\@2.0.0 * @turnkey/crypto\@2.3.0 * @turnkey/wallet-stamper\@1.0.2 ## 2.0.4 ### Patch Changes * 99ebe78: Fixed MUI components not inheriting fonts. * Updated dependencies \[053fbfb] * @turnkey/sdk-browser\@1.11.2 * @turnkey/sdk-server\@1.7.3 * @turnkey/crypto\@2.3.0 * @turnkey/wallet-stamper\@1.0.2 ## 2.0.3 ### Patch Changes * d43c52c: Add session length customization, wallet generation customization, enter to continue, more css customization and css fixes (icon sizing issues, etc) * 5419d49: fix css bundling bug * Updated dependencies \[328d6aa] * Updated dependencies \[b90947e] * Updated dependencies \[2d5977b] * Updated dependencies \[fad7c37] * @turnkey/sdk-browser\@1.11.1 * @turnkey/sdk-server\@1.7.2 * @turnkey/crypto\@2.3.0 * @turnkey/wallet-stamper\@1.0.2 ## 2.0.2 ### Patch Changes * eaf3e20: Fix css related build issues with React 19+ & NextJs 15+ ## 2.0.1 ### Patch Changes * 0da96aa: Add readme to react sdk ## 2.0.0 ### Major Changes * 95717d7: New Feature: UI components - Auth, Export, Import. Leverages server and client directives on NextJS 13+ to abstract functionalities away from the developer ### Patch Changes * c8330fa: Add a user identifier for sms rate limiting * 12d5aaa: Update TurnkeySDKBrowserConfig type with an optional iframeUrl field. The TurnkeyContext provider will check for an iframeUrl otherwise it will fallback to the default. * Updated dependencies \[7988bc1] * Updated dependencies \[c895c8f] * Updated dependencies \[538d4fc] * Updated dependencies \[12d5aaa] * @turnkey/sdk-browser\@1.11.0 * @turnkey/wallet-stamper\@1.0.2 * @turnkey/sdk-server\@1.7.1 * @turnkey/crypto\@2.3.0 ## 1.1.2 ### Patch Changes * @turnkey/sdk-browser\@1.10.2 * @turnkey/wallet-stamper\@1.0.1 ## 1.1.1 ### Patch Changes * @turnkey/sdk-browser\@1.10.1 * @turnkey/wallet-stamper\@1.0.0 ## 1.1.0 ### Minor Changes * The `useTurnkey` hook now returns the new `walletClient`, used for authenticating requests via wallet signatures * Added new `client` object returned from the `useTurnkey` hook. This is the authenticated client. It will be null if the user is not authenticated. Example: ```typescript const { client } = useTurnkey(); ``` ### Patch Changes * Updated dependencies \[8bea78f] * @turnkey/wallet-stamper\@2.0.0 * @turnkey/sdk-browser\@1.10.0 ## 1.0.14 ### Patch Changes * Updated dependencies \[3dd74ac] * Updated dependencies \[1e36edf] * Updated dependencies \[4df8914] * Updated dependencies \[11a9e2f] * @turnkey/sdk-browser\@1.9.0 ## 1.0.13 ### Patch Changes * Updated dependencies \[9ebd062] * @turnkey/sdk-browser\@1.8.0 ## 1.0.12 ### Patch Changes * Updated dependencies \[96d7f99] * @turnkey/sdk-browser\@1.7.1 ## 1.0.11 ### Patch Changes * Updated dependencies \[ff059d5] * @turnkey/sdk-browser\@1.7.0 ## 1.0.10 ### Patch Changes * Updated dependencies \[c988ed0] * @turnkey/sdk-browser\@1.6.0 ## 1.0.9 ### Patch Changes * Updated dependencies \[1813ed5] * @turnkey/sdk-browser\@1.5.0 ## 1.0.8 ### Patch Changes * Updated dependencies \[bab5393] * Updated dependencies \[a16073c] * Updated dependencies \[7e7d209] * @turnkey/sdk-browser\@1.4.0 ## 1.0.7 ### Patch Changes * Updated dependencies \[93dee46] * @turnkey/sdk-browser\@1.3.0 ## 1.0.6 ### Patch Changes * Updated dependencies \[e2f2e0b] * @turnkey/sdk-browser\@1.2.4 ## 1.0.5 ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@1.2.3 ## 1.0.4 ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@1.2.2 ## 1.0.3 ### Patch Changes * f17a229: Update to oauth related endpoints to drop jwks uri from oauth providers * Updated dependencies \[f17a229] * @turnkey/sdk-browser\@1.2.1 ## 1.0.2 ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@1.2.0 ## 1.0.1 ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@1.1.0 ## 1.0.0 ### Major Changes * Stable Release: Add Oauth integration. New suborg creation version will now require an oauthProviders field under root users. ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@1.0.0 ## 0.4.1 ### Patch Changes * @turnkey/sdk-browser\@0.4.1 ## 0.4.0 ### Minor Changes * e4b29da: Deprecate the `getAuthBundle()` path for passkey sessions and replace it with `getReadWriteSession()` to store authBundles with their expirationTimestamps so applications can better manually manage active writing sessions ### Patch Changes * Updated dependencies \[e4b29da] * @turnkey/sdk-browser\@0.4.0 ## 0.3.0 ### Minor Changes * d409d81: Add support for Passkey Sessions ### Patch Changes * Updated dependencies \[d409d81] * @turnkey/sdk-browser\@0.3.0 ## 0.2.1 ### Patch Changes * @turnkey/sdk-browser\@0.2.1 ## 0.2.0 ### Minor Changes * updated syntax ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@0.2.0 ## 0.1.0 ### Minor Changes * Ready for 0.1.0 ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@0.1.0 ## 0.0.1 Initial (experimental) release! This is an alpha release and subject to change. # SDK Server Source: https://docs.turnkey.com/changelogs/sdk-server/readme # @turnkey/sdk-server ## 3.0.1 ### Patch Changes * 7b72769: Add sendFromEmailSenderName to sendOtp server action ## 3.0.0 ### Major Changes * d1083bd: initOtpAuth now defaults to v2 (breaking) which allows alphanumeric boolean and otpLength (6-9) to be passed + associated updates to server actions. More details below. * This release introduces the `INIT_OTP_AUTH_V2` activity. The difference between it and `INIT_OTP_AUTH` is that it can now accept `alphanumeric` and `otpLength` for selecting crockford bech32 alphanumeric codes and the length of those codes. By default alphanumeric = true, otpLength = 9 * This release introduces `sendFromEmailSenderName` to `INIT_OTP_AUTH`, `INIT_OTP_AUTH_V2`, `EMAIL_AUTH` and `EMAIL_AUTH_V2`. This is an optional custom sender name for use with sendFromEmailAddress; if left empty, will default to 'Notifications'. ### Patch Changes * Updated dependencies \[d1083bd] * Updated dependencies \[f94d36e] * @turnkey/http\@3.0.0 * @turnkey/wallet-stamper\@1.0.3 ## 2.6.1 ### Patch Changes * 5ec5187: Fix initOtpAuth bug with improper version result (to be updated to V2 following release r2025.3.8) ## 2.6.0 ### Minor Changes * ecdb29a: Update API as per mono v2025.3.2 - Add CREATE\_USERS\_V3 ### Patch Changes * 0e4e959: bump update policy activity to v2 * c9ae537: Update nextJs to >= 15.2.3 as per github advisory: [https://github.com/advisories/GHSA-f82v-jwr5-mffw](https://github.com/advisories/GHSA-f82v-jwr5-mffw) For Next.js 15.x, this issue is fixed in 15.2.3 For Next.js 14.x, this issue is fixed in 14.2.25 For Next.js 13.x, this issue is fixed in 13.5.9 For Next.js 12.x, this issue is fixed in 12.3.5 * 72890f5: ### @turnkey/sdk-browser * Move all type definitions to [`./__types__/base.ts`](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts) * `TurnkeyBrowserClient` * `refereshSession()` now consumes a [RefreshSessionParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L213) parameter * `loginWithBundle()` now consumes a [LoginWithBundleParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L219) parameter * `loginWithPasskey()` now consumes a [LoginWithPasskeyParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L224) parameter * `loginWithWallet()` now consumes a [LoginWithWalletParams](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-browser/src/__types__/base.ts#L231) parameter ### @turnkey/sdk-react * `Auth.tsx` * updated `passkeyClient?.loginWithPasskey()` to implement new method signature * updated `walletClient?.loginWithWallet()` to implement new method signature ### @turnkey/sdk-server * Move all type definitions to [`./__types__/base.ts`](https://github.com/tkhq/sdk/blob/494911d948d0a53c0d00aa01e9821aefd5e3f80d/packages/sdk-server/src/__types__/base.ts) * Updated dependencies \[ecdb29a] * @turnkey/http\@2.22.0 * @turnkey/wallet-stamper\@1.0.3 ## 2.5.0 ### Minor Changes * 93540e7: ## Major Package Updates ### @turnkey/sdk-browser * create abstract `TurnkeyBaseClient` class which extends `TurnkeySDKClientBase` * `TurnkeyBrowserClient`, `TurnkeyIframeClient`, `TurnkeyPasskeyClient`, and `TurnkeyWalletClient` all extend `TurnkeyBaseClient` * TurnkeyBrowserClient * Session Management * `refreshSession` - attempts to refresh an existing, active session and will extend the session expiry using the `expirationSeconds` parameter * loginWithBundle - authenticate a user via a credential bundle and creates a read-write session * loginWithPasskey - attempts to authenticate a user via passkey and create a read-only or read-write session * loginWithSession - takes a `Session`, which can be either read-only or read-write, created via a server action and attempts to authenticate the user * TurnkeyPasskeyClient * Session Management * createPasskeySession - leverages passkey authentication to create a read-write session. Once authenticated, the user will not be prompted for additional passkey taps. ### @turnkey/sdk-react * update `TurnkeyContext` to use new `.getSession()` method to check if there is an active session * `OTPVerification` component no longer receives `authIframeClient` or `onValidateSuccess` props ## Minor Package Updates ### @turnkey/sdk-server * expose `sendCredential` server action * add `SessionType` enum * `READ_ONLY` & `READ_WRITE` ### @turnkey/eip-1193-provider * update dependencies in `package.json` * moved from `peerDependencies` to `dependencies` * `"@turnkey/http": "workspace:*"` * `"@turnkey/sdk-browser": "workspace:*"` * moved from `devDependencies` to `dependencies` * `"@turnkey/api-key-stamper": "workspace:*"` * specify TypeScript version ^5.1.5 ### Patch Changes * fdb8bf0: Add loading indicators for EWK. Exposed email customization to EWK. ## 2.4.0 ### Minor Changes * 9317588: Adds wallet as an authentication option in the Embedded Wallet Kit components for sdk-react ## 2.3.0 ### Minor Changes * 56a307e: Update api to mono v2025.3.0 ### Patch Changes * Updated dependencies \[56a307e] * @turnkey/http\@2.21.0 ## 2.2.0 ### Minor Changes * 3c44c4a: Updates per mono release v2025.2.2 ### Patch Changes * bfc833f: Add getOrCreateSuborg server action * Updated dependencies \[3c44c4a] * @turnkey/http\@2.20.0 ## 2.1.0 ### Minor Changes * 57f9cb0: Update endpoints - surface GetWalletAccount ### Patch Changes * 69d2571: Upgrade elliptic * Updated dependencies \[57f9cb0] * @turnkey/http\@2.19.0 ## 2.0.1 ### Patch Changes * 755833b: refactor stamper out of config object and move it directly onto the client to match @turnkey/http ## 2.0.0 ### Major Changes * 1ebd4e2: Add server actions ### Minor Changes * 6695af2: Update per mono release v2025.1.11 ### Patch Changes * Updated dependencies \[6695af2] * @turnkey/http\@2.18.0 ## 1.7.3 ### Patch Changes * 053fbfb: Update mono dependencies * Updated dependencies \[053fbfb] * @turnkey/http\@2.17.3 ## 1.7.2 ### Patch Changes * 328d6aa: Add defaultXrpAccountAtIndex helper * b90947e: Update default account exports, surface WalletAccount type * fad7c37: @turnkey/iframe-stamper - Implemented MessageChannel API for secure communication between the parent and iframe. @turnkey/sdk-browser - fixed spelling in package.json @turnkey/sdk-server - fixed spelling in package.json * Updated dependencies \[2d5977b] * @turnkey/api-key-stamper\@0.4.4 * @turnkey/http\@2.17.2 ## 1.7.1 ### Patch Changes * 538d4fc: Update api endpoints - NEW: User verification, SMS customization params * Updated dependencies \[538d4fc] * @turnkey/http\@2.17.1 ## 1.7.0 ### Minor Changes * 78bc39c: Add default accounts for various address types * Add wallet account ID to list wallets endpoint ### Patch Changes * Updated dependencies \[78bc39c] * @turnkey/http\@2.17.0 ## 1.6.0 ### Minor Changes * 3dd74ac: Added functionality for constructing and returning stamped requests for all packages * 4df8914: Version bump corresponding to mono release v2024.10.10. More detailed changelog to follow ### Patch Changes * Updated dependencies \[4df8914] * @turnkey/http\@2.16.0 ## 1.5.0 ### Minor Changes * 9ebd062: Release OTP functionality ### Patch Changes * Updated dependencies \[9ebd062] * @turnkey/http\@2.15.0 ## 1.4.2 ### Patch Changes * abe7138: Export DEFAULT\_SOLANA\_ACCOUNTS * 96d7f99: Update dependencies * Updated dependencies \[96d7f99] * @turnkey/http\@2.14.2 * @turnkey/api-key-stamper\@0.4.3 ## 1.4.1 ### Patch Changes * ff059d5: Update dependencies * Updated dependencies \[ff059d5] * @turnkey/http\@2.14.1 * @turnkey/api-key-stamper\@0.4.2 ## 1.4.0 ### Minor Changes * c988ed0: Support activity polling (e.g. for awaiting consensus) * \[Breaking] Update the `activityPoller` parameter for configuring polling behavior * Polling continues until either a max number of retries is reached, or if the activity hits a terminal status The shape of the parameter has gone from: ``` { duration: number; timeout: number; } ``` to ``` { intervalMs: number; numRetries: number; } ``` ### Patch Changes * Updated dependencies \[848f8d3] * @turnkey/http\@2.14.0 ## 1.3.0 ### Minor Changes * 93dee46: Add create read write session v2 which allows for user targeting directly from stamp or optional userId in intent ### Patch Changes * Updated dependencies \[93dee46] * @turnkey/http\@2.13.0 ## 1.2.4 ### Patch Changes * Updated dependencies \[e2f2e0b] * @turnkey/http\@2.12.3 ## 1.2.3 ### Patch Changes * Fix activity versioning for CREATE\_SUB\_ORGANIZATION (V5=>V6) ## 1.2.2 ### Patch Changes * Updated dependencies \[2d7e5a9] * @turnkey/api-key-stamper\@0.4.1 * @turnkey/http\@2.12.2 ## 1.2.1 ### Patch Changes * f17a229: Update to oauth related endpoints to drop jwks uri from oauth providers * Updated dependencies \[f17a229] * @turnkey/http\@2.12.1 ## 1.2.0 ### Minor Changes * Add Email Auth V2 - Optional invalidate exisiting Email Authentication API keys ### Patch Changes * Updated dependencies * @turnkey/http\@2.12.0 ## 1.1.0 ### Minor Changes * Update to use new endpoints. Including CREATE\_READ\_WRITE\_SESSION which allows one shot passkey sessions (returns org information and a credential bundle) and CREATE\_API\_KEYS\_V2 which allows a curve type to be passed (SECP256K1 or P256) ### Patch Changes * Updated dependencies * @turnkey/http\@2.11.0 ## 1.0.0 ### Major Changes * Stable Release: Add Oauth integration. New suborg creation version will now require an oauthProviders field under root users. ## 0.2.0 ### Minor Changes * updated syntax ### Patch Changes * e4d2a84: Update client name ## 0.1.0 ### Minor Changes * Ready for 0.1.0 ## 0.0.1 Initial (experimental) release! This is an alpha release and subject to change. # Solana Source: https://docs.turnkey.com/changelogs/solana/readme # @turnkey/solana ## 1.0.21 ### Patch Changes * Updated dependencies \[7b72769] * @turnkey/sdk-server\@3.0.1 ## 1.0.20 ### Patch Changes * Updated dependencies \[e501690] * Updated dependencies \[d1083bd] * Updated dependencies \[f94d36e] * @turnkey/sdk-browser\@4.0.0 * @turnkey/sdk-server\@3.0.0 * @turnkey/http\@3.0.0 ## 1.0.19 ### Patch Changes * Updated dependencies \[bf87774] * @turnkey/sdk-browser\@3.1.0 ## 1.0.18 ### Patch Changes * Updated dependencies \[5ec5187] * @turnkey/sdk-browser\@3.0.1 * @turnkey/sdk-server\@2.6.1 ## 1.0.17 ### Patch Changes * Updated dependencies \[0e4e959] * Updated dependencies \[856f449] * Updated dependencies \[c9ae537] * Updated dependencies \[d4ce5fa] * Updated dependencies \[ecdb29a] * Updated dependencies \[72890f5] * @turnkey/sdk-browser\@3.0.0 * @turnkey/sdk-server\@2.6.0 * @turnkey/http\@2.22.0 ## 1.0.16 ### Patch Changes * Updated dependencies \[93540e7] * Updated dependencies \[fdb8bf0] * Updated dependencies \[9147962] * @turnkey/sdk-browser\@2.0.0 * @turnkey/sdk-server\@2.5.0 ## 1.0.15 ### Patch Changes * Updated dependencies \[233ae71] * Updated dependencies \[9317588] * @turnkey/sdk-browser\@1.16.0 * @turnkey/sdk-server\@2.4.0 ## 1.0.14 ### Patch Changes * Updated dependencies \[56a307e] * @turnkey/sdk-browser\@1.15.0 * @turnkey/sdk-server\@2.3.0 * @turnkey/http\@2.21.0 ## 1.0.13 ### Patch Changes * Updated dependencies \[3c44c4a] * Updated dependencies \[bfc833f] * @turnkey/sdk-browser\@1.14.0 * @turnkey/sdk-server\@2.2.0 * @turnkey/http\@2.20.0 ## 1.0.12 ### Patch Changes * Updated dependencies \[69d2571] * Updated dependencies \[57f9cb0] * @turnkey/sdk-browser\@1.13.0 * @turnkey/sdk-server\@2.1.0 * @turnkey/http\@2.19.0 ## 1.0.11 ### Patch Changes * Updated dependencies \[755833b] * @turnkey/sdk-browser\@1.12.1 * @turnkey/sdk-server\@2.0.1 ## 1.0.10 ### Patch Changes * Updated dependencies \[6695af2] * Updated dependencies \[1ebd4e2] * @turnkey/sdk-browser\@1.12.0 * @turnkey/sdk-server\@2.0.0 * @turnkey/http\@2.18.0 ## 1.0.9 ### Patch Changes * Updated dependencies \[053fbfb] * @turnkey/sdk-browser\@1.11.2 * @turnkey/sdk-server\@1.7.3 * @turnkey/http\@2.17.3 ## 1.0.8 ### Patch Changes * Updated dependencies \[328d6aa] * Updated dependencies \[b90947e] * Updated dependencies \[2d5977b] * Updated dependencies \[fad7c37] * @turnkey/sdk-browser\@1.11.1 * @turnkey/sdk-server\@1.7.2 * @turnkey/http\@2.17.2 ## 1.0.7 ### Patch Changes * c895c8f: Update @solana/web3.js from ^1.88.1 to ^1.95.8 * Updated dependencies \[7988bc1] * Updated dependencies \[538d4fc] * Updated dependencies \[12d5aaa] * @turnkey/sdk-browser\@1.11.0 * @turnkey/sdk-server\@1.7.1 * @turnkey/http\@2.17.1 ## 1.0.6 ### Patch Changes * @turnkey/sdk-browser\@1.10.2 ## 1.0.5 ### Patch Changes * Updated dependencies \[78bc39c] * @turnkey/sdk-server\@1.7.0 * @turnkey/http\@2.17.0 * @turnkey/sdk-browser\@1.10.1 ## 1.0.4 ### Patch Changes * 9eaf38a: Add optional org id for all signing methods ## 1.0.3 ### Patch Changes * Updated dependencies \[8bea78f] * @turnkey/sdk-browser\@1.10.0 ## 1.0.2 ### Patch Changes * b55bc32: Add optional org id to addSignature function * Updated dependencies \[3dd74ac] * Updated dependencies \[1e36edf] * Updated dependencies \[4df8914] * Updated dependencies \[11a9e2f] * @turnkey/sdk-browser\@1.9.0 * @turnkey/sdk-server\@1.6.0 * @turnkey/http\@2.16.0 ## 1.0.1 ### Patch Changes * Updated dependencies \[9ebd062] * @turnkey/sdk-browser\@1.8.0 * @turnkey/sdk-server\@1.5.0 * @turnkey/http\@2.15.0 ## 1.0.0 ### Major Changes * a4f0f69: Integrate @turnkey/solana with Turnkey's Sign Transaction endpoint. There are no breaking changes, but a major release felt right given this is effectively adding "full" Solana support. This release introduces a new method: `signTransaction`. Under the hood, this creates an activity of type `ACTIVITY_TYPE_SIGN_TRANSACTION_V2`. There is **no action required** for existing users of `addSignature`. * `addSignature` does not use our Policy Engine, and instead signs a transaction's message straight up * While `addSignature` mutates the incoming transaction by adding a signature to it directly, `signTransaction` returns a new transaction object * Both legacy and versioned (V0) transactions are supported For some examples of how you can use Turnkey's Policy Engine with Solana transactions, see [https://docs.turnkey.com/concepts/policies/examples](https://docs.turnkey.com/concepts/policies/examples). ### Patch Changes * Updated dependencies \[abe7138] * Updated dependencies \[96d7f99] * @turnkey/sdk-server\@1.4.2 * @turnkey/sdk-browser\@1.7.1 * @turnkey/http\@2.14.2 ## 0.5.1 ### Patch Changes * Updated dependencies \[ff059d5] * Updated dependencies \[ff059d5] * @turnkey/sdk-browser\@1.7.0 * @turnkey/sdk-server\@1.4.1 * @turnkey/http\@2.14.1 ## 0.5.0 ### Minor Changes * bdded80: Support awaiting consensus ### Patch Changes * Updated dependencies \[c988ed0] * Updated dependencies \[848f8d3] * @turnkey/sdk-browser\@1.6.0 * @turnkey/sdk-server\@1.4.0 * @turnkey/http\@2.14.0 ## 0.4.3 ### Patch Changes * Updated dependencies \[1813ed5] * @turnkey/sdk-browser\@1.5.0 ## 0.4.2 ### Patch Changes * Updated dependencies \[bab5393] * Updated dependencies \[a16073c] * Updated dependencies \[7e7d209] * @turnkey/sdk-browser\@1.4.0 ## 0.4.1 ### Patch Changes * Updated dependencies \[93dee46] * @turnkey/http\@2.13.0 * @turnkey/sdk-browser\@1.3.0 * @turnkey/sdk-server\@1.3.0 ## 0.4.0 ### Minor Changes * c342954: Add compatibility with @turnkey/sdk-server and @turnkey/sdk-browser ## 0.3.10 ### Patch Changes * Updated dependencies \[e2f2e0b] * @turnkey/http\@2.12.3 ## 0.3.9 ### Patch Changes * Updated dependencies \[2d7e5a9] * @turnkey/http\@2.12.2 ## 0.3.8 ### Patch Changes * Updated dependencies \[f17a229] * @turnkey/http\@2.12.1 ## 0.3.7 ### Patch Changes * Updated dependencies * @turnkey/http\@2.12.0 ## 0.3.6 ### Patch Changes * Updated dependencies * @turnkey/http\@2.11.0 ## 0.3.5 ### Patch Changes * Updated dependencies \[7a9ce7a] * @turnkey/http\@2.10.0 ## 0.3.4 ### Patch Changes * Updated dependencies * @turnkey/http\@2.9.1 ## 0.3.3 ### Patch Changes * Updated dependencies \[83b62b5] * @turnkey/http\@2.9.0 ## 0.3.2 ### Patch Changes * Updated dependencies \[46a7d90] * @turnkey/http\@2.8.0 ## 0.3.1 ### Patch Changes Adjust logic for signing transactions and versioned transactions to avoid typechecks (#218) ## 0.3.0 ### Minor Changes Add support for signing Solana versioned transactions (#216) ## 0.2.2 ### Patch Changes * Updated dependencies * @turnkey/http\@2.7.1 ## 0.2.1 ### Patch Changes * Updated dependencies \[d73725b] * @turnkey/http\@2.7.0 ## 0.2.0 ### Minor Changes * \#202: implements `signMessage` on the Solana `TurnkeySigner` ## 0.1.1 * Fix readme link ## 0.1.0 * Initial release # Telegram Cloud Storage Stamper Source: https://docs.turnkey.com/changelogs/telegram-cloud-storage-stamper/readme # @turnkey/telegram-cloud-storage-stamper ## 2.0.0 ### Major Changes * 24ca647: Remove default export and used all named exports for consistency ### Package imports for `@turnkey/telegram-cloud-storage-stamper` #### for versions \< v2.0.0 ```typescript import TelegramCloudStorageStamper, { CloudStorageAPIKey, } from "@turnkey/telegram-cloud-storage-stamper"; ``` #### for versions >= v2.0.0 ```typescript import { TelegramCloudStorageStamper, CloudStorageAPIKey, } from "@turnkey/telegram-cloud-storage-stamper"; ``` ## 1.0.3 ### Patch Changes * Updated dependencies \[2d5977b] * @turnkey/api-key-stamper\@0.4.4 ## 1.0.2 ### Patch Changes * Export the default cloud storage api key location ## 1.0.1 ### Patch Changes * Update the default cloud storage key to conform to cloud storage key constraints ## 1.0.0 ### Major Changes * Initial release of the telegram-cloud-storage-stamper package. This package is to be used alongside Telegram mini-app development and provides a stamping utility and an interface into Telegram Cloud Storage. More can be read in the [readme](../packages/telegram-cloud-storage-stamper/readme.md). # Viem Source: https://docs.turnkey.com/changelogs/viem/readme # @turnkey/viem ## 0.7.2 ### Patch Changes * Updated dependencies \[7b72769] * @turnkey/sdk-server\@3.0.1 ## 0.7.1 ### Patch Changes * 123406b: The organizationId parameter is ignored when using a client other than TurnkeyClient (e.g., passkeyClient). Consequently, the SDK calls the client without the specified organizationId, which is unintended. This patch resolves the issue * Updated dependencies \[e501690] * Updated dependencies \[d1083bd] * Updated dependencies \[f94d36e] * @turnkey/sdk-browser\@4.0.0 * @turnkey/sdk-server\@3.0.0 * @turnkey/http\@3.0.0 ## 0.7.0 ### Minor Changes * d99fe40: Upgrade upstream viem dependency ### Patch Changes * Updated dependencies \[bf87774] * @turnkey/sdk-browser\@3.1.0 ## 0.6.18 ### Patch Changes * Updated dependencies \[5ec5187] * @turnkey/sdk-browser\@3.0.1 * @turnkey/sdk-server\@2.6.1 ## 0.6.17 ### Patch Changes * Updated dependencies \[0e4e959] * Updated dependencies \[856f449] * Updated dependencies \[c9ae537] * Updated dependencies \[d4ce5fa] * Updated dependencies \[ecdb29a] * Updated dependencies \[72890f5] * @turnkey/sdk-browser\@3.0.0 * @turnkey/sdk-server\@2.6.0 * @turnkey/http\@2.22.0 ## 0.6.16 ### Patch Changes * Updated dependencies \[93540e7] * Updated dependencies \[fdb8bf0] * Updated dependencies \[9147962] * @turnkey/sdk-browser\@2.0.0 * @turnkey/sdk-server\@2.5.0 ## 0.6.15 ### Patch Changes * Updated dependencies \[233ae71] * Updated dependencies \[9317588] * @turnkey/sdk-browser\@1.16.0 * @turnkey/sdk-server\@2.4.0 ## 0.6.14 ### Patch Changes * Updated dependencies \[56a307e] * @turnkey/sdk-browser\@1.15.0 * @turnkey/sdk-server\@2.3.0 * @turnkey/http\@2.21.0 ## 0.6.13 ### Patch Changes * Updated dependencies \[3c44c4a] * Updated dependencies \[bfc833f] * @turnkey/sdk-browser\@1.14.0 * @turnkey/sdk-server\@2.2.0 * @turnkey/http\@2.20.0 ## 0.6.12 ### Patch Changes * Updated dependencies \[69d2571] * Updated dependencies \[57f9cb0] * @turnkey/sdk-browser\@1.13.0 * @turnkey/sdk-server\@2.1.0 * @turnkey/http\@2.19.0 ## 0.6.11 ### Patch Changes * Updated dependencies \[755833b] * @turnkey/sdk-browser\@1.12.1 * @turnkey/sdk-server\@2.0.1 ## 0.6.10 ### Patch Changes * Updated dependencies \[6695af2] * Updated dependencies \[1ebd4e2] * @turnkey/sdk-browser\@1.12.0 * @turnkey/sdk-server\@2.0.0 * @turnkey/http\@2.18.0 ## 0.6.9 ### Patch Changes * Updated dependencies \[053fbfb] * @turnkey/sdk-browser\@1.11.2 * @turnkey/sdk-server\@1.7.3 * @turnkey/http\@2.17.3 ## 0.6.8 ### Patch Changes * Updated dependencies \[328d6aa] * Updated dependencies \[b90947e] * Updated dependencies \[2d5977b] * Updated dependencies \[fad7c37] * @turnkey/sdk-browser\@1.11.1 * @turnkey/sdk-server\@1.7.2 * @turnkey/api-key-stamper\@0.4.4 * @turnkey/http\@2.17.2 ## 0.6.7 ### Patch Changes * Updated dependencies \[7988bc1] * Updated dependencies \[538d4fc] * Updated dependencies \[12d5aaa] * @turnkey/sdk-browser\@1.11.0 * @turnkey/sdk-server\@1.7.1 * @turnkey/http\@2.17.1 ## 0.6.6 ### Patch Changes * @turnkey/sdk-browser\@1.10.2 ## 0.6.5 ### Patch Changes * Updated dependencies \[78bc39c] * @turnkey/sdk-server\@1.7.0 * @turnkey/http\@2.17.0 * @turnkey/sdk-browser\@1.10.1 ## 0.6.4 ### Patch Changes * Updated dependencies \[8bea78f] * @turnkey/sdk-browser\@1.10.0 ## 0.6.3 ### Patch Changes * Updated dependencies \[3dd74ac] * Updated dependencies \[1e36edf] * Updated dependencies \[4df8914] * Updated dependencies \[11a9e2f] * @turnkey/sdk-browser\@1.9.0 * @turnkey/sdk-server\@1.6.0 * @turnkey/http\@2.16.0 ## 0.6.2 ### Patch Changes * Updated dependencies \[9ebd062] * @turnkey/sdk-browser\@1.8.0 * @turnkey/sdk-server\@1.5.0 * @turnkey/http\@2.15.0 ## 0.6.1 ### Patch Changes * Updated dependencies \[abe7138] * Updated dependencies \[96d7f99] * @turnkey/sdk-server\@1.4.2 * @turnkey/sdk-browser\@1.7.1 * @turnkey/http\@2.14.2 * @turnkey/api-key-stamper\@0.4.3 ## 0.6.0 ### Minor Changes * 2bb9ea0: Add synchronous createAccount variant (thank you @mshrieve) * Closes [https://github.com/tkhq/sdk/issues/349](https://github.com/tkhq/sdk/issues/349) * Originally attributed to [https://github.com/tkhq/sdk/pull/348](https://github.com/tkhq/sdk/pull/348) * Upshot: no change required if your setup was working. However, if you would like a synchronous option for creating a Viem account, now you may do so with `createAccountWithAddress` ### Patch Changes * Updated dependencies \[ff059d5] * Updated dependencies \[ff059d5] * @turnkey/sdk-browser\@1.7.0 * @turnkey/sdk-server\@1.4.1 * @turnkey/http\@2.14.1 * @turnkey/api-key-stamper\@0.4.2 ## 0.5.0 ### Minor Changes * 848f8d3: Support awaiting consensus and improve error handling * Add new error types that extend `BaseError` (and thus implement `error.walk`) * `TurnkeyConsensusNeededError` wraps consensus-related errors * `TurnkeyActivityError` wraps base Turnkey errors * Add a few new helper functions: * `serializeSignature` serializes a raw signature * `isTurnkeyActivityConsensusNeededError` and `isTurnkeyActivityError` use `error.walk` to check the type of a Viem error ### Patch Changes * Updated dependencies \[c988ed0] * Updated dependencies \[848f8d3] * @turnkey/sdk-browser\@1.6.0 * @turnkey/sdk-server\@1.4.0 * @turnkey/http\@2.14.0 ## 0.4.31 ### Patch Changes * Updated dependencies \[1813ed5] * @turnkey/sdk-browser\@1.5.0 ## 0.4.30 ### Patch Changes * Updated dependencies \[bab5393] * Updated dependencies \[a16073c] * Updated dependencies \[7e7d209] * @turnkey/sdk-browser\@1.4.0 ## 0.4.29 ### Patch Changes * Updated dependencies \[93dee46] * @turnkey/http\@2.13.0 * @turnkey/sdk-browser\@1.3.0 * @turnkey/sdk-server\@1.3.0 ## 0.4.28 ### Patch Changes * Updated dependencies \[e2f2e0b] * @turnkey/sdk-browser\@1.2.4 * @turnkey/sdk-server\@1.2.4 * @turnkey/http\@2.12.3 ## 0.4.27 ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@1.2.3 * @turnkey/sdk-server\@1.2.3 ## 0.4.26 ### Patch Changes * Updated dependencies \[2d7e5a9] * Updated dependencies \[f4b607f] * @turnkey/api-key-stamper\@0.4.1 * @turnkey/http\@2.12.2 * @turnkey/sdk-browser\@1.2.2 * @turnkey/sdk-server\@1.2.2 ## 0.4.25 ### Patch Changes * Updated dependencies \[f17a229] * @turnkey/http\@2.12.1 * @turnkey/sdk-browser\@1.2.1 * @turnkey/sdk-server\@1.2.1 ## 0.4.24 ### Patch Changes * Updated dependencies * @turnkey/http\@2.12.0 * @turnkey/sdk-browser\@1.2.0 * @turnkey/sdk-server\@1.2.0 ## 0.4.23 ### Patch Changes * Updated dependencies * @turnkey/http\@2.11.0 * @turnkey/sdk-browser\@1.1.0 * @turnkey/sdk-server\@1.1.0 ## 0.4.22 ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@1.0.0 * @turnkey/sdk-server\@1.0.0 ## 0.4.21 ### Patch Changes * @turnkey/sdk-browser\@0.4.1 ## 0.4.20 ### Patch Changes * d59e1b6: Add export of turnkey viem account functions * Updated dependencies \[e4b29da] * @turnkey/sdk-browser\@0.4.0 ## 0.4.19 ### Patch Changes * Updated dependencies \[d409d81] * @turnkey/sdk-browser\@0.3.0 ## 0.4.18 ### Patch Changes * @turnkey/sdk-browser\@0.2.1 ## 0.4.17 ### Patch Changes * Updated dependencies * Updated dependencies \[e4d2a84] * @turnkey/sdk-browser\@0.2.0 * @turnkey/sdk-server\@0.2.0 ## 0.4.16 ### Patch Changes * Updated dependencies * @turnkey/sdk-browser\@0.1.0 * @turnkey/sdk-server\@0.1.0 ## 0.4.15 ### Patch Changes * a6502e6: Add support for new Turnkey Client types ## 0.4.14 ### Patch Changes * Updated dependencies \[7a9ce7a] * @turnkey/http\@2.10.0 ## 0.4.13 ### Patch Changes * Updated dependencies * @turnkey/http\@2.9.1 ## 0.4.12 ### Patch Changes * Updated dependencies \[83b62b5] * @turnkey/http\@2.9.0 ## 0.4.11 ### Patch Changes * Updated dependencies \[46a7d90] * @turnkey/http\@2.8.0 ## 0.4.10 ### Patch Changes * Updated dependencies * @turnkey/http\@2.7.1 ## 0.4.9 ### Patch Changes * Updated dependencies (\[c3b423b], \[d73725b]) * @turnkey/api-key-stamper\@0.4.0 * @turnkey/http\@2.7.0 ## 0.4.8 ### Patch Changes * 4794c64: Updated dependencies ## 0.4.7 ### Patch Changes * Updated dependencies \[f9d636c] * @turnkey/http\@2.6.2 ## 0.4.6 ### Patch Changes * Updated dependencies \[52e2389] * @turnkey/http\@2.6.1 ## 0.4.5 ### Patch Changes * Updated dependencies \[7a3c890] * @turnkey/http\@2.6.0 ## 0.4.4 ### Patch Changes * Upgrade to Node v18 (#184) * Updated dependencies * @turnkey/api-key-stamper\@0.3.1 * @turnkey/http\@2.5.1 ## 0.4.3 ### Patch Changes * Updated dependencies \[464ac0e] * @turnkey/http\@2.5.0 ## 0.4.2 ### Patch Changes * @turnkey/http\@2.4.2 ## 0.4.1 ### Patch Changes * Updated dependencies \[f87ced8] * @turnkey/http\@2.4.1 ## 0.4.0 ### Minor Changes * Use rollup to build ESM and CommonJS, fix ESM support (#174) ### Patch Changes * Updated dependencies \[fc5b291] * @turnkey/api-key-stamper\@0.3.0 * @turnkey/http\@2.4.0 ## 0.3.4 ### Patch Changes * Updated dependencies * @turnkey/api-key-stamper\@0.2.0 * @turnkey/http\@2.3.1 ## 0.3.3 ### Patch Changes * Updated dependencies \[f1bd68a] * @turnkey/http\@2.3.0 ## 0.3.2 ### Patch Changes * Updated dependencies \[ed50a0f] * Updated dependencies * @turnkey/http\@2.2.0 ## 0.3.0 ### Minor Changes * cf8631a: Update interface to support `signWith` This change supports signing with wallet account addresses, private key addresses, or private key IDs. See below for an example: ```js const httpClient = new TurnkeyClient( { baseUrl: "https://api.turnkey.com", }, // This uses API key credentials. // If you're using passkeys, use `@turnkey/webauthn-stamper` to collect webauthn signatures: // new WebauthnStamper({...options...}) new ApiKeyStamper({ apiPublicKey: "...", apiPrivateKey: "...", }), ); // Create the Viem custom account const turnkeyAccount = await createAccount({ client: httpClient, organizationId: "...", signWith: "...", // optional; will be fetched from Turnkey if not provided ethereumAddress: "...", }); ``` ## 0.2.7 ### Patch Changes * Updated dependencies \[bb6ea0b] * @turnkey/http\@2.1.0 ## 0.2.6 ### Patch Changes * 59dcd2f: Unpin typescript * da7c960: Bump Viem dependency to fix `getAddresses()` for LocalAccount * Updated dependencies * @turnkey/http\@2.0.0 * Updated the shape of signing ## 0.2.5 ### Patch Changes * Updated dependencies * @turnkey/http\@1.3.0 ## 0.2.4 ### Patch Changes * 0ec2d94: Addresses a bug when signing raw messages (see [https://github.com/tkhq/sdk/issues/116](https://github.com/tkhq/sdk/issues/116)) ## 0.2.3 ### Patch Changes * Updated dependencies * @turnkey/http\@1.2.0 ## 0.2.2 ### Patch Changes * Updated dependencies * @turnkey/api-key-stamper\@0.1.1 * @turnkey/http\@1.1.1 ## 0.2.1 ### Patch Changes * Fix code sample in the readme; add more details and links ## 0.2.0 ### Minor Changes * Add new `createAccount` method and deprecates the existing `createApiAccount`. `createAccount` offers a superset of functionality and works with stampers (`@turnkey/api-key-stamper` / `@turnkey/webauthn-stamper`) to integrate with API keys or passkeys. ### Patch Changes * Updated dependencies: @turnkey/http\@1.1.0 * New dependency: @turnkey/api-key-stamper\@0.1.0 ## 0.1.1 ### Patch Changes * readme updates ## 0.1.0 Initial release! # Wallet Stamper Source: https://docs.turnkey.com/changelogs/wallet-stamper/readme # @turnkey/wallet-stamper ## 1.0.3 ### Patch Changes * Updated dependencies \[2bc0046] * @turnkey/crypto\@2.3.1 ## 1.0.2 ### Patch Changes * c895c8f: Update @solana/web3.js from ^1.88.1 to ^1.95.8 * @turnkey/crypto\@2.3.0 ## 1.0.1 ### Patch Changes * Updated dependencies \[668edfa] * @turnkey/crypto\@2.3.0 ## 1.0.0 ### Major Changes * Renamed `recoverPublicKey` to `getPublicKey` on the `EthereumWallet` interface to improve clarity and consistency across wallet interfaces * Changed `getPublicKey` method signature to take no parameters ```typescript // Old method signature recoverPublicKey(message: string): Promise; ``` ```typescript // New method signature getPublicKey(): Promise; ``` * Added an `EthereumWallet` implementation as a helper to simplify support for Ethereum wallets: ```typescript import { EthereumWallet } from "@turnkey/wallet-stamper"; const wallet = new EthereumWallet(); // Instantiate the WalletStamper with the EthereumWallet const walletStamper = new WalletStamper(wallet); // Instantiate the TurnkeyClient with the WalletStamper const client = new TurnkeyClient({ baseUrl: BASE_URL }, walletStamper); ``` ### Patch Changes * Updated dependencies \[8bea78f] * @turnkey/crypto\@2.2.0 ## 0.0.5 ### Patch Changes * Updated dependencies \[e5c4fe9] * @turnkey/encoding\@0.4.0 ## 0.0.4 ### Patch Changes * Updated dependencies \[93666ff] * @turnkey/encoding\@0.3.0 ## 0.0.3 ### Patch Changes * Updated dependencies \[2d7e5a9] * Updated dependencies \[f4b607f] * @turnkey/encoding\@0.2.1 ## 0.0.2 ### Patch Changes * 68a14dd: Initial release! 🎉 # Webauthn Stamper Source: https://docs.turnkey.com/changelogs/webauthn-stamper/readme # @turnkey/webauthn-stamper ## 0.5.0 ### Minor Changes * Remove dependency on `noble/hashes` and `Buffer` in favor of a minimal sha256 lib * Introduce `@turnkey/encoding` to consolidate utility functions ## 0.4.3 ### Patch Changes * Upgrade to Node v18 (#184) ## 0.4.2 ### Patch Changes * Make sha256 computation synchronous to resolve ios passkey prompt issues (#179) ## 0.4.1 ### Patch Changes * Fix universal files to stop using `require`. Use ES6 imports instead (#178) ## 0.4.0 ### Minor Changes * Use rollup to build ESM and CommonJS, fix ESM support (#174) ## 0.3.0 ### Minor Changes * Add support for ESM (#154) ## 0.2.0 ### Minor Changes * Adds Buffer polyfill for environments where it is not globally available ([https://github.com/tkhq/sdk/pull/125](https://github.com/tkhq/sdk/pull/125)) ## 0.1.0 Initial release # Organizations Source: https://docs.turnkey.com/concepts/organizations An organization is a logical grouping of resources (e.g. users, policies, wallets). These resources can only be accessed by authorized and permissioned users within the organization. Resources are not shared between organizations. ## Root Quorum All organizations are controlled by a [Root Quorum](/concepts/users/root-quorum) which contains the root users and the required threshold of approvals to take any action. Only the root quorum can update the root quorum or feature set. ## Features Organization features are Turnkey product offerings that organizations can opt-in to or opt-out of. Note that these features can be set and updated using the activities `ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE` and `ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE`. The following is a list of such features: | Name | Description | Default | Notes | | -------------------------------- | --------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | FEATURE\_NAME\_EMAIL\_AUTH | Enables email authentication activities | Enabled | Can only be initiated by a parent organization for a sub-organization. | | FEATURE\_NAME\_EMAIL\_RECOVERY | Enables email recovery activities | Enabled | Can only be initiated by a parent organization for a sub-organization. | | FEATURE\_NAME\_WEBAUTHN\_ORIGINS | The origin Webauthn credentials are scoped to | Disabled | Parent organization feature applies to all sub-organizations. If not enabled, sub-organizations default to allowing all origins: "\*". For Passkey WaaS, we highly recommend enabling this feature. Example value: "[https://www.turnkey.com"](https://www.turnkey.com%22) | | FEATURE\_NAME\_WEBHOOK | A URL to receive activity notification events | Disabled | This feature is currently experimental. Example value: "[https://your.service.com/webhook"](https://your.service.com/webhook%22) | ## Permissions All activity requests are subject to enforcement by Turnkey's policy engine. The policy engine determines if a request is allowed by checking the following: * Does this request violate our feature set? * Email recovery cannot be initiated if disabled * Email auth cannot be initiated if disabled * Should this request be denied by default? * All import requests must target your own user * Does this request meet the root quorum threshold? * What is the outcome of evaluating this request against all organization policies? Outcomes include: * `OUTCOME_ALLOW`: the request is allowed to process * `OUTCOME_REQUIRES_CONSENSUS`: the request needs additional approvals * `OUTCOME_REJECTED`: the request should be rejected * `OUTCOME_DENY_EXPLICIT`: the request has been explicitly denied via policies * `OUTCOME_DENY_IMPLICIT`: the request has been implicitly denied as no policies grant the required permissions * Should this request be allowed by default? * Users can manage their own credentials unless policies explicitly deny this ## Resource Limits Organizations have [resource limits](/concepts/resource-limits) for performance and security considerations. If you're bumping into these limits, check out sub-organizations below. ## Sub-Organizations A sub-organization is an isolated organization that has a pointer to a parent organization. The parent organization has **read** access to all sub-organizations, but no **write** access. This means users within the parent organization have no ability to use wallets or alter any resources in the sub-organization. For more information on sub-organizations and common use cases for this functionality, follow along in the next section . # Overview Source: https://docs.turnkey.com/concepts/overview Turnkey is flexible, scalable, and secure wallet infrastructure that can be used for transaction automation (e.g., payments flows, smart contract management), or non-custodial embedded wallets. Turnkey offers low-level primitives that can be combined to accomplish a variety of goals. Turnkey’s security and flexibility enables you to build cutting-edge user experiences, whether you’re using our bare-bones API or pre-built UI components. To make the most out of your implementation, we recommend reading through the following Concepts page for a better understanding of how our products work, and how to best utilize all of Turnkey’s features. ### How Turnkey works At the core of Turnkey is an important concept: instead of directly managing private keys, wallets are accessed through authenticators like passkeys, social logins, or API keys: all concepts screenshot * **Organizations (parent orgs)** in Turnkey are top-level entities that contain users, wallets, and policies for a business, with the initial “parent organization” typically representing an entire Turnkey-powered application. * Parent organizations can create **sub-organizations (sub-orgs)**, which are fully segregated organizations nested under the parent organization. Parent orgs cannot modify the contents of a sub-org, and sub-orgs and typically represent an end user. * Both parent organizations and sub-organizations contain a set of **resources and authenticators** that you can configure, including their own users, wallets, API keys, private keys, and policies. * **Activities** (like signing transactions or creating users) are governed by **policies** created via Turnkey’s policy engine, though root users can bypass the policy engine when meeting root quorum requirements. * **Wallets** in Turnkey are HD seed phrases that can generate multiple wallet accounts (addresses) for signing operations. ### Managing Turnkey interactions and organizations There are two primary ways for users to interact with Turnkey — via the Turnkey Dashboard, and by submitting activity requests via our public API. The Turnkey Dashboard, which is where you’ll first create your Turnkey parent organization, is where root users of your parent organization will typically manage administrative activities. It supports passkey authentication only. On the other hand, interactions with Turnkey at scale (primarily, interactions initiated by end users) can be done via programmatically calling the Turnkey public API and submitting activity requests, with a variety of authentication methods supported. ## Concepts dictionary For more details on individual concepts, feel free to explore our concept-specific documentation (also accessible through the left navbar). ### Organizations An organization is a logical grouping of resources like users, policies, and wallets. There are two types of organizations: | Organization type | Description | | :------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Parent Organization | When you first setup your implementation of Turnkey by signing up on the dashboard you create a parent organization controlled by your business. In most implementations, a top-level organization represents an entire Turnkey-powered implementation. For more information on Turnkey parent organizations [look here](/concepts/organizations). | | Sub-Organization | A fully segregated organization nested under the parent organization. Parent organizations have read access to all their sub-organizations, but do not have write access. Each sub-organization typically maps to an individual end user in a Turnkey-powered application. Parent organizations can initiate limited actions for sub-organizations that then must be completed by the sub-organization, or without the need for completion by the sub-organization (e.g. `INIT_OTP_AUTH` or `INIT_USER_EMAIL_RECOVERY` require completion by sub-organization, `EMAIL_AUTH` does not). For more information on Turnkey sub-organizations [look here](/concepts/sub-organizations). | ### Users Turnkey users are resources within organizations or sub-organizations that can submit activities to Turnkey via a valid credential (e.g., API key, passkey). These requests can be made either by making direct API calls or through the Turnkey Dashboard. Users must be set up to authenticate to Turnkey with credentials (API keys, passkeys), or via other authentication methods such as OAuth, or email auth, with upper limits on credentials defined here in our [resource limits](/concepts/resource-limits). Users can also have associated “tags” which are logical groupings that can be referenced in policies. Users can only submit activities within their given organization — they cannot take action across organizations. There are two main types of users: | User type | Description | | :----------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Root Users | The first user(s) created in an organization will have root permissions, meaning they can bypass the policy engine to take any action within that specific organization. This ability can be limited via root quorum, which requires a threshold of root users to access root permissions. For example, if there are five root users and the threshold is three, at least three users must approve an activity for the root quorum threshold to be reached. When you first create a Turnkey organization, your user is automatically created as the sole member of the root quorum by default. | | Normal Users | Other than managing their own credentials, non-root users have no permissions unless explicitly granted by [policies](/concepts/policies/overview). By combining non-root users with policies granting permission for specific actions, you can build support for experiences providing [delegated access](/concepts/policies/delegated-access) to business controlled service account. | In parent organizations, a user often maps to an individual from your team with administrative privileges and responsibilities. In sub-organizations, which are often used to manage an end user's resources, a user can represent an end user and their credentials. If there is only one user representing the end user with only end-user controlled credentials then this would be more akin to a standard non-custodial setup. However, this flexible primitive can often represent other aspects of your backend or application. For example, a Turnkey user might map to a: * Backend service used to automate certain transactions * Service with delegated access to take action on behalf of an end user * Required co-signer for all end user transactions For more information on Turnkey users [look here](/concepts/users/introduction). ### Credentials Interacting with the Turnkey API requires each API call to be authenticated by cryptographically stamping it with a credential. This process is abstracted away in our SDKs and ensures that the request cannot be tampered with as it travels to the secure enclave. Credentials include API keys and passkeys / Webauthn devices for all Users, while sub-organization users can also use email or OAuth to authenticate. Email and OAuth leverage API keys under the hood. For more information on Turnkey user credentials [look here](/concepts/users/credentials). ### Activities Activities are specific actions taken by users, such as signing a transaction, adding a new user, or creating a sub-organization. Activity requests are always evaluated through our policy engine, and can evaluate to ALLOW, DENY, or REQUIRES\_CONSENSUS (i.e., requires additional approvals before being allowed). For more information on Turnkey activities [look here](/developer-reference/api-overview/submissions). ### Policies Policies, enforced by Turnkey’s policy engine, grant users permissions to perform activities. These policies are a series of logical statements (e.g., User ID == 123 or ETH address == 0x543…9b34) that evaluate to either “ALLOW” or “DENY.” Through these policies you can set granular controls on which users can take which actions with which wallets. Policies can also require multi-party approval / consensus, meaning a threshold of certain users will be required to approve the activity. As mentioned above, the root quorum will bypass the policy engine. For more information on Turnkey policies [look here](/concepts/policies/overview). ### Wallets and Private Keys Resources used to generate crypto addresses and sign transactions or messages. We currently support secp256k1 and ed25519 curves and have two main types: | Resource type | Description | | :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Wallets (preferred) | A hierarchical deterministic (HD) wallet, which is a collection of cryptographic key pairs derived from a common seed phrase. A wallet (i.e., a single seed phrase) can have many wallet accounts (i.e., a set of derived addresses). Wallets support various cryptographic curves and can be represented by a checksummed mnemonic phrase, making them easier to back up and recover. We limit each organization to 100 Wallets, but there is no limit on the total number of wallet accounts. For more information on Turnkey HD wallets [look here](/concepts/wallets). | | Private Keys | Raw private keys represented by an alphanumeric string. We limit each organization to 1,000 private keys, therefore we recommend using wallets instead of private keys for better scalability. | Learn more about leveraging Wallets across different crypto ecosystems on our [Ecosystem Support](/networks/framework) page. Understand Turnkey's core features and fundamentals. {" "} Learn about Organizations on Turnkey Learn about sub-organizations on Turnkey {" "} 3 items {" "} Learn about Wallets on Turnkey {" "} Organization resource limits 5 items # Delegated Access Source: https://docs.turnkey.com/concepts/policies/delegated-access With Turnkey you can create multi-user accounts with flexible co-ownership controls. This primitive enables you to establish delegated access to a user’s wallet, reducing or removing the need for them to manually approve each action. You can provide a smoother user experience while ensuring that end-users maintain full control over their wallets. ## Overview Delegated access works by creating a specialized business-controlled user within each end-user’s sub-organization that has carefully scoped permissions to perform only specific actions, such as signing transactions to designated addresses. This can enable your backend to do things like: * Automate common transactions (e.g., staking, redemptions) * Sign transactions to whitelisted addresses without user involvement * Perform scheduled operations * Respond to specific onchain events programmatically ## Implementation flow Here’s how to implement delegated access for an embedded wallet setup: * Create a sub-organization with two root users: The end user and your “Delegated User” with an API key authenticator that you control * Enable the Delegated Account to take particular actions by setting policies explicitly allowing those specific actions * Update the root quorum to ensure only the end-user retains root privileges A simple example demonstrating the delegated acess setup can be found [here](https://github.com/tkhq/sdk/tree/main/examples/delegated-access). ## Step-by-step implementation ### Step 1: Create a sub-organization with two root users[​](#step-1-create-a-sub-organization-with-two-root-users "Direct link to Step 1: Create a sub-organization with two root users") * Create your sub-organization with the two root users being: * The end-user * A user you control (we'll call it the ‘Delegated Account’) ```json { "type": "ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V7", "timestampMs": "", "organizationId": "your-organization-id", "parameters": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "enduser@example.com", "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": ["AUTHENTICATOR_TRANSPORT_HYBRID"] } } ], "apiKeys": [], "oidcProviders": [] }, { "userName": "Delegated Account", "userEmail": "(optional)", "authenticators": [], "apiKeys": [ { "apiKeyName": "", "publicKey": "" } ], "oidcProviders": [] } ], "rootQuorumThreshold": 1, "wallet": { "walletName": "Default ETH Wallet", "accounts": [ { "curve": "CURVE_SECP256K1", "pathFormat": "PATH_FORMAT_BIP32", "path": "m/44'/60'/0'/0/0", "addressFormat": "ADDRESS_FORMAT_ETHEREUM" } ] } } } ``` ### Step 2: Limit the permissions of the Delegated Account user via policies * Create a custom policy granting the Delegated Account specific permissions. You might grant that user permissions to: * Sign any transaction * Sign only transactions to a specific address * Create new users in the sub-org * Or any other activity you want to be able to take using your Delegated Account Here’s one example, granting the Delegated Account only the permission to sign ethereum transactions to a specific receiver address: ```json { "type": "ACTIVITY_TYPE_CREATE_POLICY", "timestampMs": "", "organizationId": "sub-organization-id", "parameters": { "policyName": "Allow Delegated Account to sign transactions to specific address", "policy": { "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == )", "condition": "eth.tx.to == " }, } } ``` ### Step 3: Remove the Delegated Account from the root quorum using the Delegated Account's credentials: ```json // Update the root quorum of the sub organization to ONLY include the end user, removing the delegated access user { "type": "ACTIVITY_TYPE_UPDATE_ROOT_QUORUM", "timestampMs": "", "organizationId": "", "parameters": { "threshold": 1, "userIds": [ "" ] } } ``` After completing these steps, the sub-organization will have two users: the end-user (the only root-user) and the Delegated Account user, which only has the permissions granted earlier via policies and no longer retains root user privileges. ## Delegated Access Code Example Below is a code example outlining the implementation of the delegated access setup flow described above ```js import { Turnkey } from "@turnkey/sdk-server"; import dotenv from "dotenv"; dotenv.config(); // Initialize the Turnkey Server Client on the server-side const turnkeyServer = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY, apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }).apiClient(); // To create an API key programmatically check https://github.com/tkhq/sdk/blob/main/examples/kitchen-sink/src/sdk-server/createApiKey.ts const publicKey = ""; const curveType = "API_KEY_CURVE_P256"; // this is the default const apiKeys = [ { apiKeyName: "Delegated - API Key", publicKey, curveType, }, ]; // STEP 1: Create a sub org with End User and Delegated access user in Root Quorum const subOrg = await turnkeyClient.createSubOrganization({ organizationId: process.env.TURNKEY_ORGANIZATION_ID!, subOrganizationName: `Sub Org - With Delegated Access User`, rootUsers: [ { userName: "Delegated Access User", apiKeys, authenticators: [], oauthProviders: [] }, { userName: "End User", userEmail: "", apiKeys: [], authenticators: [], oauthProviders: [] }, ], rootQuorumThreshold: 1, wallet: { "walletName": "Default ETH Wallet", "accounts": [ { "curve": "CURVE_SECP256K1", "pathFormat": "PATH_FORMAT_BIP32", "path": "m/44'/60'/0'/0/0", "addressFormat": "ADDRESS_FORMAT_ETHEREUM" } ] }, }); console.log("sub-org id:", subOrg.subOrganizationId); // Initializing the Turkey client used by the Delegated Access User // Notice the subOrganizationId created above const turnkeyDelegatedAccessClient = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPrivateKey: process.env.DELEGATED_API_PRIVATE_KEY!, apiPublicKey: process.env.DELEGATED_API_PUBLIC_KEY!, defaultOrganizationId: subOrg.subOrganizationId, }).apiClient(); // STEP 2: Create a policy allowing the Delegated access user to send Ethereum transactions to a particular address // Creating a policy for the Delegated account const delegated_userid = subOrg.rootUserIds[0]; const policyName = "Allow Delegated Account to sign transactions to specific address"; const effect = "EFFECT_ALLOW"; const consensus = `approvers.any(user, user.id == '${delegated_userid}')`; const condition = `eth.tx.to == '${process.env.RECIPIENT_ADDRESS}'`; const notes = ""; const { policyId } = await turnkeyDelegated.createPolicy({ policyName, condition, consensus, effect, notes, }); // STEP 3: Update the root quorum to only include the End User, removing the Delegated Access user // Remove the Delegated Account from the root quorum const RootQuorum = await turnkeyDelegated.updateRootQuorum({ threshold: 1, userIds: [subOrg.rootUserIds[1]], // retain the end user }); ``` # Policy examples Source: https://docs.turnkey.com/concepts/policies/examples ## Access control #### Allow a specific user to create wallets ```json { "policyName": "Allow user to create wallets", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "activity.resource == 'WALLET' && activity.action == 'CREATE'" } ``` #### Allow users with a specific tag to create users ```json { "policyName": "Allow user_tag to create users", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.tags.contains(''))", "condition": "activity.resource == 'USER' && activity.action == 'CREATE'" } ``` #### Require two users with a specific tag to add policies ```json { "policyName": "Require two users with user_tag to create policies", "effect": "EFFECT_ALLOW", "consensus": "approvers.filter(user, user.tags.contains('')).count() >= 2", "condition": "activity.resource == 'POLICY' && activity.action == 'CREATE'" } ``` #### Deny all delete actions for users with a specific tag ```json { "policyName": "Only user_tag can take actions", "effect": "EFFECT_DENY", "consensus": "approvers.any(user, user.tags.contains(''))", "condition": "activity.action == 'DELETE'" } ``` #### Allow a specific user (e.g. API-only user) to create a sub-org ```json { "policyName": "Allow user to create a sub-org", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "activity.resource == 'ORGANIZATION' && activity.action == 'CREATE'" } ``` #### Allow a specific user to perform auth type activities (full list [here](/concepts/policies/language#activity-breakdown)) Note: The `activity.resource` portion determines which activities can be performed. The `activity.action` determines what types of actions can be taken upon those resources. ```json { "policyName": "Allow user to initiate auth type activities", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "activity.resource == 'AUTH' && activity.action == 'CREATE'" } ``` #### Allow a specific user to perform a specific activity type (full list [here](/concepts/policies/language#activity-breakdown)) Note: Activities may be upgraded over time, and thus new versions may be introduced. These policies will NOT be valid if an activity type is upgraded and requests are made on the new activity type. For example, if Turnkey introduces `ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V3` (upgraded from `ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2`) and a request is made with the newer `V3` version, this policy with not allow that user to perform `ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V3` activities. ```json JSON { "policyName": "Allow user to perform create read write session v2", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "activity.type == 'ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2'" } ``` ## Signing control #### Allow a specific user to sign transactions with any account address within a specific wallet ```JSON { "policyName": "Allow to sign transactions with ", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "wallet.id == ''" } ``` #### Allow a specific user to sign transactions with a specific wallet account address ```json { "policyName": "Allow to sign transactions with ", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "wallet_account.address == ''" } ``` #### Allow a specific user to sign transactions with a specific private key ```json { "policyName": "Allow to sign transactions with ", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "private_key.id == ''" } ``` ### Ethereum (EVM) Note: see the [language section](/concepts/policies/language#appendix) for more details. #### Allow ERC-20 transfers for a specific token smart contract ```json { "policyName": "Enable ERC-20 transfers for ", "effect": "EFFECT_ALLOW", "condition": "eth.tx.to == '' && eth.tx.data[0..10] == '0xa9059cbb'" } ``` #### Allow anyone to sign transactions for testnet (Sepolia) ```json { "policyName": "Allow signing ethereum sepolia transactions", "effect": "EFFECT_ALLOW", "condition": "eth.tx.chain_id == 11155111" } ``` #### Allow ETH transactions with a specific nonce range ```json { "policyName": "Allow signing Ethereum transactions with an early nonce", "effect": "EFFECT_ALLOW", "condition": "eth.tx.nonce <= 3" } ``` ### Solana Note: see the [language section](/concepts/policies/language#appendix) for various approaches on writing Solana policies. #### Allow Solana transactions that include a transfer from one specific sender ```json { "policyName": "Enable transactions with a transfer sent by ", "effect": "EFFECT_ALLOW", "condition": "solana.tx.transfers.all(transfer, transfer.from == '')" } ``` #### Allow Solana transactions that include a transfer to only one specific recipient ```json { "policyName": "Enable transactions with a single transfer sent to ", "effect": "EFFECT_ALLOW", "condition": "solana.tx.transfers.count == 1 && solana.tx.transfers[0].to == ''" } ``` #### Allow Solana transactions that have exactly one transfer, to one specific recipient ```json { "policyName": "Enable transactions with a transfer sent to ", "effect": "EFFECT_ALLOW", "condition": "solana.tx.transfers.all(transfer, transfer.to == '')" } ``` #### Allow Solana transactions that only use the Solana System Program ```json { "policyName": "Enable transactions that only use the system program", "effect": "EFFECT_ALLOW", "condition": "solana.tx.program_keys.all(p, p == '11111111111111111111111111111111')" } ``` #### Deny all Solana transactions transferring to an undesired address ```json { "policyName": "Reject transactions with a transfer sent to ", "effect": "EFFECT_DENY", "condition": "solana.tx.transfers.any(transfer, transfer.to == '')" } ``` #### Allow Solana transactions with specific expected instruction data ```json { "policyName": "Enable transactions where the first instruction has precisely ", "effect": "EFFECT_ALLOW", "condition": "solana.tx.instructions[0].instruction_data_hex == ''" } ``` #### Allow Solana transactions whose first instruction involves a specific address ```json { "policyName": "Enable transactions where the first instruction has a first account involving
", "effect": "EFFECT_ALLOW", "condition": "solana.tx.instructions[0].accounts[0].account_key == '
'" } ``` #### Solana SPL token transfers -- Context and Examples Turnkey’s policy engine supports policies for SPL token transfers. Specifically, we support creating policies for the `Transfer`, `TransferChecked` and `TransferCheckedWithFee` instructions across both the Solana Token Program and the Solana Token 2022 Program. Some important context for using SPL token policies with Turnkey: **Token Account Addresses** For context, Solana implements SPL token balances for a particular wallet address by creating a whole new account called a "token account" which has a pointer in its data field labeled "owner" that points back to the wallet address in question. So to hold a particular token in your Solana wallet, you have to have to create a new token account meant to hold that token, owned by your Solana wallet. For policies related to the receiving token address of an SPL transfer, the token address receiving the tokens will have to be used, NOT the wallet address that is the owner for the receiving token address. This is because, while both the owning wallet address and the receiving token address are specified in the transfer instruction, the owning wallet address of the recipient token address is not specified. For this we highly recommend using the convention of “associated token addresses” to set policies that, for example, allow SPL token transfers to a particular wallet address. For further context on associated token addresses check out Solana’s documentation on it: [https://spl.solana.com/associated-token-account](https://spl.solana.com/associated-token-account) An example implementation of using a policy to allow transfers to the associated token address of the intended recipient wallet address can be found in our SDK examples [here](https://github.com/tkhq/sdk/tree/main/examples/with-solana#6-running-the-create-spl-token-transfer-with-policy-example). **Mint Address Accessibility** The mint account address of the token will only be accessible when the transaction is constructed using instructions that specify the mint address – `TransferChecked` and `TransferCheckedWithFee`. For transactions constructed using the simple `Transfer` method, the mint account will be considered empty. Here are some example policies for SPL transfers: #### Allow a user to sign Solana transactions that include a single instruction which is an SPL token transfer from a particular sending token address ```json { "policyName": "Allow user to sign Solana transactions that include only a single SPL Transfer FROM ", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "solana.tx.instructions.count() == 1 && solana.tx.spl_transfers.count() == 1 && solana.tx.spl_transfers.all(transfer, transfer.from == '')" } ``` #### Allow a user to sign Solana transactions only if ALL of the instructions are SPL transfers TO a particular token address ```json { "policyName": "Allow user to sign Solana transactions only if ALL of the instructions are SPL transfers TO ", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "solana.tx.instructions.count() == solana.tx.spl_transfers.count() && solana.tx.spl_transfers.all(transfer, transfer.to == '')" } ``` #### Allow users with a specific tag to sign Solana transactions only if ALL of the instructions are SPL token transfers with a specific address as the owner of the sending token address ```json { "policyName": "Allow users with to sign Solana transactions only if ALL of the instructions are SPL token transfers with as the owner of the sending token address", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.tags.contains('')" } ``` #### Allow a user to sign Solana transactions that include a single instruction which is an SPL token transfer where the atomic units of the transfer are less than a threshold amount ```json { "policyName": "Allow user to sign Solana transactions that include a single instruction which is an SPL token transfer where the atomic units of the transfer are less than ", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "solana.tx.instructions.count() == 1 && solana.tx.spl_transfers.count() == 1 && solana.tx.spl_transfers.all(transfer, transfer.amount < )" } ``` #### Allow a user to sign Solana transactions only if ALL of the instructions are SPL token transfers where the token mint address is a particular address ```json { "policyName": "Allow to sign a Solana transaction only if ALL of the instructions are SPL token transfers where the token mint address is ", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "solana.tx.instructions.count() == solana.tx.spl_transfers.count() && solana.tx.spl_transfers.all(transfer, transfer.token_mint == '')" } ``` #### Allow a user to sign Solana transactions that includes a single instruction which is an SPL token transfer where one of the multisig signers of the owner is a particular address ```json { "policyName": "Allow to sign a Solana transaction only if ALL of it's instructions are SPL token transfers where one of the multisig signers of the owner is ", "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "solana.tx.instructions.count() == 1 && solana.tx.spl_transfers.count() == 1 && solana.tx.spl_transfers.all(transfer, transfer.signers.any(s, s == ''))" } ``` ### Tron Note: see the [language section](/concepts/policies/language#appendix) for more details. #### Allow Tether TRC-20 transfers on the Nile Testnet This policy allows for all transfer calls on the Tether smart contract on the Nile testnet. The contract addresses on Nile testnet and Tron mainnet for Tether are different! ```json { "policyName": "Enable Tether TRC-20 transfers on the Nile Testnet for the Tether contract address: "TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf"", "effect": "EFFECT_ALLOW", "condition": "tron.tx.contract[0].contract_address == 'TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf' && tron.tx.contract[0].data[0..8] == 'a9059cbb'" } ``` #### Allow TRX transfers under 10,000,000 SUN (10 TRX) The amount field is denoted in SUN, the lowest denomination of TRX. ```json { "policyName": "Allow TRX transfers under 10 TRX", "effect": "EFFECT_ALLOW", "condition": "tron.tx.contract[0].amount < 10000000" } ``` #### Allow all TransferContract transactions This policy allows for any TRX Transfer ```json { "policyName": "Allow all TRX transfers", "effect": "EFFECT_ALLOW", "condition": "tron.tx.contract[0].type == 'TransferContract'" } ``` # Policy language Source: https://docs.turnkey.com/concepts/policies/language This page provides an overview of how to author policies using our policy language. To begin, we'll need to get familiar with the language's grammar, keywords, and types. ## Grammar The grammar has been designed for flexibility and expressiveness. We currently support the following operations: | Operation | Operators | Example | Types | | ---------- | ---------------------------- | ---------------------------- | ------------------------ | | logical | &&, \|\| | "true && false" | (bool, bool) -> bool | | comparison | ==, !=, \<, >, \<=, >= | "1 \< 2" | (int, int) -> bool | | comparison | ==, != | "'a' != 'b'" | (string, string) -> bool | | comparison | in | "1 in \[1, 2, 3]" | (T, list\) -> bool | | access | x\[\] | \[1,2,3]\[0] | (list\) -> T | | access | x\[\] | "'abc'\[0]" | (string) -> string | | access | x\[\..\] | \[1,2,3]\[0..2] | (list\) -> (list\) | | access | x\[\..\] | "'abc'\[0..2]" | (string) -> string | | access | x.\ | "user.tags" | (struct) -> T | | function | x.all(item, \) | "\[1,1,1].all(x, x == 1)" | (list\) -> bool | | function | x.any(item, \) | "\[1,2,3].any(x, x == 1)" | (list\) -> bool | | function | x.contains(\) | "\[1,2,3].contains(1)" | (list\) -> bool | | function | x.count() | "\[1,2,3].count()" | (list\) -> int | | function | x.filter(item, \) | "\[1,2,3].filter(x, x == 1)" | (list\) -> (list\) | ## Keywords Keywords are reserved words that are dynamically interchanged for real values at evaluation time. Each field supports a different set of keywords. ### Consensus | Keyword | Type | Description | | ------------- | ----------- | ---------------------------------------- | | **approvers** | list\ | The users that have approved an activity | ### Condition | Keyword | Type | Description | | ---------------- | ------------------- | ------------------------------------------------------------ | | **activity** | Activity | The activity metadata of the request | | **eth.tx** | EthereumTransaction | The parsed Ethereum transaction payload (see Appendix below) | | **solana.tx** | SolanaTransaction | The parsed Solana transaction payload (see Appendix below) | | **tron.tx** | TronTransaction | The parsed Tron transaction payload (see Appendix below) | | **wallet** | Wallet | The target wallet used in sign requests | | **private\_key** | PrivateKey | The target private key used in sign requests | ## Types The language is strongly typed which makes policies easy to author and maintain. ### Primitive | Type | Example | Notes | | ------------ | -------------- | ----------------------------------------------- | | **bool** | true | | | **int** | 256 | i128 | | **string** | 'a' | only single quotes are supported | | **list\** | \[1, 2, 3] | a list of type T | | **struct** | \{ id: 'abc' } | a key-value map of \{ field:T } (defined below) | ### Struct | Struct | Field | Type | Description | | ----------------------- | ---------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **User** | id | string | The identifier of the user | | | tags | list\ | The collection of tags for the user | | | email | string | The email address of the user | | | alias | string | The alias of the user | | **Activity** | type | string | The type of the activity (e.g. ACTIVITY\_TYPE\_SIGN\_TRANSACTION\_V2) | | | resource | string | The resource type the activity targets: `USER`, `PRIVATE_KEY`, `POLICY`, `WALLET`, `ORGANIZATION`, `INVITATION`, `CREDENTIAL`, `CONFIG`, `RECOVERY`, `AUTH`, `PAYMENT_METHOD`, `SUBSCRIPTION` | | | action | string | The action of the activity: `CREATE`, `UPDATE`, `DELETE`, `SIGN`, `EXPORT`, `IMPORT` | | **Wallet** | id | string | The identifier of the wallet | | | imported | bool | Boolean indicating whether or not this wallet has been imported | | | exported | bool | Boolean indicating whether or not this wallet has been exported | | | label | string | The label of this wallet | | **Wallet Account** | address | string | The wallet account address | | **PrivateKey** | id | string | The identifier of the private key | | | tags | list\ | The collection of tags for the private key | | | imported | bool | Boolean indicating whether or not this private key has been imported | | | exported | bool | Boolean indicating whether or not this private key has been exported | | | label | string | The label of this private key | | **EthereumTransaction** | from | string | The sender address of the transaction | | | to | string | The receiver address of the transaction (can be an EOA or smart contract) | | | data | string | The arbitrary calldata of the transaction (hex-encoded) | | | value | int | The amount being sent (in wei) | | | gas | int | The maximum allowed gas for the transaction | | | gas\_price | int | The price of gas for the transaction (Note: this field was used in legacy transactions and was replaced with max\_fee\_per\_gas in EIP 1559 transactions, however when evaluating policies on EIP 1559 transactions, this field will be populated with the same value as max\_fee\_per\_gas) | | | chain\_id | int | The chain identifier for the transaction | | | nonce | int | The nonce for the transaction | | | max\_fee\_per\_gas | int | EIP 1559 field specifying the max amount to pay per unit of gas for the transaction (Note: This is the sum of the gas for the transaction and the priority fee described below) | | | max\_priority\_fee\_per\_gas | int | EIP 1559 field specifying the max amount of the tip to be paid to miners for the transaction | | | max\_fee\_per\_blob\_gas | int | EIP 4844 field specifying the maximum fee users are willing to pay per unit of blob gas, akin to the tip in EIP 1559 | | | type | string | The EVM transaction type. This should be one of the following: "LEGACY", "TYPE\_1" (EIP 2930), "TYPE\_2" (EIP 1559), "TYPE\_3" (EIP 4844), "TYPE\_4" (EIP 7702) | | **SolanaTransaction** | account\_keys | list\ | The accounts (public keys) involved in the transaction | | | program\_keys | list\ | The programs (public keys) involved in the transaction | | | instructions | list\ | A list of Instructions (see below) | | | transfers | list\ | A list of Transfers (see below) | | | recent\_blockhash | string | The recent blockhash specified in a transaction | | | spl\_transfers | list\ | A list of SPLTransfers (see below) | | | address\_table\_lookups | list\ | A list of AddressTableLookups (see below) | | **TronTransaction** | ref\_block\_bytes | string | The height of the transaction reference block | | | ref\_block\_hash | string | The hash of the transaction reference block | | | expiration | int | Transaction expiration time in milliseconds | | | timestamp | int | Transaction timestamp in milliseconds | | | data | string | Transaction memo (not the call data!) | | | fee\_limit | int | The maximum energy cost allowed for the execution of smart contract transactions | | | contract | list\ | A list of TronContract. This is the main content of a Tron transaction. This determines the type of transaction being executed and its parameters (see below) | #### Nested Structs | Struct | Field | Type | Description | | ---------------------- | ----------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Instruction** | program\_key | string | The program (public key) involved in the instruction | | | accounts | list\ | A list of Accounts involved in the instruction | | | instruction\_data\_hex | string | Raw hex bytes corresponding to instruction data | | | address\_table\_lookups | list\ | A list of AddressTableLookups used in the instruction. Learn more [here](https://solana.com/docs/advanced/lookup-tables) | | **Transfer** | from | string | A Solana account (public key) representing the sender of the transfer | | | to | string | A Solana account (public key) representing the recipient of the transfer | | | amount | int | The native SOL amount for the transfer (lamports) | | **SPLTransfer** | from | string | A Solana account (public key) representing the token account that is sending tokens in this SPL transfer | | | to | string | A Solana account (public key) representing the token account that is receiving tokens in this SPL transfer | | | amount | int | The amount (noted in raw atomic units) of this SPL transfer | | | owner | string | A Solana account (public key) representing the owner of the sending token account for this SPL transfer | | | signers | list\ | A list of Solana accounts (public keys) representing the multisig signers (if they exist) for this SPL transfer | | | token\_mint | string | A Solana account (public key) representing the token mint of the token being transferred in this SPL transfer | | **Account** | account\_key | string | A Solana account (public key) | | | signer | boolean | An indicator of whether or not the account is a signer | | | writable | boolean | An indicator of whether or not the account can perform a write operation | | **AddressTableLookup** | address\_table\_key | string | A Solana address (public key) corresponding to the address table | | | writable\_indexes | list\ | Indexes corresponding to accounts that can perform writes | | | readonly\_indexes | list\ | Indexes corresponding to accounts that can only perform reads | | **TronContract** | type | string | The contract type, a complete list can be found in the [Tron Protocol Documentation](https://github.com/tronprotocol/protocol/blob/2a678934da3992b1a67f975769bbb2d31989451f/core/Tron.proto#L338-L379) | | | permission\_id | int | The transaction permission type | | | owner\_address | string | The address of the caller of the transaction | | | to\_address | string | The address of the recipient (Only available for TransferContract's) | | | amount | int | The amount of TRX to send (Only available for TransferContract's) | | | contract\_address | string | The address of the contract being called (Only available for TriggerSmartContract's) | | | call\_value | int | The amount of TRX passed to the contract (Only available for TriggerSmartContract's) | | | data | string | The function selector, and the functions parameters of the contract (Only available for TriggerSmartContract's) | | | call\_token\_value | int | The amount of a TRC-10 token passed to the contract (Only available for TriggerSmartContract's) | | | token\_id | int | The TRC-10 token id (Only available for TriggerSmartContract's) | ## Activity Breakdown | Resource Type | Action | Activity Type | | ------------------- | ------ | -----------------------------------------------: | | **ORGANIZATION** | CREATE | ACTIVITY\_TYPE\_CREATE\_SUB\_ORGANIZATION\_V7 | | | DELETE | ACTIVITY\_TYPE\_DELETE\_ORGANIZATION | | | DELETE | ACTIVITY\_TYPE\_DELETE\_SUB\_ORGANIZATION | | **INVITATION** | CREATE | ACTIVITY\_TYPE\_CREATE\_INVITATIONS | | | DELETE | ACTIVITY\_TYPE\_DELETE\_INVITATION | | **POLICY** | CREATE | ACTIVITY\_TYPE\_CREATE\_POLICY\_V3 | | | CREATE | ACTIVITY\_TYPE\_CREATE\_POLICIES | | | UPDATE | ACTIVITY\_TYPE\_UPDATE\_POLICY\_V2 | | | DELETE | ACTIVITY\_TYPE\_DELETE\_POLICY | | **WALLET** | CREATE | ACTIVITY\_TYPE\_CREATE\_WALLET | | | CREATE | ACTIVITY\_TYPE\_CREATE\_WALLET\_ACCOUNTS | | | EXPORT | ACTIVITY\_TYPE\_EXPORT\_WALLET | | | EXPORT | ACTIVITY\_TYPE\_EXPORT\_WALLET\_ACCOUNT | | | IMPORT | ACTIVITY\_TYPE\_INIT\_IMPORT\_WALLET | | | IMPORT | ACTIVITY\_TYPE\_IMPORT\_WALLET | | | DELETE | ACTIVITY\_TYPE\_DELETE\_WALLETS | | | UPDATE | ACTIVITY\_TYPE\_UPDATE\_WALLET | | **PRIVATE\_KEY** | CREATE | ACTIVITY\_TYPE\_CREATE\_PRIVATE\_KEYS\_V2 | | | CREATE | ACTIVITY\_TYPE\_CREATE\_PRIVATE\_KEY\_TAG | | | UPDATE | ACTIVITY\_TYPE\_UPDATE\_PRIVATE\_KEY\_TAG | | | DELETE | ACTIVITY\_TYPE\_DISABLE\_PRIVATE\_KEY | | | DELETE | ACTIVITY\_TYPE\_DELETE\_PRIVATE\_KEY\_TAGS | | | DELETE | ACTIVITY\_TYPE\_DELETE\_PRIVATE\_KEYS | | | EXPORT | ACTIVITY\_TYPE\_EXPORT\_PRIVATE\_KEY | | | IMPORT | ACTIVITY\_TYPE\_INIT\_IMPORT\_PRIVATE\_KEY | | | IMPORT | ACTIVITY\_TYPE\_IMPORT\_PRIVATE\_KEY | | | SIGN | ACTIVITY\_TYPE\_SIGN\_RAW\_PAYLOAD\_V2 | | | SIGN | ACTIVITY\_TYPE\_SIGN\_RAW\_PAYLOADS | | | SIGN | ACTIVITY\_TYPE\_SIGN\_TRANSACTION\_V2 | | **USER** | CREATE | ACTIVITY\_TYPE\_CREATE\_USERS\_V2 | | | CREATE | ACTIVITY\_TYPE\_CREATE\_USER\_TAG | | | CREATE | ACTIVITY\_TYPE\_CREATE\_API\_ONLY\_USERS | | | UPDATE | ACTIVITY\_TYPE\_UPDATE\_USER | | | UPDATE | ACTIVITY\_TYPE\_UPDATE\_USER\_TAG | | | DELETE | ACTIVITY\_TYPE\_DELETE\_USERS | | | DELETE | ACTIVITY\_TYPE\_DELETE\_USER\_TAGS | | **CREDENTIAL** | CREATE | ACTIVITY\_TYPE\_CREATE\_API\_KEYS\_V2 | | | CREATE | ACTIVITY\_TYPE\_CREATE\_AUTHENTICATORS\_V2 | | | DELETE | ACTIVITY\_TYPE\_DELETE\_API\_KEYS | | | DELETE | ACTIVITY\_TYPE\_DELETE\_AUTHENTICATORS | | | CREATE | ACTIVITY\_TYPE\_CREATE\_OAUTH\_PROVIDERS | | | DELETE | ACTIVITY\_TYPE\_DELETE\_OAUTH\_PROVIDERS | | **PAYMENT\_METHOD** | UPDATE | ACTIVITY\_TYPE\_SET\_PAYMENT\_METHOD\_V2 | | | DELETE | ACTIVITY\_TYPE\_DELETE\_PAYMENT\_METHOD | | **SUBSCRIPTION** | CREATE | ACTIVITY\_TYPE\_ACTIVATE\_BILLING\_TIER | | **CONFIG** | UPDATE | ACTIVITY\_TYPE\_UPDATE\_ALLOWED\_ORIGINS | | **RECOVERY** | CREATE | ACTIVITY\_TYPE\_INIT\_USER\_EMAIL\_RECOVERY | | **AUTH** | CREATE | ACTIVITY\_TYPE\_EMAIL\_AUTH\_V2 | | | CREATE | ACTIVITY\_TYPE\_INIT\_OTP\_AUTH | | | CREATE | ACTIVITY\_TYPE\_OTP\_AUTH | | | CREATE | ACTIVITY\_TYPE\_OAUTH | | | CREATE | ACTIVITY\_TYPE\_CREATE\_READ\_WRITE\_SESSION\_V2 | ## Appendix ### Root quorum activities There are a select few activities that are not governed by policies, but rather by an organization's [root quorum](/concepts/users/root-quorum). These activities are: `ACTIVITY\_TYPE\_UPDATE\_ROOT\_QUORUM`, `ACTIVITY\_TYPE\_SET\_ORGANIZATION\_FEATURE`, `ACTIVITY\_TYPE\_REMOVE\_ORGANIZATION\_FEATURE`. For example, if a policy is added that allows a specific non-root user to perform `ACTIVITY\_TYPE\_SET\_ORGANIZATION\_FEATURE` activities, these requests will still fail as they are subject specifically to root quorum. ### Ethereum Our Ethereum policy language (accessible via `eth.tx`) allows for the granular governance of signing Ethereum (EVM-compatible) transactions. Our policy engine exposes a [fairly standard set of properties](https://ethereum.org/en/developers/docs/transactions/#typed-transaction-envelope) belonging to a transaction. See the [Ethereum policy examples](/concepts/policies/examples#ethereum-evm) for sample scenarios. ### Solana Similarly, our Solana policy language (accessible via `solana.tx`) allows for control over signing Solana transactions. Note that there are some fundamental differences between the architecture of the two types of transactions, hence the resulting differences in policy structure. Notably, within our policy engine, a Solana transaction contains a list of Transfers, currently corresponding to native SOL transfers. Each transfer within a transaction is considered a separate entity. Here are some approaches you might take to govern native SOL transfers: * *All* transfers need to match the policy condition. Useful for allowlists ([example](/concepts/policies/examples#allow-solana-transactions-that-include-a-transfer-with-only-one-specific-recipient)) * *Just one* transfer needs to match the policy condition. Useful for blocklists ([example](/concepts/policies/examples#deny-all-solana-transactions-transferring-to-an-undesired-address)) * Only match if there is a *single* transfer in the transaction, *and* that transfer meets the criteria ([example](/concepts/policies/examples#allow-solana-transactions-that-have-exactly-one-transfer-with-one-specific-recipient)). This is the most secure approach, and thus most restrictive. See the [Solana policy examples](/concepts/policies/examples#solana) for sample scenarios. ### Tron Our Tron policy language (accessible via `tron.tx`) allows for policy control over signing Tron transactions. Our policy language supports the standard fields in a Tron transaction: [https://developers.tron.network/docs/tron-protocol-transaction](https://developers.tron.network/docs/tron-protocol-transaction). To reference a Contract within a Transaction you should use `tron.tx.contract[0].field_name` in your policy where field\_name is some field of the contract used in your transaction. While Tron only currently supports 1 contract per transaction this could change in the future, and were ready for it if it does! The policy engine currently supports the following Tron contract types: * TransferContract (TRX transfers) * TriggerSmartContract (Smart contract, including, but not limited to TRC-20, invocations) See the [Tron policy examples](/concepts/policies/examples#tron) for sample scenarios. # Policy overview Source: https://docs.turnkey.com/concepts/policies/overview Our policy engine is the foundation for flexible controls and permissions within your organization. This page provides an overview of how to author policies. ## Policy structure Our policies are defined using **JSON**. The `effect` determines if an activity should be allowed or denied based on the evaluation of the `consensus` and `condition` fields. `consensus` and `condition` are composed of ergonomic expressions written in our [policy language](/concepts/policies/language) that must evaluate to a `bool`. `consensus` determines which user(s) may take an action (e.g. a given user ID). `condition` determines the conditions under which the policy applies (e.g. signing with a specific wallet). These fields can be used alone or together. #### See below for an example policy that allows a single user to send transactions to a single address ```json { "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '4b894565-fa11-42fc-b813-5bf4ea3d53f9')", "condition": "eth.tx.to == ''" } ``` ## Policy evaluation All policies defined within an Organization are evaluated on each request. The image below describes how an activity outcome is determined when resolving multiple policies. The rule follows the below steps: If a quorum of root users takes the action, the final outcome is `OUTCOME_ALLOW` Else if any applicable policy has `EFFECT_DENY`, the final outcome is `OUTCOME_DENY`. This is also referred to as "explicit deny." Else if at least one applicable policy has `EFFECT_ALLOW`, then the final outcome is `OUTCOME_ALLOW` Else the final outcome is `OUTCOME_DENY`. This is also referred to as "implicit deny." In cases of conflicts, `EFFECT_DENY` always wins. Stated differently: policy overview Almost all actions on Turnkey are implicitly denied by default. There are a few exceptions, however: * Root users bypass any policies. * All users have implicit GET (read) permissions in their own Organization and any associated Sub-Organizations. * All users have implicit permission to change their own credentials. * All users have implicit permission to approve an activity if they were included in consensus (i.e., a user specified as part of the consensus required to approve a SIGN\_TRANSACTION activity does not need separate, explicit permission to sign transactions). To learn more about our Policies, checkout our Policy Language [here](/concepts/policies/language). # Policy quickstart Source: https://docs.turnkey.com/concepts/policies/quickstart This guide will help you add an additional user to your Turnkey organization and set permissions for that user through Policies. Specifically, we will create an API-only user with permissions to sign transactions to an allowlisted address. This assumes that you previously completed the [Sign a transaction](/getting-started/quickstart) guide, and thus have already set up: * Your Turnkey organization * An API key for the Root User * A Wallet with an Ethereum account ## Create your new users New users in your Turnkey organization can be created by navigating to the "Users" tab and clicking "Add User". Screen Shot 2023-02-17 at 9.42.29 AM.png In the create user flow, you have the option to grant API key or web access to your new user. For this example, we're going to create an API-only user. Screen Shot 2023-02-21 at 6.17.11 PM.png Under access types, select "API key". Enter the user name "Policy Test". This will be an API-only user, and therefore an email is not required. Click continue and create a new API key to associate with the user using the following command: ```bash turnkey generate api-key --organization $ORGANIZATION_ID --key-name policy_test ``` This will create 2 files, "policy\_test.public" and "policy\_test.private". Copy the contents of the ".public" file and paste it into "API public key". Finish the create user flow and authenticate. Your new user will appear in the Users table. Note down the user ID as you will use it in the next step. ## Create policies for your new users. Next we will create a policy to grant permissions to the new user. Navigate to the "Policies" tab and click on "Add new policy". Screen Shot 2023-05-10 at 1.29.00 PM.png Choose a name and note to describe your new policy. Next, enter the following policy, making sure to replace `` with an Ethereum address of your choosing and `` with the user ID of your recently created API user. ```json { "effect": "EFFECT_ALLOW", "consensus": "approvers.any(user, user.id == '')", "condition": "eth.tx.to == ''" } ``` ## Test your policies Generate sample transactions using our [transaction tool](https://build.tx.xyz). **You'll want to create two transactions**: one transaction to the address you selected in your whitelist policy above, and one to any other address. Next, try signing these two different transactions by replacing `` in the code snippet below. As a reminder, this guide assumes you've completed the [Quickstart](/getting-started/quickstart) guide, and have set `$ORGANIZATION_ID` as an environment variable. ```json turnkey request --path /public/v1/submit/sign_transaction --body '{ "timestampMs": "'"$(date +%s)"'000", "type": "ACTIVITY_TYPE_SIGN_TRANSACTION_V2", "organizationId": "'"$ORGANIZATION_ID"'", "parameters": { "signWith": "", "type": "TRANSACTION_TYPE_ETHEREUM", "unsignedTransaction": "" } }' --key-name policy_test ``` You'll see that the activity to allowlisted address comes back as `COMPLETED`, while the activity to the non-allowlisted address comes back as `FAILED`. You've successfully set your first policy! ## Extra credit * Try out some of our [policy examples](/concepts/policies/examples) * Check out the [policy overview](/concepts/policies/overview) * Learn how to author policies with our [policy language](/concepts/policies/overview) # Resource Limits Source: https://docs.turnkey.com/concepts/resource-limits We have limits on the number of resources within a single organization to avoid performance slowdowns and overly complex permission models. You can scale your organizational resources beyond these limits via . You can create an unlimited number of sub-organizations within a single organization. Currently, the resource limits within a single organization are as follows: | Resource | Maximum parent org allowance | Maximum sub-org allowance | | :----------------------------- | :--------------------------: | :-----------------------: | | Private keys | 1,000 | 1,000 | | HD Wallets | 100 | 100 | | HD Wallet Accounts | unlimited | unlimited | | Users | 100 | 100 | | Policies | 100 | 100 | | Invitations | 100 | 100 | | Tags | 100 | 10 | | Authenticators per user | 10 | 10 | | API keys per user (long-lived) | 10 | 10 | | API keys per user (expiring) | 10 | 10 | | Sub-Organizations | unlimited | 0 | | OAuth providers per user | 10 | 10 | Note that if you create an expiring API key that would exceed the limit above, Turnkey automatically deletes one of your existing keys using the following priority: 1. Expired API keys are deleted first 2. If no expired keys exist, the oldest unexpired key is deleted If you are approaching any of these limits in your implementation and require support, reach out to the Turnkey team ([help@turnkey.com](mailto:help@turnkey.com)). # Sub-Organizations Source: https://docs.turnkey.com/concepts/sub-organizations Using Turnkey's flexible infrastructure, you can programmatically create and manage sub-organizations for your end-users. sub-organizations aren't subject to size limits: you can create as many sub-organizations as needed. The parent organization has **read-only** visibility into all of its sub-organizations, and activities performed in sub-organizations roll up to the parent for billing purposes. We envision sub-organizations being very useful to model your End-Users if you're a business using Turnkey for key management. Let's explore how. ## Creating Sub-Organizations Creating a new sub-organization is an activity performed by the parent organization. The activity itself takes the following attributes as inputs: * organization name * a list of root users * a root quorum threshold * \[optional] a wallet (note: in versions prior to V4, this was a private key) Root users can be programmatic or human, with one or many credentials attached. ## Using Sub-Organizations [Sub-Organizations as Wallets](/embedded-wallets/sub-organizations-as-wallets) explains how you might want to use this primitive as a way to model end-user controlled wallets, or custodial wallets. If you have another use-case in mind, or questions/feedback on this page, reach out to [welcome@turnkey.com](mailto:welcome@turnkey.com)! ## Deleting Sub-Organizations To delete a sub-organization, you can use the [delete sub-organization activity](/api-reference/organizations/delete-sub-organization). Before proceeding, ensure that all private keys and wallets within the sub-organization have been exported to prevent any loss of funds. Alternatively, you can set the `deleteWithoutExport` parameter to `true` to bypass this requirement. By default, the `deleteWithoutExport` parameter is set to `false`. This activity must be initiated by a root user in the sub-organization that is to be deleted. A parent org cannot delete a sub-organization without its participation. # Introduction to users Source: https://docs.turnkey.com/concepts/users/introduction Turnkey users are resources within organizations or sub-organizations that can submit activities to Turnkey via a valid credential (e.g., API key, passkey). These requests can be made either by making direct API calls or through the Turnkey Dashboard. Users must have at least one valid credential (one of API key, passkey), with upper limits on credentials defined here in our [resource limits](/concepts/resource-limits). Users can also have associated “tags” which are logical groupings that can be referenced in policies. Users can only submit activities within their given organization — they cannot take action across organizations. A User's attributes are: * UUID: a globally unique ID (e.g. `fc6372d1-723d-4f7e-8554-dc3a212e4aec`), used as a unique identifier for a User in the context of Policies or User Tags, or Quorums. * Name and email * Authenticators: a list of authenticators (see below for information) * API key: a list of API keys (see below for information) * User tags: a list of User Tag UUIDs A **user belongs to one organization**, and one organization can have many (**up to 100**) users. If you need to create more users, consider using Sub-Organizations. # Wallets Source: https://docs.turnkey.com/concepts/wallets A [hierarchical deterministic (HD) Wallet](https://learnmeabitcoin.com/technical/hd-wallets) is a collection of cryptographic private/public key pairs that share a common seed. A Wallet is used to generate Accounts. ```json { "walletId": "eb98ae4c-07eb-4117-9b2d-8a453c0e1e64", "walletName": "default" } ``` #### Configuration Wallet seeds are generated with a default mnemonic length of 12 words. The [BIP-39 specification](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) supports mnemonic lengths of 12, 15, 18, 21, and 24 words. To enhance your Wallet's security, you may consider opting for a longer mnemonic length. This optional `mnemonicLength` field can be set when creating a Wallet. It's important to note that once the Wallet seed is generated, the mnemonic is permanent and cannot be altered. ## Accounts An account contains the directions for deriving a cryptographic key pair and corresponding address from a Wallet. In practice, this looks like: * The Wallet seed and Account curve are used to create a root key pair * The Account path format and path are used to derive an extended key pair from the root key pair * The Account address format is used to derive the address from the extended public key ```json { "address": "0x7aAE6F67798D1Ea0b8bFB5b64231B2f12049DB5e", "addressFormat": "ADDRESS_FORMAT_ETHEREUM", "curve": "CURVE_SECP256K1", "path": "m/44'/60'/0'/0/0", "pathFormat": "PATH_FORMAT_BIP32", "walletId": "eb98ae4c-07eb-4117-9b2d-8a453c0e1e64" } ``` **The account address is used to sign with the underlying extended private key.** #### HD Wallet Default Paths HD wallets use standardized derivation paths to generate multiple accounts from a single seed. These paths follow a specific structure that allows for consistent address generation across different wallet implementations. Here are common default paths for some of the ecosystems supported by Turnkey: * Ethereum: `m/44'/60'/0'/0/0` * Cosmos: `m/44'/118'/0'/0/0` * Solana: `m/44'/501'/0'/0'` For a complete list of coin types and possible HD paths, refer to the [SLIP-0044 specification](https://github.com/satoshilabs/slips/blob/master/slip-0044.md). #### Address formats and curves See below for specific address formats that you can currently derive on Turnkey: | Type | Address Format | Curve | Default HD Path | | -------- | ----------------------------------------- | ---------------- | ------------------ | | n/a | ADDRESS\_FORMAT\_COMPRESSED | CURVE\_SECP256K1 | m/0'/0 | | n/a | ADDRESS\_FORMAT\_UNCOMPRESSED | CURVE\_SECP256K1 | m/0'/0 | | Ethereum | ADDRESS\_FORMAT\_ETHEREUM | CURVE\_SECP256K1 | m/44'/60'/0'/0/0 | | Cosmos | ADDRESS\_FORMAT\_COSMOS | CURVE\_SECP256K1 | m/44'/118'/0'/0/0 | | Solana | ADDRESS\_FORMAT\_SOLANA | CURVE\_ED25519 | m/44'/501'/0'/0 | | Tron | ADDRESS\_FORMAT\_TRON | CURVE\_SECP256K1 | m/44'/195'/0'/0/0 | | Sui | ADDRESS\_FORMAT\_SUI | CURVE\_ED25519 | m/44'/784'/0'/0/0 | | Aptos | ADDRESS\_FORMAT\_APTOS | CURVE\_ED25519 | m/44'/637'/0'/0'/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_MAINNET\_P2PKH | CURVE\_SECP256K1 | m/44'/0'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_MAINNET\_P2SH | CURVE\_SECP256K1 | m/49'/0'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_MAINNET\_P2WPKH | CURVE\_SECP256K1 | m/84'/0'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_MAINNET\_P2WSH | CURVE\_SECP256K1 | m/48'/0'/0'/2'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_MAINNET\_P2TR | CURVE\_SECP256K1 | m/86'/0'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_TESTNET\_P2PKH | CURVE\_SECP256K1 | m/44'/1'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_TESTNET\_P2SH | CURVE\_SECP256K1 | m/49'/1'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_TESTNET\_P2WPKH | CURVE\_SECP256K1 | m/84'/1'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_TESTNET\_P2WSH | CURVE\_SECP256K1 | m/48'/1'/0'/2'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_TESTNET\_P2TR | CURVE\_SECP256K1 | m/86'/1'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_SIGNET\_P2PKH | CURVE\_SECP256K1 | m/44'/1'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_SIGNET\_P2SH | CURVE\_SECP256K1 | m/49'/1'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_SIGNET\_P2WPKH | CURVE\_SECP256K1 | m/84'/1'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_SIGNET\_P2WSH | CURVE\_SECP256K1 | m/48'/1'/0'/2'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_SIGNET\_P2TR | CURVE\_SECP256K1 | m/86'/1'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_REGTEST\_P2PKH | CURVE\_SECP256K1 | m/44'/1'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_REGTEST\_P2SH | CURVE\_SECP256K1 | m/49'/1'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_REGTEST\_P2WPKH | CURVE\_SECP256K1 | m/84'/1'/0'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_REGTEST\_P2WSH | CURVE\_SECP256K1 | m/48'/1'/0'/2'/0/0 | | Bitcoin | ADDRESS\_FORMAT\_BITCOIN\_REGTEST\_P2TR | CURVE\_SECP256K1 | m/86'/1'/0'/0/0 | | Sei | ADDRESS\_FORMAT\_SEI | CURVE\_ED25519 | m/44'/118'/0'/0/0 | | Stellar | ADDRESS\_FORMAT\_XLM | CURVE\_ED25519 | m/44'/148'/0'/0'/0 | | Dogecoin | ADDRESS\_FORMAT\_DOGE\_MAINNET | CURVE\_SECP256K1 | m/44'/3'/0'/0/0 | | Dogecoin | ADDRESS\_FORMAT\_DOGE\_TESTNET | CURVE\_SECP256K1 | m/44'/1'/0'/0/0 | | TON | ADDRESS\_FORMAT\_TON\_V3R2 | CURVE\_ED25519 | m/44'/607'/0'/0/0 | | TON | ADDRESS\_FORMAT\_TON\_V4R2 | CURVE\_ED25519 | m/44'/607'/0'/0/0 | | XRP | ADDRESS\_FORMAT\_XRP | CURVE\_SECP256K1 | m/44'/144'/0'/0/0 | | FLARE | ADDRESS\_FORMAT\_XRP | CURVE\_SECP256K1 | m/44'/144'/0'/0/0 | #### Where can I learn more? In addition to the guide mentioned above on [HD Wallets](https://learnmeabitcoin.com/technical/hd-wallets), there is also a page specifically on [Derivation Paths](https://learnmeabitcoin.com/technical/derivation-paths). #### What if I don't see the address format for my network? You can use `ADDRESS_FORMAT_COMPRESSED` to generate a public key which can be used to sign with (only sign raw payloads supported). #### What is the difference between Sign Transaction and Sign Raw Payload ? [SignRawPayload](https://docs.turnkey.com/api-reference/activities/sign-raw-payload): network-agnostic, curve-based signing of messages. [SignTransaction](https://docs.turnkey.com/api-reference/activities/sign-transaction): network-specific transaction signing, including [transaction parsing](https://docs.turnkey.com/networks/overview#:~:text=Tier%204%3A%20Transaction%20parsing%20and%20policy%20creation) and compatibility with our policy engine. #### What if I don't see the curve for my network? Contact us at [hello@turnkey.com](mailto:hello@turnkey.com). ## Delete wallets To delete wallets you can call the [delete wallets activity](/api-reference/wallets/delete-wallets). Before deleting a wallet it must have been exported to prevent loss of funds, or you can pass in the `deleteWithoutExport` parameter with the value `true` to override this. The `deleteWithoutExport` parameter, if not passed in, is default `false`. Note that this activity must be initiated by the wallet owner. ## Private Keys Turnkey also supports raw private keys, but we recommend using Wallets since they offer several advantages: * Wallets can be used across various cryptographic curves * Wallets can generate millions of addresses for various digital assets * Wallets can be represented by a checksummed, mnemonic phrase making them easier to backup and recover ## Export keys Exporting on Turnkey enables you or your end users to export a copy of a Wallet or Private Key from our system at any time. While most Turnkey users opt to keep Wallets within Turnkey's secure infrastructure, the export functionality means you are never locked into Turnkey, and gives you the freedom to design your own backup processes as you see fit. Check out our [Export Wallet guide](/wallets/export-wallets) to allow your users to securely export their wallets. ## Import keys Importing on Turnkey enables you or your end users to import a Wallet or Private Key to our system. Check out our [Import Wallet guide](/wallets/import-wallets) to allow your users to securely import their wallets. ## Delete keys To delete private keys you can call the [delete private keys activity](/api-reference/private-keys/delete-private-keys). Before deleting a private key it must have been exported to prevent loss of funds, or you can pass in the `deleteWithoutExport` parameter with the value `true` to override this. The `deleteWithoutExport` parameter, if not passed in, is default `false`. Note that this activity must be initiated by the private key owner. # Errors Source: https://docs.turnkey.com/developer-reference/api-overview/errors An error returned by the Turnkey API might look something like this: ```bash Turnkey error 3: organization mismatch: request is targeting organization ("USER SUB ORG"), but voters are in organization ("OUR MAIN ORG") ``` Within this error message there are a few different parts that are worth breaking down. First the GRPC Error code. This looks like this: ```bash Turnkey error 3: ``` This GRPC error wraps what we call a Turnkey Error which looks something like: ```bash organization mismatch: request is targeting organization ("USER SUB ORG"), but voters are in organization ("OUR MAIN ORG") ``` What is more important to you as a developer is the TurnkeyError. This will give you information about what error occurred and how you can handle it. In fact, you should **not** perform error handling based on the GRPC code. These codes are meant to be used internally and will eventually be removed from our error responses. More on that [here](#grpc-error-codes). This page enumerates all errors that might be received while using the Turnkey API and also provides information about causes for these errors and helpful troubleshooting tips. ## All Error Codes for Actions The below table enumerates all errors across different actions that can be taken using the API. It contains both the GRPC codes as well as the HTTP codes corresponding with each error as well as the displayed error message. More on GRPC error codes below this table. Click on the message to view a details explanation of possible causes and trouble shooting tips for that specific error | GRPC Code | HTTP Code | Message | | :---------------- | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | InvalidArgument | 400 | [malformed organization ID provided](#malformed-organization-id-provided) | | InvalidArgument | 400 | [bad request body](#bad-request-body) | | InvalidArgument | 400 | [failed to load organizations](#failed-to-load-organizations) | | InvalidArgument | 400 | [policy label must be unique](#policy-label-must-be-unique) | | InvalidArgument | 400 | [invalid policy consensus](#invalid-policy-consensus) | | InvalidArgument | 400 | [invalid policy condition](#invalid-policy-condition) | | InvalidArgument | 400 | [quorum threshold must be non-zero integer](#quorum-threshold-must-be-non-zero-integer) | | InvalidArgument | 400 | [quorum users missing](#quorum-users-missing) | | InvalidArgument | 400 | [invalid api key expiration](#invalid-api-key-expiration) | | InvalidArgument | 400 | [missing parameter: user authenticator attestation](#missing-parameter-user-authenticator-attestation) | | InvalidArgument | 400 | [invalid authenticator attestation](#invalid-authenticator-attestation) | | InvalidArgument | 400 | [missing parameter: user authenticator attestation auth data](#missing-parameter-user-authenticator-attestation-auth-data) | | InvalidArgument | 400 | [missing wallet params](#missing-wallet-params) | | InvalidArgument | 400 | [invalid path format](#invalid-path-format) | | InvalidArgument | 400 | [invalid path](#invalid-path) | | InvalidArgument | 400 | [invalid address format](#invalid-address-format) | | InvalidArgument | 400 | [invalid curve](#invalid-curve) | | InvalidArgument | 400 | [curve required](#curve-required) | | InvalidArgument | 400 | [invalid payload encoding](#invalid-payload-encoding) | | InvalidArgument | 400 | [invalid hash function](#invalid-hash-function) | | InvalidArgument | 400 | [invalid magic link template](#invalid-magic-link-template) | | InvalidArgument | 400 | [failed to get email template contents](#failed-to-get-email-template-contents) | | InvalidArgument | 400 | [failed to unmarshal template variables](#failed-to-unmarshal-template-variables) | | Unauthenticated | 401 | [no valid authentication signature found for request](#no-valid-authentication-signature-found-for-request) | | Unauthenticated | 401 | [could not find public key in organization](#could-not-find-public-key-in-organization) | | Unauthenticated | 401 | [failed while looking up public key in parent organization](#failed-while-looking-up-public-key-in-parent-organization) | | Unauthenticated | 401 | [could not find public key in organization or its parent organization](#could-not-find-public-key-in-organization-or-its-parent-organization) | | Unauthenticated | 401 | [could not verify WebAuthN signature](#could-not-verify-webauthn-signature) | | Unauthenticated | 401 | [credential ID could not be found in organization or its parent organization](#credential-id-could-not-be-found-in-organization-or-its-parent-organization) | | Unauthenticated | 401 | [public key could not be found in organization or its parent organization](#public-key-could-not-be-found-in-organization-or-its-parent-organization) | | Unauthenticated | 401 | [more than one suborg associated with a credential ID](#more-than-one-suborg-associated-with-a-credential-id) | | Unauthenticated | 401 | [more than one suborg associated with a public key](#more-than-one-suborg-associated-with-a-public-key) | | Unauthenticated | 401 | [could not verify api key signature](#could-not-verify-api-key-signature) | | Unauthenticated | 401 | [expired api key](#expired-api-key) | | Unauthenticated | 401 | [malformed activity stamp](#malformed-activity-stamp) | | Unauthenticated | 401 | [could not extract webauthn stamp](#could-not-extract-webauthn-stamp) | | Unauthenticated | 401 | [could not extract api key stamp](#could-not-extract-api-key-stamp) | | Unauthenticated | 401 | [cannot authenticate public API activity request without a stamp (X-Stamp/X-Stamp-Webauthn header)](#cannot-authenticate-public-api-activity-request-without-a-stamp-x-stampx-stamp-webauthn-header) | | PermissionDenied | 403 | [request not authorized](#request-not-authorized) | | PermissionDenied | 403 | [api operations disabled](#api-operations-disabled) | | PermissionDenied | 403 | [authentication failed](#authentication-failed) | | NotFound | 404 | [webauthn authenticator not found in organization](#webauthn-authenticator-not-found-in-organization) | | NotFound | 404 | [webauthn authenticator not found in organization or parent organization](#webauthn-authenticator-not-found-in-organization-or-parent-organization) | | NotFound | 404 | [no organization found with the given ID](#no-organization-found-with-the-given-id) | | NotFound | 404 | [No activity found with fingerprint. Consensus activities must target an existing activity by fingerprint](#no-activity-found-with-fingerprint-consensus-activities-must-target-an-existing-activity-by-fingerprint) | | ResourceExhausted | 429 | [user has exceeded maximum authenticators](#user-has-exceeded-maximum-authenticators) | | ResourceExhausted | 429 | [user has exceeded maximum long-lived api keys](#user-has-exceeded-maximum-long-lived-api-keys) | | ResourceExhausted | 429 | [user has exceeded maximum short-lived api keys](#user-has-exceeded-maximum-short-lived-api-keys) | | ResourceExhausted | 429 | [this organization cannot execute activities because it is over its allotted quota. Please reach out to the Turnkey team (help@turnkey.com) for more information.](#this-organization-cannot-execute-activities-because-it-is-over-its-allotted-quota-please-reach-out-to-the-turnkey-team-helpturnkeycom-for-more-information) | | ResourceExhausted | 429 | [this sub-organization cannot execute activities because its parent is over its allotted quota. Please reach out to the Turnkey team (help@turnkey.com) for more information.](#this-sub-organization-cannot-execute-activities-because-its-parent-is-over-its-allotted-quota-please-reach-out-to-the-turnkey-team-helpturnkeycom-for-more-information) | | ResourceExhausted | 429 | [this organization cannot execute activities because it has been rate limited. Please reach out to the Turnkey team (help@turnkey.com) for more information.](#this-organization-cannot-execute-activities-because-it-has-been-rate-limited-please-reach-out-to-the-turnkey-team-helpturnkeycom-for-more-information) | | ResourceExhausted | 429 | [this sub-organization cannot execute activities because its parent has been rate limited. Please reach out to the Turnkey team (help@turnkey.com) for more information.](#this-sub-organization-cannot-execute-activities-because-its-parent-has-been-rate-limited-please-reach-out-to-the-turnkey-team-helpturnkeycom-for-more-information) | | Internal | 500 | [internal server error](#internal-server-error) | ## GRPC Error Codes Turnkey uses GRPC internally to communicate with our internal services whenever an API request is made. Due to this some errors will be wrapped with GRPC error messages. These error codes are listed below for your convenience, however these will not remain in Turnkey error messages forever and you should **not** do error handling based on these codes as these could be removed at any time. In the following example `Turnkey error 3:` represents a grpc error (error code 3, INVALID\_ARGUMENT) wrapping a Turnkey error. Example ```bash Turnkey error 3: organization mismatch: request is targeting organization ("USER SUB ORG"), but voters are in organization ("OUR MAIN ORG") ``` ### GRPC Status Codes Reference | Code | Number | Description | | -------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | OK | 0 | Not an error; returned on success. | | CANCELLED | 1 | The operation was cancelled, typically by the caller. | | UNKNOWN | 2 | Unknown error. For example, this error may be returned when a `Status` value received from another address space belongs to an error space that is not known in this address space. Also errors raised by APIs that do not return enough error information may be converted to this error. | | INVALID\_ARGUMENT | 3 | The client specified an invalid argument. Note that this differs from `FAILED_PRECONDITION`. `INVALID_ARGUMENT` indicates arguments that are problematic regardless of the state of the system (e.g., a malformed file name). | | DEADLINE\_EXCEEDED | 4 | The deadline expired before the operation could complete. For operations that change the state of the system, this error may be returned even if the operation has completed successfully. For example, a successful response from a server could have been delayed long | | NOT\_FOUND | 5 | Some requested entity (e.g., file or directory) was not found. Note to server developers: if a request is denied for an entire class of users, such as gradual feature rollout or undocumented allowlist, `NOT_FOUND` may be used. If a request is denied for some users within a class of users, such as user-based access control, `PERMISSION_DENIED` must be used. | | ALREADY\_EXISTS | 6 | The entity that a client attempted to create (e.g., file or directory) already exists. | | PERMISSION\_DENIED | 7 | The caller does not have permission to execute the specified operation. `PERMISSION_DENIED` must not be used for rejections caused by exhausting some resource (use `RESOURCE_EXHAUSTED` instead for those errors). `PERMISSION_DENIED` must not be used if the caller can not be identified (use `UNAUTHENTICATED` instead for those errors). This error code does not imply the request is valid or the requested entity exists or satisfies other pre-conditions. | | RESOURCE\_EXHAUSTED | 8 | Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space. | | FAILED\_PRECONDITION | 9 | The operation was rejected because the system is not in a state required for the operation's execution. For example, the directory to be deleted is non-empty, an rmdir operation is applied to a non-directory, etc. Service implementors can use the following guidelines to decide between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`: (a) Use `UNAVAILABLE` if the client can retry just the failing call. (b) Use `ABORTED` if the client should retry at a higher level (e.g., when a client-specified test-and-set fails, indicating the client should restart a read-modify-write sequence). (c) Use `FAILED_PRECONDITION` if the client should not retry until the system state has been explicitly fixed. E.g., if an "rmdir" fails because the directory is non-empty, `FAILED_PRECONDITION` should be returned since the client should not retry unless the files are deleted from the directory. | | ABORTED | 10 | The operation was aborted, typically due to a concurrency issue such as a sequencer check failure or transaction abort. See the guidelines above for deciding between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`. | | OUT\_OF\_RANGE | 11 | The operation was attempted past the valid range. E.g., seeking or reading past end-of-file. Unlike `INVALID_ARGUMENT`, this error indicates a problem that may be fixed if the system state changes. For example, a 32-bit file system will generate `INVALID_ARGUMENT` if asked to read at an offset that is not in the range \[0,2^32-1], but it will generate `OUT_OF_RANGE` if asked to read from an offset past the current file size. There is a fair bit of overlap between `FAILED_PRECONDITION` and `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific error) when it applies so that callers who are iterating through a space can easily look for an `OUT_OF_RANGE` error to detect when they are done. | | UNIMPLEMENTED | 12 | The operation is not implemented or is not supported/enabled in this service. | | INTERNAL | 13 | Internal errors. This means that some invariants expected by the underlying system have been broken. This error code is reserved for serious errors. | | UNAVAILABLE | 14 | The service is currently unavailable. This is most likely a transient condition, which can be corrected by retrying with a backoff. Note that it is not always safe to retry non-idempotent operations. | | DATA\_LOSS | 15 | Unrecoverable data loss or corruption. | | UNAUTHENTICATED | 16 | The request does not have valid authentication credentials for the operation. | Source: [https://grpc.io/docs/guides/status-codes/](https://grpc.io/docs/guides/status-codes/) ## Troubleshooting ### no organization found with the given ID Common causes: * An unknown organization ID was passed in a request made to the Turnkey API Troubleshooting tips: * Confirm that you are using the proper Organization ID. All Turnkey resources are identified with a UUID, so confirm you are not passing a different resource's UUID as the organization ID in your request. ### malformed organization ID provided Common causes: * An improperly formatted organization ID UUID was passed in a request made to the Turnkey API Troubleshooting tips: * Confirm the the UUID conforms to the UUID standard `XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX` ### bad request body Common causes: * A malformed request body was passed in a request made to the Turnky API Troubleshooting tips: * A typical activity request has the `type`, `timestampMS`, and `organizationId` parameters at the top level and then a `parameters` parameter with more specific parameters based on the request type. For example a CREATE\_WALLET activity request body might look something like this: ```json { "type": "ACTIVITY_TYPE_CREATE_WALLET", "timestampMs": "", "organizationId": "string", "parameters": { "walletName": "string", "accounts": [ { "curve": "CURVE_SECP256K1", "pathFormat": "PATH_FORMAT_BIP32", "path": "string", "addressFormat": "ADDRESS_FORMAT_UNCOMPRESSED" } ], "mnemonicLength": 0 } } ``` * A get resource request body might look slightly different with less fields. An example of a GET\_WALLET request body looks something like this: ```json { "organizationId": "string", "walletId": "string" } ``` ### api operations disabled Common causes: * Turnkey has disabled API operations globally. Troubleshooting tips: * This situation will only happen in the most extreme case and should not be something you need to worry about. ### this organization cannot execute activities because it is over its allotted quota. Please reach out to the Turnkey team ([help@turnkey.com](mailto:help@turnkey.com)) for more information. Common causes: * You have exceeded your monthly signing quota. The first 25 signatures a month are free for "free" users. * You have reached a resource limit on a particular resource. You can find out about our resource limits [here](/concepts/resource-limits). Troubleshooting tips: * If you need to increase your signature limit take a look at our [pricing page](https://www.turnkey.com/pricing) and contact us at [help@turnkey.com](mailto:help@turnkey.com)! * Resource limits are imposed globally and cannot be increased, speak with our team at [help@turnkey.com](mailto:help@turnkey.com) to understand how to better integrate Turnkey with your system to utilize Turnkey to its highest potential. ### this sub-organization cannot execute activities because its parent is over its allotted quota. Please reach out to the Turnkey team ([help@turnkey.com](mailto:help@turnkey.com)) for more information. Common causes: * You have exceeded your monthly signing quota. The first 25 signatures a month are free for "free" users. * You have reached a resource limit on a particular resource. You can find out about our resource limits [here](/concepts/resource-limits). Troubleshooting tips: * If you need to increase your signature limit take a look at our [pricing page](https://www.turnkey.com/pricing) and contact us at [help@turnkey.com](mailto:help@turnkey.com)! * Resource limits are imposed globally and cannot be increased, speak with our team at [help@turnkey.com](mailto:help@turnkey.com) to understand how to better integrate Turnkey with your system to utilize Turnkey to its highest potential. ### this organization cannot execute activities because it has been rate limited. Please reach out to the Turnkey team ([help@turnkey.com](mailto:help@turnkey.com)) for more information. Common causes: * You have exceeded your rate limit. We need to maintain a per-customer rate limit to ensure that the service we provide to all of our customers service can be exceptional. Troubleshooting tips: * If you are interested in increasing your rate limit reach out to us at [help@turnkey.com](mailto:help@turnkey.com)! ### this sub-organization cannot execute activities because its parent has been rate limited. Please reach out to the Turnkey team ([help@turnkey.com](mailto:help@turnkey.com)) for more information. Common causes: * You have exceeded your rate limit. We need to maintain a per-customer rate limit to ensure that the service we provide to all of our customers service can be exceptional. Troubleshooting tips: * If you are interested in increasing your rate limit reach out to us at [help@turnkey.com](mailto:help@turnkey.com)! ### request not authorized Common causes: * A user that created a request is not allowed to complete the action that was requested. * For example a parent-organization trying to create a wallet within a sub-organization that does not have a delegated access API key. Troubleshooting tips: * Confirm that you are using the correct credentials for the request you are making. * Confirm that all necessary [policies](/concepts/policies/overview) are in place so that the action that is requested can be performed. ### no valid authentication signature found for request Common causes: * No signature, or [stamp](/developer-reference/api-overview/stamps), is attached to a request. All requests made to Turnkey's api must be stamped so that Turnkey can authenticate and authorize the user who performed the request. Troubleshooting tips: * Take a look at the page on [stamps](/developer-reference/api-overview/stamps) to get some information about stamps, what they are, and how they are created. * At a base level our SDK's abstract away the complicated stamping process for you. [Here](https://github.com/tkhq/sdk/tree/main/examples) are some example projects with our JS/TS SDK to get you started! ### could not find public key in organization Common causes: * The public key corresponding to the signature in a stamp is not found in the organization the request is targeting. This means that a request was formatted properly, but the authenticator used to create the request is not associated with the organization that the request was made for. Troubleshooting tips: * Ensure that you have added the proper authenticators to the organization you are targeting. * Ensure that you are targeting the proper organization. ### failed while looking up public key in parent organization Common causes: * The public key corresponding to the signature in a stamp is not found in the organization the request is targeting. This means that a request was formatted properly, but the authenticator used to create the request is not associated with the organization that the request was made for. Troubleshooting tips: * Ensure that you have added the proper authenticators to the organization you are targeting. * Ensure that you are targeting the proper organization. ### could not find public key in organization or its parent organization Common causes: * The public key corresponding to the signature in a stamp is not found in the organization the request is targeting. This means that a request was formatted properly, but the authenticator used to create the request is not associated with the organization that the request was made for. Troubleshooting tips: * Ensure that you have added the proper authenticators to the organization you are targeting. * Ensure that you are targeting the proper organization. ### could not verify WebAuthN signature Common causes: * The signature used to create a stamp for a request cannot be verified for the organization the request is targeting. Again this means the request is formatted properly, but the authenticator used to create the request is not associated with the organization that the request was made for. Troubleshooting tips: * Ensure that you have added the proper authenticators to the organization you are targeting. * Ensure that you are targeting the proper organization. ### credential ID could not be found in organization or its parent organization Common causes: * Turnkey cannot translate a public key obtained from a stamp that was created with a WebAuthn authenticator to a parent organization or one of its corresponding sub-organizations that the request was made for. Troubleshooting tips: * Ensure that you have added the proper authenticators to the organization you are targeting. * Ensure that you are targeting the proper organization. ### public key could not be found in organization or its parent organization Common causes: * Turnkey cannot translate a public key obtained from a stamp to a parent organization or one of its corresponding sub-organizations that the request was made for. Troubleshooting tips: * Ensure that you have added the proper authenticators to the organization you are targeting. * Ensure that you are targeting the proper organization. ### more than one suborg associated with a credential ID Common causes: * This error occurs for requests like [whoami](/api-reference/sessions/who-am-i). In particular this request tries to go backwards from the stamp to the public key then to a corresponding sub-orgnaization under a parent organization. If there are multiple sub-organizations with the same public key corresponding to an authenticator it is unknown who is initiating that particular request without more context. Troubleshooting tips: * Inlcude the sub-organization ID in the whoami request body. * Avoid including the same authenticator in multiple sub-organizations ### more than one suborg associated with a public key Common causes: * This error occurs for requests like [whoami](/api-reference/sessions/who-am-i). In particular this request tries to go backwards from the stamp to the public key then to a corresponding sub-orgnaization under a parent organization. If there are multiple sub-organizations with the same public key it is unknown who is initiating that particular request without more context. Troubleshooting tips: * Inlcude the sub-organization ID in the whoami request body. * Avoid including the same authenticator in multiple sub-organizations ### could not verify api key signature Common causes: * The signature used to create a stamp for a request cannot be verified for the organization the request is targeting. This means the request is formatted properly, but the api-key used to create the request is not associated with the organization that the request was made for. Troubleshooting tips: * Ensure that you have added the proper api-keys to the organization you are targeting. * Ensure that you are targeting the proper organization. ### expired api key Common causes: * The API key used for the request has expired Troubleshooting tips: * Create a new API key to use for the request * Create an API key that doesn't expire ### malformed activity stamp Common causes: * The stamp attached to a request is not formatted properly. Troubleshooting tips: * Take a look at the page on [stamps](/developer-reference/api-overview/stamps) to get some information about stamps, what they are, and how they are created. * At a base level our SDK's abstract away the complicated stamping process for you. [Here](https://github.com/tkhq/sdk/tree/main/examples) are some example projects with our JS/TS SDK to get you started! ### could not extract webauthn stamp Common causes: * A stamp is not attached to a request. Troubleshooting tips: * Take a look at the page on [stamps](/developer-reference/api-overview/stamps) to get some information about stamps, what they are, and how they are created. * At a base level our SDK's abstract away the complicated stamping process for you. [Here](https://github.com/tkhq/sdk/tree/main/examples) are some example projects with our JS/TS SDK to get you started! ### could not extract api key stamp Common causes: * A stamp is not attached to a request. Troubleshooting tips: * Take a look at the page on [stamps](/developer-reference/api-overview/stamps) to get some information about stamps, what they are, and how they are created. * At a base level our SDK's abstract away the complicated stamping process for you. [Here](https://github.com/tkhq/sdk/tree/main/examples) are some example projects with our JS/TS SDK to get you started! ### cannot authenticate public API activity request without a stamp (X-Stamp/X-Stamp-Webauthn header) Common causes: * A stamp is not attached to a request. Troubleshooting tips: * Take a look at the page on [stamps](/developer-reference/api-overview/stamps) to get some information about stamps, what they are, and how they are created. * At a base level our SDK's abstract away the complicated stamping process for you. [Here](https://github.com/tkhq/sdk/tree/main/examples) are some example projects with our JS/TS SDK to get you started! ### webauthn authenticator not found in organization Common causes: * The signature used to create a stamp for a request cannot be verified for the organization the request is targeting. This means the request is formatted properly, but the webauthn authenticator used to create the request is not associated with the organization that the request was made for. Troubleshooting tips: * Ensure that you have added the proper authenticator to the organization you are targeting. * Ensure that you are targeting the proper organization. ### webauthn authenticator not found in organization or parent organization Common causes: * The signature used to create a stamp for a request cannot be verified for the organization the request is targeting. This means the request is formatted properly, but the webauthn authenticator used to create the request is not associated with the organization that the request was made for. Troubleshooting tips: * Ensure that you have added the proper authenticator to the organization you are targeting. * Ensure that you are targeting the proper organization. ### invalid payload encoding Common causes: * This error is specific to the [sign\_raw\_payload](/api-reference/signing/sign-raw-payload) endpoint. A valid encoding needs to be passed so that Turnkey can properly sign the requested message. Troubleshooting tips: * Use a valid encoding scheme from the following: `PAYLOAD_ENCODING_HEXADECIMAL`, `PAYLOAD_ENCODING_TEXT_UTF8` ### invalid hash function Common causes: * This error is specific to the [sign\_raw\_payload](/api-reference/signing/sign-raw-payload) endpoint. A valid hash function needs to be passed so that Turnkey can properly hash and sign the requested message. Troubleshooting tips: * Use a valid hash function scheme from the following: `HASH_FUNCTION_NO_OP`, `HASH_FUNCTION_SHA256`, `HASH_FUNCTION_KECCAK256`, `HASH_FUNCTION_NOT_APPLICABLE` * More information about `HASH_FUNCTION_NO_OP` [here](/faq#what-does-hash_function_no_op-mean) * More information about `HASH_FUNCTION_NOT_APPLICABLE` [here](/faq#what-is-hash_function_not_applicable-and-how-does-it-differ-from-hash_function_no_op) ### invalid magic link template Common causes: * The email template provided for specific activities is invalid. Troubleshooting tips: * Read more about [bespoke email templates](/embedded-wallets/sub-organization-auth#bespoke-email-templates) * Reach out to Turnkey at [help@turnkey.com](mailto:help@turnkey.com)! ### failed to get email template contents Common causes: * There was an error getting the email template for an associated activity Troubleshooting tips: * Reach out to Turnkey at [help@turnkey.com](mailto:help@turnkey.com)! ### failed to unmarshal template variables Common causes: * There are invalid template variables used in your email template. Troubleshooting tips: * Read more about [bespoke email templates](/embedded-wallets/sub-organization-auth#bespoke-email-templates) * Reach out to Turnkey at [help@turnkey.com](mailto:help@turnkey.com)! ### authentication failed Common causes: * Turnkey was unable to authenticate the user based on the stamp provided. Troubleshooting tips: * Ensure that all proper authenticators and api-keys have been added to the organization. * Read more about how to create a stamp for a request [here](/developer-reference/api-overview/stamps) ### failed to load organizations Common causes: * A request is targeting an unknown organization ID. Troubleshooting tips: * Ensure that the passed organization ID in the request is valid. ### policy label must be unique Common causes: * A new policy that is to be created shares the same name as a different policy. Policy names must be unique, and names in general must be unique per resource, so that they can be properly identified. Troubleshooting tips: * Change the label/name that will be used for the new policy. * Delete the old policy. * Update the old policy to have a new name. ### invalid policy consensus Common causes: * An invalid consensus expression is passed. Troubleshooting tips: * Read more about policy structure [here](/concepts/policies/overview#policy-structure) ### invalid policy condition Common causes: * An invalid condition expression is passed. Troubleshooting tips: * Read more about policy structure [here](/concepts/policies/overview#policy-structure) ### quorum threshold must be non-zero integer Common causes: * Quorum is the required amount of approvals by [root quorum members](/concepts/users/root-quorum) needed for an action to take place within an organization. Troubleshooting tips: * When creating a sub-organization or updating the root quroum amount, use a non-zero positive integer. ### quorum users missing Common causes: * A user marked as part of the root quorum is missing from the set of users within an organization. This is a validation error that can occur when trying to delete a user that is part of the root quorum. Troubleshooting tips: * Before deleting the user, remove them from the root quroum using [Update Root Quorum](/api-reference/organizations/update-root-quorum) ### invalid api key expiration Common causes: * An invalid expiration time was passed in for an api key's expiration time parameter when using [Create API Key](/api-reference/api-keys/create-api-keys) Troubleshooting tips: * The `expirationSeconds` parameter is passed as string of seconds of how long the key should last. Any non-positive non-integer string will be considered invalid. ### missing parameter: user authenticator attestation Common causes: * An attestation parameter is not passed when performing a request regarding an authenticator. For example [Create Authenticators](/api-reference/authenticators/create-authenticators) Troubleshooting tips: * The attestation generated by the authenticator includes a new key pair, the challenge, and device metadata that is signed, read more about attestations [here](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API/Attestation_and_Assertion). * An example of getting the correct parameters needed to use the Create Authenticators endpoint can be found within our [react-components](https://github.com/tkhq/sdk/blob/main/examples/react-components/src/app/dashboard/page.tsx#L246-L276) SDK example ### invalid authenticator attestation Common causes: * An attestation parameter is not valid when performing a request regarding an authenticator. For example [Create Authenticators](/api-reference/authenticators/create-authenticators) Troubleshooting tips: * The attestation generated by the authenticator includes a new key pair, the challenge, and device metadata that is signed, read more about attestations [here](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API/Attestation_and_Assertion). * An example of getting the correct parameters needed to use the Create Authenticators endpoint can be found within our [react-components](https://github.com/tkhq/sdk/blob/main/examples/react-components/src/app/dashboard/page.tsx#L246-L276) SDK example ### missing parameter: user authenticator attestation auth data Common causes: * The attestation auth data parameter is not valid when performing a request regarding an authenticator. For example [Create Authenticators](/api-reference/authenticators/create-authenticators). This parameter is obtained as part of the attestation object. Troubleshooting tips: * An example of getting the correct parameters needed to use the Create Authenticators endpoint can be found within our [react-components](https://github.com/tkhq/sdk/blob/main/examples/react-components/src/app/dashboard/page.tsx#L246-L276) SDK example ### user has exceeded maximum authenticators Common causes: * Turnkey allows up to 10 authenticators per user. This is a hard resource limit. More information on resource limits [here](/concepts/resource-limits). Troubleshooting Tips: * Delete any unnecessary authenticators attached to a user. * Create a new user within the same organization and attach the authenicator to that user. ### user has exceeded maximum long-lived api keys Common causes: * Turnkey allows up to 10 long-lived api keys per user. This is a hard resource limit. More information on resource limits [here](/concepts/resource-limits). Troubleshooting Tips: * Delete any unnecessary long-lived API keys attached to a user. * Create a new user within the same organization and attach the API key to that user. ### user has exceeded maximum short-lived api keys Common causes: * Turnkey allows up to 10 short-lived api keys per user. This is a hard resource limit. More information on resource limits [here](/concepts/resource-limits). Short-lived API keys will automatically be deleted from an organization when they are expired. Troubleshooting Tips: * Delete any unnecessary short-lived API keys attached to a user. * Create a new user within the same organization and attach the API key to that user. ### missing wallet params Common causes: * Some wallet/wallet account parameters have been omitted when creating a sub-organization Troubleshooting tips: * Include all of the required parameters when creating a wallet during sub-organization creation. More info on the parameters [here](/api-reference/organizations/create-sub-organization). ### invalid path format Common causes: * This error occurs when an invalid path format parameter is passed to a request like [Create Wallet Accounts](/api-reference/wallets/create-wallet-accounts). Troubleshooting tips: * For now the path format must be: `PATH_FORMAT_BIP32`. ### invalid path Common causes: * An invalid path parameter is passed to a request like [Create Wallet Accounts](/api-reference/wallets/create-wallet-accounts). Paths cannot be reused within the same HD wallet. Troubleshooting tips: * The path is a string that is used to derive a new account within an HD wallet. A list of default paths per address format can be found [here](/concepts/wallets#hd-wallet-default-paths) * Paths cannot be reused within the same HD wallet. ### invalid address format Common causes: * An invalid address format parameter is passed to a request like [Create Wallet Accounts](/api-reference/wallets/create-wallet-accounts). Troubleshooting tips: * Turnkey offers a wide range of support for many ecosystems. A list of valid address formats can be found in the table [here](/concepts/wallets#address-formats-and-curves). * More about Turnkey and general ecosystem support can be found [here](/networks/framework). ### invalid curve Common causes: * An invalid curve parameter is passed to a request like [Create Wallet Accounts](/api-reference/wallets/create-wallet-accounts). Troubleshooting tips: * Before ecosystem level integrations Turnkey offers support on a curve level. This makes us extendable to any ecosystem that is based on a curve we support. A list of valid curve parameters can be found in the table [here](/concepts/wallets#address-formats-and-curves). * More about Turnkey and general ecosystem support can be found [here](/networks/framework). ### curve required Common causes: * The curve parameter is not passed to a request like [Create Wallet Accounts](/api-reference/wallets/create-wallet-accounts). Troubleshooting tips: * Before ecosystem level integrations Turnkey offers support on a curve level. This makes us extendable to any ecosystem that is based on a curve we support. A list of valid curve parameters can be found in the table [here](/concepts/wallets#address-formats-and-curves). * More about Turnkey and general ecosystem support can be found [here](/networks/framework). ### failed to parse transaction Common causes: * The unsignedTransaction payload cannot be decoded by the policy engine, it might have not been serlialized properly. Troubleshooting tips: * Try to decode the payload independently and see if it returns the expected result. * We've noticed that for EIP1559 transaction types, the go-ethereum [MarshalBinary()](https://pkg.go.dev/github.com/ethereum/go-ethereum/core/types#Transaction.MarshalBinary) function will include the R, S, V values which should not be present within the serialized payload. Try to reconstruct the RLP payload manually without the R, S, V values, see the example below: ```go package main import ( "encoding/hex" "fmt" "log" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" ) func main() { to := common.HexToAddress("0x...") txData := &types.DynamicFeeTx{ ChainID: big.NewInt(1), Nonce: 0, GasTipCap: big.NewInt(12344), GasFeeCap: big.NewInt(10010000000), Gas: 100000, To: &to, Value: big.NewInt(1), Data: hexDecode(""), AccessList: types.AccessList{}, // Optional } // RLP-encode only the fields included in the unsigned tx unsignedRLP := encodeUnsignedDynamicFeeTx(txData) // Prepend EIP-1559 type byte (0x02) serializedUnsigned := append([]byte{types.DynamicFeeTxType}, unsignedRLP...) fmt.Printf("Unsigned serialized tx: 0x%x\n", serializedUnsigned) } func encodeUnsignedDynamicFeeTx(tx *types.DynamicFeeTx) []byte { rlpInput := []interface{}{ tx.ChainID, tx.Nonce, tx.GasTipCap, tx.GasFeeCap, tx.Gas, tx.To, tx.Value, tx.Data, tx.AccessList, } out, err := rlp.EncodeToBytes(rlpInput) if err != nil { log.Fatalf("failed to encode RLP: %v", err) } return out } func hexDecode(input string) []byte { b, err := hex.DecodeString(input) if err != nil { log.Fatal(err) } return b } ``` ### No activity found with fingerprint. Consensus activities must target an existing activity by fingerprint Common causes: * This error occurs during the [Approve/Reject Activity](/api-reference/consensus/approve-activity) activity. The fingerprint parameter must be a fingerprint of a valid activity. Troubleshooting tips: * Confirm that a valid fingerprint of an activity that requires approval or rejection is passed as part of this activity. ### internal server error Common causes: * This error is thrown for a variety of internal server errors that are not due to user error. These activities will have an error id passed with them like: `internal server error (9fbfda54-7141-4192-ae72-8bac3512149a)` that can be used for troubleshooting. Troubleshooting tips: * Retry the activity. This could be a fluke case and the following activity could pass without failure. * If you think there is problem or if your service is degraded, please reach out to Turnkey [help@turnkey.com](mailto:help@turnkey.com) and provide the error id in the error message. # Introduction Source: https://docs.turnkey.com/developer-reference/api-overview/intro Turnkey's API is a remote procedure call (RPC) API. ## RPC/HTTP We chose RPC-over-HTTP for convenience and ease-of-use. Most of our users should be able to integrate with our API without a major re-architecture of their existing systems. Many client libraries are available to make requests to a RPC/HTTP API, across many languages. Turnkey will provide SDKs for the most popular programming languages. For other languages, a RPC/HTTP API ensures there is an easy integration path available via raw http clients. ## POST-only If you look at the [API reference](/api-reference/overview) you'll notice that all API calls to Turnkey are HTTP POST requests. Requests contain a POST body and a header with a digital signature over the POST body. We call this digital signature a [Stamp](/developer-reference/api-overview/stamps). Requests must be stamped by registered user credentials and verified by Turnkey's secure enclaves before they are processed. This ensures cryptographic integrity end-to-end which eliminates the ability for any party to modify a user's request. ### Queries and Submissions Turnkey's API is divided into 2 broad categories: queries and submissions. * Queries are read requests (e.g. `get_users`, `list_users`) * Submissions are requests to execute a workload (e.g. `create_policy`, `sign_transaction`, `delete_user`) ## Dive Deeper * Creating your first [Stamp](/developer-reference/api-overview/stamps) * Fetching data with [Queries](/developer-reference/api-overview/queries) * Executing workloads with [Submissions](/developer-reference/api-overview/submissions) # Queries Source: https://docs.turnkey.com/developer-reference/api-overview/queries Queries are read requests to Turnkey's API. Query URL paths are prefixed with `/public/v1/query`. Queries are not subject to enforcement of the policy engine. All users within an organization can read any data within the organization. Additionally, parent organizations have the ability to query data for all of their sub-organizations. # Stamps Source: https://docs.turnkey.com/developer-reference/api-overview/stamps Every request made to Turnkey must include a signature over the POST body attached as a HTTP header. Our secure enclave applications use this signature to verify the integrity and authenticity of the request. ### API Keys To create a valid, API key stamped request follow these steps: Sign the JSON-encoded POST body with your API key to produce a `signature` (DER-encoded) Hex encode the `signature` Create a JSON-encoded stamp: * `publicKey`: the public key of API key, note that only P-256 keys (API\_KEY\_CURVE\_P256) are currenlty supported * `signature`: the signature produced by the API key * `scheme`: `SIGNATURE_SCHEME_TK_API_P256` Base64URL encode the stamp Attach the encoded string to your request as a `X-Stamp` header Submit the stamped request to Turnkey's API ### WebAuthn To create a valid, Webauthn authenticator stamped request follow these steps: Compute the webauthn challenge by hashing the POST body bytes (JSON encoded) with SHA256. For example, if the POST body is `{"organization_id": "1234", "type": "ACTIVITY_TYPE_CREATE_API_KEYS", "params": {"for": "example"}`, the webauthn challenge is the string `7e8b4653fc7e51dc119cea031942f4693b4742ceca4dda269b925802b38b2147` Include the challenge amongst WebAuthn signing options. Refer to the existing stamper implementations in the [following section](#stampers)) for examples * Note that if you need to pass the challenge as bytes, you'll need to utf8-encode the challenge string (in JS, the challenge bytes will be `TextEncoder().encode("7e8b4653fc7e51dc119cea031942f4693b4742ceca4dda269b925802b38b2147")`) * Additional note for React Native contexts: the resulting string should then additionally be base64-encoded. See [implementation](https://github.com/tkhq/sdk/blob/b52db566e79a65eec8d8e7066053d6a3ac5f3943/packages/react-native-passkey-stamper/src/util.ts#L5-L10) Create a JSON-encoded stamp: * `credentialId`: the id of the webauthn authenticator * `authenticatorData`: the authenticator data produced by Webauthn assertion * `clientDataJson`: the client data produced by the Webauthn assertion * `signature`: the signature produced by the Webauthn assertion Attach the JSON-encoded stamp to your request as a `X-Stamp-Webauthn` header * Header names are case-insensitive (so `X-Stamp-Webauthn` and `X-Stamp-WebAuthn` are considered equivalent) * Unlike API key stamps, the format is just JSON; no base64URL encoding necessary! For example: `X-Stamp-Webauthn: {"authenticatorData":"UaQZ...","clientDataJson":"eyJ0...","credentialId":"Grf...","signature":"MEQ..."}` Submit the stamped request to Turnkey's API. If you would like your client request to be proxied through a backend, refer to the patterns mentioned [here](/authentication/passkeys/integration#proxying-signed-requests). An example application that uses this pattern can be found at wallet.tx.xyz (code [here](https://github.com/tkhq/demo-embedded-wallet/)) ### Stampers Our [JS SDK](https://github.com/tkhq/sdk) and [CLI](https://github.com/tkhq/tkcli) abstract request stamping for you. If you choose to use an independent client, you will need to implement this yourself. For reference, check out our implementations: Our CLI has a `--no-post` option to generate stamps without sending anything over the network. This is a useful tool should you have trouble with debugging stamping-related logic. A sample command might look something like: ```json turnkey request --no-post --host api.turnkey.com --path /api/v1/sign --body '{"payload": "hello from TKHQ"}' { "curlCommand": "curl -X POST -d'{\"payload\": \"hello from TKHQ\"}' -H'X-Stamp: eyJwdWJsaWNLZXkiOiIwMzI3YTUwMDMyZTZmMDYzMWQ1NjA1YjZhZGEzMmI3NzkwNzRmMzQ2ZTgxYjY4ZTEyODAxNjQwZjFjOWVlMDNkYWUiLCJzaWduYXR1cmUiOiIzMDQ0MDIyMDM2MjNkZWZkNjE4ZWIzZTIxOTk3MDQ5NjQwN2ViZTkyNDQ3MzE3ZGFkNzVlNDEyYmQ0YTYyNjdjM2I1ZTIyMjMwMjIwMjQ1Yjc0MDg0OGE3MmQwOGI2MGQ2Yzg0ZjMzOTczN2I2M2RiM2JjYmFkYjNiZDBkY2IxYmZiODY1NzE1ZDhiNSIsInNjaGVtZSI6IlNJR05BVFVSRV9TQ0hFTUVfVEtfQVBJX1AyNTYifQ' -v 'https://api.turnkey.com/api/v1/sign'", "message": "{\"payload\": \"hello from TKHQ\"}", "stamp": "eyJwdWJsaWNLZXkiOiIwMzI3YTUwMDMyZTZmMDYzMWQ1NjA1YjZhZGEzMmI3NzkwNzRmMzQ2ZTgxYjY4ZTEyODAxNjQwZjFjOWVlMDNkYWUiLCJzaWduYXR1cmUiOiIzMDQ0MDIyMDM2MjNkZWZkNjE4ZWIzZTIxOTk3MDQ5NjQwN2ViZTkyNDQ3MzE3ZGFkNzVlNDEyYmQ0YTYyNjdjM2I1ZTIyMjMwMjIwMjQ1Yjc0MDg0OGE3MmQwOGI2MGQ2Yzg0ZjMzOTczN2I2M2RiM2JjYmFkYjNiZDBkY2IxYmZiODY1NzE1ZDhiNSIsInNjaGVtZSI6IlNJR05BVFVSRV9TQ0hFTUVfVEtfQVBJX1AyNTYifQ" } ``` # Submissions Source: https://docs.turnkey.com/developer-reference/api-overview/submissions Submissions are requests to securely execute a workload. Submission URL paths are prefixed with `/public/v1/submit`. Submissions requests, if valid, produce an `Activity`. ### Activities Activities typically create, modify, or utilize a resource within Turnkey and are subject to consensus or condition enforcement via the policy engine. Activities are executed optimistically synchronous. This means that if we can process the request synchronously, we will. Otherwise, we'll fallback to asynchronous processing. Your services or applications should account for this by checking the response for the activity state: * If `activity.status == ACTIVITY_STATUS_COMPLETED`, `activity.result` field will be populated with a successful response. * If `activity.status == ACTIVITY_STATUS_FAILED`, `activity.failure` field will be populated with a failure reason. * If `activity.status == ACTIVITY_STATUS_CONSENSUS_NEEDED`, additional signatures are required to process the request. * If `activity.status == ACTIVITY_STATUS_PENDING`, the request is processing asynchronously. You can get activity status updates by: * Re-submitting the request. See the notes on idempotency below. * Polling `get_activity` with the `activity.id` ### Idempotency The submission API is idempotent. For each request, the POST body is hashed into a fingerprint. Any two requests with the same fingerprint are considered the same request. If you resubmit the request, you'll get the same activity. If you want a new activity, you should modify the request timestamp `timestampMs` to produce a new fingerprint. # Using LLMs Source: https://docs.turnkey.com/developer-reference/using-llms ### Using AI to integrate Turnkey Turnkey documentation is now AI-enhanced. Whether you're using ChatGPT, Claude, or a custom LLM integration, we've made it easy to feed Turnkey docs directly into your models—and even easier to surface relevant answers programmatically or in your dev tools. #### LLM Feed Files To help LLMs stay current on how Turnkey works, we expose two continuously updated files for ingestion: * [`llms.txt`](https://docs.turnkey.com/llms.txt) - A concise, high-signal list of top-level docs pages, great for smaller models or quick context building. * [`llms-full.txt`](https://docs.turnkey.com/llms-full.txt) - A more exhaustive listing that includes nearly all pages, ideal for full-context indexing. You can regularly ingest these URLs into your custom GPTs or other LLM apps to ensure Turnkey-specific questions are grounded in accurate technical detail. #### Search Turnkey Docs with Mintlify MCP You can integrate our documentation with any Mintlify MCP-compatible client to perform contextual searches without leaving your development environment. To install and register the Turnkey MCP server, run: ```bash npx @mintlify/mcp@latest add turnkey-0e7c1f5b ``` On execution, you will see output similar to: ``` 🛠 Installing Tools: search Search across the Turnkey documentation to fetch relevant context for a given query ✔ Created new MCP server at ~/.mcp/turnkey-0e7c1f5b ? Select MCP client: › Use arrow keys to select. Return to submit. ❯ Cursor Windsurf Claude Desktop All To start the server, run: ``` ```bash node ~/.mcp/turnkey-0e7c1f5b/src/index.js ``` **Supported MCP Clients:** * Cursor * Windsurf * Claude Desktop * All #### Chat With Our Docs (Contextual Deep Links) We've enabled Mintlify's `contextual` feature across Turnkey's docs: * You can copy any Turnkey docs page as Markdown for reuse or embedding. * Even better: you can launch a chat session with Claude or ChatGPT preloaded with that specific page's context. This is perfect for troubleshooting, code generation, or just diving deeper into a topic with AI assistance. To enable this, we're using Mintlify's contextual param:\ [Learn more here.](https://mintlify.com/docs/settings/global#param-contextual) # Activity Webhooks Source: https://docs.turnkey.com/developer-reference/webhooks Webhooks provide a powerful mechanism to receive real-time notifications about activity requests in your Turnkey organization. Additionally, you'll be able to receive all activity requests for both the parent organization and all its child organizations. This functionality can be enabled via the organization feature capabilities of our platform, as detailed in the section on [organization features](/concepts/organizations#features). This guide is designed to walk you through the process of setting up webhooks, from environment preparation to verification of successful event capturing. ## Prerequisites Before diving into webhook configuration, ensure you have completed the necessary preliminary steps outlined in our [Quickstart Guide](/getting-started/quickstart#create-your-turnkey-organization). This guide will assist you in setting up a new organization and installing the Turnkey CLI. Note: We'll create a new API Key for testing webhooks below. ## Environment Setup Begin by setting the necessary environment variables: ```bash ORGANIZATION_ID=KEY_NAME=webhook-test ``` ### API Key Generation Generate a new API key using the Turnkey CLI with the following command: ```bash turnkey generate api-key --organization $ORGANIZATION_ID --key-name $KEY_NAME ``` ### Ngrok Installation and Setup Ngrok is a handy tool that allows you to expose your local server to the internet. Follow these steps to set it up: Download Ngrok from [their website](https://ngrok.com/download). Follow the provided instructions to install Ngrok and configure your auth token. ### Local Server Setup Open a new terminal window and set up a local server to listen for incoming webhook events: ```bash nc -l 8000 ``` ### Ngrok Tunneling In another terminal, initiate Ngrok to forward HTTP requests to your local server: ```bash ngrok http 8000 ``` Here's an output of the above command: ```bash Session Status online Account Satoshi Nakamoto (Plan: Free) Update update available (version 3.7.0, Ctrl-U to update) Version 3.6.0 Region United States (us) Latency 22ms Web Interface http://127.0.0.1:4041 Forwarding https://04b2-121-74-183-35.ngrok-free.app -> http://localhost:8000 Connections ttl opn rt1 rt5 p50 p90 0 0 0.00 0.00 0.00 0.00 ``` Save the ngrok URL as an environment variable: ```bash WEBHOOK_URL=https://04•••35.ngrok-free.app # Replace with the URL provided by ngrok ``` ### Verifying Ngrok Setup To ensure Ngrok is correctly forwarding requests, perform a test using curl: ```bash curl -X POST $WEBHOOK_URL -d "{}" ``` Example output: ```bash POST / HTTP/1.1 Host:04b2-121-74-183-35.ngrok-free.app User-Agent: curl/8.4.0 Content-Length: 2 Accept: */* Content-Type: application/x-www-form-urlencoded X-Forwarded-For: 195.88.127.47 X-Forwarded-Host: 04b2-121-74-183-35.ngrok-free.app X-Forwarded-Proto: https Accept-Encoding: gzip {} ``` After executing this command, you should see the request appear in the terminal where `nc` is running. Terminate the `nc` session by pressing CTRL+C and restart it by rerunning the `nc` command. ## Configuring the Webhook URL Set your webhook URL using the Turnkey CLI with the following command: ```bash turnkey request --path /public/v1/submit/set_organization_feature --body '{ "timestampMs": "'"$(date +%s)"'000", "type": "ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE", "organizationId": "'"$ORGANIZATION_ID"'", "parameters": { "name": "FEATURE_NAME_WEBHOOK", "value": "'"$WEBHOOK_URL"'" } }' --key-name=$KEY_NAME ``` ### Testing Your Webhook Assuming the previous request executed successfully it's time to test out your webhook! In order to verify that your webhook is correctly configured and receiving data, we can simply execute the previous turnkey request command again which creates a new activity request that will be captured by your webhook. Monitor the terminal with `nc` running to observe the incoming webhook data. ## Conclusion By following these steps, you should now have a functioning webhook setup that captures all activity requests for your organization and its sub-organizations. If you encounter any issues or have feedback about this feature, reach out on [slack](https://join.slack.com/t/clubturnkey/shared_invite/zt-31v4yhgw6-PwBzyNsWCCBTk2xft3EoHQ)! # Add an Additional Passkey Source: https://docs.turnkey.com/embedded-wallets/code-examples/add-credential This guide demonstrates how to add a new credential (specifically, a passkey) to an existing wallet using the Turnkey SDK. ### Initialize the Passkey Client Begin by initializing the Turnkey SDK by passing in a config object containing: * `rpId`: The [Relying Party](https://developer.mozilla.org/en-US/docs/Glossary/Relying_party) Identifier, which is the effective domain of your application. * `apiBaseUrl`: The base URL of the Turnkey API: `https://api.turnkey.com` * `defaultOrganizationId`: Your parent organization ID, which you can find in the [Turnkey dashboard](https://app.turnkey.com/dashboard). The `rpId` is used in WebAuthn to uniquely identify the server that the passkey is associated with. The `rpId` is typically the effective domain of the web application, which is the domain portion of the URL without any subdomains. For example, if your application is hosted at `app.example.com`, the `rpId` would typically be `example.com`. This ensures that credentials are scoped to the correct domain and cannot be used by other domains, enhancing security. First, wrap your application with the `TurnkeyProvider` in your `app/layout.tsx` file: ```ts app/layout.tsx import { TurnkeyProvider } from "@turnkey/sdk-react"; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( {children} ); } ``` Then, create a new file `app/add-passkey.tsx` where we'll implement the passkey functionality: ```tsx app/add-passkey.tsx "use client"; import { useState } from "react"; import { useTurnkey } from "@turnkey/sdk-react"; export default function AddPasskey() { const { passkeyClient } = useTurnkey(); // We'll add more functionality here in the following steps return
{/* We'll add UI elements here */}
; } ```
Create a new file `src/add-passkey.ts`: ```ts src/add-passkey.ts import { Turnkey } from "@turnkey/sdk-browser"; // Initialize the Turnkey SDK with your organization credentials const turnkey = new Turnkey({ rpId: process.env.TURNKEY_RP_ID, // Your relying party ID apiBaseUrl: process.env.TURNKEY_API_BASE_URL, // Turnkey API base URL defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, // Your parent organization ID }); // Initialize the Passkey Client const passkeyClient = turnkey.passkeyClient(); // We'll add more functionality here in the following steps ```
### Authenticate the User Now that that the Passkey Client is initialized, we'll call the `login` function which will prompt the user to authenticate with their passkey. Additionally, this function will set the current user in local storage upon successful authentication, which will be used later when creating an additional authenticator. The user object which gets stored in local storage is defined as follows: ``` export interface User { userId: string; username: string; organization: SubOrganization; readOnlySession?: ReadOnlySession; } ``` ```tsx app/add-passkey.tsx // ... previous code export default function AddPasskey() { // We'll need the base Turnkey client to get the current user const { passkeyClient, turnkey } = useTurnkey(); // ... previous code const getUser = async () => { // Get the current user from local storage, // we'll need the `userId` to create the authenticator in the next step const user = await turnkey?.getCurrentUser(); if (user) { console.log("User retrieved successfully"); } // return the user to be used in the next step return user; }; return (
); } ```
```ts src/add-passkey.ts // ... previous code const login = async () => { const response = await passkeyClient.login(); if (response.organizationId) { console.log("User authenticated successfully"); } else { console.log("User authentication failed"); } }; ```
### Get the current user Before creating a new passkey, we'll get the current user. This function will retrieve the user from local storage, which was set after calling the `login` function. We'll need the `userId` to create the authenticator in the final step. ```ts app/add-passkey.tsx // ... previous code export default function AddPasskey() { // We'll need the base Turnkey client to get the current user const { passkeyClient, turnkey } = useTurnkey(); // ... previous code const getUser = async () => { // Get the current user from local storage, // we'll need the `userId` to create the authenticator in the next step const user = await turnkey?.getCurrentUser(); if (user) { console.log("User retrieved successfully"); } // return the user to be used in the next step return user; }; return (
); } ```
```ts src/add-passkey.ts // ... previous code const getCurrentUser = async () => { // Get the current user from local storage, // we'll need the `userId` to create the authenticator in the next step const user = await turnkey?.getCurrentUser(); if (user) { console.log("User retrieved successfully"); } // return the user to be used in the next step return user; }; ```
### Create User Passkey Now that you have authenticated the user, you can call the `createUserPasskey` function to create a new user passkey credential. Calling this method will prompt the user to create a passkey, which will be securely stored by their browser. This credential will be associated with the user's account and used for future authentication. Once the credential is created, we'll use it in the next step to create a new authenticator for the user. The credential includes an encoded challenge and attestation. The encoded challenge ensures the request is fresh and legitimate, while the attestation verifies the authenticity of the device creating the credential. For more information on how passkeys work, including details on the challenge and attestation objects, you can refer to the [Passkeys Documentation](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API#passkeys). ```tsx app/add-passkey.tsx // ... previous code export default function AddPasskey() { const { passkeyClient } = useTurnkey(); // ... previous code // We'll pass the user object returned from `getUser` to this function const createNewPasskey = async (user: User) => { const credential = await passkeyClient?.createUserPasskey({ publicKey: { // This is the name of the passkey that will be displayed to the user rp: { name: "Wallet Passkey", }, user: { // We can use the username as the name and display name name: user.username, displayName: user.username, }, }, }); // we'll use this credential in the next step to create a new authenticator return credential; }; return (/* ... */); } ``` ```ts src/add-passkey.ts // ... previous code // We'll pass the user object returned from `getUser` to this function const createNewPasskey = async (user: User) => { const credential = await passkeyClient?.createUserPasskey({ publicKey: { // This is the name of the passkey that will be displayed to the user rp: { name: "Wallet Passkey", }, user: { // We can use the username as the name and display name name: user.username, displayName: user.username, }, }, }); // we'll use this credential in the next step to create a new authenticator return credential; }; ``` ### Add the credential to the wallet Now that you have created a new user passkey credential, we'll use this credential to create a new passkey authenticator for the user. We'll need the userId to create the authenticator, so we'll get the current user first. This value comes from local storage which was set in the previous step when the user successfully authenticated via the `login` function. ```tsx app/add-passkey.tsx // ... previous code export default function AddPasskey() { const { passkeyClient, turnkey } = useTurnkey(); // ... previous code const addPasskey = async () => { const user = await getUser(); const credential = await createNewPasskey(user); const authenticatorsResponse = await passkeyClient.createAuthenticators({ authenticators: [ { authenticatorName: "New Passkey Authenticator", challenge: credential.encodedChallenge, attestation: credential.attestation, }, ], userId: user.userId, }); // Check if the authenticator was created successfully if (authenticatorsResponse?.activity.id) { console.log("Authenticator created successfully"); } }; return (
{/* Add a button to add the passkey to the wallet */}
); } ``` ```tsx app/add-passkey.tsx "use client"; import { useState } from "react"; import { useTurnkey } from "@turnkey/sdk-react"; export default function AddPasskey() { const { passkeyClient, turnkey } = useTurnkey(); const login = async () => { const response = await passkeyClient?.login(); if (response.organizationId) { console.log("User authenticated successfully"); } else { console.log("User authentication failed"); } }; const getUser = async () => { const user = await turnkey?.getCurrentUser(); if (user) { console.log("User retrieved successfully"); } return user; }; const createNewPasskey = async (user: User) => { const credential = await passkeyClient?.createUserPasskey({ publicKey: { rp: { name: "Wallet Passkey", }, user: { name: user.username, displayName: user.username, }, }, }); return credential; }; const addPasskey = async () => { const user = await getUser(); const credential = await createNewPasskey(user); const authenticatorsResponse = await passkeyClient.createAuthenticators({ authenticators: [ { authenticatorName: "New Passkey Authenticator", challenge: credential.encodedChallenge, attestation: credential.attestation, }, ], userId: user.userId, }); if (authenticatorsResponse?.activity.id) { console.log("Authenticator created successfully"); } }; return (
); } ```
```ts src/add-passkey.ts // ... previous code const addPasskey = async () => { const user = await getUser(); const credential = await createNewPasskey(user); // Check if the credential was created successfully if (!credential) { console.log("Credential not created"); return; } const authenticatorsResponse = await passkeyClient.createAuthenticators({ authenticators: [ { authenticatorName: "New Passkey Authenticator", challenge: credential.encodedChallenge, attestation: credential.attestation, }, ], userId: user.userId, }); // Check if the authenticator was created successfully if (authenticatorsResponse?.activity.id) { console.log("Authenticator created successfully"); } }; ```
### Optional: Read/Write Sessions In some cases, you may want to create a read/write session for the user to reduce the number of passkey prompts. This session can be used instead of the passkey to sign requests to Turnkey's API to improve the user experience. In the this tutorial we used the passkey to authenticate the request to create a new authenticator. The result is that the user will be prompted 3 times: 1. To login 2. To create the new passkey 3. To authenticate the request to create a new authenticator By creating a read/write session, we can reduce the number of passkey prompts to 2: 1. To login and create a session 2. To authenticate the request to create a new authenticator To create a read/write session, we simply replace `passkeyClient.login()` with `passkeyClient.loginWithReadwriteSession()`: ```ts src/add-passkey.ts // ... previous code const login = async () => { const response = await passkeyClient.loginWithReadwriteSession(); // ... previous code }; ``` Assuming the login is successful, a read/write session object will be stored in local storage. We'll use the stored session in conjunction with the iframe client to authenticate the create authenticator request. We'll use the active client returned from the `useTurnkey` hook which will be initialized with the read/write session. The rest of the code remains the same. ```tsx app/add-passkey.tsx // ... previous code export default function AddPasskey() { const { getActiveClient, turnkey } = useTurnkey(); // ... previous code const addPasskey = async () => { const user = await getUser(); const credential = await createNewPasskey(user); // Get the active client which returns the iframe client initialized with the read/write session const activeClient = await getActiveClient(); // Since we're using the read/write session this won't prompt the user const authenticatorsResponse = await activeClient.createAuthenticators({ // ... }); // ... rest of the code remains the same }; return (/* ... */); } ``` ##### 1. Initialize the iframe client We'll create a new function to initialize the iframe client and inject the read/write session. ```ts src/add-passkey.ts // ... previous code const getIframeClient = async () => { const iframeContainerId = "turnkey-auth-container-id"; const authIframeClient = await turnkey.iframeClient( document.getElementById(iframeContainerId), ); const readWriteSession = await turnkey?.getReadWriteSession(); if (readWriteSession) { const injected = await authIframeClient?.injectCredentialBundle( readWriteSession.authBundle, ); } return authIframeClient; }; ``` When using the TypeScript SDK, you'll need to ensure that the HTML element exists somewhere in the rendered DOM. ```
``` ##### 2. Update the `addPasskey` function We'll update the `addPasskey` function to use the iframe client to authenticate the request to create a new authenticator. ```ts src/add-passkey.ts // ... previous code const addPasskey = async () => { // ... previous code const iframeClient = await getIframeClient(); const authenticatorsResponse = await iframeClient.createAuthenticators({ // ... }); // ... rest of the code remains the same }; ``` ## Conclusion In this guide, we've walked through the process of adding a new credential to an existing wallet using the Turnkey SDK. By following these steps, you can improve the usability of your application by allowing users to create multiple authentication methods. This flexibility enables users to add a hardware security device like a Yubikey, or a native passkey via providers like iCloud keychain or 1Password, enhancing their overall experience with your application. For a complete example, check out our [demo embedded wallet](https://github.com/tkhq/demo-embedded-wallet/blob/main/src/components/add-passkey.tsx). # Authenticate a User with Email Source: https://docs.turnkey.com/embedded-wallets/code-examples/authenticate-user-email ```JavaScript import { Turnkey } from "@turnkey/sdk-browser"; const turnkey = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); ``` Note that the iframe client must be initialized with the dom element where the iframe will be injected. If you are using the [react-sdk](/sdks/react) you can import the `iframeClient` from the `useTurnkey()` hook without this step and the iframe dom element will be managed for you. Note that the `iframeClient` must be initialized before calling `emailAuth` because you need the `iframePublicKey` as a parameter to the `emailAuth` call. ```JavaScript import { Turnkey, TurnkeySDKBrowserConfig } from "@turnkey/sdk-browser"; const turnkeyConfig: TurnkeySDKBrowserConfig = {...}; const turnkey = new Turnkey(turnkeyConfig); const iframeContainerId = "turnkey-auth-iframe-container-id"; // ensure the HTML element exists somewhere in the rendered DOM
const iframeClient = await turnkey.iframeClient(document.getElementById(iframeContainerId)) ``` ```JavaScript await turnkey.serverSign( "emailAuth", [{ email: , targetPublicKey: iframeClient.iframePublicKey, organizationId: }] ) ``` If you need to lookup the user `subOrganizationId` by email, you can call the `getSubOrgIds` method with the `filterType` parameter set to `"EMAIL"` ```JavaScript const subOrgIds = await turnkey.serverSign( "getSubOrgIds", [{ filterType: "EMAIL", filterValue: }] ) const userSubOrganizationId = subOrgIds.organizationIds[0]; ``` ```JavaScript const authenticationResponse = await iframeClient.injectCredentialBundle(credentialBundle); if (authenticationResponse) { // user is authenticated and can perform actions from the `iframeClient` await iframeClient.login(); navigate("/authenticated-route"); } else { // credential bundle does not match emailed credential navigate("/not-authenticated-route"); } ``` ```JavaScript const currentUserSession = await turnkey.currentUserSession(); const walletsResponse = await currentUserSession.getWallets(); const walletName = walletsResponse.wallets[0].walletName; ``` ```JavaScript import { DEFAULT_ETHEREUM_ACCOUNTS } from "@turnkey/sdk-browser"; const newWalletResponse = await iframeClient.createWallet({ walletName: "New Wallet for User", accounts: DEFAULT_ETHEREUM_ACCOUNTS, }); ``` # Authenticate a User with a Passkey Credential Source: https://docs.turnkey.com/embedded-wallets/code-examples/authenticate-user-passkey ```tsx import { Turnkey } from "@turnkey/sdk-browser"; const turnkey = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); const passkeyClient = turnkey.passkeyClient(); ``` ```tsx const response = await passkeyClient.login(); if (response.organizationId) { navigate("/authenticated-route"); } else { navigate("/not-authenticated-route"); } ``` ```tsx const currentUserSession = await turnkey.currentUserSession(); const walletsResponse = await currentUserSession.getWallets(); const walletName = walletsResponse.wallets[0].walletName; ``` This will always prompt a user to confirm the action with their passkey credential ```tsx import { DEFAULT_ETHEREUM_ACCOUNTS } from "@turnkey/sdk-browser"; const newWalletResponse = await passkeyClient.createWallet({ walletName: "New Wallet for User", accounts: DEFAULT_ETHEREUM_ACCOUNTS, }); ``` # Create a User Passkey Session Source: https://docs.turnkey.com/embedded-wallets/code-examples/create-passkey-session A passkey session is an expiring session enabled by an initial passkey authentication. You could think of this as a "lightning mode" of sorts: creating a passkey session allows users to authenticate subsequent requests touch-free. Under the hood, this is powered by our [indexedDbStamper](/sdks/advanced/indexed-db-stamper). These sessions are enabled by creating a short-lived embedded API key in the browser, stored in localStorage, and cryptographically scoped to a public key generated by IndexedDB. By calling `loginWithPasskey()`, the SDK stores the session and active client in localStorage. The signing key material remains securely stored in the browser’s IndexedDB and is never extractable. Turnkey uses this public key to scope and encrypt the session to the appropriate user. ## Steps using `@turnkey/sdk-react` This process is made seamless by leveraging our [React package](/sdks/react). Read on for a non-React implementation below. ```js import { TurnkeyProvider } from "@turnkey/sdk-react"; const turnkeyConfig = { apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, rpId: process.env.RPID, }; ...
{/* Your app components */}
```
```js import { useTurnkey } from "@turnkey/sdk-react"; const { passkeyClient, indexedDbClient } = useTurnkey(); await indexedDbClient.init(); const publicKey = await indexedDbClient.getPublicKey(); await passkeyClient.loginWithPasskey({ publicKey, sessionType: "READ_WRITE", // or "READ_ONLY" expirationSeconds: 900, }); ``` ```js const { getActiveClient } = useTurnkey(); const client = await getActiveClient(); const whoami = await client.getWhoami({ organizationId: , }); ``` `getActiveClient()` returns the currently active client (e.g. IndexedDb-backed), refreshing automatically if needed.
## Alternative Steps (non-React) ```js import { Turnkey } from "@turnkey/sdk-browser"; const turnkey = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); const passkeyClient = turnkey.passkeyClient(); const indexedDbClient = turnkey.indexedDbClient(); await indexedDbClient.init(); ``` ```js const publicKey = await indexedDbClient.getPublicKey(); await passkeyClient.loginWithPasskey({ publicKey, sessionType: "SESSION_TYPE_READ_WRITE", // or "SESSION_TYPE_READ_ONLY" expirationSeconds: 900, }); ``` ```js const whoami = await turnkey.getWhoami({ organizationId: , }); ``` Once `loginWithPasskey` completes, the session is stored in localStorage and all requests are signed using the IndexedDb-backed keypair. # Create a Sub-Org with a Passkey User Source: https://docs.turnkey.com/embedded-wallets/code-examples/create-sub-org-passkey In this guide, we'll walk through the process of creating a new end user with a passkey. ## Overview Generally, these new users will take the form of a [Turnkey Sub-Organization](/concepts/sub-organizations). This process involves using the following Turnkey SDK packages: 1. [`@turnkey/sdk-server`](https://www.npmjs.com/package/@turnkey/sdk-server): Used on the server-side to leverage the parent organization's public/private API key pair to create the new user's sub-organization. 2. [`@turnkey/sdk-browser`](https://www.npmjs.com/package/@turnkey/sdk-browser): Used on the client-side to complete the email recovery process by adding an end-user passkey. 3. [`@turnkey/sdk-react`](https://www.npmjs.com/package/@turnkey/sdk-react): Used for Next.js applications to initialize the Turnkey SDK. The process of creating a new sub-organization is split between client-side and server-side operations to prevent exposing the parent organization's private API key. For a refresher on the relationship between your application's end users and Turnkey Sub-Organizations, see [this page](/embedded-wallets/overview#how-it-works) for more. ## Implementation ### Initialize the Turnkey SDK on the Browser Wrap the root layout of your application with the `TurnkeyProvider` providing the required configuration options. This allows you to use the Turnkey client throughout your app via the `useTurnkey()` hook. ```tsx app/layout.tsx import { TurnkeyProvider } from "@turnkey/sdk-react"; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( {children} ); } ``` The `NEXT_PUBLIC_ORGANIZATION_ID` should be set to the parent organization ID which can be found in the [Turnkey Dashboard](https://app.turnkey.com/dashboard). The `NEXT_PUBLIC_TURNKEY_RP_ID` should be set to your application's desired relying party ID; this is typically your domain, or localhost if developing locally. See [this page](/authentication/passkeys/options#rp) for more details. ```tsx src/turnkey.ts import { Turnkey } from "@turnkey/sdk-browser"; // Initialize the Turnkey SDK with your organization ID and API base URL const turnkeyBrowser = new Turnkey({ rpId: process.env.TURNKEY_RP_ID, apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); ``` The `TURNKEY_ORGANIZATION_ID` should be set to the parent organization ID which can be found in the [Turnkey Dashboard](https://app.turnkey.com/dashboard). The `TURNKEY_RP_ID` should be set to your application's desired relying party ID; this is typically your domain, or localhost if developing locally. See [this page](/authentication/passkeys/options#rp) for more details. ### Initialize the Passkey Client Next, we'll initialize the `passkeyClient`, which will enable your application to interact with passkeys. We add the `"use client"` directive to the Recovery component to as react hooks can only be used client-side. ```tsx app/create-suborg.tsx "use client"; import { useTurnkey } from "@turnkey/sdk-react"; export default function CreateSubOrganization() { const { passkeyClient } = useTurnkey(); return
{/* ... rest of the code */}
; } ```
```tsx src/create-suborg.ts import { Turnkey } from "@turnkey/sdk-browser"; // Initialize the Turnkey SDK with your organization credentials const turnkey = new Turnkey({ rpId: process.env.TURNKEY_RP_ID, // Your relying party ID apiBaseUrl: process.env.TURNKEY_API_BASE_URL, // Turnkey API base URL defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, // Your parent organization ID }); // Initialize the Passkey Client const passkeyClient = turnkey.passkeyClient(); // We'll add more functionality here in the following steps ```
### Create User Passkey In order to create a new passkey for a user, you can call the `createUserPasskey` SDK function. Calling this method will prompt the user to create a passkey, which will be securely stored by their browser. This credential will be associated with the user's account (sub-organization) and used for future authentication. Once the credential is created, we'll use it in the next step to create a new sub-organization that corresponds to the user. The result of `createUserPasskey` includes an encoded challenge and attestation. The encoded challenge ensures the request is fresh and legitimate, while the attestation verifies the authenticity of the device creating the credential. For more information on how passkeys work, including details on the challenge and attestation objects, you can refer to the [Passkeys Documentation](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API#passkeys). ```tsx app/create-suborg.tsx // ... previous code export default function CreateSubOrganization() { const { passkeyClient } = useTurnkey(); const createNewPasskey = async () => { const credential = await passkeyClient?.createUserPasskey({ publicKey: { // This is the name of the passkey that will be displayed to the user rp: { name: "Wallet Passkey", }, user: { // We can use the username as the name and display name name: "Default User Name", displayName: "Default User Name", }, }, }); // we'll use this credential in the next step to create a new sub-organization return credential; }; // ... rest of the code return (/* ... */); } ``` ```tsx src/create-suborg.ts // ... previous code const createNewPasskey = async () => { const credential = await passkeyClient?.createUserPasskey({ publicKey: { // This is the name of the passkey that will be displayed to the user rp: { name: "Wallet Passkey", }, user: { // We can use the username as the name and display name name: "Default User Name", displayName: "Default User Name", }, }, }); // we'll use this credential in the next step to create a new sub-organization return credential; }; ``` ### Initialize the Turnkey SDK on the Server Initialize the Turnkey SDK on the **server-side** using the `@turnkey/sdk-server` package. This allows you to use the parent organization's public/private API key pair to create sub-organizations. For Next.js, add the `"use server"` directive at the top of the file where you're initializing the Turnkey server client. This will ensure that the function is executed on the server-side and will have access to the server-side environment variables e.g. your parent organization's public/private API key pair. For more information on Next.js server actions, see the Next.js documentation on [Server Actions and Mutations](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations). ```tsx app/actions.ts "use server"; import { Turnkey } from "@turnkey/sdk-server"; // Initialize the Turnkey Server Client on the server-side const turnkeyServer = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY, apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }).apiClient(); ``` ```tsx src/turnkey.ts import { Turnkey } from "@turnkey/sdk-server"; // Initialize the Turnkey Server Client on the server-side const turnkeyServer = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY, apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }).apiClient(); ``` ### Create a Function for Sub-Org Creation Next we'll create a new function called `createSubOrganization` that will be used to create a new sub-organization from the server-side. This method will be called from the client-side with the end-user's details. We export the `createSubOrganization` server action to be called from the client-side. ```tsx app/actions.tsx import { DEFAULT_ETHEREUM_ACCOUNTS } from "@turnkey/sdk-browser"; // ... previous code type TAttestation = { credentialId: string; clientDataJson: string; attestationObject: string; transports: ( | "AUTHENTICATOR_TRANSPORT_BLE" | "AUTHENTICATOR_TRANSPORT_INTERNAL" | "AUTHENTICATOR_TRANSPORT_NFC" | "AUTHENTICATOR_TRANSPORT_USB" | "AUTHENTICATOR_TRANSPORT_HYBRID" )[]; }; export const createSubOrganization = async ( email: string, credential: string, attestation: string, ) => { const createSubOrgResponse = await turnkeyServer.createSubOrganization({ subOrganizationName: "My New Suborg", rootUsers: [ { userName: "Default User Name", userEmail: email, apiKeys: [], authenticators: [ { authenticatorName: "Default Passkey", challenge: challenge, attestation: attestation, }, ], oauthProviders: [], }, ], rootQuorumThreshold: 1, wallet: { walletName: "Default Wallet", accounts: DEFAULT_ETHEREUM_ACCOUNTS, }, }); return createSubOrgResponse; }; ``` ```tsx src/turnkey-server.ts /// ... previous code type TAttestation = { credentialId: string; clientDataJson: string; attestationObject: string; transports: ( | "AUTHENTICATOR_TRANSPORT_BLE" | "AUTHENTICATOR_TRANSPORT_INTERNAL" | "AUTHENTICATOR_TRANSPORT_NFC" | "AUTHENTICATOR_TRANSPORT_USB" | "AUTHENTICATOR_TRANSPORT_HYBRID" )[]; }; export const createSubOrganization = async ( email: string, credential: string, attestation: string, ) => { const createSubOrgResponse = await turnkeyServer.createSubOrganization({ subOrganizationName: "My New Suborg", rootUsers: [ { userName: "Default User Name", userEmail: email, apiKeys: [], authenticators: [ { authenticatorName: "Default Passkey", challenge: challenge, attestation: attestation, }, ], oauthProviders: [], }, ], rootQuorumThreshold: 1, wallet: { walletName: "Default Wallet", accounts: DEFAULT_ETHEREUM_ACCOUNTS, }, }); return createSubOrgResponse; }; ``` ### Complete Create Sub-Organization At this stage, we create the sub-organization using the **server-side** function we created in the previous step. ```tsx app/create-suborg.tsx import { createSubOrganization } from "./actions"; ``` ```tsx app/create-suborg.tsx // ... import { useForm } from "react-hook-form"; type TSubOrgFormData = { email: string; }; export default function CreateSubOrganization() { // ... // Use form handler for suborg creation const { register: subOrgFormRegister, handleSubmit: subOrgFormSubmit } = useForm(); // Maintain state const [createSubOrganizationResponse, setCreateSubOrganizationResponse] = useState(null); const createSubOrg = async (data: TSubOrgFormData) => { const { encodedChallenge: challenge, attestation } = await createNewPasskey(); const createSubOrganizationResponse = await createSubOrganization( data.email, challenge, attestation, ); setCreateSubOrganizationResponse(createSubOrganizationResponse); }; return (
{createSubOrganizationResponse ? (

You've created a sub-organization!

) : (
)}
); } ``` ```tsx "use client"; import { useState } from "react"; import { useTurnkey } from "@turnkey/sdk-react"; import { useForm } from "react-hook-form"; // Import the createSubOrganization server action import { createSubOrganization } from "./actions"; type TSubOrgFormData = { email: string; }; type TAttestation = { credentialId: string; clientDataJson: string; attestationObject: string; transports: ( | "AUTHENTICATOR_TRANSPORT_BLE" | "AUTHENTICATOR_TRANSPORT_INTERNAL" | "AUTHENTICATOR_TRANSPORT_NFC" | "AUTHENTICATOR_TRANSPORT_USB" | "AUTHENTICATOR_TRANSPORT_HYBRID" )[]; }; export default function CreateSubOrganization() { const { passkeyClient } = useTurnkey(); // Use form handler for suborg creation const { register: subOrgFormRegister, handleSubmit: subOrgFormSubmit } = useForm(); // Maintain state const [createSubOrganizationResponse, setCreateSubOrganizationResponse] = useState(null); const createNewPasskey = async () => { const credential = await passkeyClient?.createUserPasskey({ publicKey: { // This is the name of the passkey that will be displayed to the user rp: { name: "Wallet Passkey", }, user: { // We can use the username as the name and display name name: "Default User Name", displayName: "Default User Name", }, }, }); // we'll use this credential in the next step to create a new sub-organization return credential; }; const createSubOrg = async (data: TSubOrgFormData) => { const { encodedChallenge: challenge, attestation } = await createNewPasskey(); const createSubOrganizationResponse = await createSubOrganization( data.email, challenge, attestation, ); setCreateSubOrganizationResponse(createSubOrganizationResponse); }; return (
{createSubOrganizationResponse ? (

You've created a sub-organization!

) : (
)}
); } ```
```tsx app/create-suborg.tsx import { createSubOrganization } from "./turnkey-server"; ``` ```tsx src/turnkey.ts import { createSubOrganization } from "./turnkey-server"; // ... rest of the code const createSubOrganizationResponse = await createSubOrganization( email, attestation, challenge, ); ```
## Examples A few mini examples where sub-orgs are created with passkeys, see the following: # Create a User with Email Only Source: https://docs.turnkey.com/embedded-wallets/code-examples/create-user-email This example demonstrates how to create a sub organization using just an end-user's email: passkeys not required! Note that this flow does not require emails to be verified. ```JavaScript import { Turnkey } from "@turnkey/sdk-browser"; const turnkey = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); ``` ```JavaScript import { DEFAULT_ETHEREUM_ACCOUNTS } from "@turnkey/sdk-browser;" const subOrganizationConfig = { subOrganizationName: , rootUsers: [{ userName: , userEmail: , apiKeys: [], authenticators: [], oauthProviders: [] }], rootQuorumThreshold: 1, wallet: { walletName: , accounts: DEFAULT_ETHEREUM_ACCOUNTS } }; ``` ```JavaScript await turnkey.serverSign("createSubOrganization", [subOrganizationConfig]); ``` This is all that is needed to create a user without any authentication credential other than their email address, in the [login](/embedded-wallets/code-examples/authenticate-user-email) flow you can see how to then authenticate the user after their `subOrganization` is created. # Recover a User with Email Source: https://docs.turnkey.com/embedded-wallets/code-examples/email-recovery In this guide, we'll walk through the process of recovering a user using their email. Email Recovery is a legacy flow, now superseded by [Email Auth](/embedded-wallets/code-examples/authenticate-user-email), which can used to implement recovery flows and more. ## Overview This process involves using the following Turnkey SDK packages: 1. [`@turnkey/sdk-server`](https://www.npmjs.com/package/@turnkey/sdk-server): Used on the server-side to leverage the parent organization's public/private API key pair for initializing the email recovery. 2. [`@turnkey/sdk-browser`](https://www.npmjs.com/package/@turnkey/sdk-browser): Used on the client-side to complete the email recovery process by adding an end-user passkey. 3. [`@turnkey/sdk-react`](https://www.npmjs.com/package/@turnkey/sdk-react): Used for Next.js applications to initialize the Turnkey SDK. The email recovery process is split between client-side and server-side operations to prevent exposing the parent organization's private API key. For an in-depth understanding of the email recovery process at Turnkey, refer to our docs on [email recovery](/authentication/email#recovery-flow). ## Implementation ### Initialize the Turnkey SDKs Begin by initializing the Turnkey SDK with your organization ID and the Turnkey API's base URL on the **client-side**. Wrap the root layout of your application with the `TurnkeyProvider` providing the required configuration options. This allows you to use the Turnkey client throughout your app via the `useTurnkey()` hook. ```tsx app/layout.tsx import { TurnkeyProvider } from "@turnkey/sdk-react"; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( {children} ); } ``` The `NEXT_PUBLIC_ORGANIZATION_ID` should be set to the parent organization ID which can be found in the [Turnkey Dashboard](https://app.turnkey.com/dashboard). The `NEXT_PUBLIC_TURNKEY_RP_ID` should be set to your application's desired relying party ID; this is typically your domain, or localhost if developing locally. See [this page](/authentication/passkeys/options#rp) for more details. ```tsx src/turnkey.ts import { Turnkey } from "@turnkey/sdk-browser"; // Initialize the Turnkey SDK with your organization ID and API base URL const turnkeyBrowser = new Turnkey({ rpId: process.env.TURNKEY_RP_ID, apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); ``` The `TURNKEY_ORGANIZATION_ID` should be set to the parent organization ID which can be found in the [Turnkey Dashboard](https://app.turnkey.com/dashboard). The `TURNKEY_RP_ID` should be set to your application's desired relying party ID; this is typically your domain, or localhost if developing locally. See [this page](/authentication/passkeys/options#rp) for more details. #### Server-side Initialization Initialize the Turnkey SDK on the **server-side** using the `@turnkey/sdk-server` package. This allows you to use the parent organization's public/private API key pair to initialize the email recovery process securely. For Next.js, add the `"use server"` directive at the top of the file where you're initializing the Turnkey server client. This will ensure that the function is executed on the server-side and will have access to the server-side environment variables e.g. your parent organization's public/private API key pair. For more information on Next.js server actions, see the Next.js documentation on [Server Actions and Mutations](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations). ```tsx app/actions.ts "use server"; import { Turnkey } from "@turnkey/sdk-server"; // Initialize the Turnkey Server Client on the server-side const turnkeyServer = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY, apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }).apiClient(); ``` ```tsx src/turnkey.ts import { Turnkey } from "@turnkey/sdk-server"; // Initialize the Turnkey Server Client on the server-side const turnkeyServer = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY, apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }).apiClient(); ``` #### Initialize the Iframe Client Next, we'll initialize the `iframeClient` which will create a secure iframe within your application. The `iframeClient` must be initialized before beginning the user recovery process, as we'll need the iframe's public key as a parameter for the `initEmailRecovery` method. We add the `"use client"` directive to the Recovery component to as react hooks can only be used client-side. ```tsx app/recovery.tsx "use client"; import { useTurnkey } from "@turnkey/sdk-react"; export default function Recovery() { const { authIframeClient } = useTurnkey(); return
{/* ... rest of the code */}
; } ```
```ts src/turnkey.ts const iframeContainerId = "turnkey-recovery-iframe-container-id"; const authIframeClient = await turnkey.iframeClient( document.getElementById(iframeContainerId), ); ``` When using the TypeScript SDK, you'll need to ensure that the HTML element exists somewhere in the rendered DOM. ```html index.html
``` ### Create a Recovery Function Next we'll create a new function called `initEmailRecovery` that will be used to initialize the email recovery process on the server-side. This method will be called from the client-side with the user's email and the target public key from the iframe client. Calling the `initEmailRecovery` method will trigger an email sent to the user containing a credential bundle which will be used to authenticate the authIframeClient in the next step. We export the `initEmailRecovery` server action to be called from the client-side. ```tsx app/actions.ts // ... previous code export const initEmailRecovery = async ({ email, targetPublicKey, }: { email: string; targetPublicKey: string; }) => { const recoveryResponse = await turnkeyServer.initUserEmailRecovery({ email, targetPublicKey, }); return recoveryResponse; }; ``` ```tsx src/turnkey-server.ts export const initEmailRecovery = async ({ email, targetPublicKey, }: { email: string; targetPublicKey: string; }) => { const recoveryResponse = await turnkeyServer.initUserEmailRecovery({ email, targetPublicKey, }); return recoveryResponse; }; ``` ### Initialize Email Recovery At this stage, we initialize the email recovery process using the **server-side** function we created in the previous step. The user will need to paste the credential bundle they receive in their email into your app, which is then used to authenticate the `authIframeClient` via the `injectCredentialBundle` method. ```tsx app/recovery.tsx import { initEmailRecovery } from "./actions"; ``` ```tsx app/recovery.tsx // ... export default function Recovery() { // ... // Create a state variable for the user's email const [email, setEmail] = useState(""); return (
setEmail(e.target.value)} type="text" />
); } ```
```tsx app/recovery.tsx //... export default function Recovery() { // ... // We'll use this later to conditionally render the input for the credential bundle const [initRecoveryResponse, setInitRecoveryResponse] = useState(null); const initRecovery = async (email: string) => { // Call the initEmailRecovery server action const response = await initEmailRecovery({ email, targetPublicKey: authIframeClient?.iframePublicKey, }); if (response) { setInitRecoveryResponse(response); } }; return (
{/* */}
); } ```
```tsx app/recovery.tsx //... export default function Recovery() { // ... const [initRecoveryResponse, setInitRecoveryResponse] = useState(null); const [credentialBundle, setCredentialBundle] = useState(""); return (
{/* If we have initiated the recovery process we'll render an input for the user to paste their credential bundle they received in their email */} {initRecoveryResponse ? ( setCredentialBundle(e.target.value)} type="text" /> ) : ( setEmail(e.target.value)} type="text" /> )}
); } ``` ```ts "use client"; import { useState } from "react"; import { useTurnkey } from "@turnkey/sdk-react"; // Import the initEmailRecovery server action import { initEmailRecovery } from "./actions"; export default function Recovery() { const { authIframeClient } = useTurnkey(); // Create a state variable for the user's email const [email, setEmail] = useState(""); const [initRecoveryResponse, setInitRecoveryResponse] = useState(null); const [credentialBundle, setCredentialBundle] = useState(""); const initRecovery = async (email: string) => { // Call the initEmailRecovery server action const response = await initEmailRecovery({ email, targetPublicKey: authIframeClient?.iframePublicKey, }); if (response) { setInitRecoveryResponse(response); } }; return (
{/* If we have initiated the recovery process we'll render an input for the user to paste their credential bundle they received in their email */} {initRecoveryResponse ? ( setCredentialBundle(e.target.value)} type="text" /> ) : ( setEmail(e.target.value)} type="text" /> )}
); } ```
```tsx src/turnkey.ts import { initEmailRecovery } from "./turnkey-server"; // ... rest of the code const initRecoveryResponse = await initEmailRecovery({ email, targetPublicKey: authIframeClient?.iframePublicKey, }); // Inject the recovery bundle into the iframe client // The recovery bundle is the credential bundle that the user will receive in their email // The application will need to provide a way for the user to input this recovery bundle // by pasting it into the UI await authIframeClient.injectCredentialBundle(credentialBundle); ```
### Create User Passkey Next, we'll create a new passkey for the user and associate it with the email that was used in the recovery process. Assuming that the user has successfully received and entered their credential bundle, we generate a passkey to be used authenticate Turnkey requests. We'll add a new function called `completeRecovery` that will create a new passkey for the user which will be used in the final recovery step. ```ts app/recovery.tsx //...export default function Recovery() { //... // We'll use //... export default function Recovery() { //... // We'll use the useTurnkey hook to get the turnkey instance const { authIframeClient, turnkey } = useTurnkey(); const completeRecovery = async () => { const passkeyClient = await turnkey.passkeyClient(); const passkeyResponse = await passkeyClient?.createUserPasskey({ publicKey: { user: { name: email, displayName: email, }, }, }); }; return
{/* ... */}
; } ```
```tsx app/recovery.tsx //... export default function Recovery() { //... const completeRecovery = async () => {/* ... */*/}; return (
{/* ... */} {/* If we have the credential bundle, we'll render a button to complete the recovery process */} {credentialBundle ? ( ) : ( )}
); } ```
```ts src/turnkey.ts const completeRecovery = async () => { const passkeyClient = await turnkey.passkeyClient(); const passkeyResponse = await passkeyClient?.createUserPasskey({ publicKey: { user: { name: email, displayName: email, }, }, }); }; ```
### Complete Email Recovery Finally, we complete the email recovery process by passing the `encodedChallenge` and `attestation` from the passkey we previously created to the `recoverUser` method. This method will complete the email recovery process and if successful, will return a response containing the authenticator ID of the new passkey authenticator. ```ts app/recovery.tsx //... export default function Recovery() { // We'll use the useTurnkey hook to get the turnkey instance const { authIframeClient, turnkey } = useTurnkey(); const [initRecoveryResponse, setInitRecoveryResponse] = useState(null); const completeRecovery = async () => { const passkeyClient = await turnkey.passkeyClient(); const passkeyResponse = await passkeyClient?.createUserPasskey({ publicKey: { user: { name: email, displayName: email, }, }, }); // If we have the encodedChallenge and attestation, we can complete the recovery process if (passkeyResponse?.encodedChallenge && passkeyResponse?.attestation) { const response = await authIframeClient!.recoverUser({ organizationId: initRecoveryResponse?.activity.organizationId, userId: initRecoveryResponse.userId, authenticator: { // This should be set by the user to name their authenticator authenticatorName: "User Passkey", challenge: passkeyResponse.encodedChallenge, attestation: passkeyResponse.attestation, }, }); if (response) { console.log("User recovered successfully"); } } }; return (
{/* ... */} {/* If we have the credential bundle, we'll render a button to complete the recovery process */} {credentialBundle ? ( ) : ( )}
); } ``` ```ts app/recovery.tsx "use client"; import { useState } from "react"; import { useTurnkey } from "@turnkey/sdk-react"; // Import the initEmailRecovery server action import { initEmailRecovery } from "./actions"; export default function Recovery() { const { authIframeClient, turnkey } = useTurnkey(); // Create a state variable for the user's email const [email, setEmail] = useState(""); const [initRecoveryResponse, setInitRecoveryResponse] = useState(null); const [credentialBundle, setCredentialBundle] = useState(""); const initRecovery = async (email: string) => { // Call the initEmailRecovery server action const response = await initEmailRecovery({ email, targetPublicKey: authIframeClient?.iframePublicKey, }); if (response) { setInitRecoveryResponse(response); } }; const completeRecovery = async () => { const passkeyClient = await turnkey.passkeyClient(); const passkeyResponse = await passkeyClient?.createUserPasskey({ publicKey: { user: { name: email, displayName: email, }, }, }); // If we have the encodedChallenge and attestation, we can complete the recovery process if (passkeyResponse?.encodedChallenge && passkeyResponse?.attestation) { const response = await authIframeClient!.recoverUser({ organizationId: initRecoveryResponse?.activity.organizationId, userId: initRecoveryResponse.userId, authenticator: { // This should be set by the user to name their authenticator authenticatorName: "User Passkey", challenge: passkeyResponse.encodedChallenge, attestation: passkeyResponse.attestation, }, }); if (response) { console.log("User recovered successfully"); } } }; return (
{initRecoveryResponse ? ( setCredentialBundle(e.target.value)} type="text" /> ) : ( setEmail(e.target.value)} type="text" /> )} {credentialBundle ? ( ) : ( )}
); } ```
```ts src/turnkey.ts const completeRecovery = async () => { const passkeyClient = await turnkey.passkeyClient(); const passkeyResponse = await passkeyClient?.createUserPasskey({ publicKey: { user: { name: email, displayName: email, }, }, }); // If we have the encodedChallenge and attestation, we can complete the recovery process if (passkeyResponse?.encodedChallenge && passkeyResponse?.attestation) { const response = await authIframeClient!.recoverUser({ organizationId: initRecoveryResponse?.activity.organizationId, userId: initRecoveryResponse.userId, authenticator: { // This should be set by the user to name their authenticator authenticatorName: "User Passkey", challenge: passkeyResponse.encodedChallenge, attestation: passkeyResponse.attestation, }, }); if (response) { console.log("User recovered successfully"); } } }; ```
## Conclusion In this guide, we've walked through the process of recovering a user using their email using the Turnkey SDKs. By following these steps, you can implement email recovery in your application, providing users with a reliable way to regain access to their accounts or to onboard new users using only their email address. To remind, this is a legacy flow, if you intend to implement a fresh recovery mechanism please use [Email Auth](/embedded-wallets/code-examples/authenticate-user-email), which supports all activities, including adding new authenticators. # Export Wallet or Private Key Source: https://docs.turnkey.com/embedded-wallets/code-examples/export This is a guide to exporting your wallet or private key from Turnkey. For more information about the security of this flow, check out [Enclave secure channels](/security/enclave-secure-channels). ## Implementation guides Follow along with the Turnkey CLI, Embedded iframe, NodeJS, and Local Storage guides. ### CLI Install the latest version of Turnkey CLI to access the new import functionality. You can find detailed instructions for installation [here](https://github.com/tkhq/tkcli). #### Steps ```bash turnkey wallets export --name "New Wallet" -k --organization --export-bundle-output --host api.turnkey.com ``` * The `--export-bundle-output` flag (required) is the desired output file path for the “encrypted bundle” that will be returned by Turnkey. This bundle contains the encrypted key material. ```bash turnkey decrypt --export-bundle-input --organization --signer-quorum-key 04bce6666ca6c12e0e00a503a52c301319687dca588165b551d369496bd1189235bd8302ae5e001fde51d1e22baa1d44249f2de9705c63797316fc8b7e3969a665 --encryption-key-name >> "" ``` * The `--export-bundle-input` flag (required) is the filepath for the “encrypted bundle” (from the previous step) that will be decrypted. * The `--plaintext-output` flag (optional) is a filepath for the decrypted plaintext to be written to. * The `--signer-quorum-key` flag (optional) is the public key of Turnkey's signer enclave. This is a static value. * The `--encryption-key-name` flag (optional) is a local encryption key. This is required for import and export using the CLI. A new one can be generated using `turnkey generate encryption-key`. See `turnkey generate --help` for more details. Congrats! You've exported your wallet 🎉 #### Private Key support ```bash turnkey private-keys export --name "New Private Key" --encryption-key-name --organization --export-bundle-output --host api.turnkey.com ``` * The `--export-bundle-output` flag (required) is the desired output file path for the “encrypted bundle” that will be returned by Turnkey. This bundle contains the encrypted key material. ```bash turnkey decrypt --export-bundle-input --organization --signer-quorum-key 04bce6666ca6c12e0e00a503a52c301319687dca588165b551d369496bd1189235bd8302ae5e001fde51d1e22baa1d44249f2de9705c63797316fc8b7e3969a665 --encryption-key-name >> "" ``` * The `--export-bundle-input` flag (required) is the file path for the “encrypted bundle” (from the previous step) that will be decrypted. * The `--plaintext-output` flag (optional) is a filepath for the decrypted plaintext to be written to. * The `--signer-quorum-key` flag (optional) is the public key of Turnkey's signer enclave. This is a static value. * The `--solana-address` flag (optional) is the solana address corresponding to the private key you're exporting. This will export the private key in a format compatible with most solana wallets (e.g. phantom). If unset, the resulting private key will be plain hex. * The `--encryption-key-name` flag (optional) is a local encryption key. This is required for import and export using the CLI. A new one can be generated using `turnkey generate encryption-key`. See `turnkey generate --help` for more details. Congrats! You've exported your private key 🎉 #### Wallet Account support ```bash turnkey wallets accounts export --address "" -k --organization --export-bundle-output --host api.turnkey.com ``` * The `--export-bundle-output` flag (required) is the desired output file path for the “encrypted bundle” that will be returned by Turnkey. This bundle contains the encrypted key material. ```bash turnkey decrypt --export-bundle-input --organization --signer-quorum-key 04bce6666ca6c12e0e00a503a52c301319687dca588165b551d369496bd1189235bd8302ae5e001fde51d1e22baa1d44249f2de9705c63797316fc8b7e3969a665 --encryption-key-name >> "" ``` * The `--export-bundle-input` flag (required) is the file path for the “encrypted bundle” (from the previous step) that will be decrypted. * The `--plaintext-output` flag (optional) is a filepath for the decrypted plaintext to be written to. * The `--signer-quorum-key` flag (optional) is the public key of Turnkey's signer enclave. This is a static value. * The `--solana-address` flag (optional) is the solana address corresponding to the private key you're exporting. This will export the private key in a format compatible with most solana wallets (e.g. phantom). If unset, the resulting private key will be plain hex. * The `--encryption-key-name` flag (optional) is a local encryption key. This is required for import and export using the CLI. A new one can be generated using `turnkey generate encryption-key`. See `turnkey generate --help` for more details. Congrats! You've exported your private key 🎉 ### Embedded iframe * We have released open-source code to create target encryption keys and decrypt exported wallet mnemonics. We've deployed a static HTML page hosted on `export.turnkey.com` meant to be embedded as an iframe element (see the code [here](https://github.com/tkhq/frames)). This ensures the mnemonics are encrypted to keys that the user has access to, but that your organization does not (because they live in the iframe, on a separate domain). * We have also built a package to help you insert this iframe and interact with it in the context of export: [`@turnkey/iframe-stamper`](https://www.npmjs.com/package/@turnkey/iframe-stamper) In the rest of this guide we'll assume you are using these helpers. #### Steps Here's a diagram summarizing the wallet export flow step-by-step ([direct link](/assets/files/wallet_export_steps-5bb19c72eb9596fab8db3b1dcc52e60a.png)): wallet export steps Let's review these steps in detail: When a user on your application clicks "export", display a new export UI. We recommend setting this export UI as a new hosted page of your application that contains language explaining the security best practices users should follow once they've successfully exported their wallet. Remember: once the wallet has been exported, Turnkey can no longer ensure its security. While the UI is in a loading state, your application uses [`@turnkey/iframe-stamper`](https://www.npmjs.com/package/@turnkey/iframe-stamper) to insert a new iframe element: ```ts const iframeStamper = new IframeStamper({ iframeUrl: "https://export.turnkey.com", // Configure how the iframe element is inserted on the page iframeContainer: yourContainer, iframeElementId: "turnkey-iframe", }); // Inserts the iframe in the DOM. This creates the new encryption target key const publicKey = await iframeStamper.init(); // Set state to not display iframe let displayIframe = "none"; return ( // The iframe element can be hidden until the wallet is exported
); ``` Your code receives the iframe public key. Your application prompts the user to sign a new `EXPORT_WALLET` activity with the wallet ID and the iframe public key in the parameters. Your application polls for the activity response, which contains an export bundle. Remember: this export bundle is an encrypted mnemonic which can only be decrypted within the iframe. Need help setting up async polling? Checkout our guide and helper [here](https://github.com/tkhq/sdk/tree/main/packages/http#withasyncpolling-helper). Your application injects the export bundle into the iframe for decryption and displays the iframe upon success: ```ts // Inject export bundle into iframe let success = await iframeStamper.injectWalletExportBundle(exportBundle); if (success !== true) { throw new Error("unexpected error while injecting export bundle"); } // If successfully injected, update the state to display the iframe iframeDisplay = "block"; ``` Export is complete! The iframe now displays a sentence of words separated by spaces. wallet mnemonic The exported wallet will remain stored within Turnkey’s infrastructure. In your Turnkey dashboard, the exported user Wallet will be flagged as “Exported”. #### Export as Private Keys Turnkey also supports exporting Wallet Accounts and Private Keys as private keys. ##### Wallet Accounts Follow the same steps above for exporting Wallets as mnemonics, but instead use the `EXPORT_WALLET_ACCOUNT` activity and the `injectKeyExportBundle` method from the [`@turnkey/iframe-stamper`](https://www.npmjs.com/package/@turnkey/iframe-stamper). You can pass an optional `keyFormat` parameter to `injectKeyExportBundle()` that will apply either hexadecimal or Solana-specific formatting to the private key that is exported in the iframe. The default key format is `HEXADECIMAL`, which is used by MetaMask, MyEtherWallet, Phantom, Ledger, and Trezor for Ethereum keys. For Solana keys, you will need to pass the `SOLANA` key format. ##### Private Keys Follow the same steps above for exporting Wallets as mnemonics, but instead use the `EXPORT_PRIVATE_KEY` activity and the `injectKeyExportBundle` method from the [`@turnkey/iframe-stamper`](https://www.npmjs.com/package/@turnkey/iframe-stamper). You can pass an optional `keyFormat` parameter to `injectKeyExportBundle()` that will apply either hexadecimal or Solana-specific formatting to the private key that is exported in the iframe. The default key format is `HEXADECIMAL`, which is used by MetaMask, MyEtherWallet, Phantom, Ledger, and Trezor for Ethereum keys. For Solana keys, you will need to pass the `SOLANA` key format. private key export At the end of a successful private key export, the iframe displays a private key. ### NodeJS A full example Node script can be found here: [https://github.com/tkhq/sdk/tree/main/examples/export-in-node](https://github.com/tkhq/sdk/tree/main/examples/export-in-node) #### Steps ```ts import { Turnkey } from "@turnkey/sdk-server"; import { generateP256KeyPair, decryptExportBundle } from "@turnkey/crypto"; ... const turnkeyClient = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPublicKey: process.env.API_PUBLIC_KEY!, apiPrivateKey: process.env.API_PRIVATE_KEY!, defaultOrganizationId: process.env.ORGANIZATION_ID!, }); ``` ```ts const keyPair = generateP256KeyPair(); const privateKey = keyPair.privateKey; const publicKey = keyPair.publicKeyUncompressed; ``` ```ts const exportResult = await turnkeyClient.apiClient().exportWallet({ walletId: walletId, targetPublicKey: publicKey, }); ``` ```ts const decryptedBundle = await decryptExportBundle({ exportBundle: exportResult.exportBundle, embeddedKey: privateKey, organizationId, returnMnemonic: true, }); ``` Congrats! You've exported your wallet 🎉 The process is largely similar for both private keys and individual wallet accounts. #### Private Key support ```ts import { Turnkey } from "@turnkey/sdk-server"; import { generateP256KeyPair, decryptExportBundle } from "@turnkey/crypto"; ... const turnkeyClient = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPublicKey: process.env.API_PUBLIC_KEY!, apiPrivateKey: process.env.API_PRIVATE_KEY!, defaultOrganizationId: process.env.ORGANIZATION_ID!, }); ``` ```ts const keyPair = generateP256KeyPair(); const privateKey = keyPair.privateKey; const publicKey = keyPair.publicKeyUncompressed; ``` ```ts const exportResult = await turnkeyClient.apiClient().exportPrivateKey({ privateKeyId: privateKeyId, targetPublicKey: publicKey, }); ``` ```ts const decryptedBundle = await decryptExportBundle({ exportBundle: exportResult.exportBundle, embeddedKey: privateKey, organizationId, returnMnemonic: false, keyFormat: "HEXADECIMAL", // optionally specify a key format. Defaults to hexadecimal, but use `SOLANA` to export a private key for use in Solana wallets }); ``` Congrats! You've exported your private key 🎉 #### Wallet Account support ```ts import { Turnkey } from "@turnkey/sdk-server"; import { generateP256KeyPair, decryptExportBundle } from "@turnkey/crypto"; ... const turnkeyClient = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPublicKey: process.env.API_PUBLIC_KEY!, apiPrivateKey: process.env.API_PRIVATE_KEY!, defaultOrganizationId: process.env.ORGANIZATION_ID!, }); ``` ```ts const keyPair = generateP256KeyPair(); const privateKey = keyPair.privateKey; const publicKey = keyPair.publicKeyUncompressed; ``` ```ts const exportResult = await turnkeyClient.apiClient().exportWalletAccount({ address: address, // your specific wallet account address targetPublicKey: publicKey, }); ``` ```ts const decryptedBundle = await decryptExportBundle({ exportBundle: exportResult.exportBundle, embeddedKey: privateKey, organizationId, returnMnemonic: false, keyFormat: "HEXADECIMAL", // optionally specify a key format. Defaults to hexadecimal, but use `SOLANA` to export a private key for use in Solana wallets }); ``` Congrats! You've exported your wallet account 🎉 ### Local Storage If you do not have access to an iframe (e.g. in a mobile context) or would prefer not to use an iframe, using Local Storage is an alternative method. Note that there are security considerations here due to the fact that anyone in control of your domain can access Local Storage variables. #### Steps ```ts import { Turnkey } from "@turnkey/sdk-browser"; import { generateP256KeyPair, decryptExportBundle } from "@turnkey/crypto"; ... const turnkey = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); const passkeyClient = turnkey.passkeyClient(); ``` ```ts const embeddedKeyPair = generateP256KeyPair(); const embeddedPrivateKey = keyPair.privateKey; const embeddedPublicKey = keyPair.publicKeyUncompressed; ``` ```ts // Storage keys const STORAGE_KEYS = { EMBEDDED_PRIVATE_KEY: "@turnkey/embedded_private_key", EMBEDDED_PUBLIC_KEY: "@turnkey/embedded_public_key", }; await LocalStorage.setItem( STORAGE_KEYS.EMBEDDED_PRIVATE_KEY, embeddedPrivateKey ); // Note that the public key can always be derived separately via the `getPublicKey` from `@turnkey/crypto` await LocalStorage.setItem(STORAGE_KEYS.EMBEDDED_PUBLIC_KEY, embeddedPublicKey); ``` 4. Call export (Turnkey activity), using the embedded key as the target key for the `exportWallet` activity: ```ts const exportResult = await passkeyClient.exportWallet({ walletId, // desired wallet ID targetPublicKey: embeddedPublicKey, }); ``` ```ts const decryptedBundle = await decryptExportBundle({ exportBundle: exportResult.exportBundle, embeddedKey: embeddedPrivateKey, organizationId, // your organization ID (this may be a suborg) returnMnemonic: true, }); ``` ```ts await LocalStorage.removeItem( STORAGE_KEYS.EMBEDDED_PRIVATE_KEY, embeddedPrivateKey ); await LocalStorage.removeItem( STORAGE_KEYS.EMBEDDED_PUBLIC_KEY, embeddedPublicKey ); ``` Congrats! You've exported your wallet 🎉 The process is largely similar for both private keys and individual wallet accounts. #### Private Key support ```ts import { Turnkey } from "@turnkey/sdk-browser"; import { generateP256KeyPair, decryptExportBundle } from "@turnkey/crypto"; ... const turnkey = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); const passkeyClient = turnkey.passkeyClient(); ``` ```ts const keyPair = generateP256KeyPair(); const privateKey = keyPair.privateKey; const publicKey = keyPair.publicKeyUncompressed; ``` ```ts // Storage keys const STORAGE_KEYS = { EMBEDDED_PRIVATE_KEY: "@turnkey/embedded_private_key", EMBEDDED_PUBLIC_KEY: "@turnkey/embedded_public_key", }; await LocalStorage.setItem(STORAGE_KEYS.EMBEDDED_PRIVATE_KEY, privateKey); // Note that the public key can always be derived separately via the `getPublicKey` from `@turnkey/crypto` await LocalStorage.setItem(STORAGE_KEYS.EMBEDDED_PUBLIC_KEY, publicKey); ``` ```ts const exportResult = await passkeyClient.exportPrivateKey({ privateKeyId, // desired private key ID targetPublicKey: publicKey, }); ``` ```ts const decryptedBundle = await decryptExportBundle({ exportBundle: exportResult.exportBundle, embeddedKey: privateKey, organizationId, // your organization ID (this may be a suborg) returnMnemonic: false, // N/A as we're working with a private key, not a wallet keyFormat: "HEXADECIMAL", // optionally specify a key format. Defaults to hexadecimal, but use `SOLANA` to export a private key for use in Solana wallets }); ``` ```ts await LocalStorage.removeItem( STORAGE_KEYS.EMBEDDED_PRIVATE_KEY, embeddedPrivateKey ); await LocalStorage.removeItem( STORAGE_KEYS.EMBEDDED_PUBLIC_KEY, embeddedPublicKey ); ``` Congrats! You've exported your private key 🎉 #### Wallet Account support ```ts import { Turnkey } from "@turnkey/sdk-browser"; import { generateP256KeyPair, decryptExportBundle } from "@turnkey/crypto"; ... const turnkey = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); const passkeyClient = turnkey.passkeyClient(); ``` ```ts const keyPair = generateP256KeyPair(); const privateKey = keyPair.privateKey; const publicKey = keyPair.publicKeyUncompressed; ``` ```ts // Storage keys const STORAGE_KEYS = { EMBEDDED_PRIVATE_KEY: "@turnkey/embedded_private_key", EMBEDDED_PUBLIC_KEY: "@turnkey/embedded_public_key", }; await LocalStorage.setItem(STORAGE_KEYS.EMBEDDED_PRIVATE_KEY, privateKey); // Note that the public key can always be derived separately via the `getPublicKey` from `@turnkey/crypto` await LocalStorage.setItem(STORAGE_KEYS.EMBEDDED_PUBLIC_KEY, publicKey); ``` 4. Call export (Turnkey activity), using the embedded key as the target key for the `exportWalletAccount` activity: ```ts const exportResult = await passkeyClient.exportWalletAccount({ address, // your specific wallet account address targetPublicKey: publicKey, }); ``` ```ts const decryptedBundle = await decryptExportBundle({ exportBundle: exportResult.exportBundle, embeddedKey: privateKey, organizationId, // your organization ID (this may be a suborg) returnMnemonic: false, // N/A as we're working with a wallet account, not a wallet keyFormat: "HEXADECIMAL", // optionally specify a key format. Defaults to hexadecimal, but use `SOLANA` to export a private key for use in Solana wallets }); ``` ```ts await LocalStorage.removeItem( STORAGE_KEYS.EMBEDDED_PRIVATE_KEY, embeddedPrivateKey ); await LocalStorage.removeItem( STORAGE_KEYS.EMBEDDED_PUBLIC_KEY, embeddedPublicKey ); ``` Congrats! You've exported your wallet account 🎉 ## Solana notes Solana paths do not include an `index`. Creating a wallet account with an index specified could lead to unexpected behavior when exporting and importing into another wallet. When importing into a multichain wallet such as Phantom, see [this guide](https://help.phantom.app/hc/en-us/articles/12988493966227-What-derivation-paths-does-Phantom-wallet-support#:~:text=The%20addresses%20are%20grouped%20into,'%2F0'%2F0%2F0.) on matching private keys across Solana, Ethereum, and Polygon. ## UI customization Everything is customizable in the import iframe except the sentence of mnemonic words, which is minimally styled: the text is left-aligned and the padding and margins are zero. Here's an example of how you can configure the styling of the iframe. ```ts const iframeCss = ` iframe { box-sizing: border-box; width: 400px; height: 120px; border-radius: 8px; border-width: 1px; border-style: solid; border-color: rgba(216, 219, 227, 1); padding: 20px; } `; return (
); ``` # Import Wallet or Private Key Source: https://docs.turnkey.com/embedded-wallets/code-examples/import This is a guide to importing your wallet or private key into Turnkey. For more information about the security of this flow, check out [Enclave secure channels](/security/enclave-secure-channels). ## Implementation guides Follow along with the Turnkey CLI, Embedded iframe, NodeJS, and Local Storage guides. ### CLI Install the latest version of Turnkey CLI to access the new import functionality. You can find detailed instructions for installation [here](https://github.com/tkhq/tkcli). #### Steps ```bash turnkey generate encryption-key \ --organization $ORGANIZATION_ID \ --user $USER_ID \ --encryption-key-name demo-encryption-key ``` * The `--user` flag (required) is the id of the user importing the private key; this is required because the underlying encryption keys used for import are scoped to each user. * The `--encryption-key-name` flag is to specify a name for the encryption key. Note that an encryption key !== Turnkey API key; an encryption key is used exclusively for secure activities like import and export. ```bash turnkey wallets init-import \ --user $USER_ID \ --import-bundle-output "./import_bundle.txt" \ --key-name demo-api-key ``` * The `--import-bundle-output` (required) flag is the desired output file path for the “import bundle” that will be received from Turnkey. The “import bundle” contains the ephemeral public key generated by the Turnkey signer enclave for the specified user. The private key plaintext is encrypted to this public key in Step 2. * Reminder: The `--key-name` flag specifies the name of API key with which to interact with the Turnkey API service. This should be the name of a previously created key. If you do not have one, visit the quickstart guide for help creating one. ```bash turnkey encrypt \ --user $USER_ID \ --import-bundle-input "./import_bundle.txt" \ --plaintext-input /dev/fd/3 3<<<"$MNEMONIC_1" \ --encrypted-bundle-output "./encrypted_bundle.txt" \ --encryption-key-name demo-encryption-key ``` * The `--import-bundle-input` flag (required) is the desired input file path for the “import bundle”. * The `--plaintext-input` flag is the desired input file path for the private key plaintext. You can pass a filename here or feed the plaintext string directly into the standard input as shown above. * The `--encrypted-bundle-output` (required) flag is the desired output file path for the “encrypted bundle” that will be sent to Turnkey in Step 3. The “encrypted bundle” contains the ephemeral public key generated by the CLI as part of the shared secret computation with the Turnkey signer enclave. It also contains the ciphertext, which is the plaintext input encrypted by the Turnkey signer’s ephemeral public key. ```bash turnkey wallets import \ --user $USER_ID \ --name "demo key" \ --encrypted-bundle-input "./encrypted_bundle.txt" \ --key-name demo-api-key ``` * The `--encrypted-bundle-input` (required) flag is the desired input file path for the “encrypted bundle” that will be sent to Turnkey. * Options are listed [here](/concepts/wallets) for the `--curve` and `--address-format` flags. #### Private Key support Turnkey CLI also supports importing private keys. Follow the same steps as importing a wallet via CLI but use the `turnkey private-keys` commands instead. In Step 2 (`encrypt`), pass a `--key-format` flag for key-specific formatting; the options for private keys are: * `hexadecimal`: Used for Ethereum. Examples: `0x13eff5b3f9c63eab5d53cff5149f01606b69325496e0e98b53afa938d890cd2e, 13eff5b3f9c63eab5d53cff5149f01606b69325496e0e98b53afa938d890cd2e` * `solana`: Used for Solana. It’s a base58-encoding of the concatenation of the private key and public key bytes. Example: `2P3qgS5A18gGmZJmYHNxYrDYPyfm6S3dJgs8tPW6ki6i2o4yx7K8r5N8CF7JpEtQiW8mx1kSktpgyDG1xuWNzfsM` ```bash turnkey encrypt \ --import-bundle-input "./import_bundle.txt" \ --plaintext-input /dev/fd/3 3<<<"$RAW_KEY_1" \ --key-format “hexadecimal” \ --encrypted-bundle-output "./encrypted_bundle.txt" ``` ### Embedded iframe * We have released open-source code to create target encryption keys and encrypt wallet mnemonics for import. We've deployed a static HTML page hosted on `import.turnkey.com` meant to be embedded as an iframe element (see the code [here](https://github.com/tkhq/frames)). This ensures the mnemonics and keys are encrypted to keys that the user has access to, but that your organization does not (because they live in the iframe, on a separate domain). * We have also built a package to help you insert this iframe and interact with it in the context of import: [`@turnkey/iframe-stamper`](https://www.npmjs.com/package/@turnkey/iframe-stamper) In the rest of this guide we'll assume you are using these helpers. #### Steps Here's a diagram summarizing the wallet import flow step-by-step ([direct link](/assets/files/wallet_import_steps-6c4753c1e726e1632ce475bc838388c2.png)): wallet import steps Let's review these steps in detail: When a user on your application clicks "import", display a new import UI. We recommend setting this import UI as a new hosted page of your application that contains the iframe element that the user will enter their mnemonic into and an import button. While the UI is in a loading state, your application uses [`@turnkey/iframe-stamper`](https://www.npmjs.com/package/@turnkey/iframe-stamper) to insert a new iframe element: ```js const iframeStamper = new IframeStamper({ iframeUrl: "https://import.turnkey.com", // Configure how the iframe element is inserted on the page iframeContainer: yourContainer, iframeElementId: "turnkey-iframe", }); // Inserts the iframe in the DOM. await iframeStamper.init(); // Set state to not display iframe let displayIframe = "none"; return ( // The iframe element does not need to be displayed yet
); ``` Your application prompts the user to sign a new `INIT_IMPORT_WALLET` activity with the ID of the user importing the wallet. Your application polls for the activity response, which contains an import bundle. Need help setting up async polling? Checkout our guide and helper [here](https://github.com/tkhq/sdk/tree/main/packages/http#withasyncpolling-helper). Your application injects the import bundle into the iframe and displays the iframe upon success: ```js // Inject import bundle into iframe let success = await iframeStamper.injectImportBundle(importBundle); if (success !== true) { throw new Error("unexpected error while injecting import bundle"); } // If successfully injected, update the state to display the iframe iframeDisplay = "block"; ``` When a user clicks on the import button on your web page, your application can extract the encrypted mnemonic bundle from the iframe: ```js // Extract the encrypted bundle from the iframe let encryptedBundle = await iframeStamper.extractWalletEncryptedBundle(importBundle); ``` Your applications passes the encrypted bundle as a parameter in a new `IMPORT_WALLET` activity and prompts the user to sign it. Import is complete! In your Turnkey dashboard, the imported user Wallet will be flagged as “Imported”. ### NodeJS A full example Node script can be found here: [https://github.com/tkhq/sdk/tree/main/examples/import-in-node](https://github.com/tkhq/sdk/tree/main/examples/import-in-node) #### Steps ```ts import { Turnkey } from "@turnkey/sdk-server"; import { encryptPrivateKeyToBundle, encryptWalletToBundle, } from "@turnkey/crypto"; ... const turnkeyClient = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPublicKey: process.env.API_PUBLIC_KEY!, apiPrivateKey: process.env.API_PRIVATE_KEY!, defaultOrganizationId: process.env.ORGANIZATION_ID!, }); ``` ```ts const initResult = await turnkeyClient.apiClient().initImportWallet({ userId, }); ``` ```ts const walletBundle = await encryptWalletToBundle({ mnemonic, importBundle: initResult.importBundle, userId, organizationId, }); ``` ```ts const walletImportResult = await turnkeyClient.apiClient().importWallet({ userId: userId, walletName: "Your imported wallet!", encryptedBundle: walletBundle, accounts: [], // these are the wallet accounts you'd like to derive; after all, you've just imported a HD wallet! See https://learnmeabitcoin.com/technical/hd-wallets for more }); ``` Congrats! You've imported your wallet 🎉 #### Private Key support The process for importing a private key instead of wallet is largely similar, but has a key difference in that you must specify the format of your imported private key: ```js import { Turnkey } from "@turnkey/sdk-server"; import { encryptPrivateKeyToBundle, encryptWalletToBundle, } from "@turnkey/crypto"; ... const turnkeyClient = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", apiPublicKey: process.env.API_PUBLIC_KEY!, apiPrivateKey: process.env.API_PRIVATE_KEY!, defaultOrganizationId: process.env.ORGANIZATION_ID!, }); ``` ```js const initResult = await turnkeyClient.apiClient().initImportPrivateKey({ userId, }); ``` ```js const privateKeyBundle = await encryptPrivateKeyToBundle({ privateKey, keyFormat, importBundle: initResult.importBundle, userId, organizationId, }); ``` ```js const privateKeyImportResult = await turnkeyClient .apiClient() .importPrivateKey({ userId: userId, privateKeyName: "Your imported private key!", encryptedBundle: privateKeyBundle, curve: keyFormat == "SOLANA" ? "CURVE_ED25519" : "CURVE_SECP256K1", addressFormats: keyFormat == "SOLANA" ? ["ADDRESS_FORMAT_SOLANA"] : ["ADDRESS_FORMAT_ETHEREUM"], }); ``` Congrats! You've imported your private key 🎉 ### Local Storage If you do not have access to an iframe (e.g. in a mobile context) or would prefer not to use an iframe, you can opt to use other environment-agnostic methods to perform import using Turnkey libraries. So while this section is called Local Storage (for consistency with the [Export](/embedded-wallets/code-examples/export) guide), nothing is stored in Local Storage; instead, the relevant `encrypt{Wallet, PrivateKey}ToBundle` method uses an [ephemeral key](https://github.com/tkhq/sdk/blob/6b3ea14d1184c5394449ecaad2b0f445e373823f/packages/crypto/src/crypto.ts#L62-L70). #### Steps ```ts import { Turnkey } from "@turnkey/sdk-browser"; import { generateP256KeyPair, encryptWalletToBundle } from "@turnkey/crypto"; ... const turnkey = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); const passkeyClient = turnkey.passkeyClient(); ``` ```ts const initResult = await passkeyClient.initImportWallet({ userId, // your user ID }); ``` ```ts const walletBundle = await encryptWalletToBundle({ mnemonic, importBundle: initResult.importBundle, userId, // your user ID organizationId, // your organization ID }); ``` ```ts const walletImportResult = await passkeyClient.importWallet({ userId, // your user ID walletName: "Your imported wallet!", // your desired name for the resulting imported wallet encryptedBundle: walletBundle, accounts: [], // these are the wallet accounts you'd like to derive; after all, you've just imported a HD wallet! See https://learnmeabitcoin.com/technical/hd-wallets for more }); ``` Congrats! You've imported your wallet 🎉 The process for importing a private key instead of wallet is largely similar, but has a key difference in that you must specify the format of your imported private key: #### Private Key support ```ts import { Turnkey } from "@turnkey/sdk-browser"; import { generateP256KeyPair, encryptPrivateKeyToBundle } from "@turnkey/crypto"; ... const turnkey = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); const passkeyClient = turnkey.passkeyClient(); ``` ``` const initResult = await passkeyClient.initImportPrivateKey({ userId, // your user ID }); ``` ```ts const privateKeyBundle = await encryptPrivateKeyToBundle({ privateKey, // your private key string keyFormat, // your desired key format. See the Private Key notes section for more importBundle: initResult.importBundle, userId, // your user ID organizationId, // your organization ID }); ``` ```ts const privateKeyImportResult = await passkeyClient.importPrivateKey({ userId, privateKeyName: "Your imported private key!", // your desired name for the resulting imported private key encryptedBundle: privateKeyBundle, curve: keyFormat == "SOLANA" ? "CURVE_ED25519" : "CURVE_SECP256K1", addressFormats: keyFormat == "SOLANA" ? ["ADDRESS_FORMAT_SOLANA"] : ["ADDRESS_FORMAT_ETHEREUM"], }); ``` Congrats! You've imported your private key 🎉 ## Private Key notes Turnkey also supports importing Private Keys. Follow the same steps above for importing Wallets as mnemonics, but instead use the `INIT_IMPORT_PRIVATE_KEY` and `IMPORT_PRIVATE_KEY` activities and the `extractKeyEncryptedBundle` method from the [`@turnkey/iframe-stamper`](https://www.npmjs.com/package/@turnkey/iframe-stamper). You can pass an optional `keyFormat` to `extractKeyEncryptedBundle(keyFormat)` that will apply either `Hexadecimal` or `Solana` formatting to the private key that is entered in the iframe. The default key format is `hexadecimal`, which is used by MetaMask, MyEtherWallet, Phantom, Ledger, and Trezor for Ethereum keys. For Solana keys, you will need to pass the `solana` key format. ## UI customization Everything is customizable in the import iframe except the sentence of mnemonic words, which is minimally styled: the text is left-aligned and the padding and margins are zero. Here's an example of how you can configure the styling of the iframe. ```css const iframeCss = ` iframe { box-sizing: border-box; width: 400px; height: 120px; border-radius: 8px; border-width: 1px; border-style: solid; border-color: rgba(216, 219, 227, 1); padding: 20px; } `; return (
); ``` # Signing Transactions Source: https://docs.turnkey.com/embedded-wallets/code-examples/signing-transactions This is a guide to signing transactions in the browser context. While these snippets leverage Ethers, it can be swapped out for other signers in the Viem or Solana contexts. See [here](https://github.com/tkhq/sdk/tree/main/examples/with-eth-passkeys-galore) for an example with both Ethers and Viem in the passkey + browser context, and [here](https://github.com/tkhq/sdk/tree/main/examples/with-solana-passkeys) for a similar example with Solana. ## Steps using `@turnkey/sdk-react` This process is made the most seamless by leveraging our [React package](/sdks/react). Read on for a non-React implementation. ```js import { TurnkeyProvider } from "@turnkey/sdk-react"; const turnkeyConfig = { apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, // prefix with NEXT_PUBLIC for NextJS rpId: process.env.RPID, // your application's domain iframeUrl: "https://auth.turnkey.com" } ...
// Rest of app ...
```
```js import { ethers } from "ethers"; import { TurnkeySigner } from "@turnkey/ethers"; import { useTurnkey } from "@turnkey/sdk-react"; const { turnkey, passkeyClient } = useTurnkey(); const provider = new ethers.JsonRpcProvider(); const currentUser = await turnkey.getCurrentUser(); const turnkeySigner = new TurnkeySigner({ client: passkeyClient, organizationId: currentUser.organization.organizationId, signWith: "" }) const connectedSigner = turnkeySigner.connect(provider); ``` ```js const transactionRequest = { to: "", value: ethers.parseEther(""), type: 2, }; const sendTransaction = await connectedSigner.sendTransaction(transactionRequest); ```
## Alternative Steps (non-React) ```js import { Turnkey } from "@turnkey/sdk-browser"; const turnkey = new Turnkey({ apiBaseUrl: "https://api.turnkey.com", defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }); const passkeyClient = turnkey.passkeyClient(); ``` ``` import { ethers } from "ethers"; import { TurnkeySigner } from "@turnkey/ethers"; const provider = new ethers.JsonRpcProvider(); const currentUser = await turnkey.getCurrentUser(); // assumes user details have been stored in LocalStorage via `login()` const turnkeySigner = new TurnkeySigner({ client: passkeyClient, organizationId: currentUser.organization.organizationId, signWith: "" }) const connectedSigner = turnkeySigner.connect(provider); ``` ```js const transactionRequest = { to: "", value: ethers.parseEther(""), type: 2, }; const sendTransaction = await connectedSigner.sendTransaction(transactionRequest); ``` # Wallet Authentication Source: https://docs.turnkey.com/embedded-wallets/code-examples/wallet-auth In this guide, we'll explore how to leverage the `WalletClient` in the Turnkey SDK to authenticate requests to Turnkey's API using either Solana or Ethereum wallets. ## Initialize Begin by initializing the Turnkey SDK by passing in a config object containing: * `apiBaseUrl`: The base URL of the Turnkey API: `https://api.turnkey.com`. * `defaultOrganizationId`: Your parent organization ID, which you can find in the [Turnkey dashboard](https://app.turnkey.com/dashboard). * `wallet`: The wallet interface used to sign requests. In this example, we'll use the `EthereumWallet` interface. ```ts config.ts import { EthereumWallet } from "@turnkey/wallet-stamper"; export const turnkeyConfig = { // Turnkey API base URL apiBaseUrl: "https://api.turnkey.com", // Your parent organization ID defaultOrganizationId: process.env.NEXT_PUBLIC_ORGANIZATION_ID, // The wallet interface used to sign requests wallet: new EthereumWallet(), }; ``` First, wrap your application with the `TurnkeyProvider` in your `app/layout.tsx` file: ```tsx app/layout.tsx import { TurnkeyProvider } from "@turnkey/sdk-react"; import { turnkeyConfig } from "./config"; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( {/* Pass the Turnkey config defined above to the TurnkeyProvider */} {children} ); } ``` Then, create a new page component `app/page.tsx` where we'll implement the wallet authentication functionality: ```tsx app/page.tsx "use client"; import { useState } from "react"; import { useTurnkey } from "@turnkey/sdk-react"; export default function WalletAuth() { const { walletClient } = useTurnkey(); // We'll add more functionality here in the following steps return
{/* We'll add UI elements here */}
; } ```
Create a new file `src/wallet-auth.ts` where we'll implement the wallet authentication functionality: ```ts src/wallet-auth.ts import { Turnkey } from "@turnkey/sdk-browser"; import { EthereumWallet } from "@turnkey/wallet-stamper"; import { turnkeyConfig } from "./config"; // Initialize the Turnkey SDK with the config object defined above const turnkey = new Turnkey(turnkeyConfig); // Initialize the Wallet Client with the EthereumWallet interface const walletClient = turnkey.walletClient(new EthereumWallet()); // We'll add more functionality here in the following steps ```
## Sign Up In this section, we'll guide you through the process of implementing a sign-up flow using an Ethereum wallet for authentication. The sign-up process involves creating a new sub-organization within your existing organization. This requires authentication of the parent organization using its public/private key pair. Additionally, we'll cover how to verify if a user already has an associated sub-organization before proceeding. ### Server-side Initialize the Turnkey SDK on the **server-side** using the `@turnkey/sdk-server` package. This setup enables you to authenticate requests to Turnkey's API using the parent organization's public/private API key pair. This is required to create new sub-organizations on behalf of a user. For Next.js, add the `"use server"` directive at the top of the file where you're initializing the Turnkey server client. This will ensure that the function is executed on the server-side and will have access to the server-side environment variables e.g. your parent organization's public/private API key pair. For more information on Next.js server actions, see the Next.js documentation on [Server Actions and Mutations](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations). ```tsx app/actions.ts "use server"; import { Turnkey } from "@turnkey/sdk-server"; import { turnkeyConfig } from "./config"; const { apiBaseUrl, defaultOrganizationId } = turnkeyConfig; // Initialize the Turnkey Server Client on the server-side const turnkeyServer = new Turnkey({ apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY, apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY, apiBaseUrl, defaultOrganizationId, }).apiClient(); ``` ```ts src/wallet-auth-server.ts import { Turnkey } from "@turnkey/sdk-server"; import { turnkeyConfig } from "./config"; const { apiBaseUrl, defaultOrganizationId } = turnkeyConfig; // Initialize the Turnkey Server Client on the server-side const turnkeyServer = new Turnkey({ apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY, apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY, apiBaseUrl, defaultOrganizationId, }).apiClient(); ``` ### Check for Existing User Before signing up a new user, we can try and retrieve the user's sub-organization ID using the public key associated with the Ethereum or Solana account they want to authenticate with. If a sub-organization is found, we can proceed with authentication; otherwise, we assume the user is signing up. We'll use the `getPublicKey` method on the `WalletClient` instance which will retrieve the public key from the user's wallet. The main distinction between signing with an Ethereum Wallet and a Solana Wallet lies in how the public key is obtained. For Solana, the public key can be directly derived from the wallet. In contrast, with Ethereum, the secp256k1 public key isn't directly accessible. Instead, you need to first obtain a signature from the user and then recover the public key from that signature. This requires an additional step of signing a message with the user's Ethereum wallet before we can retrieve the public key. We'll define this function in the server-side code we initialized earlier. ```ts app/actions.ts "use server"; // ... export const getSubOrg = async (publicKey: string) => { const { organizationIds } = await turnkeyServer.getSubOrgIds({ // The parent organization ID organizationId: turnkeyConfig.defaultOrganizationId, filterType: "PUBLIC_KEY", filterValue: publicKey, }); return organizationIds[0]; }; ``` Next, we'll add the client-side functionality to the `app/page.tsx` file we created earlier importing the `getSubOrg` function we defined in our server action. ```tsx app/page.tsx "use client"; import { useState } from "react"; import { useTurnkey } from "@turnkey/sdk-react"; // Import the getSubOrg function we defined earlier import { getSubOrg } from "./actions"; export default function WalletAuth() { const { walletClient } = useTurnkey(); const login = async () => { // Get the public key of the wallet, for Ethereum wallets this will trigger a prompt for the user to sign a message const publicKey = await walletClient?.getPublicKey(); if (!publicKey) { throw new Error("No public key found"); } const subOrg = await getSubOrg(publicKey); if (subOrg) { // User already has a sub-organization } else { // User does not have a sub-organization, proceed with sign-up } }; return (
); } ```
We'll define the `getSubOrg` function in the server-side code we initialized earlier. ```ts src/wallet-auth.ts "use server"; // ... export const getSubOrg = async (publicKey: string) => { const { organizationIds } = await turnkeyServer.getSubOrgIds({ // The parent organization ID organizationId: turnkeyConfig.defaultOrganizationId, filterType: "PUBLIC_KEY", filterValue: publicKey, }); return organizationIds[0]; }; ``` We'll use the `getSubOrg` function in the login method to check if a user already has a sub-organization. ```ts src/wallet-auth.ts import { getSubOrg } from "./wallet-auth-server"; // ... const walletClient = turnkey.walletClient(new EthereumWallet()); export const login = async () => { // Get the public key of the wallet, for Ethereum wallets this will trigger a prompt for the user to sign a message const publicKey = await walletClient.getPublicKey(); if (!publicKey) { throw new Error("No public key found"); } const subOrg = await getSubOrg(publicKey); if (subOrg) { // User already has a sub-organization } else { // User does not have a sub-organization, proceed with sign-up } }; ```
### Create Sub-Organization Next, we'll define a method to create a sub-organization for new user sign-ups. For more information, refer to the [Sub-Organizations](/concepts/sub-organizations) guide. We'll define another server action `createSubOrg` to create a sub-organization for new user sign-ups. ```ts app/actions.ts "use server"; // ... // Import the default Ethereum accounts helper import { DEFAULT_ETHEREUM_ACCOUNTS } from "@turnkey/sdk-browser"; export const createSubOrg = async ( publicKey: string, curveType: "API_KEY_CURVE_ED25519" | "API_KEY_CURVE_SECP256K1", ) => { const apiKeys = [ { apiKeyName: `Wallet Auth - ${publicKey}`, // The public key of the wallet that will be added as an API key and used to stamp future requests publicKey, // We set the curve type to 'API_KEY_CURVE_ED25519' for solana wallets // If using an Ethereum wallet, set the curve type to 'API_KEY_CURVE_SECP256K1' curveType, }, ]; const subOrg = await turnkeyServer.createSubOrganization({ // The parent organization ID organizationId: turnkeyConfig.defaultOrganizationId, subOrganizationName: "New Sub Org", rootUsers: [ { // Replace with user provided values if desired userName: "New User", userEmail: "wallet@domain.com", apiKeys, authenticators: [], oauthProviders: [] }, ], rootQuorumThreshold: 1, wallet: { walletName: "Default Wallet", // This is used to create a new Ethereum wallet for the sub-organization accounts: DEFAULT_ETHEREUM_ACCOUNTS, }, }); return subOrg; }; ``` Then, we'll import and use this `createSubOrg` function within the login method. The curve type is set to `API_KEY_CURVE_SECP256K1` since we're using an Ethereum wallet in this example. ```tsx app/page.tsx "use client"; import { getSubOrg, createSubOrg } from "./actions"; // ... export default function WalletAuth() { const { walletClient } = useTurnkey(); const login = async () => { // Get the public key of the wallet, for Ethereum wallets this will trigger a prompt for the user to sign a message const publicKey = await walletClient?.getPublicKey(); if (!publicKey) { throw new Error("No public key found"); } const subOrg = await getSubOrg(publicKey); if (subOrg) { // User already has a sub-organization } else { // User does not have a sub-organization, proceed with sign-up const subOrg = await createSubOrg(publicKey, "API_KEY_CURVE_SECP256K1"); // In the next step we'll add logic sign in the user if (!subOrg) { throw new Error("Failed to create sub-organization"); } } }; return (
); } ```
We'll define another server-side function `createSubOrg`, to create a sub-organization for new user sign-ups. ```ts src/wallet-auth-server.ts // ... // Import the default Ethereum accounts helper import { DEFAULT_ETHEREUM_ACCOUNTS } from "@turnkey/sdk-browser"; export const createSubOrg = async ( publicKey: string, curveType: "API_KEY_CURVE_ED25519" | "API_KEY_CURVE_SECP256K1", ) => { const apiKeys = [ { apiKeyName: `Wallet Auth - ${publicKey}`, // The public key of the wallet that will be added as an API key and used to stamp future requests publicKey, // We set the curve type to 'API_KEY_CURVE_ED25519' for solana wallets // If using an Ethereum wallet, set the curve type to 'API_KEY_CURVE_SECP256K1' curveType, }, ]; const subOrg = await turnkeyServer.createSubOrganization({ // The parent organization ID organizationId: turnkeyConfig.defaultOrganizationId, subOrganizationName: "New Sub Org", rootUsers: [ { // Replace with user provided values if desired userName: "New User", userEmail: "wallet@domain.com", apiKeys, authenticators: [], oauthProviders: [] }, ], rootQuorumThreshold: 1, wallet: { walletName: "Default Wallet", // This is used to create a new Ethereum wallet for the sub-organization accounts: DEFAULT_ETHEREUM_ACCOUNTS, }, }); return subOrg; }; ``` Then, we'll import and use this `createSubOrg` function within the login method. The curve type is set to `API_KEY_CURVE_SECP256K1` since we're using an Ethereum wallet in this example. ```ts src/wallet-auth.ts import { getSubOrg, createSubOrg } from "./wallet-auth-server"; // ... const walletClient = turnkey.walletClient(new EthereumWallet()); export const login = async () => { const publicKey = await walletClient.getPublicKey(); if (!publicKey) { throw new Error("No public key found"); } const subOrg = await getSubOrg(publicKey); if (subOrg) { // User already has a sub-organization } else { // User does not have a sub-organization, proceed with sign-up const subOrg = await createSubOrg(publicKey, "API_KEY_CURVE_SECP256K1"); // In the next step we'll add logic to sign in the user if (!subOrg) { throw new Error("Failed to create sub-organization"); } } }; ```
## Sign In At this point, we have a working sign-up flow. Next, we'll implement the signing in functionality by creating a read-only session and retrieving the user's wallets. ### Read-only Session Create a read-only session for the user by calling the `login` method on the `WalletClient` instance. This will save a read-only session token to the `localStorage` to authenticate future read requests. ```tsx app/page.tsx "use client"; import { getSubOrg, createSubOrg } from "./actions"; // ... export default function WalletAuth() { const { walletClient, client } = useTurnkey(); // State to hold the user's wallets const [wallets, setWallets] = useState([]); const login = async () => { // Get the public key of the wallet, for Ethereum wallets this will trigger a prompt for the user to sign a message const publicKey = await walletClient?.getPublicKey(); if (!publicKey) { throw new Error("No public key found"); } const subOrg = await getSubOrg(publicKey); if (subOrg) { const loginResponse = await walletClient.login({ organizationId: subOrgId, }); if (loginResponse?.organizationId) { const wallets = await client.getWallets({ organizationId: loginResponse.organizationId, }); setWallets(wallets); } } else { // ... } }; // Render the user's wallets if defined if (wallets) { return (
{wallets.map((wallet) => (
{wallet.walletName}
))}
); } return ( // ... ); } ```
```ts src/wallet-auth.ts import { getSubOrg, createSubOrg } from "./wallet-auth-server"; // ... export const login = async (publicKey: string) => { //... const subOrg = await getSubOrg(publicKey); if (subOrg) { const loginResponse = await walletClient.login({ organizationId: subOrgId, }); if (loginResponse?.organizationId) { const wallets = await client.getWallets({ organizationId: loginResponse.organizationId, }); // Log the user's wallets console.log(wallets); } } else { // ... } }; ```
### Retrieve Wallets Once the user is authenticated, we can retrieve the user's wallets by calling the `getWallets` method on the `WalletClient` instance. ```tsx app/page.tsx "use client"; import { getSubOrg, createSubOrg } from "./actions"; // ... export default function WalletAuth() { const { walletClient, client } = useTurnkey(); // State to hold the user's wallets const [wallets, setWallets] = useState([]); const login = async () => { // Get the public key of the wallet, for Ethereum wallets this will trigger a prompt for the user to sign a message const publicKey = await walletClient?.getPublicKey(); if (!publicKey) { throw new Error("No public key found"); } const subOrg = await getSubOrg(publicKey); if (subOrg) { const loginResponse = await walletClient.login({ organizationId: subOrgId, }); if (loginResponse?.organizationId) { const wallets = await client.getWallets({ organizationId: loginResponse.organizationId, }); setWallets(wallets); } } else { // ... } }; // Render the user's wallets if defined if (wallets) { return (
{wallets.map((wallet) => (
{wallet.walletName}
))}
); } return ( // ... ); } ```
```ts src/wallet-auth.ts import { getSubOrg, createSubOrg } from "./wallet-auth-server"; // ... export const login = async (publicKey: string) => { //... const subOrg = await getSubOrg(publicKey); if (subOrg) { const loginResponse = await walletClient.login({ organizationId: subOrgId, }); if (loginResponse?.organizationId) { const wallets = await client.getWallets({ organizationId: loginResponse.organizationId, }); // Log the user's wallets console.log(wallets); } } else { // ... } }; ```
### Read-write Session It is also possible to create a read-write session for the user by calling the `loginWithWallet` method on the `WalletClient` instance. This will save a read-write session token to the `localStorage` to authenticate future read/write requests. This session can be used with the `TurnkeyIndexedDbClient` to make read/write requests to the Turnkey API. ```tsx app/page.tsx "use client"; // ... export default function WalletAuth() { const { walletClient, indexedDbClient } = useTurnkey(); // State to hold the read-write client const [readWriteClient, setReadWriteClient] = useState( null, ); const login = async () => { // ... if (subOrg) { // Create a read-write session by calling the loginWithWallet method const readWriteResponse = await walletClient.loginWithWallet({ sessionType: "SESSION_TYPE_READ_WRITE", publicKey: indexedDbClient.getPublicKey(), }); // If the login was successful, get the active client and set it to the state if (readWriteResponse) { setReadWriteClient(indexedDbClient) } } else { // ... } }; // ... } ``` Define a new function `addWallet` which will create a new wallet using the read-write client. We'll also add a button to trigger this function. ```tsx app/page.tsx "use client"; // ... export default function WalletAuth() { const { walletClient, indexedDbClient } = useTurnkey(); // State to hold the read-write client const [readWriteClient, setReadWriteClient] = useState( null, ); const login = async () => { //... }; const addWallet = async () => { if (readWriteClient) { const newWalletResponse = await readWriteClient.createWallet({ walletName: "New Wallet", accounts: DEFAULT_ETHEREUM_ACCOUNTS, }); } }; if (wallets) { return (
{wallets.map((wallet) => (
{wallet.walletName}
))}
); } return (
); } ```
### Examples You can find examples of how to implement the above functionality using both an iframeClient and indexedDbClient and more in the following repositories: # Features Source: https://docs.turnkey.com/embedded-wallets/features/overview {" "} {" "} {" "} {" "} {" "} # Overview Source: https://docs.turnkey.com/embedded-wallets/overview export const SquareCard = ({icon, label, className = "", ...props}) => { return
{icon}
{label}
; }; export const Logo = ({id, className = "", fill = "", ...props}) => { if (id === "react") { return React Logo ; } if (id === "react-native") { return React Native Logo ; } if (id === "android-kotlin") { return Android Kotlin Logo ; } if (id === "ios-swift") { return iOS Swift Logo ; } if (id === "unity") { return Unity Logo ; } if (id === "flutter") { return Flutter Logo ; } if (id === "rest-api") { return Rest API Logo ; } if (id === 'typescript') { return ; } if (id === "go") { return Go Logo ; } if (id === "rust") { return ; } if (id === "python") { return Python Logo ; } if (id === 'ruby') { return ; } return null; }; With Embedded Wallets, you can create custom wallet experiences that are seamlessly integrated into your product, without compromising on security. Whether you need custodial or non-custodial wallets, our infrastructure provides the foundation for building innovative, user-friendly crypto products. ### Why Embedded Wallets? Embedded Wallets give you the freedom to design and control the entire user experience, while offloading the complexity and risk of private key management to Turnkey. With Embedded Wallets, you can: * Leverage pre-built UI components to speed up your integration * Easily create a variety of wallets for your users * Authenticate users via email, phone number, biometrics, social logins, etc * Determine delegated access and co-owernership controls * Access out-of-the-box support for multiple chains and assets * Sign multiple transactions without additional approvals * Access simple integrations for gas sponsorship and smart contract wallets ### Custodial vs non-custodial Turnkey's Embedded Wallets are built on top of Sub-Organizations. Each wallet is represented by a sub-organization, which can be configured with different security settings and access controls. * For custodial wallets, your application holds the master key and can initiate transactions on behalf of users. * For non-custodial wallets, users hold their own private keys and must approve each transaction, using one of their configured [authentication](/authentication/overview) methods. Below, we'll dive into how we set each of these up but first, let's make sure you're familiar with the Embedded Wallets concepts and architecture. ### Embedded Wallets Quickstart If you haven't yet, get started quickly using Turnkey's Account/Embedded Wallets Setup. You'll learn how to: * Create an Account * Get Your Organization ID * Create an API Key * Set up Turnkey's React SDK in a Next.js application * Configure authentication with email sign-in * Implement message signing functionality using a user's Turnkey wallet * Handle user sessions and wallet interactions Get started [here](/getting-started/embedded-wallet-quickstart) and come back when you're ready. ### Integrating Embedded Wallets Now that you've gotten started, this guide walks through 3 ways to use sub-organizations as Embedded Wallets for your users. We first show that it can be used to create non-custodial wallets, or end-user controlled wallets. Then we explain how you can create custodial wallets, and lastly shared custody wallets. #### Non-Custodial Wallets In this example wallet implementation, you will create a segregated sub-organization for each end-user, and leverage [passkeys](/authentication/passkeys/introduction) as cryptographic proof of ownership to ensure only the end-user has the ability to approve signing. Your application will construct transactions on behalf of the end-user, and then surface the relevant Turnkey activity request client-side for end-user approval. Note that Turnkey is not a customer authentication platform. This gives you the flexibility to create the user experience you envision. Typically, Turnkey integrators implement their own standard end-user authentication flows for login, then employ passkeys behind that login for transaction signing. If you'd like to see a live example, head over to our [✨Demo Embedded Wallet✨](https://wallet.tx.xyz/), and follow along with the code [here](https://github.com/tkhq/demo-embedded-wallet). **Before you start** Make sure you've set up your primary Turnkey organization with at least one API user for programmatic user onboarding. Check out our [Quickstart guide](/getting-started/quickstart) if you need help getting started. After the end-user is logged in, your application prompts the user for passkey creation on the application domain. Our JavaScript SDK has a helper for this: `getWebAuthnAttestation`. See [this example](https://github.com/tkhq/sdk/tree/main/examples/with-federated-passkeys). Your application then uses an API-only user to create a new sub-organization on behalf of the end-user with a `CREATE_SUB_ORGANIZATION` activity. In the example below, the new sub-organization has one root user controlled by the end user's passkey, and an associated Ethereum wallet: ```js { "type": "ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V4", "timestampMs": "", "organizationId": "", "parameters": { "subOrganizationName": "", "rootUsers": [ { "userName": "", "userEmail": "(optional)", "authenticators": [ { "authenticatorName": "", "challenge": "", "attestation": { "credentialId": "", "clientDataJson": "", "attestationObject": "", "transports": ["AUTHENTICATOR_TRANSPORT_HYBRID"] } } ], "apiKeys": [] } ], "rootQuorumThreshold": 1, "wallet": { "walletName": "Default Wallet", "accounts": [ { "curve": "CURVE_SECP256K1", "pathFormat": "PATH_FORMAT_BIP32", "path": "m/44'/60'/0'/0/0", "addressFormat": "ADDRESS_FORMAT_ETHEREUM" } ] } } } ``` The response will contain the new sub-organization ID as well as details about its associated Ethereum wallet: ```js { "subOrganizationId": "", // the organization_id that the end-user must use when signing requests "wallet": { "walletId": "", // the wallet ID used to generate more accounts "addresses": "" // the addresses you can now sign with } } ``` Note: root users created with sub-organizations can have both API keys and authenticators (e.g. passkeys). In this example we only expect passkeys. See [Sub-Organizations as shared wallets](#sub-organizations-as-shared-wallets) for a use case which requires both. With this setup each end-user now has sole control over their sub-organization and any resources created within it. Your application cannot take any actions on resources within the sub-organization without explicit cryptographic authorization from the end-user in the form of a passkey signature. It's important to note that the initial activity to create a sub-organization has to be authorized by an API key of a user in your main Turnkey organization. Otherwise, anyone would be able to create sub-organizations in your organization! Here's an [example](https://github.com/tkhq/sdk/blob/a2bfbf3cbd6040902bbe4c247900ac560be42925/examples/with-federated-passkeys/src/pages/index.tsx#L88-L116) where the initial registration is done, and posted to a NextJS backend. The NextJS backend inserts the attestation and signs the `CREATE_SUB_ORGANIZATION_V4` activity [here](https://github.com/tkhq/sdk/blob/ba360baeb60d80276f7faeca602b99190fe5affe/examples/with-federated-passkeys/src/pages/api/createSubOrg.ts#L27-L106). While the **first wallet creation is already done** (our `CREATE_SUB_ORGANIZATION` activity accepts a `wallet` parameter!), your end-users can derive more accounts or create more wallets after the fact by using their passkeys to sign a `CREATE_WALLET` activity. We've abstracted getting WebAuthn signatures and creating signed Turnkey requests behind typed methods (e.g. `createWallet`). Our `TurnkeyClient` (from [`@turnkey/http`](https://www.npmjs.com/package/@turnkey/http)) can be initialized with a `WebauthnStamper` (from [`@turnkey/webauthn-stamper`](https://www.npmjs.com/package/@turnkey/webauthn-stamper)): ```js import { WebauthnStamper } from "@turnkey/webauthn-stamper"; import { TurnkeyClient } from "@turnkey/http"; const stamper = new WebAuthnStamper({ rpId: "your-domain.com", }); // New HTTP client able to sign with passkeys! const httpClient = new TurnkeyClient( { baseUrl: "https://api.turnkey.com" }, stamper ); // Signs and sends a request to Turnkey await httpClient.createWallet({ type: "ACTIVITY_TYPE_CREATE_WALLET", organizationId: "", timestampMs: String(Date.now()), parameters: { walletName: "New Wallet", accounts: [ { curve: "CURVE_SECP256K1", pathFormat: "PATH_FORMAT_BIP32", path: "m/44'/60'/0'/0/0", addressFormat: "ADDRESS_FORMAT_ETHEREUM", }, ], }, }); ``` In the snippet above we send the activity directly to Turnkey's backend. Our SDK also comes with abstractions to create a `signedRequest`, which contain all the components needed to forward it to Turnkey: URL, body, and a stamp header (with name and value properties). Use `httpClient.stampCreateWallet` to get a signed request. Your backend server can then proxy it to Turnkey. Next, we can derive additional accounts (addresses) given a single HD wallet. The shape of the request is as follows: ```js { "type": "ACTIVITY_TYPE_CREATE_WALLET_ACCOUNTS", "timestampMs": "", "organizationId": "", "parameters": { "walletId": "", "accounts": [ { "curve": "CURVE_SECP256K1", "pathFormat": "PATH_FORMAT_BIP32", "path": "m/44'/60'/0'/0/0", "addressFormat": "ADDRESS_FORMAT_ETHEREUM" } ] } } ``` The end-user must provide a signature over each `SIGN_TRANSACTION` activity with their passkey. In your application, a user action (for example tapping a "Withdraw Rewards" button) might trigger the flow. The details of this transaction should be presented to the user for confirmation, followed by a passkey prompt to sign the Turnkey activity. An activity to sign a transaction looks like the following: The end-user must provide a signature over each `SIGN_TRANSACTION` activity with their passkey. In your application, a user action (for example tapping a "Withdraw Rewards" button) might trigger the flow. The details of this transaction should be presented to the user for confirmation, followed by a passkey prompt to sign the Turnkey activity. An activity to sign a transaction looks like the following: ```js { "type": "ACTIVITY_TYPE_SIGN_TRANSACTION_V2", "timestampMs": "", "organizationId": "", "parameters": { "signWith": "", "type": "TRANSACTION_TYPE_ETHEREUM", "unsignedTransaction": "" } } ``` Turnkey returns a signed transaction in the activity result which your application can broadcast using any provider you'd like. #### Custodial Wallets Most of the steps outlined in the previous section remain unchanged: applications creating custodial wallets should still create segregated sub-organizations for their end-users to avoid limits (we currently have a maximum of 100 users per organization, whereas an organization can have unlimited sub-organizations). The main difference is in the Root Quorum settings: upon creating a new sub-organization, your business's API key is used to bootstrap each end-user organization. The `CREATE_SUB_ORGANIZATION_V4` activity becomes: ```json { "type": "ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V4", "timestampMs": "", "organizationId": "", "parameters": { "subOrganizationName": "", "rootUsers": [{ "userName": "", "userEmail": "(optional)", "authenticators": [], "apiKeys": [ "apiKeyName": "", "publicKey": "" ], }], "rootQuorumThreshold": 1, "wallet": { "walletName": "Default ETH Wallet", "accounts": [ { "curve": "CURVE_SECP256K1", "pathFormat": "PATH_FORMAT_BIP32", "path": "m/44'/60'/0'/0/0", "addressFormat": "ADDRESS_FORMAT_ETHEREUM", }, ], }, } } ``` (Note the empty `"authenticators"` list!) Key creation and signatures can also be performed with this root API user, and the end-user doesn't need to be involved in the activity signing process. Policies can be use to segregate permissions if needed: you could, for example, bootstrap each sub-org with 2 API users: one to create keys and setup the organization policies; the other to sign transactions. #### Shared Wallets For the sake of completeness: it is possible to create "shared custody" wallets with the sub-organization primitive. To do this, an application would setup sub-organizations with the following settings: * Root quorum threshold: 2 * Root users: * 1 user representing the end-user (with their Passkey as an authenticator) * 1 user representing the business (with an API key attached) The signing process would then have to involve **both** the user and the business since the root quorum threshold is 2. To reduce friction for the end-user, many clients opt to start with a root quorum of 1. This way, you can take certain actions with your business's API key root user **prior** to updating the root quorum threshold to 2. Looking for more support? Check out our Demos, SDKs and Code Examples below! ## Demos ### Demo Embedded Wallet ([code](https://github.com/tkhq/demo-embedded-wallet)) A comprehensive demo showcasing how to build an embedded wallet using Turnkey. This demo uses the [`@turnkey/sdk-browser`](https://www.npmjs.com/package/@turnkey/sdk-browser), [`@turnkey/sdk-react`](https://www.npmjs.com/package/@turnkey/sdk-react) and [`@turnkey/sdk-server`](https://www.npmjs.com/package/@turnkey/sdk-server) packages and includes features such as: * User authentication with passkeys, email auth, and OAuth * Creating new wallets and wallet accounts * Sending and receiving funds * Importing/Exporting a wallet * Adding a credential to the wallet demo embedded wallet login view demo embedded wallet dashboard view See [https://github.com/tkhq/demo-embedded-wallet](https://github.com/tkhq/demo-embedded-wallet) for the code. ### Demo Consumer Wallet ([code](https://github.com/tkhq/demo-consumer-wallet)) A minimal consumer wallet app powered by Turnkey. Behind the scenes, it uses [`@turnkey/ethers`](https://www.npmjs.com/package/@turnkey/ethers) for signing and WalletConnect (v1) for accessing dapps.