@nowahapp/sdk
v0.2.0
Published
Official SDK for the Nowah Travel API
Maintainers
Readme
Why Nowah?
Nowah unifies the fragmented travel API landscape into a single, developer-friendly interface. Instead of integrating separately with GDS systems, hotel aggregators, payment processors, and travel data providers, you get one SDK that handles everything.
| Capability | What you get | |------------|-------------| | Flight Search | Real-time pricing across 300+ airlines via Duffel | | Hotel Search | Global inventory with instant quotes | | Booking Engine | End-to-end booking with payment processing | | Trip Management | Full lifecycle: create, update, cancel, track | | AI Travel Agent | Conversational booking with streaming responses | | Seat Intelligence | Seat maps, recommendations, and selection | | Live Flight Tracking | Real-time flight status and airport delays | | Travel Intelligence | Visa requirements, weather, safety, currency | | Itinerary Generation | AI-powered day-by-day travel plans | | Claims & Compensation | Automated delay/cancellation claim filing |
Installation
npm install @nowahapp/sdkyarn add @nowahapp/sdkpnpm add @nowahapp/sdkRequirements: Node.js 18+ | TypeScript 5.0+ (optional, for type support)
Quick Start
import { createClient } from '@nowahapp/sdk';
const nowah = createClient({
apiKey: process.env.NOWAH_API_KEY!,
});
// Search flights from San Francisco to Tokyo
const results = await nowah.searchFlights({
origin: 'SFO',
destination: 'NRT',
departureDate: '2026-05-01',
passengers: { adults: 1 },
cabinClass: 'business',
});
// Create a trip from the best offer
const trip = await nowah.createTrip({
selectedOfferId: results.offers[0].id,
});
// Book with traveler details
const booking = await nowah.bookFlight({
tripId: trip.id,
travelerInfo: [{
given_name: 'Jane',
family_name: 'Doe',
born_on: '1990-01-15',
gender: 'f',
email: '[email protected]',
phone_number: '+14155551234',
}],
});
console.log(`Booked! Confirmation: ${booking.bookingReference}`);Authentication
Get your API key from the Nowah Developer Platform.
| Key Format | Environment | Use Case |
|------------|-------------|----------|
| nwh_live_v1_* | Production | Real bookings, real charges |
| nwh_test_v1_* | Sandbox | Testing, no real charges |
import { NowahClient } from '@nowahapp/sdk';
// Using the class directly
const client = new NowahClient({
apiKey: 'nwh_live_v1_...',
});
// Or using the factory function
import { createClient } from '@nowahapp/sdk';
const client = createClient({ apiKey: 'nwh_live_v1_...' });Security: Never hardcode API keys. Use environment variables or a secrets manager.
API Reference
Flights
Search real-time flight availability across 300+ airlines with flexible filtering.
// One-way search
const oneWay = await client.searchFlights({
origin: 'LAX',
destination: 'NRT',
departureDate: '2026-05-01',
passengers: { adults: 2 },
});
// Round-trip search with cabin class
const roundTrip = await client.searchFlights({
origin: 'LAX',
destination: 'NRT',
departureDate: '2026-05-01',
returnDate: '2026-05-15',
passengers: { adults: 2, children: 1 },
cabinClass: 'business',
});
// Response includes offers sorted by price
roundTrip.offers.forEach(offer => {
console.log(`${offer.airline} - ${offer.totalAmount} ${offer.currency}`);
offer.slices.forEach(slice => {
console.log(` ${slice.origin} -> ${slice.destination} | ${slice.stops} stops | ${slice.duration}`);
});
});// Get full offer details (baggage, fare rules, etc.)
const offer = await client.getOffer({
offerId: 'off_...',
includeServices: true,
includeSeatMap: true,
});
// Get available ancillary services for an offer
const services = await client.getOfferServices('off_...');// Search airports and cities
const locations = await client.searchLocations({ query: 'Tokyo', limit: 5 });
// Returns: [{ iata: 'NRT', name: 'Narita International', city: 'Tokyo', ... }]Hotels
Search global hotel inventory and get instant quotes.
// Search hotels by coordinates
const hotels = await client.searchHotels({
latitude: 35.6762,
longitude: 139.6503,
checkIn: '2026-05-01',
checkOut: '2026-05-05',
guests: 2,
rooms: 1,
radius: 10,
});
// Get a detailed quote for a specific rate
const quote = await client.getHotelQuote({ rateId: 'rate_...' });Booking
Book flights and hotels with built-in idempotency protection. The SDK automatically generates idempotency keys for all booking operations to prevent duplicate charges.
// Book a flight
const booking = await client.bookFlight({
tripId: 'trip_...',
travelerInfo: [{
given_name: 'Jane',
family_name: 'Doe',
born_on: '1990-01-15',
gender: 'f',
email: '[email protected]',
phone_number: '+14155551234',
type: 'adult',
}],
});
// Book a hotel
const hotelBooking = await client.bookHotel({
tripId: 'trip_...',
rateId: 'rate_...',
guests: [{
givenName: 'Jane',
familyName: 'Doe',
email: '[email protected]',
}],
specialRequests: 'High floor, non-smoking',
});
// Check booking fees
const fees = await client.getBookingFees();Trip Management
Full trip lifecycle management from creation to completion.
// List all trips (paginated)
const trips = await client.listTrips({ limit: 20 });
// Create a trip from a selected offer
const trip = await client.createTrip({
selectedOfferId: 'off_...',
});
// Get full trip details with bookings and documents
const details = await client.getTrip('trip_...');
// Update trip metadata
await client.updateTrip({
tripId: 'trip_...',
name: 'Tokyo Spring Adventure',
notes: 'Remember to book airport transfer',
travelers: [
{ firstName: 'Jane', lastName: 'Doe', email: '[email protected]' },
],
});
// Get trip documents (e-tickets, confirmations, invoices)
const docs = await client.getTripDocuments('trip_...');
// Cancel a trip
await client.cancelTrip({
tripId: 'trip_...',
reason: 'Schedule conflict',
});Payments
Stripe-powered payment processing with saved cards and checkout sessions.
// Create a Stripe checkout session
const session = await client.createCheckoutSession({
tripId: 'trip_...',
amount: 428.30,
currency: 'USD',
successUrl: 'https://myapp.com/booking/success',
cancelUrl: 'https://myapp.com/booking/cancel',
});
// Redirect user to: session.url
// List saved payment methods
const methods = await client.listPaymentMethods();
// Pay with a saved card (instant)
const payment = await client.payWithSavedCard({
tripId: 'trip_...',
amount: 428.30,
currency: 'USD',
paymentMethodId: 'pm_...',
});
// Check payment status
const status = await client.getPaymentStatus('pi_...');
// Manage payment methods
await client.managePaymentMethod({
paymentMethodId: 'pm_...',
action: 'set_default',
});
await client.managePaymentMethod({
paymentMethodId: 'pm_old_...',
action: 'delete',
});Order Management
Post-booking operations: cancellations, changes, and ancillary services.
// Get a cancellation quote (refund estimate)
const cancelQuote = await client.getCancellationQuote('order_...');
console.log(`Refund amount: ${cancelQuote.refundAmount} ${cancelQuote.currency}`);
// Confirm cancellation (idempotent)
await client.confirmCancellation('cancel_...');
// Get available services for an existing order
const services = await client.getOrderServices('order_...');
// Add baggage, seat selection, or other services
await client.addOrderServices({
orderId: 'order_...',
services: [
{ id: 'bag_23kg', quantity: 1 },
{ id: 'seat_14A', quantity: 1 },
],
payment: { type: 'instant', currency: 'USD', amount: '45.00' },
});
// Request a flight change
const changeOffer = await client.createChangeRequest({
orderId: 'order_...',
slices: {
remove: [{ sliceId: 'slice_outbound' }],
add: [{
origin: 'SFO',
destination: 'NRT',
departureDate: '2026-05-08',
cabinClass: 'business',
}],
},
});
// Confirm the change
await client.confirmFlightChange({
changeOfferId: changeOffer.id,
payment: { type: 'instant', currency: 'USD', amount: '125.00' },
});Seat Intelligence
Seat maps, best seat recommendations, and seats to avoid.
// Get the full seat map layout
const layout = await client.getSeatInfo({
airlineCode: 'UA',
aircraftType: '777-300ER',
type: 'layout',
});
// Get the best seats
const bestSeats = await client.getSeatInfo({
airlineCode: 'UA',
aircraftType: '777-300ER',
type: 'best',
cabinClass: 'economy',
});
// Get seats to avoid
const avoidSeats = await client.getSeatInfo({
airlineCode: 'UA',
aircraftType: '777-300ER',
type: 'avoid',
});
// AI-powered seat recommendations based on preferences
const recs = await client.getSeatRecommendations({
airlineCode: 'UA',
aircraftType: '777-300ER',
cabinClass: 'economy',
preferences: {
seatType: 'window',
extraLegroom: true,
quietZone: true,
},
});Live Flight Tracking
Real-time flight status, position tracking, and airport delay monitoring.
// Get flight status
const status = await client.getFlightInfo({
flightNumber: 'UA100',
date: '2026-04-15',
type: 'status',
});
// Get live aircraft position
const position = await client.getFlightInfo({
flightNumber: 'UA100',
type: 'position',
});
// Track all flights in a booking
const tracking = await client.getBookingTracking('booking_...');
// Check airport delays
const delays = await client.getAirportDelays('SFO');
console.log(`SFO average delay: ${delays.averageDelay} minutes`);Travel Intelligence
Visa requirements, weather, currency conversion, and safety information for any destination.
// Visa requirements
const visa = await client.getVisaRequirements({
passport: 'US',
destination: 'JP',
});
console.log(`Visa required: ${visa.required}`);
console.log(`Max stay: ${visa.maxStay}`);
// Current weather
const current = await client.getWeather({
type: 'current',
location: 'Tokyo',
});
// Weather forecast
const forecast = await client.getWeather({
type: 'forecast',
location: 'Tokyo',
days: 7,
});
// Currency conversion
const converted = await client.convertCurrency({
from: 'USD',
to: 'JPY',
amount: 1000,
});
console.log(`$1,000 = ${converted.result} JPY`);
// Exchange rates (no amount)
const rates = await client.convertCurrency({ from: 'USD', to: 'JPY' });
// Country safety information
const safety = await client.getSafetyInfo('JP');Points of Interest & Itineraries
Discover places and generate AI-powered travel itineraries.
// Search POIs by keyword near coordinates
const restaurants = await client.findPois({
query: 'ramen',
lat: 35.6595,
lon: 139.7004,
types: 'restaurant',
limit: 10,
});
// Find nearby POIs by radius
const nearby = await client.findPois({
lat: 35.6595,
lon: 139.7004,
radius: 1000,
types: 'attraction',
});
// Generate an AI itinerary
const itinerary = await client.generateItinerary({
lat: 35.6762,
lon: 139.6503,
date: '2026-05-01',
interests: ['food', 'culture', 'technology'],
pace: 'moderate',
budget: 'mid',
start_time: '09:00',
end_time: '21:00',
});AI Travel Agent
Conversational travel assistant with streaming support for real-time responses.
// Simple chat (non-streaming)
const response = await client.chatWithAgent({
threadId: 'thread_...',
message: 'Find me the cheapest direct flight from SF to Tokyo in May',
stream: false,
});
// Streaming chat (for real-time UI)
const stream = await client.chatWithAgent({
threadId: 'thread_...',
message: 'What are the best neighborhoods to stay in Tokyo?',
stream: true,
});
// stream contains the full concatenated response textClaims & Compensation
Automated eligibility checking and claim filing for flight disruptions.
// Check if a booking qualifies for compensation
const eligibility = await client.checkClaimEligibility({
bookingId: 'booking_...',
claimType: 'delay',
});
if (eligibility.eligible) {
// File the claim
const claim = await client.fileClaim({
bookingId: 'booking_...',
claimType: 'delay',
description: 'Flight delayed 4+ hours, missed connection',
contactEmail: '[email protected]',
});
console.log(`Claim filed: ${claim.id} | Estimated: ${claim.estimatedCompensation}`);
}
// List all claims with status filter
const pendingClaims = await client.listClaims({ status: 'pending' });
const approvedClaims = await client.listClaims({ status: 'approved' });Supported claim types: delay | cancellation | downgrade | lost_baggage | damaged_baggage
Usage & Quota
Monitor your API consumption and quota.
// Get usage stats for current billing period
const usage = await client.getUsageStats();
// Filter by time period
const daily = await client.getUsageStats({ period: 'day' });
// Filter by endpoint
const flightUsage = await client.getUsageStats({ endpoint: '/v1/flights/search' });Error Handling
All API errors are thrown as NowahError instances with structured error information.
import { NowahError } from '@nowahapp/sdk';
try {
const results = await client.searchFlights({ ... });
} catch (err) {
if (err instanceof NowahError) {
console.error(err.message); // Human-readable: "Monthly quota exceeded"
console.error(err.status); // HTTP status: 429
console.error(err.code); // Machine-readable: "QUOTA_EXCEEDED"
console.error(err.retryable); // true for 5xx, false for 4xx
}
}| Status | Code | Meaning |
|--------|------|---------|
| 400 | INVALID_REQUEST | Bad request parameters |
| 401 | INVALID_KEY | Invalid or missing API key |
| 401 | KEY_EXPIRED | API key has expired |
| 401 | KEY_REVOKED | API key was revoked |
| 403 | INSUFFICIENT_SCOPE | Key lacks required scope |
| 429 | RATE_LIMITED | Too many requests |
| 429 | QUOTA_EXCEEDED | Monthly quota exhausted |
| 500+ | INTERNAL_ERROR | Server error (retryable) |
Automatic retries: The SDK retries 5xx errors and network failures once with exponential backoff. 4xx errors are never retried.
Configuration
const client = new NowahClient({
// Required: Your API key
apiKey: 'nwh_live_v1_...',
// Optional: Override the base URL (defaults to https://claw.nowah.xyz)
baseUrl: 'https://claw.nowah.xyz',
});Environments
| Environment | Base URL | API Keys |
|-------------|----------|----------|
| Production | https://claw.nowah.xyz (default) | nwh_live_v1_* |
| Sandbox | https://dev-claw.nowah.xyz | nwh_test_v1_* |
SDK Internals
Idempotency
Booking, cancellation, and service operations automatically include idempotency keys via the X-Idempotency-Key header. This prevents duplicate charges if a request is retried due to network issues.
Retry Policy
| Scenario | Behavior | |----------|----------| | 5xx server errors | Retry once with 1s backoff | | Network timeouts | Retry once with 1s backoff | | 4xx client errors | No retry (fail immediately) | | Streaming requests | No retry (long-lived connection) |
Timeouts
| Request Type | Timeout | |-------------|---------| | Standard API calls | 30 seconds | | Streaming (AI agent) | 120 seconds |
TypeScript
The SDK is written in TypeScript and ships with full type definitions. All method parameters and return types are fully typed.
import type {
SearchFlightsParams,
SearchFlightsResult,
FlightOffer,
FlightSlice,
FlightSegment,
TravelerInfo,
BookFlightParams,
NowahClientOptions,
// ... 65+ exported types
} from '@nowahapp/sdk';Links
- Nowah Developer Platform - Get your API key
- API Documentation - Full API reference
- Status Page - API uptime and incidents
License
Apache 2.0 - see LICENSE
Copyright 2025-2026 Nowah Inc.
