Skip to main content
Glama
duffelStaysClient.ts3.07 kB
/** * Duffel Stays API Client */ import axios, { AxiosInstance } from 'axios'; export interface StaySearchParams { location: string; // e.g. city or airport code check_in_date: string; // YYYY-MM-DD check_out_date: string; // YYYY-MM-DD guests: number; rooms?: number; radius_km?: number; // Add more params as needed } export interface StayOffer { hotel_id: string; offer_id: string; hotel_name: string; address: string; price: { amount: string; currency: string; }; room_type: string; cancellation_policy: string; // Add more fields as needed } export interface StayOfferResponse { offers: StayOffer[]; } import { StayReviewRequest, StayReviewResponse } from '../models/stayReview.js'; export class DuffelStaysClient { private client: AxiosInstance; private baseUrl: string = 'https://api.duffel.com/stays'; constructor() { const apiKey = process.env.DUFFEL_API_KEY; if (!apiKey) { throw new Error('DUFFEL_API_KEY environment variable is not set'); } this.client = axios.create({ baseURL: this.baseUrl, headers: { 'Accept': 'application/json', 'Duffel-Version': 'v1', 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, timeout: 60000, }); } /** * Search for hotel/accommodation offers */ async searchOffers(params: StaySearchParams): Promise<StayOfferResponse> { // Duffel API docs: https://duffel.com/docs/api/v2/offers const response = await this.client.post('/offers', { location: params.location, check_in_date: params.check_in_date, check_out_date: params.check_out_date, guests: params.guests, rooms: params.rooms, radius_km: params.radius_km, }); // Adapt to Duffel's real response structure const offers = (response.data.data || []).map((offer: any) => ({ offer_id: offer.id, hotel_id: offer.hotel?.id || '', hotel_name: offer.hotel?.name || '', address: offer.hotel?.address?.line_1 || '', price: offer.total_amount ? { amount: offer.total_amount, currency: offer.currency } : { amount: '', currency: '' }, room_type: offer.room_type || '', cancellation_policy: offer.cancellation_policy || '', })); return { offers }; } /** * Fetch stay reviews */ async getStayReviews(params: StayReviewRequest): Promise<StayReviewResponse> { const { stay_id, after, before, limit } = params; const query: Record<string, string | number> = {}; if (after) query.after = after; if (before) query.before = before; if (limit) query.limit = limit; const response = await this.client.get(`/accommodation/${stay_id}/reviews`, { params: query, headers: { 'Duffel-Version': 'v2' } }); const meta = response.data.meta || {}; const reviews = (response.data.data?.reviews || []).map((r: any) => ({ text: r.text, score: r.score, reviewer_name: r.reviewer_name, created_at: r.created_at, })); return { meta, reviews }; } }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/clockworked247/flights-mcp-ts'

If you have feedback or need assistance with the MCP directory API, please join our Discord server