npm package: @gojinko/api-client
Description: Typed API client for the Jinko BFF. Methods mirror the MCP tools and CLI commands 1:1.
Latest version: 1.0.0

# @gojinko/api-client

Typed API client for the Jinko BFF. Methods mirror the MCP tools and CLI commands 1:1.

## Install

```bash
npm install @gojinko/api-client
```

## Quick Start

```typescript
import { createJinkoClient } from '@gojinko/api-client';

// Uses credentials from ~/.jinko/config.yaml or JINKO_API_KEY env
const client = await createJinkoClient();

// Or pass an API key directly
const client = await createJinkoClient({ apiKey: 'jnk_...' });
```

## Authentication

The client resolves credentials automatically in this order:

1. `apiKey` option passed to `createJinkoClient()`
2. `JINKO_API_KEY` environment variable
3. `~/.jinko/config.yaml` — API key or OAuth tokens (managed by `jinko auth login`)

OAuth tokens auto-refresh when they expire.

## Methods

### Discovery (cached)

| Method | BFF Endpoint |
|---|---|
| `client.findFlight()` | `POST /flights/search` |
| `client.findDestination()` | `POST /flights/destination-search` |
| `client.flightCalendar()` | `POST /flights/search` |

### Live search & trip building

| Method | BFF Endpoint |
|---|---|
| `client.flightSearch()` | `POST /flights/shop` |
| `client.trip()` | `POST /trips` |

### Checkout

| Method | BFF Endpoint |
|---|---|
| `client.checkout(tripId)` | `POST /trips/checkout` |
| `client.selectAncillaries()` | `POST /trips/ancillaries` |
| `client.getTrip(tripId)` | `GET /trips/:id` |

### Post-booking

| Method | BFF Endpoint |
|---|---|
| `client.refundCheck()` | `POST /flights/refund-check` |
| `client.refundCommit()` | `POST /flights/refund-commit` |

## Usage

### find_flight — Cached search

```typescript
const flights = await client.findFlight({
  passengers: { adt: 1 },
  filters: {
    locations: { origins: ['PAR'], destinations: ['NYC'] },
    dates: { departure_dates: ['2026-06-15'] },
    trip_type: 'oneway',
  },
  sort: 'lowest',
  limit: 10,
});
```

### flight_search — Live search / price-check

```typescript
// Search mode
const results = await client.flightSearch({
  origin: 'PAR',
  destination: 'NYC',
  departure_date: '2026-06-15',
  trip_type: 'oneway',
  passengers: { adults: 1 },
});

// Price-check mode (returns trip_item_token)
const fares = await client.flightSearch({
  offer_token: 'tok_abc123',
  passengers: { adults: 1 },
});
```

### trip — Create trip, add flight, set travelers

```typescript
const trip = await client.trip({
  add_item: { trip_item_token: 'tok_xyz' },
  upsert_travelers: {
    travelers: [{
      first_name: 'Jane',
      last_name: 'Doe',
      date_of_birth: '1990-01-15',
      gender: 'FEMALE',
      passenger_type: 'ADULT',
    }],
    contact: { email: 'jane@example.com', phone: '+33612345678' },
  },
});
// → { trip_id, ... }
```

### checkout — Schedule checkout

```typescript
const checkout = await client.checkout('42');
// {
//   session_id, checkout_url, expires_at, status,
//   total_amount: { amount, currency },
//   items: [ { item_id, kind, price, pax_count, available_ancillaries, selected_ancillaries } ],
// }

// Send the user to checkout.checkout_url to complete payment.
```

### selectAncillaries — Add baggage, seats, meals

```typescript
await client.selectAncillaries({
  trip_id: '42',
  item_id: 'item_1',
  selections: [
    { offer_id: 'offer_bag_checked_1', quantity: 1 },
    { offer_id: 'offer_seat_12A', pax_ref_id: 'pax_1', quantity: 1 },
  ],
});
```

### getTrip — Full lifecycle state

```typescript
const status = await client.getTrip('42');
// {
//   trip_id, status,
//   travelers, contact, items, total_amount,
//   quote:       { quoted_cart_id, status, expires_at },
//   fulfillment: { fulfillment_cart_id, status, phase, scheduled_at },
//   bookings:    [ { item_id, booking_reference, pnr, provider_status } ],
//   created_at, updated_at,
// }
```

Poll `getTrip()` until `status === 'fulfilled'` (or `'partially_fulfilled'`) to read the PNRs.

### refundCheck / refundCommit

```typescript
const eligibility = await client.refundCheck({ booking_reference: 'ref_123', pnr: 'ABC123' });
const refund      = await client.refundCommit({ booking_reference: 'ref_123', pnr: 'ABC123', reason: 'schedule change' });
```

## Token Flow

```
findFlight / findDestination / flightCalendar → offer_token        (cached)
flightSearch (offer_token)                    → trip_item_token    (live)
trip (trip_item_token + travelers + contact)  → trip_id
checkout (trip_id)                            → checkout_url + items + ancillaries
  [user pays on checkout_url]
getTrip (trip_id)                             → bookings / PNRs
```

Quote is automatic — it's handled internally by `checkout()`. You don't call it.

## Error Handling

```typescript
import { createJinkoClient, ApiError, AuthError } from '@gojinko/api-client';

try {
  const client = await createJinkoClient();
} catch (error) {
  if (error instanceof AuthError) {
    // No credentials configured — run `jinko auth login`
  }
  if (error instanceof ApiError) {
    console.error(error.code, error.message, error.statusCode);
  }
}
```

## Types

```typescript
import type {
  FlightFindRequest,
  FlightDestinationSearchRequest,
  FlightSearchRequest,
  TripRequest,
  CheckoutRequest,
  CheckoutResponse,
  TripQuotedItem,
  AncillaryOffer,
  SelectedAncillary,
  TripStatusResponse,
  QuoteSummary,
  FulfillmentSummary,
  BookingRef,
  SelectAncillariesRequest,
  RefundCheckRequest,
  RefundCommitRequest,
  Traveler,
  Contact,
  Money,
} from '@gojinko/api-client';
```

## Raw Client

The underlying openapi-fetch client is still accessible:

```typescript
const response = await client.raw.POST('/api/v1/flights/shop' as never, {
  body: { /* ... */ },
} as never);
```