Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tkhq/sdk/llms.txt

Use this file to discover all available pages before exploring further.

@turnkey/sdk-server is the server-side SDK for interacting with the Turnkey API from a Node.js environment. Its primary use cases are:
  • Standing up an Auth Proxy to forward signed requests from the browser to Turnkey without exposing server API keys to the client
  • Executing server actions (Next.js Server Actions or equivalent) for flows like OTP, OAuth login, and sub-organization management
  • Making direct API calls to Turnkey with full API key authorization
Use the proxy handler to keep your Turnkey API keys on the server. The browser SDK sends requests to your proxy endpoint, which forwards them to Turnkey after verifying the method is allowed.

Installation

npm install @turnkey/sdk-server

The Turnkey class (TurnkeyServerSDK)

The main entry point is the Turnkey class (exported as Turnkey, internally named TurnkeyServerSDK).

Instantiation

const { Turnkey } = require("@turnkey/sdk-server");

const turnkey = new Turnkey({
  apiBaseUrl: process.env.NEXT_PUBLIC_BASE_URL,
  defaultOrganizationId: process.env.NEXT_PUBLIC_ORGANIZATION_ID,
  apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY,
  apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY,
});
apiBaseUrl
string
required
Turnkey API base URL (e.g., https://api.turnkey.com).
defaultOrganizationId
string
required
Your Turnkey parent organization ID.
apiPrivateKey
string
required
Your Turnkey API private key. Keep this on the server — never expose it to the browser.
apiPublicKey
string
required
Your Turnkey API public key.
activityPoller
object
Configuration for polling activity results (timeout and interval).

Getting an API client

Call turnkey.apiClient() to get a TurnkeyApiClient instance stamped with your API credentials:
const apiClient = turnkey.apiClient();

// Call any Turnkey API method
const { wallets } = await apiClient.getWallets({
  organizationId: "suborg-id",
});
You can optionally pass different API credentials to scope a specific client:
const apiClient = turnkey.apiClient({
  apiPublicKey: "other-public-key",
  apiPrivateKey: "other-private-key",
});

Proxy handlers

The proxy handlers expose a single endpoint that the browser SDK calls to forward signed requests to Turnkey. Only the methods listed in allowedMethods (or the built-in defaults) are accepted.
The default allowed methods are: oauth, createReadWriteSession, createSubOrganization, emailAuth, and initUserEmailRecovery.

Express

const express = require("express");
const { Turnkey } = require("@turnkey/sdk-server");

const app = express();
app.use(express.json());

const turnkey = new Turnkey({
  apiBaseUrl: process.env.NEXT_PUBLIC_BASE_URL,
  defaultOrganizationId: process.env.NEXT_PUBLIC_ORGANIZATION_ID,
  apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY,
  apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY,
});

const turnkeyProxyHandler = turnkey.expressProxyHandler({});

app.post("/apiProxy", turnkeyProxyHandler);

app.listen(3000);
To restrict which methods are proxied, pass an allowedMethods array:
const handler = turnkey.expressProxyHandler({
  allowedMethods: ["createSubOrganization", "oauth"],
});

Next.js

Use nextProxyHandler for Next.js API routes:
import { Turnkey } from "@turnkey/sdk-server";
import type { NextApiRequest, NextApiResponse } from "next";

const turnkey = new Turnkey({
  apiBaseUrl: process.env.NEXT_PUBLIC_BASE_URL!,
  defaultOrganizationId: process.env.NEXT_PUBLIC_ORGANIZATION_ID!,
  apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY!,
  apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY!,
});

export default turnkey.nextProxyHandler({});

Server actions

@turnkey/sdk-server exports a server object containing ready-to-use server actions for common flows. These are designed to run in a Next.js Server Actions context but can be adapted to any server environment.
import { server } from "@turnkey/sdk-server";

server.sendOtp

Send an OTP to a user’s email address or phone number.
const response = await server.sendOtp({
  contact: "user@example.com",
  otpType: "OTP_TYPE_EMAIL",
  appName: "My App",
});
// response.otpId — use this to verify the OTP

server.verifyOtp

Verify an OTP code and receive a verification token.
const response = await server.verifyOtp({
  otpId: "otp-id",
  otpCode: "123456",
});
// response.verificationToken — use this with otpLogin

server.otpLogin

Complete a login flow using an OTP verification token.
const response = await server.otpLogin({
  suborgID: "suborg-id",
  verificationToken: "token",
  publicKey: "ephemeral-public-key",
});
// response.session — the signed session JWT

server.oauthLogin

Complete an OAuth login using an OIDC token from a provider.
const response = await server.oauthLogin({
  suborgID: "suborg-id",
  oidcToken: "id-token-from-provider",
  publicKey: "ephemeral-public-key",
});
// response.session — the signed session JWT

server.createSuborg

Create a new sub-organization for a user. Automatically creates Ethereum and Solana wallet accounts by default.
const response = await server.createSuborg({
  email: "user@example.com",
  // or phoneNumber: "+15555550100"
  // passkey: { ... }       — passkey attestation
  // oauthProviders: [ ... ] — OAuth provider details
});
// response.subOrganizationId

server.getSuborgs

Look up existing sub-organizations by a filter (email, phone number, public key, etc.).
const { organizationIds } = await server.getSuborgs({
  filterType: "EMAIL",
  filterValue: "user@example.com",
});

server.getOrCreateSuborg

Find existing sub-organizations matching the filter, or create a new one if none are found. This is the recommended action for unified login/signup flows.
const { subOrganizationIds } = await server.getOrCreateSuborg({
  filterType: "EMAIL",
  filterValue: "user@example.com",
  additionalData: {
    email: "user@example.com",
  },
});

server.getUsers

Retrieve users within an organization.
const { users } = await server.getUsers({
  organizationId: "suborg-id",
});

server.createOauthProviders

Link additional OAuth providers to an existing user.
const response = await server.createOauthProviders({
  organizationId: "suborg-id",
  userId: "user-id",
  oauthProviders: [
    { providerName: "Google", oidcToken: "id-token" },
  ],
});

server.sendCredential

Send an email authentication credential (magic link / email auth flow).
await server.sendCredential({
  email: "user@example.com",
  targetPublicKey: "ephemeral-public-key",
  suborgID: "suborg-id",
  emailCustomization: { appName: "My App" },
});

Client classes

TurnkeyServerClient

A low-level client that extends TurnkeySDKClientBase. Provides access to all Turnkey API methods. Constructed with a TurnkeySDKClientConfig that includes a stamper.
import { TurnkeyServerClient } from "@turnkey/sdk-server";
import { ApiKeyStamper } from "@turnkey/api-key-stamper";

const client = new TurnkeyServerClient({
  stamper: new ApiKeyStamper({
    apiPublicKey: "your-public-key",
    apiPrivateKey: "your-private-key",
  }),
  apiBaseUrl: "https://api.turnkey.com",
  organizationId: "your-org-id",
});

TurnkeyApiClient

TurnkeyApiClient extends TurnkeyServerClient and is the concrete class returned by turnkey.apiClient(). It is the recommended way to make authenticated API calls from the server:
const apiClient = turnkey.apiClient();

// All Turnkey API methods are available
const { subOrganizationId } = await apiClient.createSubOrganization({ ... });
const { wallets } = await apiClient.getWallets({ organizationId: "..." });
const { session } = await apiClient.stampLogin({ ... });

Build docs developers (and LLMs) love