---
title: "Приклади"
description: "Готові для копіювання підходи SDK для вітрини оренди та серверної інтеграції: каталог на дати, форма запиту на бронювання, товари на продаж, синхронізація нових бронювань і обробка обмежень частоти запитів."
canonical_url: "https://requiply.com/docs/uk/developers/examples"
---
# Приклади

> Готові для копіювання підходи SDK для вітрини оренди та серверної інтеграції: каталог на дати, форма запиту на бронювання, товари на продаж, синхронізація нових бронювань і обробка обмежень частоти запитів.

Фрагменти передбачають клієнт `requiply` зі [Швидкого старту](https://requiply.com/docs/uk/developers/typescript-sdk/quick-start): публічний ключ для прикладів вітрини, секретний ключ для серверних прикладів. Ідентифікатори на кшталт `cameraKitId` позначають UUID, які ви читаєте з каталогу.

## Вітрина: каталог на вибрані дати

```ts
const { items, nextCursor } = await requiply.inventory.list({
  startDate: '2026-07-01T10:00:00+03:00',
  endDate: '2026-07-03T18:00:00+03:00',
  limit: 50,
});

for (const item of items) {
  console.log(item.name, item.basePrice, item.currency, `${item.availableQuantity} free`);
}
```

Щоб перелічити лише товари, у яких хоча б одна одиниця вільна на весь період, використовуйте `availability.items()` з тими самими датами.

## Вітрина: лише допустимий час видачі

```ts
const { workingHours, timezone } = await requiply.org.info();

function isOpen(day: string, time: string) {
  const hours = workingHours.find((entry) => entry.day === day);
  return !!hours?.isWorkingDay && time >= hours.startTime && time <= hours.endTime;
}

isOpen('saturday', '10:00'); // compare in the organization's timezone
```

## Вітрина: форма запиту на бронювання

```ts
const result = await requiply.bookings.create({
  startDate: '2026-07-01T10:00:00',
  endDate: '2026-07-03T18:00:00',
  items: [{ groupId: cameraKitId, quantity: 1 }],
  deliveryType: 'pickup',
  asRequest: true,
  client: { name: 'Olena', email: 'olena@example.com', phone: '+380951234567' },
});

if (result.success) {
  showThankYou(`Request #${result.reservationOrgId} received`);
} else if (result.reason === 'minimum_duration' && result.minimumDuration) {
  const { earliestReturn, timeZone } = result.minimumDuration;
  showError(`The earliest return is ${earliestReturn} (${timeZone})`);
} else {
  showError(result.message ?? 'These dates cannot be booked');
}
```

## Вітрина: додавання товарів на продаж

Працює, лише поки організація [продає клієнтам](https://requiply.com/docs/uk/developers/typescript-sdk/sales#%D0%B7-%D0%BF%D1%83%D0%B1%D0%BB%D1%96%D1%87%D0%BD%D0%B8%D0%BC-%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BC).

```ts
import { RequiplyError, type PublicV1SaleItem } from '@requiply/api-sdk';

let goods: PublicV1SaleItem[] = [];
try {
  ({ items: goods } = await requiply.saleItems.list());
} catch (error) {
  if (!(error instanceof RequiplyError && error.reason === 'selling_disabled')) throw error;
}

try {
  const quote = await requiply.pricing.quote({
    startDate: '2026-07-01T10:00:00',
    endDate: '2026-07-03T18:00:00',
    items: [{ groupId: cameraKitId, quantity: 1 }],
    saleLines: [{ saleItemId: memoryCardId, quantity: 2 }],
  });
  console.log(quote.saleSubtotal, quote.total);
} catch (error) {
  if (error instanceof RequiplyError && error.reason === 'out_of_stock') {
    console.log('Only', error.data?.availableQuantity, 'left');
  } else {
    throw error;
  }
}
```

## Сервер: синхронізація нових бронювань

```ts
let cursor: string | undefined;

do {
  const page = await requiply.bookings.list({
    createdFrom: lastSyncAt,
    limit: 200,
    cursor,
  });

  for (const booking of page.bookings) {
    await upsertBooking(booking);
  }

  cursor = page.nextCursor ?? undefined;
} while (cursor);
```

## Сервер: знайти або створити клієнта

```ts
const { client, created } = await requiply.clients.create({
  name: 'Alex',
  email: 'alex@example.com',
});

console.log(created ? 'New client' : 'Existing client', client.id);
```

`clients.create()` повертає наявного клієнта, коли такий email чи телефон уже є в базі, тож його безпечно викликати перед кожним бронюванням.

## Скасування повільного розрахунку ціни

```ts
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5_000);

try {
  const quote = await requiply.pricing.quote(
    {
      startDate: '2026-07-01T10:00:00',
      endDate: '2026-07-03T18:00:00',
      items: [{ groupId: cameraKitId, quantity: 1 }],
    },
    { signal: controller.signal },
  );

  console.log(quote.total);
} finally {
  clearTimeout(timeout);
}
```

## Обробка обмеження частоти запитів

```ts
import { RequiplyError } from '@requiply/api-sdk';

async function withRetry<T>(call: () => Promise<T>): Promise<T> {
  try {
    return await call();
  } catch (error) {
    if (error instanceof RequiplyError && error.status === 429) {
      const seconds = error.retryAfter ?? 5;
      await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
      return call();
    }
    throw error;
  }
}

const report = await withRetry(() => requiply.reports.pipeline());
```

Читання та розрахунки ціни можна вільно повторювати. Не обгортайте так `bookings.create()` чи `sales.create()`; див. [Повторні спроби](https://requiply.com/docs/uk/developers/typescript-sdk/request-options#%D0%BF%D0%BE%D0%B2%D1%82%D0%BE%D1%80%D0%BD%D1%96-%D1%81%D0%BF%D1%80%D0%BE%D0%B1%D0%B8).

## Приклади, які можна запустити в браузері

Для проєкту на StackBlitz чи подібній платформі в браузері:

- Залежте від опублікованої версії `@requiply/api-sdk` і зафіксуйте її.
- Використовуйте лише публічний ключ демо-організації, який легко замінити.
- Створюйте бронювання лише як запити з `asRequest: true`.
- Ніколи не додавайте методів із секретним ключем чи справжніх даних клієнтів.


## Sitemap

See the full [sitemap](https://requiply.com/docs/sitemap.md) for all pages.
