Skip to main content

Install and construct a client

Install the SDK, 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 on a client whose runtime is browser or react-native. It trusts the runtime you pass, so never set runtime: "server" in code that ships in a browser or app bundle.

Install

The SDK is published as @settlemint/dalp-sdk. It supports browser applications, server applications on a runtime version that the package's engines field accepts, and React Native apps that pass fetch from expo/fetch, which React Native covers.

Each DALP release publishes the SDK under the release's own version number. Install the release line that matches your instance's major and minor version:

npm install @settlemint/dalp-sdk@<major>.<minor>

Replace <major>.<minor> with your instance's version, then set the range in package.json to ~<major>.<minor>.0 so a later install stays inside that minor version. An install with no version takes the latest tag, which moves to each tagged release as it is published, including a patch to an older release line, so it does not match your instance by itself. To list the published versions and read the engines field:

npm view @settlemint/dalp-sdk versions
npm view @settlemint/dalp-sdk engines

The route surface is generated from the instance's own declaration, so a client from a later release knows about routes an older instance does not serve. Calling one fails when the call runs, not as a type error at build time.

The client these pages describe, with baseUrl and dalp.api, replaces the 3.1 client. An instance on DALP 3.1 takes the 3.1 client, and Migrate from SDK 3.1 to 3.2 maps one to the other.

Three 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 project that uses none of the three needs none of them installed, and the package imports no schema library at run time.

Construct a client

import { createDalpClient } from "@settlemint/dalp-sdk";

const dalp = createDalpClient({
  baseUrl: process.env.DALP_API_URL!,
  apiKey: process.env.DALP_API_KEY!,
  runtime: "server",
});

const me = await dalp.api.party.users.me();

createDalpClient returns six members. Three of them cover most code:

Member
What it is
api
The namespaced route tree. dalp.api.token.list(), dalp.api.governanceV2.v2.governance.votes.cast({ ... }).
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 organisation switch.

The other three dispatch by raw request parts rather than by flat arguments, for callers that assemble the path, query and body themselves: sendParts, streamParts and downloadParts. Each takes a route id and a params, query and body object, and downloadParts answers the response body as a stream of bytes.

Options

Option
Type
What it does
baseUrl
string | URL
Your instance's origin. Required. The SDK appends /api/v2 itself, so pass the origin. A path prefix on the URL stays in front of /api/v2.
apiKey
string | Secret
A server or CLI credential. The client trims it. Rejected when runtime resolves to browser or react-native.
authSurface
"console" | "portal"
Names the app the calls act for. The client sends the value in X-Dalp-Auth-Surface on every call and sends no such header when you leave it out. The platform derives the app from the request's origin and treats a declared value that disagrees as a conflict, so the header cannot move a call to the other app.
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 behaviour. 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
(input: RequestInfo | URL, init?: RequestInit) => Promise<Response>
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.

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 acts in one organisation, up to its read or read-write scope. Keep it in your infrastructure and send it only to your DALP instance.

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 a session cookie set on the page's own origin travels automatically, without an API key in the bundle. A baseUrl on another origin throws at construction, because the session cookie is host-only. Mount createDalpProxy on your app origin and keep baseUrl at window.location.origin.

Passing an apiKey here throws at construction with a configuration error that names the problem. The check runs at construction, so a key in a bundle fails when the client is built, before any request goes out.

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 while the application runs. 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. Create the key with the read or read-write scope the integration needs, as Authentication and API keys describes.

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. This protects against accidental disclosure, not against an attacker: a thrown error whose message interpolates the config, a structured log that serialises it, or a crash reporter that captures locals. Each of these stringifies the value, so each prints the marker.

The acting context

Some requests also need an acting context, such as the network or the signing wallet. The SDK sends it as request headers. The organisation is not one of them: a session acts in its active organisation, which the auth client's organization.setActive call changes, and an API key in the organisation it was issued for.

const dalp = createDalpClient({
  baseUrl,
  runtime: "browser",
  context: {
    chainId: 137,
  },
});
Field
Header
When you set it
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.
networkId
X-Network-Id
On an instance that serves more than one network family, to name the Canton network the request speaks to.
custodyAccountId
X-Custody-Account-Id
To name the custody account a read or write acts on, instead of the caller's default.
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, for example because the user switched organisation, build a new client and discard the old one. If you keep the old client, clear its held response tags, because a version tag from the old organisation means nothing under the new one:

dalp.conditionalRequests.clear();

The client also drops its held responses on its own when the X-Organization-Id or X-Participant header of a request differs from the previous request, so a client that forwards a tenant header per call never answers one tenant with another tenant's held body.

A single call can add headers of its own without rebuilding anything. See Per-call options.

Sign in and manage sessions

createDalpClient calls Platform API routes. Sign-in, sessions, organisations, invitations, API keys, passkeys, two-factor codes, and wallet verification go through a second client from the @settlemint/dalp-sdk/auth entry. The entry is separate because it loads the authentication library, which code that only calls routes does not need.

import { createDalpAuthClient } from "@settlemint/dalp-sdk/auth";

const auth = await createDalpAuthClient({ url: "https://your-instance.example.com" });
const session = await auth.getSession();

createDalpAuthClient is asynchronous and takes url, not baseUrl. Every operation resolves to { data, error } and does not throw for a refused request, so check error before you read data.

The client takes one credential source: an API key, a cookie header in cookie, or a cookieStore. It rejects an API key together with a cookie header or with a cookie store that already holds cookies, and a browser or React Native client rejects an API key, as createDalpClient does. With no source, it creates an in-memory cookie store, so the session lasts as long as that client. It also takes authSurface, extra headers that cannot replace the credential headers, fetch, runtime, and a passkey ceremony, and it has no organisation option: it signs in to the organisation the session's active organisation names, and organization.setActive changes that. A configuration it cannot accept rejects with a DalpSdkError.

With an API key, the auth client reaches only the nine routes that Authentication and API keys lists, such as the session, organisation and key lookups. Every other auth route answers 403 API_KEY_NOT_SUPPORTED_ON_ROUTE, so sign-in, key creation and passkey registration need a session.

The auth client does not share its held responses with createDalpClient. After you sign out or switch organisation through the auth client, call dalp.conditionalRequests.clear() on the route client.

Verify the setup

Check the setup with a read that needs only authentication:

const me = await dalp.api.party.users.me();
console.log(me.data.id);

A DalpApiError with status 401 means the credential did not arrive or the platform did not accept it. In a browser, the session is missing or expired. On a server, the key is absent or not valid. Status 403 means the platform accepted the credential and refused the request. That can be a role question, a read key on a write route, or a missing acting context such as no active organisation. Read error.id to tell them apart. Errors covers the other failures.

Next

Route calls, paging, and what comes back: Calling routes.

Was this page helpful?