npm package: @nowahapp/sdk
Description: Official SDK for the Nowah Travel API
Latest version: 0.2.0

<p align="center">
  <img src="https://nowah.xyz/icon.png" width="60" alt="Nowah" />
</p>

<h1 align="center">@nowahapp/sdk</h1>

<p align="center">
  <strong>The official TypeScript SDK for the Nowah Travel API</strong>
</p>

<p align="center">
  Search flights across 300+ airlines. Book hotels worldwide. Manage trips end-to-end.<br/>
  Build AI-powered travel experiences with a single API.
</p>

<p align="center">
  <a href="https://www.npmjs.com/package/@nowahapp/sdk"><img src="https://img.shields.io/npm/v/@nowahapp/sdk.svg" alt="npm version" /></a>
  <a href="https://www.npmjs.com/package/@nowahapp/sdk"><img src="https://img.shields.io/npm/dm/@nowahapp/sdk.svg" alt="npm downloads" /></a>
  <a href="https://github.com/maslinedwin/nowah-platform/blob/main/sdk/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="license" /></a>
  <a href="https://nowah.xyz/docs"><img src="https://img.shields.io/badge/docs-nowah.xyz-green.svg" alt="documentation" /></a>
</p>

---

## 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

```bash
npm install @nowahapp/sdk
```

```bash
yarn add @nowahapp/sdk
```

```bash
pnpm add @nowahapp/sdk
```

**Requirements:** Node.js 18+ | TypeScript 5.0+ (optional, for type support)

---

## Quick Start

```typescript
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: 'jane@example.com',
    phone_number: '+14155551234',
  }],
});

console.log(`Booked! Confirmation: ${booking.bookingReference}`);
```

---

## Authentication

Get your API key from the [Nowah Developer Platform](https://platform.nowah.xyz).

| Key Format | Environment | Use Case |
|------------|-------------|----------|
| `nwh_live_v1_*` | Production | Real bookings, real charges |
| `nwh_test_v1_*` | Sandbox | Testing, no real charges |

```typescript
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.

```typescript
// 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}`);
  });
});
```

```typescript
// 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_...');
```

```typescript
// 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.

```typescript
// 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.

```typescript
// 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: 'jane@example.com',
    phone_number: '+14155551234',
    type: 'adult',
  }],
});

// Book a hotel
const hotelBooking = await client.bookHotel({
  tripId: 'trip_...',
  rateId: 'rate_...',
  guests: [{
    givenName: 'Jane',
    familyName: 'Doe',
    email: 'jane@example.com',
  }],
  specialRequests: 'High floor, non-smoking',
});

// Check booking fees
const fees = await client.getBookingFees();
```

---

### Trip Management

Full trip lifecycle management from creation to completion.

```typescript
// 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: 'jane@example.com' },
  ],
});

// 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.

```typescript
// 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.

```typescript
// 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.

```typescript
// 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.

```typescript
// 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.

```typescript
// 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.

```typescript
// 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.

```typescript
// 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 text
```

---

### Claims & Compensation

Automated eligibility checking and claim filing for flight disruptions.

```typescript
// 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: 'jane@example.com',
  });
  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.

```typescript
// 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.

```typescript
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

```typescript
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.

```typescript
import type {
  SearchFlightsParams,
  SearchFlightsResult,
  FlightOffer,
  FlightSlice,
  FlightSegment,
  TravelerInfo,
  BookFlightParams,
  NowahClientOptions,
  // ... 65+ exported types
} from '@nowahapp/sdk';
```

---

## Links

- [Nowah Developer Platform](https://platform.nowah.xyz) - Get your API key
- [API Documentation](https://nowah.xyz/docs) - Full API reference
- [Status Page](https://status.nowah.xyz) - API uptime and incidents

---

## License

Apache 2.0 - see [LICENSE](./LICENSE)

Copyright 2025-2026 Nowah Inc.