spol-api-client
Typed REST client and TanStack Query factories for the sPOL REST API, generated from @polygonlabs/spol-api-schemas.
The client is code-generated by @hey-api/openapi-ts with the @polygonlabs/zod-to-openapi-heyapi plugin, which imports the actual Zod schema values the backend validates against — not types re-derived from the spec. That's the point: codecs from @polygonlabs/zod-codecs round-trip end-to-end (a wei amount arrives as a string and reaches the caller as a bigint; lastUpdated arrives as an ISO string and reaches the caller as a Date), and there is no hand-maintained type layer to drift from the service.
Install
pnpm add @polygonlabs/spol-api-client
@tanstack/react-query and react are optional peer dependencies — only required if you import the ./query subpath.
Entry points
| Entry point | Contents |
|---|---|
@polygonlabs/spol-api-client |
The singleton client, one function per operation, response/input types, and the TransportError / ResponseValidationError classes with their is*Error guards. No React dependency. |
@polygonlabs/spol-api-client/factory |
createClient / createConfig for explicit multi-instance use (SSR, multiple base URLs, custom fetch). |
@polygonlabs/spol-api-client/query |
TanStack Query options factories (listTransactionsV1Options, getSummaryV1Options, …) plus useCursorPagination — a generic "page N of M with Previous / Next" hook over the v1 cursor envelope. Requires the React peer deps. |
Usage
Configure the base URL once at application entry:
import { client } from '@polygonlabs/spol-api-client';
client.setConfig({ baseUrl: 'https://lst-api.polygon.technology' });
Call an operation (codec fields already decoded — amountPol is a bigint):
import { listTransactionsV1, isTransportError, isResponseValidationError } from '@polygonlabs/spol-api-client';
const { data, error } = await listTransactionsV1({
path: { network: 'mainnet' },
query: { limit: 20, cursor, type: 'WITHDRAW' }
});
if (isTransportError(error)) {
// request never reached the API — error.cause is the native fetch error
} else if (isResponseValidationError(error)) {
// reached the API, body didn't match the schema — error.cause is the ZodError
} else if (error) {
// typed operation error, full field access
}
Cursor pagination in React (windowed Previous / Next, each page independently cached):
import { useCursorPagination, listTransactionsV1Options } from '@polygonlabs/spol-api-client/query';
const page = useCursorPagination((cursor) =>
listTransactionsV1Options({ path: { network: 'mainnet' }, query: { limit: 20, cursor } })
);
// page.items, page.pageIndex, page.totalPages, page.goNext(), page.goPrevious()
Regeneration
src/generated/ is committed and gated by codegen-drift-check — never hand-edit it. Regenerate from the schemas package with:
pnpm --filter @polygonlabs/spol-api-client run generate
Contract-first pattern and the plugin's guarantees: apps-team-ops/docs/best-practices/rest-api-clients-codegen.md.