External API v1 Documentation

This documentation describes the external API v1 compliant with Odoo 18 standards, using native Odoo API Key authentication.

Introduction

The API v1 is a complete rewrite of the AirDoo API compliant with Odoo 18 standards. It uses native Odoo API Key authentication (auth='api_key') and follows modern RESTful conventions.

Key Features

  • Native Odoo authentication: Uses Odoo's built-in API Key system
  • Standard JSON format: Structured responses with uniform metadata
  • Idempotency: Idempotency key support to prevent duplicates
  • Price validation: Automatic verification of calculated amounts
  • Stripe integration: Secure payment flow with webhooks
  • Secure Next.js architecture: Mandatory Route Handler to protect API keys
  • Semantic versioning: Version 1.0.0

Base URL

https://your-odoo-instance.com/api/v1/airdoo/

Authentication

Authentication Method

The API v1 uses native Odoo API Key authentication via HTTP header:

Authorization: Bearer your_api_token

How to Get the API Key

  1. In Odoo: AirDoo → Configuration → Settings
  2. API Settings section: Click "Generate API Key"
  3. Use the technical user: The airdoo_api_user is automatically created with the module

API User Configuration

The technical user is defined in data/airdoo_api_user_data.xml without a plaintext password. The password is randomly generated at installation via a post_init_hook.

Important: The password is automatically generated at installation. To retrieve the API key: 1. Go to Settings → Users & Companies → Users 2. Find "AirDoo API System User" 3. Click "Generate API Key" in the "Preferences" tab

HTTP Header Example

POST /api/v1/airdoo/availability HTTP/1.1
Host: your-odoo-instance.com
Authorization: Bearer your_api_token
Content-Type: application/json
Accept: application/json

Available Endpoints

1. POST /api/v1/airdoo/availability — Check Availability

Checks availability for a period and calculates the price.

Request

{
  "accommodation_id": 1,
  "checkin": "2026-06-15",
  "checkout": "2026-06-20",
  "guest_count": 2,
  "extras": {
    "breakfast": true,
    "linen": false,
    "late_checkin": true
  }
}

Response (Success)

{
  "success": true,
  "data": {
    "available": true,
    "nights": 5,
    "pricing": {
      "base_price": 750.00,
      "avg_price_per_night": 150.00,
      "cleaning_fee": 80.00,
      "tax": 45.65,
      "extras": {
        "breakfast": 75.00,
        "late_checkin": 30.00
      },
      "discounts": {
        "weekly": 0.10
      },
      "total": 980.65
    },
    "restrictions": {
      "min_stay": 2,
      "max_stay": 30,
      "max_guests": 6,
      "checkin_time": "15:00",
      "checkout_time": "10:00"
    },
    "message": "Available"
  },
  "metadata": {
    "api_version": "1.0",
    "timestamp": "2026-02-28T12:00:00Z",
    "endpoint": "v1"
  }
}

Response (Not Available)

{
  "success": true,
  "data": {
    "available": false,
    "message": "Dates not available (conflict with booking CHALET2026-123)",
    "nights": 0,
    "pricing": null,
    "restrictions": null
  }
}

2. POST /api/v1/airdoo/bookings — Create a Booking

Creates a direct booking.

Request

{
  "accommodation_id": 1,
  "partner_data": {
    "title": "Mr.",
    "first_name": "John",
    "last_name": "Smith",
    "email": "john.smith@email.com",
    "phone": "+44712345678",
    "address": {
      "street": "123 Example Street",
      "city": "London",
      "zip": "SW1A 1AA",
      "country": "United Kingdom"
    }
  },
  "booking_data": {
    "checkin_date": "2026-06-15",
    "checkout_date": "2026-06-20",
    "adults_count": 2,
    "children_count": 1,
    "babies_count": 0,
    "guest_notes": "Wedding anniversary",
    "payment_method": "stripe",
    "payment_token": "tok_visa_123456",
    "total_amount": 980.65
  },
  "extras": {
    "breakfast": true,
    "linen": false,
    "late_checkin": true
  }
}

Response (Success)

{
  "success": true,
  "data": {
    "booking_id": 123,
    "confirmation_code": "CHALET2026-123",
    "partner_id": 456,
    "invoice_url": "https://odoo/invoice/789",
    "next_steps": [
      "Confirmation email sent",
      "Payment processed",
      "Calendar updated"
    ]
  },
  "metadata": {
    "api_version": "1.0",
    "timestamp": "2026-02-28T12:00:00Z",
    "endpoint": "v1"
  }
}

3. GET /api/v1/airdoo/bookings/<booking_id> — Retrieve a Booking

Retrieves the details of an existing booking.

Response

