# AITravel.az AI-agent-ready travel platform — Agent Tools Guide

AITravel.az is an **AI-agent-ready** travel platform. This document is a human- and
LLM-friendly guide to the public agent API. It describes every REST endpoint an AI
agent (or any HTTP client) can call to search destinations, build trip plans, look up
tours and excursions, check approximate availability, and create operator-reviewed
travel requests.

- Site: <https://aitravel.az>
- OpenAPI spec: <https://aitravel.az/openapi.json>
- Agent manifest: <https://aitravel.az/.well-known/ai-agent.json>

## Overview

The agent API is a small set of HTTP endpoints. Reads are public and require **no
authentication**. CORS is open, so the API can be called from browsers, server-side
agents, or LLM tool runtimes. The OpenAI key used internally for trip planning lives
**server-side only** and is never exposed to clients.

> **Important:** All prices returned by this API are **approximate**. No booking is ever
> final through the API. Every booking requires **human / operator confirmation**.

## Base URL and how to call

**Working base URL (live today):**

```
https://zdzwsxpbnebhbclomdcy.supabase.co/functions/v1/agent
```

This is implemented as a Supabase Edge Function. It is public, CORS-open, and needs no
auth for reads.

**Planned vanity URL (reverse-proxy — NOT live yet):**

```
https://aitravel.az/api/agent
```

Once the reverse-proxy is in place, the same endpoints will be reachable under this
cleaner URL. Until then, use the working Supabase URL above.

All endpoint paths below are relative to the base URL. For example, `POST /plan-trip`
means `POST https://zdzwsxpbnebhbclomdcy.supabase.co/functions/v1/agent/plan-trip`.

Send and expect `Content-Type: application/json`.

---

## 1. POST /plan-trip

**Purpose:** Generate a structured, day-by-day trip plan from a natural-language query.
Internally calls an LLM server-side and returns an itinerary, approximate budget, and
suggested hotels and activities.

**Method + path:** `POST /plan-trip`

### Input

| Field       | Type                    | Required | Description |
|-------------|-------------------------|----------|-------------|
| `query`     | string                  | yes      | Natural-language trip request. |
| `lang`      | `"az"` \| `"ru"` \| `"en"` | no    | Response language. Defaults to `az`. |
| `dates`     | string                  | no       | Free-text or ISO date range. |
| `budget`    | string                  | no       | Free-text budget hint (e.g. `"1500 USD"`). |
| `travelers` | string                  | no       | Free-text traveler description (e.g. `"2 adults"`). |

### Output

`TripPlan` object:

```json
{
  "summary": "5-day cultural trip to Georgia for two travelers.",
  "destinations": ["Tbilisi", "Kazbegi"],
  "budget": { "currency": "USD", "total": 1450, "perPerson": 725 },
  "itinerary": [
    {
      "day": 1,
      "city": "Tbilisi",
      "morning": "Arrive, check in, walk the Old Town.",
      "afternoon": "Narikala Fortress cable car.",
      "evening": "Dinner on Shardeni Street.",
      "tips": "Wear comfortable shoes for cobbled streets."
    }
  ],
  "hotels": ["Example Boutique Hotel, Tbilisi"],
  "activities": ["Sulfur bath visit", "Wine tasting tour"],
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

### Safety notes

- All budget figures are **approximate** estimates, not quotes.
- The plan is advisory; it does not reserve anything and cannot be treated as a booking.
- Agents must not present any figure here as a final price.

### curl example

```bash
curl -X POST \
  "https://zdzwsxpbnebhbclomdcy.supabase.co/functions/v1/agent/plan-trip" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "5-day cultural trip to Georgia for two people",
    "lang": "en",
    "dates": "2026-06-10 to 2026-06-15",
    "budget": "1500 USD",
    "travelers": "2 adults"
  }'
