Skip to content
Documentation
pozyskajpacjentaDocs

Resources

TypeScript SDK

Install @pozyskajpacjenta/sdk, create a client, and handle typed errors.

@pozyskajpacjenta/sdk is a small typed client for API v1: one method per endpoint, typed responses including the kind union of pages, and typed errors. This page covers installation, the client, every method and error handling. The current version is 0.17.0.

Install

The package is not in the public npm registry: it ships as one .tgz file with the types built in. Write to us through the contact page and we send you the current file; then install it from disk:

Shell
npm install ./pozyskajpacjenta-sdk-0.17.0.tgz
# or
pnpm add ./pozyskajpacjenta-sdk-0.17.0.tgz

Its only dependency from the registry is zod (the block types). It runs on Node 18 and later, Bun and Deno with the global fetch, and ships ESM and CommonJS builds with type declarations. The key is a secret: use the SDK on your server, never in a browser.

Without the SDK: types from OpenAPI

Prefer your own client? Generate types for every path and schema from the served document:

Shell
npx openapi-typescript https://app.pozyskajpacjenta.pl/api/v1/openapi.json -o pozyskajpacjenta-api.d.ts
TypeScript
import type { components, paths } from "./pozyskajpacjenta-api";

type Catalog =
  paths["/api/v1/booking/catalog"]["get"]["responses"]["200"]["content"]["application/json"];
type Slot = components["schemas"]["Slot"];

The document is public and needs no key. Its operationIds are the SDK's method names.

The client

TypeScript
import { PozyskajPacjentaClient } from "@pozyskajpacjenta/sdk";

const client = new PozyskajPacjentaClient({
  apiKey: process.env.PP_API_KEY ?? "",
  baseUrl: "https://app.pozyskajpacjenta.pl",
});
  • apiKey (required): the clinic's pp_live_ key.
  • baseUrl (required): there is no default, so a test frontend never talks to production by accident.
  • fetch (optional): your own implementation, for caching, retries or tests.

Dates arrive as ISO 8601 strings; slot and appointment times as epoch seconds (UTC).

Methods

MethodReturnsEndpoint
getContent(path?: string)Promise<SiteContent>GET /api/v1/content
getSite()Promise<SiteInfo>GET /api/v1/site
listLocations()Promise<{ locations: Location[] }>GET /api/v1/locations
getPrivacy()Promise<PrivacyInfo>GET /api/v1/privacy
listPages(options?: { kind? })Promise<{ pages: PageListItem[] }>GET /api/v1/pages
listServices()Promise<{ services: ServiceSummary[] }>GET /api/v1/services
getService(slug: string)Promise<{ service: ServiceDetail }>GET /api/v1/services/{slug}
listDoctors()Promise<{ doctors: DoctorSummary[] }>GET /api/v1/doctors
getDoctor(slug: string)Promise<{ doctor: DoctorDetail }>GET /api/v1/doctors/{slug}
listCaseStudies()Promise<{ caseStudies: CaseStudySummary[] }>GET /api/v1/case-studies
getCaseStudy(slug: string)Promise<{ caseStudy: CaseStudyDetail }>GET /api/v1/case-studies/{slug}
listPosts()Promise<{ posts: PostSummary[] }>GET /api/v1/posts
getPost(slug: string)Promise<{ post: PostDetail }>GET /api/v1/posts/{slug}
getBookingCatalog()Promise<BookingCatalog>GET /api/v1/booking/catalog
getSlots(params: { serviceId, resourceId?, locationId?, from, to })Promise<{ slots: Slot[] }>GET /api/v1/booking/slots
listAppointments(params?: { from?, to? })Promise<{ appointments: Appointment[] }>GET /api/v1/booking/appointments
createAppointment(input: AppointmentInput)Promise<AppointmentCreated>POST /api/v1/booking/appointments
createLead(lead: LeadInput, options?: { strict?: boolean })Promise<LeadCreated>POST /api/v1/leads
uploadMedia(file: Blob, options?: { alt?, caption?, aiGenerated?, filename? })Promise<MediaItem>POST /api/v1/media
listMedia()Promise<{ items: MediaItem[] }>GET /api/v1/media
sendFeedback(input: FeedbackInput)Promise<FeedbackCreated>POST /api/v1/feedback
listConversations(params?: { status?, locationId?, channel?, updatedSince?, cursor?, limit? })Promise<ConversationList>GET /api/v1/conversations
getConversation(id: string)Promise<ConversationDetail>GET /api/v1/conversations/{id}
listMessages(conversationId: string, params?: { cursor?, limit? })Promise<MessageList>GET /api/v1/conversations/{id}/messages
sendMessage(conversationId: string, input: SendMessageInput)Promise<MessageSent>POST /api/v1/conversations/{id}/messages

Helpers that need no request: mediaVariantUrl(url, { width, format }) and mediaSrcSet(url, { maxWidth }) build image variant addresses, phoneHref(phone) a tel: link, TIME_OF_DAY and windowFromPart(date, part) the windows of a request for a time. Every response type is exported too (SiteContent, ContentPage, BookingCatalog, Slot, Appointment, Conversation, ConversationMessage, ValidatedBlock, ThemeTokens and the entity types).

Errors

Class or functionWhen
ApiErrorAny non-2xx answer. status is the HTTP status, body the parsed error (or the text when it is not JSON), code the error code when the endpoint sends one.
SlotTakenError409 from createAppointment: the slot was taken, nothing was stored. Extends ApiError; slots are that day's free slots.
isSendRefused(e)409 from sendMessage: the clinic inbox's rules did not let the message out, nothing was sent; the reason is in code.
isApiError(e), isSlotTaken(e), isSendRefused(e)Type guards for a catch block.

Render a whole site

TypeScript
const { pages } = await client.listPages();

for (const item of pages) {
  const { site, page } = await client.getContent(item.path);
  // theme tokens to CSS variables once, then one switch on page.kind
}

Every method has a reference page with a runnable sample: start at API reference.