Install and construct a client
Install the SDK from npm, construct a client against your instance, and choose the credential for where the code runs: a session cookie or an API key.
Overview
A DALP client holds the instance URL, credential, and acting context for API calls. Use a session cookie in a browser and an API key on a server.
An API key grants the access allowed by its scope and the identity it belongs to. A key included in browser or app code is exposed to every user. The SDK rejects an API key when constructing a browser or React Native client.
Install
The SDK is published to npm as @settlemint/dalp-sdk and runs on Node 20 or later, on Bun, in any current browser, and in React Native through Expo SDK 57 (see React Native).
npm install @settlemint/dalp-sdkpnpm add @settlemint/dalp-sdkyarn add @settlemint/dalp-sdkThree peer dependencies are optional and none is installed for you. Add @tanstack/react-query only if you use the query factories; add effect only if you use the Effect surface; add zod only if you use the auth subpath, whose Better Auth client types reference it. A consumer that uses none of the three resolves none of them, and no code in the package imports a schema library at runtime.
Pin the SDK to the same major and minor version as the instance it talks to. The route surface is generated from the instance's own declaration. A client from a later release therefore knows about routes an older instance does not serve, and that failure arrives as a 404 at runtime rather than as a type error at build time.
Construct a client
import { createDalpClient } from "@settlemint/dalp-sdk";
const dalp = createDalpClient({
baseUrl: "https://your-instance.example.com",
});
const me = await dalp.api.party.users.me();createDalpClient returns three things:
| Member | What it is |
|---|---|
api | The namespaced route tree. dalp.api.token.list(), dalp.api.governanceV2.v2.governance.votes.cast({ ... }). This is what most code uses. |
execute | The same dispatch reached by route id: dalp.execute("token/list", { page: { limit: 50 } }). For code that builds its own command surface. |
conditionalRequests | The held response-version tags. Call .clear() on sign-out and on an organization switch. |
Options
| Option | Type | What it does |
|---|---|---|
baseUrl | string | URL | Your instance's origin. Required. The SDK appends the API mount itself, so pass the origin, not a path under it. |
apiKey | string | Secret | A server or CLI credential. Rejected when runtime resolves to browser or react-native. |
context | DalpClientContext | The acting context, sent as headers on every request. See The acting context. |
runtime | "browser" | "server" | "react-native" | Decides credential rules and cookie behavior. Inferred as react-native when navigator.product is ReactNative, otherwise from whether globalThis.window exists; pass it explicitly wherever that inference is not obviously right. |
fetch | typeof fetch | Your own fetch. Useful for tests, for a proxy, and for a runtime whose fetch you want to control. |
ssr | DalpSsrOptions | Forwards an incoming request's headers on a server render. See Server-side rendering. |
settlementTimeoutMs | number | How long the platform holds a queue-backed write's response before answering with a 202 handle. A single call may override it. See Mutations. |
Choose the credential
Two credentials reach the Platform API, and which one you may use follows from where your code runs rather than from what is convenient.
Session cookie, in a browser
The user signed in and the browser holds the session. Construct the client with no credential at all; it sends the cookie because it runs on your origin. This is what the Console and the Investor portal do.
API key, on a server
A backend service, a scheduled job, a CLI. The key grants its configured access and never leaves your infrastructure. Read it from your secret store, never from a variable your bundler can inline.
In a browser
export const dalp = createDalpClient({
baseUrl: window.location.origin,
runtime: "browser",
});No credential is passed. The client sends credentials with each request, so the session cookie your sign-in established travels automatically, without an API key in the bundle.
Passing an apiKey here throws at construction with a configuration error that names the problem. The refusal is at construction rather than at the first request on purpose. A check that fires only when a request goes out lets a key ship in a bundle and stay quiet until someone exercises that path, which is exactly the case where nobody is watching.
If a key reaches a browser bundle, revoke it on the platform and replace it wherever it is used. Removing it from the next bundle does not invalidate copies already downloaded.
On a server
import { createDalpClient } from "@settlemint/dalp-sdk";
const dalp = createDalpClient({
baseUrl: process.env.DALP_API_URL!,
apiKey: process.env.DALP_API_KEY!,
runtime: "server",
});Read the key from the environment or a secret manager at runtime. In Next.js, name the variable without the NEXT_PUBLIC_ prefix so the bundler cannot inline it into a client component; in Vite, keep it off the VITE_ prefix for the same reason.
To keep the key out of stack traces and logs, wrap it:
import { createDalpClient, secret } from "@settlemint/dalp-sdk";
const dalp = createDalpClient({
baseUrl: process.env.DALP_API_URL!,
apiKey: secret(process.env.DALP_API_KEY!),
runtime: "server",
});A Secret prints as a redaction marker wherever something stringifies it, and the SDK unwraps it only at the moment it sets the header. That covers the accidental paths rather than an attacker: a thrown error whose message interpolates the config, a structured log that serializes it, a crash reporter that captures locals. Those are how a server-side key most often reaches a place it should not be, and they are all String(value) under the hood.
The acting context
Most requests also need an acting context: the organization, chain, and signing wallet. The SDK sends this context in request headers.
const dalp = createDalpClient({
baseUrl,
runtime: "browser",
context: {
organizationId: "org_01J...",
chainId: 137,
},
});| Field | Header | When you set it |
|---|---|---|
organizationId | X-Organization-Id | Whenever the caller belongs to more than one organization. Almost always. |
participant | X-Participant | When acting on behalf of a participant rather than as yourself. |
executor | X-Executor | To force a signing route: the caller's own externally owned account, or their smart wallet. |
chainId | X-Chain-Id | On a multi-chain instance, to name the EVM network the request speaks to. |
selectedSigners | X-Selected-Signers | On a multisig write, to name which signers this submission counts toward. |
idempotencyKey | Idempotency-Key | Rarely at client level. A key is per instruction, not per client, so set it per call. |
The context is fixed for the life of the client. When it changes because the user switched organization, build a new client and clear the held response tags. A version tag from the old tenant means nothing under the new one:
dalp.conditionalRequests.clear();A single call can add headers of its own without rebuilding anything. See Per-call options.
Verify the setup
The cheapest end-to-end check is a read that requires authentication and nothing else:
const me = await dalp.api.party.users.me();
console.log(me.data.id);A DalpApiError with status 401 means the credential did not arrive. In a browser, the session is missing or expired; on a server, the key is absent or wrong. Status 403 means it arrived and is not permitted to do this, which is a role question rather than a wiring question. Anything else is covered in Errors.
Next
Route calls, paging, and what comes back: Calling routes.
TypeScript SDK
A typed, namespaced client for every v2 route, generated from the platform's own declaration, with TanStack Query factories and a matching Effect surface.
Calling routes
Every route is a node on one namespaced tree, called with one flat object the SDK splits into path, query, and body, returning the response envelope unchanged.