# Errors

HTTP statuses, error codes and what to do about each.

This page lists every status and error code API v1 answers with, and what your code should do about each. Errors are JSON objects with a human-readable `error`; where an endpoint knows more, it adds a machine-readable `code`.

```json Error
{
  "error": "wymagany kontakt: telefon (pole phone/tel/telefon/phone_number/numer, min. 6 cyfr) albo e-mail (pole email/e-mail/mail)",
  "code": "missing_contact"
}
```

## Branch on the status and the code

`error` is written in Polish for people and may change; `code` and the HTTP status do not. Match on them, never on the text. The one exception is 409 on booking, where `error` is the code itself: `"slot_taken"`.

## Statuses

| Status | Meaning | What to do |
| --- | --- | --- |
| 200, 201 | Done. 201 means something was created. | Read the body. |
| 400 | The request is not valid; nothing was stored. | Fix the request; `code` says what, when present. |
| 401 | The key is missing or not valid. | Check the header and the key; after a rotation, use the new key. |
| 404 | Nothing is published at this path or slug, or the clinic's site is not published. | Show your own 404. |
| 409 | The slot was taken in the meantime (booking). | Offer one of the `slots` in the body. |
| 413 | The upload is larger than 10 MB. | Send a smaller file. |
| 415 | The upload is not a JPEG, PNG, WebP or AVIF image. | Convert it. |
| 429 | Too many requests. | Wait `Retry-After` seconds, then retry. See [Rate limits](https://pozyskajpacjenta.pl/docs/rate-limits). |
| 5xx | Something failed on our side. | Retry later with backoff; nothing is guaranteed to be stored. |

## Codes

| code | Status | Where | Meaning |
| --- | --- | --- | --- |
| `invalid_json` | 400 | [createLead](https://pozyskajpacjenta.pl/docs/reference/leads/create-lead), [sendFeedback](https://pozyskajpacjenta.pl/docs/reference/feedback/send-feedback) | The body is not JSON. Nothing was stored. |
| `invalid_body` | 400 | [createLead](https://pozyskajpacjenta.pl/docs/reference/leads/create-lead), [sendFeedback](https://pozyskajpacjenta.pl/docs/reference/feedback/send-feedback) | The JSON is not an object, or a field is not valid (the message names it). |
| `missing_contact` | 400 | [createLead](https://pozyskajpacjenta.pl/docs/reference/leads/create-lead) | Only with ?strict=1: the lead has neither a phone nor an e-mail. |
| `invalid_time_request` | 400 | [createLead](https://pozyskajpacjenta.pl/docs/reference/leads/create-lead) | Only with ?strict=1: the request for a time failed validation. |
| `nfz_phone_only` | 400 | [getSlots](https://pozyskajpacjenta.pl/docs/reference/booking/get-slots), [createAppointment](https://pozyskajpacjenta.pl/docs/reference/booking/create-appointment) | The service is an NFZ one: booking by phone only. |
| `slot_taken` | 409 | [createAppointment](https://pozyskajpacjenta.pl/docs/reference/booking/create-appointment) | The slot was taken in the meantime; the body lists that day's free slots. |
| `feedback_rate_limited` | 429 | [sendFeedback](https://pozyskajpacjenta.pl/docs/reference/feedback/send-feedback) | The hourly limit of remarks for this source is used up. |

## With the SDK

The SDK throws `ApiError` for every non-2xx answer, with `status`, `body` and `code`. A taken slot throws `SlotTakenError`, whose `slots` are that day's free slots.

```ts TypeScript
import { ApiError } from "@pozyskajpacjenta/sdk";

try {
  await client.createLead(lead, { strict: true });
} catch (error) {
  if (error instanceof ApiError && error.code === "missing_contact") askForPhoneOrEmail();
  else throw error;
}
```
