Embed & API Guide · Hướng Dẫn Nhúng & API
Overview
Dovara.Biz offers three ways to integrate booking into any external website or app:
| Tier | Method | Best for |
|---|---|---|
| Tier 1 | iFrame Embed | Simple websites — paste one line of HTML |
| Tier 2 | JS Widget | Any site — floating "Book Now" button with a modal |
| Tier 3 | REST API | Developers — full server-to-server integration |
Setup
Tier 1 — iFrame Embed
Paste this HTML anywhere on your website to show the full booking wizard inline. Replace YOUR_EMBED_TOKEN with your token from Settings → Embed & API. The token identifies your booking page without exposing your internal provider ID.
<iframe
src="https://dovara.biz/book?token=YOUR_EMBED_TOKEN&embed=1"
width="100%"
height="650"
frameborder="0"
allow="forms"
loading="lazy">
</iframe>
Optional URL parameters:
| Parameter | Example | Purpose |
|---|---|---|
token | ?token=a3f8c2... | Your embed token (from Settings → Embed & API) |
lang | &lang=vi | Force a language: en, vi, th, km, lo |
embed | &embed=1 | Enables embed mode (no header/footer) |
Tier 2 — JS Widget
Paste one <script> tag anywhere in your page's <body>. A floating button appears — clicking it opens the booking form in a modal overlay.
<script
src="https://dovara.biz/widget.js"
data-token="YOUR_EMBED_TOKEN"
data-lang="en"
data-color="#0A76D8"
data-label="Book Now"
data-position="bottom-right">
</script>
Attributes:
| Attribute | Default | Description |
|---|---|---|
data-token | — | Required. Your embed token from Settings → Embed & API. Does not expose your internal provider ID. |
data-lang | en | Widget language: en, vi, th, km, lo |
data-color | #0A76D8 | Button background colour (any CSS colour) |
data-label | Book Now | Button label text |
data-position | bottom-right | bottom-right or bottom-left |
data-base-url | auto | Override base URL (advanced) |
Tier 3 — REST API
All API endpoints require your API key. Pass it as an HTTP header (recommended) or as a query parameter:
Option A — Authorization header (recommended)
Authorization: Bearer YOUR_64_CHAR_API_KEY
Option B — Query parameter
GET /api/v1/sessions.php?api_key=YOUR_64_CHAR_API_KEY&date=2026-03-25
Rate limits:
| Endpoint | Limit |
|---|---|
| GET /api/v1/sessions.php | 60 requests / minute |
| POST /api/v1/book.php | 20 requests / minute |
Rate limit is per API key per minute window. HTTP 429 is returned when exceeded, with a Retry-After: 60 header.
GET https://dovara.biz/api/v1/sessions.php
Query Parameters:
| Parameter | Required | Description |
|---|---|---|
date | No | Date in YYYY-MM-DD format. Defaults to today. |
api_key | Alt. | API key (or use Authorization header) |
The provider is identified by your API key — no provider ID is required or accepted.
Example request:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://dovara.biz/api/v1/sessions.php?date=2026-03-25"
Success response (200):
{
"status": "ok",
"date": "2026-03-25",
"sessions": [
{
"id": 7,
"time": "09:00",
"title": "Trang",
"capacity": 2,
"booked": 1,
"available": 1
},
{
"id": 8,
"time": "09:00",
"title": "Lan",
"capacity": 2,
"booked": 0,
"available": 2
}
]
}
POST https://dovara.biz/api/v1/book.php
Request body (JSON):
| Field | Required | Description |
|---|---|---|
session_id | Yes | Schedule ID from the sessions endpoint |
name | Yes | Client full name |
email | One of | Client email address |
phone | One of | Client phone number (at least email or phone required) |
note | No | Optional note to the provider |
Example request:
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"session_id": 7,
"name": "Nguyen Van A",
"email": "nvana@example.com",
"phone": "+84901234567",
"note": "Please confirm by SMS"
}' \
"https://dovara.biz/api/v1/book.php"
Success response (201):
{
"status": "ok",
"ref": "BK-1Z",
"appo_number": 2,
"appo_id": 55,
"session_id": 7,
"session_date": "2026-03-25",
"session_time": "09:00"
}
Error responses:
| HTTP | code | Meaning |
|---|---|---|
| 401 | missing_api_key | No key provided |
| 401 | invalid_api_key | Key not found or provider not public |
| 404 | session_not_found | Session doesn't exist for this provider |
| 409 | session_full | No capacity remaining |
| 409 | session_past | Session date is in the past |
| 422 | validation | Missing / invalid fields |
| 429 | rate_limited | Too many requests |
Full Example
This example queries available sessions and then books the first available one:
const API_KEY = 'YOUR_64_CHAR_API_KEY';
const BASE = 'https://dovara.biz';
const HEADERS = { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' };
const TODAY = new Date().toISOString().slice(0, 10);
async function run() {
// 1. Get sessions for today (provider derived from API key — no ID needed)
const res1 = await fetch(`${BASE}/api/v1/sessions.php?date=${TODAY}`, { headers: HEADERS });
const data1 = await res1.json();
const session = data1.sessions.find(s => s.available > 0);
if (!session) { console.log('No available sessions today.'); return; }
// 2. Book the first available session
const res2 = await fetch(`${BASE}/api/v1/book.php`, {
method: 'POST',
headers: HEADERS,
body: JSON.stringify({
session_id: session.id,
name: 'Nguyen Van A',
email: 'nvana@example.com',
phone: '+84901234567',
})
});
const data2 = await res2.json();
console.log('Booking confirmed:', data2.ref, '— Appo #', data2.appo_number);
}
run();