TypeScript client

One generated file, no dependencies. curl it and start calling.

A typed TypeScript client, generated from the same registry the router dispatches on. One file, no dependencies, no build step, no version to pin.

curl https://app.360nook.com/api/v1/client.ts > nook.ts
import { Nook, NookError } from "./nook";

const nook = new Nook(process.env.NOOK_API_KEY!);

const { data } = await nook.listContacts();

await nook.createContact(
  { email: "[email protected]", first_name: "Ana" },
  // Same key on a retry returns the original response instead of a
  // second contact. One key per operation, not per attempt.
  { idempotencyKey: "signup-8f3a" },
);

await nook.bookAppointment({
  calendar_id: "...",
  starts_at: "2026-09-10T10:00:00Z",
  contact_id: "...",
});

Errors carry their reason

A non-2xx throws a NookError that keeps what the API said, rather than flattening it to “request failed”.

try {
  await nook.createContact({ first_name: "Ana" });
} catch (e) {
  if (e instanceof NookError) {
    e.code;      // "invalid_body"
    e.fields;    // every invalid field at once, not one per round trip
    e.requestId; // quote this to support and we find your exact request
  }
}

Regenerated on every request from the endpoint registry, so it cannot describe an endpoint that does not exist. If we add one, re-run the curl.

Works anywhere fetch does — Node 18+, Deno, Bun, Workers. It runs in a browser too, but a key in a browser is a key you have given away; use OAuth there.

NextAuthentication
TypeScript client · 360Nook