{
  "success": true,
  "data": {
    "id": 123,
    "confirmation_code": "CHALET2026-123",
    "accommodation_name": "The Mountain Chalet",
    "checkin_date": "2026-06-15",
    "checkout_date": "2026-06-20",
    "nights": 5,
    "guest_count": 3,
    "composition": {
      "adults": 2,
      "children": 1,
      "babies": 0
    },
    "total_amount": 980.65,
    "status": "confirmed",
    "partner": {
      "id": 456,
      "name": "John Smith",
      "email": "john.smith@email.com",
      "phone": "+44712345678"
    }
  }
}

4. GET /api/v1/airdoo/test — Test the API

Test endpoint to verify the API is working.

Response

{
  "success": true,
  "data": {
    "status": "ok",
    "message": "API v1 functional",
    "timestamp": "2026-02-28T12:00:00Z",
    "user": "airdoo_api_user",
    "login": "airdoo_api_user"
  }
}

Data Structures

PartnerData

interface PartnerData {
  title?: string;           // "Mr.", "Mrs.", "Ms."
  first_name: string;       // First name
  last_name: string;        // Last name
  email: string;            // Email (required)
  phone?: string;           // Phone
  address?: {
    street?: string;
    city?: string;
    zip?: string;
    country?: string;
  };
}

BookingData

interface BookingData {
  checkin_date: string;     // Format: "YYYY-MM-DD"
  checkout_date: string;    // Format: "YYYY-MM-DD"
  adults_count: number;
  children_count: number;
  babies_count: number;
  guest_notes?: string;     // Notes for the host
  payment_method: string;   // "stripe", "bank_transfer", "cash"
  payment_token: string;    // Payment token
  total_amount: number;     // Total amount
}

Pricing

interface Pricing {
  base_price: number;
  avg_price_per_night: number;
  cleaning_fee: number;
  tax: number;
  extras: Record<string, number>;
  discounts: Record<string, number>;
  total: number;
}

Usage Examples

cURL Example

# Test the API
curl -X GET \
  -H "Authorization: Bearer your_api_token" \
  https://your-odoo-instance.com/api/v1/airdoo/test

# Check availability
curl -X POST \
  -H "Authorization: Bearer your_api_token" \
  -H "Content-Type: application/json" \
  -d '{
    "accommodation_id": 1,
    "checkin": "2026-06-15",
    "checkout": "2026-06-20",
    "guest_count": 2
  }' \
  https://your-odoo-instance.com/api/v1/airdoo/availability

Python Example

import requests

class AirDooV1API:
    def __init__(self, base_url, api_key):
        self.base_url = base_url.rstrip('/')
        self.headers = {
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json'
        }

    def test(self):
        response = requests.get(
            f"{self.base_url}/api/v1/airdoo/test",
            headers=self.headers
        )
        return response.json()

    def check_availability(self, accommodation_id, checkin, checkout, guest_count=2):
        response = requests.post(
            f"{self.base_url}/api/v1/airdoo/availability",
            headers=self.headers,
            json={
                'accommodation_id': accommodation_id,
                'checkin': checkin,
                'checkout': checkout,
                'guest_count': guest_count,
            }
        )
        return response.json()

# Usage
api = AirDooV1API(
    base_url='https://your-odoo-instance.com',
    api_key='your_api_key'
)
print(api.test())

Error Handling

Standard Error Format

{
  "error": {
    "code": 400,
    "message": "Error description",
    "details": {
      "field": "checkin",
      "reason": "Invalid date format"
    }
  }
}

Common Error Codes

Code Description Likely Cause
400 Bad Request Invalid or missing parameters
401 Unauthorized Missing or invalid API key
403 Forbidden Unauthorized access
404 Not Found Resource not found
409 Conflict Data conflict (dates already booked)
500 Internal Server Error Server error

Migration from Old API

Endpoint Comparison

Old API New API v1 Changes
/airdoo/api/availability /api/v1/airdoo/availability Same functionality, new format
/airdoo/api/create_booking /api/v1/airdoo/bookings RESTful naming
N/A /api/v1/airdoo/bookings/<id> New GET endpoint
N/A /api/v1/airdoo/test New test endpoint

Key Changes

  1. Authentication: Bearer Token instead of the old system
  2. Response format: Standardized structure with success, data, metadata
  3. Versioning: All endpoints under /api/v1/

Migration Example

Old code:

const response = await fetch('/airdoo/api/create_booking', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'call',
    params: { accommodation_id: 1 }
  })
});

New code:

const response = await fetch('/api/v1/airdoo/bookings', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer your_api_token',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ accommodation_id: 1 })
});

Troubleshooting

Common Issues

  1. Error 401: Check API key in headers
  2. Error 404: Check URL and accommodation ID
  3. Error 500: Check Odoo logs for details

Test with cURL

curl -v -H "Authorization: Bearer your_token" http://localhost:8069/api/v1/airdoo/test

Support

  • Email: support@kalpana.com.br

← Back: API Overview | Next: Calendar API

Version: 1.0.0 Last updated: 2026-02-28