Перейти до основного вмісту

SDK та приклади

Готові TypeScript-типи та приклад API-клієнта для швидкої інтеграції з Zapys24.


TypeScript-типи

Скопіюйте ці типи у ваш проєкт для типобезпечної роботи з API:

types/zapys24.ts
// ───────── Загальні типи ─────────

export type ApiScope =
| "business:read"
| "services:read"
| "staff:read"
| "slots:read"
| "bookings:read"
| "bookings:write"
| "reviews:read"
| "webhooks:manage";

export type ApiKeyStatus = "active" | "revoked" | "expired";
export type WebhookStatus = "active" | "inactive" | "failed";
export type WebhookDeliveryStatus =
| "pending"
| "success"
| "failed"
| "retrying";

// ───────── Бізнес ─────────

export interface Business {
id: number;
name: string;
slug: string;
type: string;
description: string;
address: string;
city: string;
phone: string;
email: string;
website?: string;
instagram?: string;
facebook?: string;
latitude: number;
longitude: number;
timezone: string;
workingHours: Record<string, { open: string; close: string } | null>;
bookingSettings: {
allowClientCancellation: boolean;
cancellationMinAdvanceMinutes: number;
maxAdvanceBookingDays: number;
};
logoUrl?: string;
averageRating: number;
reviewCount: number;
photos: BusinessPhoto[];
}

export interface BusinessPhoto {
id: number;
url: string;
thumbnailUrl: string;
order: number;
}

// ───────── Послуги ─────────

export interface Service {
id: number;
name: string;
description: string;
duration: number; // хвилини
price: number; // копійки (ділити на 100)
category: string;
isOnline: boolean;
bufferTimeBefore: number; // хвилини
bufferTimeAfter: number; // хвилини
}

// ───────── Майстри ─────────

export interface Staff {
id: number;
firstName: string;
lastName: string;
position: string;
bio?: string;
avatarUrl?: string;
rating: number;
serviceIds: number[];
schedule: StaffSchedule[];
}

export interface StaffSchedule {
dayOfWeek: string;
startTime: string;
endTime: string;
isWorkingDay: boolean;
}

// ───────── Слоти ─────────

export interface SlotsResponse {
date: string;
slots: Slot[];
}

export interface Slot {
time: string;
staffId: number;
staffName: string;
available: boolean;
}

// ───────── Бронювання ─────────

export interface CreateBookingRequest {
serviceId: number;
staffId?: number;
date: string; // YYYY-MM-DD
time: string; // HH:MM
phone: string; // +380XXXXXXXXX
firstName?: string;
lastName?: string;
email?: string;
notes?: string;
}

export interface BookingResponse {
bookingId: number;
status: string;
serviceName: string;
staffName: string;
startTime: string;
endTime: string;
price: number;
notes?: string;
}

// ───────── Відгуки ─────────

export interface Review {
id: number;
rating: number;
comment: string;
clientName: string;
staffName: string;
serviceName: string;
createdAt: string;
}

export interface PaginatedResponse<T> {
data: T[];
total: number;
page: number;
limit: number;
}

// ───────── Вебхуки ─────────

export interface Webhook {
id: number;
targetUrl: string;
events: string[];
description?: string;
status: WebhookStatus;
consecutiveFailures: number;
lastTriggeredAt?: string;
createdAt: string;
updatedAt: string;
}

export interface WebhookCreated extends Webhook {
secret: string;
}

export interface CreateWebhookRequest {
targetUrl: string;
events: string[];
description?: string;
}

export interface WebhookDelivery {
id: number;
event: string;
deliveryId: string;
responseStatusCode?: number;
responseTimeMs?: number;
deliveryStatus: WebhookDeliveryStatus;
attemptNumber: number;
errorMessage?: string;
createdAt: string;
}

// ───────── Помилки ─────────

export interface ApiError {
statusCode: number;
error: string;
message: string | string[];
retryAfter?: number;
}

// ───────── Webhook Payload ─────────

export interface WebhookPayload<T = unknown> {
id: string;
event: string;
timestamp: string;
apiVersion: string;
data: T;
}

Приклад API-клієнта (axios)

services/zapys24.ts
import axios, { type AxiosInstance } from "axios";
import type {
Business,
Service,
Staff,
SlotsResponse,
CreateBookingRequest,
BookingResponse,
Review,
PaginatedResponse,
Webhook,
WebhookCreated,
CreateWebhookRequest,
WebhookDelivery,
} from "../types/zapys24";