```

### Example response

```json
{
  "summary": "5-day cultural trip to Georgia for two travelers.",
  "destinations": ["Tbilisi", "Kazbegi"],
  "budget": { "currency": "USD", "total": 1450, "perPerson": 725 },
  "itinerary": [
    {
      "day": 1,
      "city": "Tbilisi",
      "morning": "Arrive, check in, walk the Old Town.",
      "afternoon": "Narikala Fortress cable car.",
      "evening": "Dinner on Shardeni Street.",
      "tips": "Wear comfortable shoes."
    },
    {
      "day": 2,
      "city": "Kazbegi",
      "morning": "Drive along the Georgian Military Highway.",
      "afternoon": "Gergeti Trinity Church.",
      "evening": "Mountain-view dinner.",
      "tips": "Bring a warm layer for higher altitude."
    }
  ],
  "hotels": ["Example Boutique Hotel, Tbilisi", "Mountain Lodge, Kazbegi"],
  "activities": ["Sulfur bath visit", "Wine tasting tour"],
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

---

## 2. GET /destinations

**Purpose:** Search the destination catalog with optional filters.

**Method + path:** `GET /destinations`

### Input (query parameters)

| Param        | Type   | Required | Description |
|--------------|--------|----------|-------------|
| `category`   | string | no       | Destination category filter (e.g. `beach`, `culture`). |
| `budget_max` | number | no       | Maximum approximate budget filter. |
| `season`     | string | no       | Season filter (e.g. `summer`). |
| `q`          | string | no       | Free-text search query. |

### Output

```json
{
  "destinations": [
    {
      "slug": "tbilisi",
      "name": "Tbilisi",
      "country": "Georgia",
      "city": "Tbilisi",
      "short_description": "Historic capital with thermal baths and wine culture.",
      "best_for": ["culture", "food", "city break"],
      "approximate_budget_from": 600,
      "currency": "USD",
      "duration_options": ["3 days", "5 days", "7 days"],
      "season": "all year",
      "disclaimer": "Prices are approximate."
    }
  ],
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

### Safety notes

- `approximate_budget_from` is a starting estimate only, never a quote.
- Read-only; no user data is created or modified.

### curl example

```bash
curl "https://zdzwsxpbnebhbclomdcy.supabase.co/functions/v1/agent/destinations?category=culture&budget_max=1000&season=summer&q=georgia"
```

### Example response

```json
{
  "destinations": [
    {
      "slug": "tbilisi",
      "name": "Tbilisi",
      "country": "Georgia",
      "city": "Tbilisi",
      "short_description": "Historic capital with thermal baths and wine culture.",
      "best_for": ["culture", "food", "city break"],
      "approximate_budget_from": 600,
      "currency": "USD",
      "duration_options": ["3 days", "5 days", "7 days"],
      "season": "all year",
      "disclaimer": "Prices are approximate."
    }
  ],
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

---

## 3. GET /tours

**Purpose:** Search packaged tours with optional filters.

**Method + path:** `GET /tours`

### Input (query parameters)

| Param         | Type   | Required | Description |
|---------------|--------|----------|-------------|
| `destination` | string | no       | Destination slug or name filter. |
| `category`    | string | no       | Tour category filter. |
| `budget_max`  | number | no       | Maximum approximate price filter. |

### Output

```json
{
  "tours": [
    {
      "slug": "georgia-classic-5d",
      "title": "Georgia Classic 5 Days",
      "destination": "Georgia",
      "category": "culture",
      "duration": "5 days",
      "approximate_price_from": 750,
      "currency": "USD",
      "includes": ["hotels", "breakfast", "guided tours"],
      "disclaimer": "Prices are approximate."
    }
  ],
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

### Safety notes

- `approximate_price_from` is a starting estimate only.
- Read-only; agents must not present these as final prices.

### curl example

```bash
curl "https://zdzwsxpbnebhbclomdcy.supabase.co/functions/v1/agent/tours?destination=georgia&category=culture&budget_max=1000"
```

### Example response

```json
{
  "tours": [
    {
      "slug": "georgia-classic-5d",
      "title": "Georgia Classic 5 Days",
      "destination": "Georgia",
      "category": "culture",
      "duration": "5 days",
      "approximate_price_from": 750,
      "currency": "USD",
      "includes": ["hotels", "breakfast", "guided tours"],
      "disclaimer": "Prices are approximate."
    }
  ],
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

---

## 4. GET /excursions

**Purpose:** Search day excursions in a city.

**Method + path:** `GET /excursions`

### Input (query parameters)

| Param      | Type   | Required | Description |
|------------|--------|----------|-------------|
| `city`     | string | no       | City filter. |
| `category` | string | no       | Excursion category filter. |

### Output

```json
{
  "excursions": [
    {
      "slug": "tbilisi-old-town-walk",
      "title": "Tbilisi Old Town Walking Tour",
      "city": "Tbilisi",
      "duration": "3 hours",
      "approximate_price_from": 25,
      "currency": "USD",
      "disclaimer": "Prices are approximate."
    }
  ],
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

### Safety notes

- `approximate_price_from` is a starting estimate only.
- Read-only.

### curl example

```bash
curl "https://zdzwsxpbnebhbclomdcy.supabase.co/functions/v1/agent/excursions?city=tbilisi&category=walking"
```

### Example response

```json
{
  "excursions": [
    {
      "slug": "tbilisi-old-town-walk",
      "title": "Tbilisi Old Town Walking Tour",
      "city": "Tbilisi",
      "duration": "3 hours",
      "approximate_price_from": 25,
      "currency": "USD",
      "disclaimer": "Prices are approximate."
    }
  ],
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

---

## 5. POST /create-lead

**Purpose:** Create a travel request (lead) or VIP-manager request. The result is always
a **draft** that an operator must review and confirm. Nothing is booked automatically.

**Method + path:** `POST /create-lead`

### Input

| Field         | Type                          | Required | Description |
|---------------|-------------------------------|----------|-------------|
| `type`        | `"lead"` \| `"vip_manager"`   | no       | Request type. Defaults to `lead`. |
| `name`        | string                        | no       | Customer name. |
| `contact`     | string                        | yes      | Phone, email, or messenger handle. |
| `destination` | string                        | no       | Desired destination. |
| `dates`       | string                        | no       | Desired dates. |
| `travelers`   | number                        | no       | Number of travelers. |
| `budget`      | string                        | no       | Free-text budget. |
| `message`     | string                        | yes      | Request details / free text. |
| `lang`        | string                        | no       | Preferred language (`az`, `ru`, `en`). |

### Output

```json
{
  "request_id": "req_8f2a91",
  "status": "draft_pending_operator",
  "message": "Your request was received and is pending operator confirmation.",
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

### Safety notes

- The request is created as a **draft** with status `draft_pending_operator`.
- No booking is confirmed and no price is finalized by this call.
- Collect only the contact info the user willingly provides; do not expose other users' data.
- Agents must not claim the request is booked or confirmed.

### curl example

```bash
curl -X POST \
  "https://zdzwsxpbnebhbclomdcy.supabase.co/functions/v1/agent/create-lead" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "lead",
    "name": "Aysel",
    "contact": "+994 50 000 00 00",
    "destination": "Georgia",
    "dates": "2026-06-10 to 2026-06-15",
    "travelers": 2,
    "budget": "1500 USD",
    "message": "Interested in a 5-day cultural trip.",
    "lang": "en"
  }'
```

### Example response

```json
{
  "request_id": "req_8f2a91",
  "status": "draft_pending_operator",
  "message": "Your request was received and is pending operator confirmation.",
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

---

## 6. POST /check-availability

**Purpose:** Return an **approximate** availability indication for a destination and
dates. This is never a guaranteed inventory check.

**Method + path:** `POST /check-availability`

### Input

| Field         | Type   | Required | Description |
|---------------|--------|----------|-------------|
| `destination` | string | yes      | Destination to check. |
| `dates`       | string | no       | Desired dates. |
| `travelers`   | number | no       | Number of travelers. |

### Output

```json
{
  "destination": "Georgia",
  "status": "approximate",
  "available": true,
  "note": "Likely available; subject to operator confirmation.",
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

### Safety notes

- `status` is always `"approximate"`; `available` is an indication, not a guarantee.
- Real availability and pricing are confirmed only by a human operator.

### curl example

```bash
curl -X POST \
  "https://zdzwsxpbnebhbclomdcy.supabase.co/functions/v1/agent/check-availability" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": "Georgia",
    "dates": "2026-06-10 to 2026-06-15",
    "travelers": 2
  }'
```

### Example response

```json
{
  "destination": "Georgia",
  "status": "approximate",
  "available": true,
  "note": "Likely available; subject to operator confirmation.",
  "disclaimer": "Prices are approximate. Booking requires operator confirmation."
}
```

---

## Safety & limits

- **Prices are always approximate.** Every price field (`budget`, `approximate_budget_from`,
  `approximate_price_from`, etc.) is an estimate, never a final quote.
- **Booking always requires human / operator confirmation.** No endpoint books, pays, or
  confirms anything. `POST /create-lead` only creates a draft with status
  `draft_pending_operator`.
- **Agents must not:**
  - modify or invent prices,
  - delete or alter user data,
  - expose private or other users' data,
  - claim any price or availability is final.
- Reads (`/destinations`, `/tours`, `/excursions`, `/check-availability`) are public and
  require no authentication. The OpenAI key used by `/plan-trip` is server-side only.
- A rate limit may apply (configured server-side); design agents to retry politely with
  backoff.

## Languages

- **Primary language:** `az` (Azerbaijani).
- **Supported languages:** `az`, `ru`, `en`.
- Pass the desired language via the `lang` field (`plan-trip`, `create-lead`) or rely on
  the default (`az`). Endpoints localize human-readable text where possible; structured
  fields (slugs, currency codes) remain stable across languages.
