Overview
The SDK maps route identifiers to a namespaced client. GET /tokens is dalp.api.token.list(). POST /tokens/ is dalp.. The client uses the routes included in its installed SDK version.
A call takes one flat argument and returns the response envelope. Mutations and settlement covers writes and retries.
One flat argument
Each call takes one object:
await dalp.api.token.transfer({
assetId: "0x1234...",
transfers: [{ recipient: "0xabcd...", amount: "1000" }],
});The route declaration identifies the path parameters. The SDK puts assetId in the URL and the remaining input in the body. A route that declares no request body sends everything that is not a path parameter as query parameters, whatever its method, and a route with a body sends only the query parameters it declares as query and the rest in the body.
For the transfer call above, the SDK splits the input like this:
A route with no required input takes no argument at all:
const me = await dalp.api.party.users.me();
const tokens = await dalp.api.token.list();A missing path parameter rejects the call with a TypeError naming the parameter and the route, rather than sending a request to a URL with a literal :assetId in it.
Discovering routes
In an editor, dalp.api. lists the namespaces. Each namespace lists its operations, and each operation shows its request and response types.
A namespace can also be an operation. dalp.api.token.read is a call, and routes that sit beneath it are still reachable as properties on the same node.
When you are building a command surface of your own and hold a route id as a string rather than a path, use execute:
const result = await dalp.execute("token/list", { page: { limit: 50 } });execute uses the same dispatch and transport as dalp.api and fails with the same errors. An unknown route id rejects with a TypeError naming it. Import the route table to enumerate the routes in your installed SDK:
import { routeTable } from "@settlemint/dalp-sdk/routes";
const routeIds = Object.keys(routeTable.routes);What comes back
A call resolves to the platform's response envelope, unchanged. A single-resource read resolves to { data, links }, plus any extra top-level fields that route declares. A collection resolves to { data, meta, links }. links on a collection holds self, first, prev, next, and last.
const tokens = await dalp.api.token.list({ page: { limit: 50 } });
tokens.data; // the rows
tokens.meta.total; // how many exist in total, not how many came back
tokens.links.next; // the next page's URL, or null on the last pageThe SDK returns the full envelope with compile-time response types. It also checks each JSON and event-stream success response against the route's declared response, and a body that does not match throws sdk. rather than reaching your code. A binary download is returned unchecked.
A non-2xx response throws rather than resolving. That is covered under Errors.
Paging and filtering
Most collection routes take the same parameters the API documents: sort, a page object, and a filter object. page.limit takes 1 to 200 and defaults to 50, and page.offset starts at 0. Prefix the sort field with - to sort descending.
A route that returns meta.nextCursor also takes page.cursor. Pass the cursor from the previous page together with the same sort and filters. A cursor read at any depth costs the same as the first page, and page.offset is ignored when a cursor is present. meta.nextCursor is null on the last page.
const page = await dalp.api.token.list({
sort: "name",
page: { limit: 50, offset: 0 },
});On a route that takes a page object, the flat keys limit, offset, sortBy, sortDirection, and filters are not part of the client's types, so passing one fails to compile. A call that sends one anyway, for example through sendParts, is refused by the platform with a 400 that names the key. A route that declares its own flat limit, with offset or cursor, such as GET /api/, types the keys it declares as input fields instead, as Pagination lists.
To walk every page, stop when links.next is null. A short or empty page is not the end signal, and meta.total counts the rows at the time of each request, so a collection that changes mid-walk can keep your row count below it:
const rows = [];
let offset = 0;
for (;;) {
const page = await dalp.api.token.list({ page: { limit: 100, offset } });
rows.push(...page.data);
if (page.links.next === null) break;
offset += 100;
}A collection can change while you page through it, so offset pagination can repeat or omit rows. Filter to a stable range when consistency matters. Narrow large result sets to limit request volume. Pagination defines the query parameters.
Conditional reads
The SDK holds the ETag the platform returns on a cacheable read, sends it back as If-None-Match on the next read of the same resource, and turns a 304 Not Modified answer back into the cached body. You get a normal response object either way. An unchanged response transfers no response body.
This is on by default and needs no configuration. The client holds up to 64 responses of at most 1 MiB each, drops them when a request carries a different organisation or participant header from the one before, and never holds an event stream. It also drops them after a sign-out, a session revocation or an organisation switch that it sends itself. Clear them yourself when you sign out or switch organisation through a separate authentication client:
dalp.conditionalRequests.clear();A version tag identifies a response as seen by one identity acting for one organisation. A client that keeps tags across a change of either can serve one organisation's cached rows to another, so clear them in the same step as the switch.
Per-call options
The second argument to any call is options.
await dalp.api.token.list({ page: { limit: 50 } }, { signal: controller.signal });Use the same Idempotency-Key when retrying one instruction. Generate a new key only for a new instruction. A header function runs for each request, so keep a retry key outside that function. See Retry safety.
Cancellation
Pass an AbortSignal and the request aborts with it. In React, wire it to the effect's cleanup, or let the TanStack Query factories do it for you, since they pass the query's own signal through.
const controller = new AbortController();
const promise = dalp.api.token.list({ page: { limit: 50 } }, { signal: controller.signal });
controller.abort();An aborted request rejects with the abort reason rather than a DalpApiError, because nothing came back from the platform to build one from.
Next
Writes, retry safety, and settlement: Mutations and settlement.