class Zapys24Client {
private api: AxiosInstance;

constructor(apiKey: string) {
this.api = axios.create({
baseURL: "https://api.zapys24.com/v1/integration",
headers: { "X-API-Key": apiKey },
});
}

// ── Бізнес ──

async getBusiness(): Promise<Business> {
const { data } = await this.api.get("/business");
return data;
}

// ── Послуги ──

async getServices(params?: {
category?: string;
onlineOnly?: boolean;
}): Promise<Service[]> {
const { data } = await this.api.get("/services", { params });
return data;
}

async getService(id: number): Promise<Service> {
const { data } = await this.api.get(`/services/${id}`);
return data;
}

// ── Майстри ──

async getStaff(): Promise<Staff[]> {
const { data } = await this.api.get("/staff");
return data;
}

async getStaffMember(id: number): Promise<Staff> {
const { data } = await this.api.get(`/staff/${id}`);
return data;
}

// ── Слоти ──

async getSlots(params: {
serviceId: number;
date: string;
staffId?: number;
}): Promise<SlotsResponse> {
const { data } = await this.api.get("/slots", { params });
return data;
}

async getSlotsRange(params: {
serviceId: number;
from: string;
to: string;
staffId?: number;
}): Promise<SlotsResponse[]> {
const { data } = await this.api.get("/slots/range", { params });
return data;
}

// ── Бронювання ──

async createBooking(booking: CreateBookingRequest): Promise<BookingResponse> {
const { data } = await this.api.post("/bookings", booking);
return data;
}

async getBooking(id: number): Promise<BookingResponse> {
const { data } = await this.api.get(`/bookings/${id}`);
return data;
}

async cancelBooking(id: number, reason?: string): Promise<void> {
await this.api.post(`/bookings/${id}/cancel`, { reason });
}

// ── Відгуки ──

async getReviews(params?: {
page?: number;
limit?: number;
}): Promise<PaginatedResponse<Review>> {
const { data } = await this.api.get("/reviews", { params });
return data;
}

// ── Вебхуки ──

async createWebhook(webhook: CreateWebhookRequest): Promise<WebhookCreated> {
const { data } = await this.api.post("/webhooks", webhook);
return data;
}

async getWebhooks(): Promise<Webhook[]> {
const { data } = await this.api.get("/webhooks");
return data;
}

async deleteWebhook(id: number): Promise<void> {
await this.api.delete(`/webhooks/${id}`);
}

async pingWebhook(id: number): Promise<WebhookDelivery> {
const { data } = await this.api.post(`/webhooks/${id}/ping`);
return data;
}
}

export default Zapys24Client;

Використання

import Zapys24Client from "./services/zapys24";

const client = new Zapys24Client(process.env.ZAPYS24_API_KEY!);

// Отримати послуги
const services = await client.getServices({ onlineOnly: true });

// Отримати вільні слоти
const { slots } = await client.getSlots({
serviceId: services[0].id,
date: "2026-03-15",
});

// Показати тільки вільні
const available = slots.filter((s) => s.available);

// Створити бронювання
const booking = await client.createBooking({
serviceId: services[0].id,
date: "2026-03-15",
time: available[0].time,
phone: "+380991234567",
firstName: "Олена",
});

console.log(`Записано! ID: ${booking.bookingId}`);

Повний приклад: віджет бронювання (Express + HTML)

Серверна частина

server.ts
import express from "express";
import Zapys24Client from "./services/zapys24";

const app = express();
const zapys = new Zapys24Client(process.env.ZAPYS24_API_KEY!);

app.use(express.json());

// Проксі-ендпоінти (щоб не розкривати API-ключ на клієнті)

app.get("/api/services", async (req, res) => {
const services = await zapys.getServices({ onlineOnly: true });
res.json(services);
});

app.get("/api/slots", async (req, res) => {
const { serviceId, date } = req.query;
const slots = await zapys.getSlots({
serviceId: Number(serviceId),
date: String(date),
});
res.json(slots);
});

app.post("/api/bookings", async (req, res) => {
try {
const booking = await zapys.createBooking(req.body);
res.status(201).json(booking);
} catch (err: any) {
const status = err.response?.status || 500;
const body = err.response?.data || { message: "Помилка сервера" };
res.status(status).json(body);
}
});

app.listen(3000);

Клієнтська частина

booking-widget.js
// 1. Завантажити послуги
const services = await fetch("/api/services").then((r) => r.json());

// 2. Коли клієнт обрав послугу та дату — завантажити слоти
const slots = await fetch(
`/api/slots?serviceId=${selectedServiceId}&date=${selectedDate}`,
).then((r) => r.json());

// 3. Показати тільки вільні слоти
const available = slots.slots.filter((s) => s.available);

// 4. Коли клієнт обрав час — створити бронювання
const response = await fetch("/api/bookings", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
serviceId: selectedServiceId,
date: selectedDate,
time: selectedTime,
phone: clientPhone,
firstName: clientName,
}),
});

if (response.ok) {
const booking = await response.json();
alert(`Вас записано! Номер: ${booking.bookingId}`);
} else if (response.status === 409) {
alert("Цей час щойно зайняли. Оберіть інший.");
} else {
alert("Помилка. Спробуйте ще раз.");
}

Утиліта: форматування ціни

utils/price.ts
/**
* Конвертує ціну з копійок у гривні
* @param kopecks - ціна у копійках (напр. 50000)
* @returns відформатована ціна (напр. "500,00 ₴")
*/
export function formatPrice(kopecks: number): string {
return new Intl.NumberFormat("uk-UA", {
style: "currency",
currency: "UAH",
}).format(kopecks / 100);
}

// formatPrice(50000) → "500,00 ₴"
// formatPrice(1250) → "12,50 ₴"