Calendar API

The AirDoo Calendar API provides calendar data, availability, and pricing for accommodations.

Authentication

All requests require a Bearer Token:

Authorization: Bearer your_api_token

Get the token

In Odoo: AirDoo → Configuration → Settings → Native Odoo API Key

Main Endpoint

POST /api/v1/airdoo/calendar

Method: POST Content-Type: application/json Authentication: Bearer Token required

Request Body

{
  "accommodation_id": 4,
  "month": 2,
  "year": 2026
}
Parameter Type Required Description
accommodation_id integer Odoo ID of the accommodation
month integer (1-12) Month (default = current month)
year integer Year (default = current year)

Example Request

curl -X POST "https://your-odoo.com/api/v1/airdoo/calendar" \
  -H "Authorization: Bearer your_api_token" \
  -H "Content-Type: application/json" \
  -d '{"accommodation_id": 4, "month": 2, "year": 2026}'

Successful Response (200)

{
  "success": true,
  "data": {
    "month": 2,
    "year": 2026,
    "accommodation_id": 4,
    "accommodation_name": "Chalet du Frenalay",
    "bookings": [
      {
        "id": 382,
        "confirmation_code": "HM2YEYHZXC",
        "title": "Ignace Wentz",
        "start_date": "2026-01-27",
        "end_date": "2026-02-09",
        "nights": 13,
        "status": "confirmed",
        "source": "airbnb",
        "guest_count": 0,
        "composition": {
          "adults": 1,
          "children": 0,
          "babies": 0
        },
        "total_amount": 1810.96,
        "color_index": 1,
        "notes": ""
      }
    ],
    "blocked_dates": ["2026-01-27", "2026-01-28"],
    "daily_prices": {
      "2026-02-01": 172.5,
      "2026-02-02": 172.5
    },
    "availability_summary": {
      "available_nights": 8,
      "booked_nights": 20,
      "occupancy_rate": 0.714,
      "next_available_date": "2026-02-08"
    },
    "pricing_rules": {
      "base_price": 150.0,
      "min_stay": 2,
      "max_stay": 30,
      "weekly_discount": 0.1,
      "monthly_discount": 0.2,
      "cleaning_fee": 80.0,
      "tax_rate": 0.055
    }
  },
  "metadata": {
    "api_version": "1.0",
    "timestamp": "2026-02-25T23:53:01.073654Z",
    "request_id": "9d9ed309"
  }
}

Diagnostic Endpoints

POST /api/v1/airdoo/calendar/health

Calendar service health check.

curl -X POST "https://your-odoo.com/api/v1/airdoo/calendar/health" \
  -H "Authorization: Bearer your_api_token" \
  -H "Content-Type: application/json" \
  -d '{}'

POST /api/v1/airdoo/calendar/test

Simple connectivity test.

curl -X POST "https://your-odoo.com/api/v1/airdoo/calendar/test" \
  -H "Authorization: Bearer your_api_token" \
  -H "Content-Type: application/json" \
  -d '{}'

POST /api/v1/airdoo/calendar/debug

Returns detailed diagnostic information (module data, available accommodations, etc.).

Error Codes

HTTP Code Error Code Description
400 BAD_REQUEST Invalid or missing parameters
401 UNAUTHORIZED Missing or invalid Bearer Token
403 FORBIDDEN Access denied
404 NOT_FOUND Accommodation not found
500 INTERNAL_ERROR Server error

Error Example

{
  "success": false,
  "error": {
    "code": 400,
    "message": "accommodation_id field required",
    "details": {
      "parameter": "accommodation_id",
      "expected": "integer",
      "received": null
    }
  },
  "metadata": {
    "api_version": "1.0",
    "timestamp": "2026-02-25T23:53:01.956362Z",
    "request_id": "187dd7df"
  }
}

TypeScript Implementation (Next.js)

API Utility

// lib/airdoo-api.ts
const API_BASE_URL = process.env.AIRDOO_API_URL; // Odoo backend URL (server-side)
const API_TOKEN = process.env.AIRDOO_API_TOKEN;

export async function getCalendarData(
  accommodationId: number,
  month?: number,
  year?: number
) {
  const response = await fetch(`${API_BASE_URL}/api/v1/airdoo/calendar`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      accommodation_id: accommodationId,
      ...(month && { month }),
      ...(year && { year }),
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error?.message || 'API request failed');
  }

  return await response.json();
}

Next.js Security

Never expose the token directly in client code. Call the Odoo API from a Next.js Route Handler (server-side), not from the browser.

// app/api/calendar/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const body = await request.json();

  const response = await fetch(
    `${process.env.AIRDOO_API_URL}/api/v1/airdoo/calendar`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.AIRDOO_API_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(body),
    }
  );

  const data = await response.json();
  return NextResponse.json(data);
}

Custom React Hook

// hooks/useCalendarData.ts
import { useState, useEffect } from 'react';

interface CalendarData {
  bookings: Booking[];
  blocked_dates: string[];
  daily_prices: Record<string, number>;
  availability_summary: AvailabilitySummary;
}

export function useCalendarData(accommodationId: number, month: number, year: number) {
  const [data, setData] = useState<CalendarData | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (!accommodationId) return;

    const fetchData = async () => {
      setLoading(true);
      setError(null);
      try {
        // Call your Route Handler (not Odoo directly)
        const result = await fetch('/api/calendar', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ accommodation_id: accommodationId, month, year }),
        });
        const json = await result.json();
        setData(json.data);
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Unknown error');
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [accommodationId, month, year]);

  return { data, loading, error };
}

Odoo Configuration

Verify the API Token

  1. AirDoo → Configuration → Settings
  2. API Settings section → check Native Odoo API Key

Verify Accommodations

  • Accommodations must exist in AirDoo → Accommodations
  • The accommodation_id corresponds to the Odoo record ID

Best Practices

  1. Never expose the token client-side — always use a Route Handler
  2. Cache calendar data (5 minutes recommended)
  3. Handle errors using standardized codes
  4. Validate parameters client-side before sending

← Back: API Overview | Next: Booking API →