npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nowahapp/sdk

v0.2.0

Published

Official SDK for the Nowah Travel API

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/sdk
yarn add @nowahapp/sdk
pnpm add @nowahapp/sdk

Requirements: 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 text

Claims & 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


License

Apache 2.0 - see LICENSE

Copyright 2025-2026 Nowah Inc.