Overview
All public endpoints live under the production REST API base URL. Responses are JSON.
https://apis.gabito.eu/api/v1
- Format: JSON (
Content-Type: application/json for POST bodies)
- Methods: mostly
GET (read)
- Unit data: scoped by 10-character public slug (recommended) or legacy numeric
unitId with access code
- No session JWT on public unit endpoints — slug routes for profile, services, and reviews need no access code
- Anti-enumeration: numeric
unitId URLs without an access code return 404 unit_public_numeric_route_blocked
- Field visibility: managers control which fields appear via disclosure settings; responses include a
disclosure object where relevant
This guide covers read-only GET endpoints for building your own website or widget: services, unit profile, contact, opening hours, gallery photos, promotions, bestsellers, reviews, and SEO/about text. For online booking, AI chat, and the client portal, link to Gabito-hosted pages instead of calling write APIs.
Manager-only routes under /unit-public-api/staff/* and chat/booking write endpoints require JWT or session tokens and are not documented here.
Quick start — credentials & manager panel
To call unit-scoped endpoints you need:
- Public slug — 10-character alphanumeric identifier (e.g.
AbCdEfGh12) for public pages at /public/unit/AbCdEfGh12 and API paths /public/units/s/AbCdEfGh12/…. Visible in manager → Public unit API settings. Numeric marketing URLs such as /public/unit/42 are blocked.
- Unit ID — internal numeric identifier (manager panel, client portal login). Do not expose in public marketing links.
- Unit public access code — required for online booking and public chat deep links, and for legacy numeric API routes. Not required for read-only marketing data on slug routes.
Where to find the access code
Log in to the Gabito manager panel → open Public unit API settings at:
/unit-public-api/settings
In the Public API — access code and pages section, set the system parameter unit_public_api.access_code (unit scope). The code is also stored on the unit record as public_api_access_code. Copy it into your integration — treat it like a password.
Enable the channels you need (services, profile, reviews) using the toggle in each module row. Each channel must be ON or its endpoints return 403 with unit_public_api_channel_disabled.
Discover enabled channels (slug route, no access code)
GET /public/units/s/AbCdEfGh12/spa-appearance
GET /public/units/s/AbCdEfGh12 → unit_id, name, public_slug
Replace AbCdEfGh12 with your unit’s 10-character slug from the manager panel. Legacy GET /public/units/{unitId}/spa-appearance without an access code returns 404 unit_public_numeric_route_blocked.
Short links: Gabito also supports URL shortener codes (7+ characters) at https://s.gabito.eu/{code}. These are separate from the 10-character public unit slug.
Authentication
Public marketing endpoints use the slug path prefix /public/units/s/{slug}/… — no access code required. Online booking and AI chat require public_code on Gabito-hosted page URLs. Legacy numeric API routes (/public/units/{unitId}/…) still accept the access code but are not recommended for new integrations.
Slug routes — no access code
All read-only marketing endpoints listed in Unit Public API work with only the 10-character slug in the path. Safe to call from browsers and CDNs without exposing secrets.
Access code — booking, chat, legacy numeric API
When you need the access code, send it via HTTP header (recommended) or query parameter on Gabito-hosted pages:
HTTP header (legacy numeric routes)
X-Unit-Public-Code: <your_access_code>
Query parameter (Gabito-hosted pages)
?public_code=<your_code>
?code=<your_code>
Prefer the header for server-side legacy API calls — query strings may appear in logs and referrer headers.
Common errors
404 unit_public_numeric_route_blocked — numeric unitId URL used without access code (anti-enumeration)
401 unit_public_code_required — legacy numeric route called without code
403 unit_public_code_invalid — wrong code
403 unit_public_api_not_configured — owner has not set an access code yet
404 unit_not_found — invalid slug or unitId
403 unit_public_api_channel_disabled — channel turned off in manager settings
Logged-in client-portal users accessing their own unit may bypass the public code (server-side session). Third-party sites should use slug routes for marketing data and send the access code only for booking/chat links.
Channel flags
Each data area can be enabled or disabled per unit. Flags appear in GET /public/units/s/{slug}/spa-appearance under data.channels.
{
"data": {
"unit_id": 42,
"seo": {
"public_about_text": "We are a boutique wellness studio…",
"public_hero_lead": "Book your visit online in minutes."
},
"channels": {
"customer_reviews": true,
"public_services": true,
"unit_profile": true,
"service_rankings": true,
"public_chat": true,
"online_booking": true,
"client_portal_enabled": true
}
}
}
public_services — GET …/services (catalog, promotions, bestsellers)
unit_profile — GET …/profile, GET …/opening-hours (contact, logo, gallery photos)
customer_reviews — GET …/customer-reviews, GET …/customer-reviews/stats
service_rankings — GET …/service-rankings (curated promotion and bestseller lists)
online_booking, public_chat, client_portal_enabled — no separate read API in this guide; use Gabito-hosted page URLs when these flags are true
spa-appearance, page-settings, and seo-document-head are always available on slug routes (no access code). The seo block includes public_about_text (“About the salon”) and hero copy for your landing page.
Unit Public API
Read salon data for a specific unit. Use slug routes (/public/units/s/{slug}/…) — no access code required. Rate limit: 120 requests/minute per IP on unit endpoints; sitemap: 60/minute.
Path pattern: replace {slug} with a 10-character alphanumeric slug (example: AbCdEfGh12). Legacy numeric paths /public/units/{unitId}/… mirror the same resources but require X-Unit-Public-Code — except spa-appearance and seo-document-head, which are blocked without code.
Resolve slug (no code)
- GET
/public/units/s/{slug} — unit_id, name, public_slug
SPA appearance & about text (no code)
- GET
/public/units/s/{slug}/spa-appearance — template, layout, SEO, channel flags
Use data.seo.public_about_text for the “About the salon” section and data.seo.public_hero_lead for a hero subtitle. Other SEO fields (meta title, description, canonical URL) are included when configured.
SEO document head (no code, SSR)
- GET
/public/units/s/{slug}/seo-document-head — HTML <title>, meta, Open Graph, JSON-LD for server-side rendering
Page settings (no code)
- GET
/public/units/s/{slug}/page-settings — public page module visibility and layout options
Unit profile & contact (channel: unit_profile, no code)
- GET
/public/units/s/{slug}/profile — name, address, contact, logo, gallery photos
- GET
/public/units/s/{slug}/opening-hours — opening hours only (also available inside profile when enabled)
Profile fields depend on disclosure flags: api_show_unit_name, api_show_address, api_show_phone, api_show_email, api_show_logo, api_show_gallery, etc. When gallery is enabled, gallery_groups returns grouped photo URLs configured in the manager panel.
GET /public/units/s/AbCdEfGh12/profile
{
"data": {
"unit_id": 42,
"name": "Beauty Studio Example",
"city": "Warsaw",
"phone": "+48 123 456 789",
"logo_url": "https://…",
"gallery_groups": [
{
"group_index": 1,
"auto_rotate": true,
"interval_seconds": 5,
"default_media_id": 101,
"photos": [{ "id": 101, "url": "https://…", "thumb_url": "https://…", "original_name": "reception.jpg" }]
}
]
},
"disclosure": {
"api_show_unit_name": true,
"api_show_address": false,
"api_show_phone": true
},
"message": "…"
}
Services (channel: public_services, no code)
- GET
/public/units/s/{slug}/services — services grouped by online-visible categories
Only active services with is_visible_online=true are returned. Categories hidden online are omitted entirely. Response includes currency, groups, ungrouped_services, promotion_services, and bestseller_services (curated lists for promo and bestseller panels).
{
"data": {
"currency": "PLN",
"groups": [
{
"service_category_id": 1,
"name": "Treatments",
"description": null,
"services": [
{
"service_id": 10,
"name": "Relaxing massage",
"code": "M01",
"description": "60-minute full body massage",
"duration": 60,
"net_price": "100.00",
"gross_price": "123.00",
"photo_url": null,
"photo_thumb_url": null
}
]
}
],
"ungrouped_services": [],
"promotion_services": [],
"bestseller_services": []
},
"disclosure": {
"code": { "enabled": true },
"photo": { "enabled": true },
"description": { "enabled": true },
"duration": { "enabled": true },
"price": { "enabled": true },
"employees": { "enabled": false }
}
}
Service name and service_id are always present. Other fields appear only when enabled in disclosure settings. Service photos use photo_url / photo_thumb_url when the photo disclosure flag is on.
Service rankings (channel: service_rankings, no code)
- GET
/public/units/s/{slug}/service-rankings — manager-curated promotion and bestseller service lists
Customer reviews (channel: customer_reviews, no code)
- GET
/public/units/s/{slug}/customer-reviews?page=1&per_page=20 — paginated reviews
- GET
/public/units/s/{slug}/customer-reviews/stats — aggregate ratings
Query params: page (default 1), per_page (1–50, default 20). Review text and sub-ratings appear only when enabled in template settings.
{
"data": [
{
"id": 1,
"submitted_at": "2023-10-27T12:00:00+00:00",
"client_first_name": "Anna",
"employee_name": "Maria Kowalska",
"service_names": "Massage, Facial",
"overall_rating": 5,
"opinion_text": "Excellent service."
}
],
"meta": { "current_page": 1, "last_page": 5, "per_page": 20, "total": 100 }
}
Legacy numeric routes (access code required)
The same resources are available at /public/units/{unitId}/profile, …/services, etc. with header X-Unit-Public-Code. Numeric spa-appearance and seo-document-head without code return 404 unit_public_numeric_route_blocked. Prefer slug routes for new integrations.
Gabito-hosted pages (deep links)
For online booking, AI assistant chat, and the client portal, link users to ready-made Gabito SPA pages instead of integrating write APIs. Production app base URL:
https://s.gabito.eu
Check channels.online_booking, channels.public_chat, and channels.client_portal_enabled from spa-appearance before showing a button.
Public unit hub
https://s.gabito.eu/public/unit/AbCdEfGh12 — full salon page (profile, services, reviews) without access code
- Section anchors:
#profil, #promocje, #bestsellery, #uslugi, #opinie, #kontakt
Online booking (access code required)
https://s.gabito.eu/public/unit/AbCdEfGh12/booking?public_code=<code>
- Pre-select a service:
?service_id=10&public_code=<code>
AI assistant (public chat) (access code required)
https://s.gabito.eu/public/unit/AbCdEfGh12/chat?public_code=<code>
Client portal
https://s.gabito.eu/client-portal/login?unit_id={unitId} — pre-selects the salon on the login screen
- After login, clients use
/client-portal/dashboard and related routes inside the Gabito app
These URLs open Gabito’s own UI. They do not require you to call chat, booking, or portal REST endpoints from your site.
CORS (browser integrations)
The API sends CORS headers for approved origins configured server-side (CORS_ALLOWED_ORIGINS, CORS_EXTRA_ORIGINS). Production defaults include:
https://gabito.eu, https://www.gabito.eu
https://s.gabito.eu, https://www.s.gabito.eu
If you embed fetch calls from a custom domain, that origin must be allowlisted on the API server — contact kontakt@gabito.eu for enterprise CORS setup.
Server-side integrations (Node, PHP, Python cron jobs) are not subject to CORS — call the API directly with the access code header.
Rate limits & HTTP status codes
- Unit Public API: 120 req/min per IP
- Units sitemap: 60 req/min per IP
Exceeded limits return 429 Too Many Requests. Validation errors return 422 with field messages. Disabled channels return 403 with an error code in JSON.
Tutorial — build your own services page
Minimal flow for a static or SPA site that lists a salon's services on your domain. Slug routes need no backend proxy — call the API directly from the browser or your server.
Step 1 — configuration
const API_BASE = 'https://apis.gabito.eu/api/v1';
const PUBLIC_SLUG = 'AbCdEfGh12'; // from manager → Public unit API settings
const ACCESS_CODE = process.env.GABITO_UNIT_PUBLIC_CODE; // only for booking/chat links
Step 2 — check channels & about text
const appearance = await fetch(
`${API_BASE}/public/units/s/${PUBLIC_SLUG}/spa-appearance`
).then(r => r.json());
const channels = appearance.data.channels;
const aboutText = appearance.data.seo?.public_about_text || '';
if (!channels.public_services) {
// hide services section — channel disabled
}
if (channels.online_booking) {
// show link: https://s.gabito.eu/public/unit/${PUBLIC_SLUG}/booking?public_code=${ACCESS_CODE}
}
Step 3 — fetch profile and services
const [profile, services] = await Promise.all([
fetch(`${API_BASE}/public/units/s/${PUBLIC_SLUG}/profile`).then(r => r.json()),
fetch(`${API_BASE}/public/units/s/${PUBLIC_SLUG}/services`).then(r => r.json()),
]);
Step 4 — render
Use profile.data for contact and gallery. Use aboutText for the “About the salon” block. Iterate services.data.groups and optionally promotion_services / bestseller_services — check services.disclosure.price.enabled before showing prices.
Step 5 — optional reviews block
const stats = await fetch(
`${API_BASE}/public/units/s/${PUBLIC_SLUG}/customer-reviews/stats`
).then(r => r.json());
Security: slug routes expose no secrets — safe for client-side fetch. Keep the access code server-side and append it only to booking and chat deep links (?public_code=), never to marketing API calls.
Integration scenarios
- Custom marketing website with live service catalog, promotions, bestsellers, and reviews
- Embedded service list or review widget on Webflow, Shopify, or any existing website
- Mobile app showing salon profile, opening hours, gallery, and service menu
- Partner aggregators syncing read-only catalog and customer ratings
- “Book now” / “Chat with us” / “Client portal” buttons linking to Gabito-hosted pages
Sitemap for indexable public pages: GET https://apis.gabito.eu/api/v1/public/units-sitemap.xml (lists slug URLs only).
For dedicated CORS origins, higher rate limits, or webhooks — email us.
Test the API on your own unit
Create a trial account, enable Public Unit API in the manager panel at /unit-public-api/settings, copy your public slug, and call the slug endpoints above with curl or Postman.