> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flynet.org/llms.txt
> Use this file to discover all available pages before exploring further.

# User passport

> Who a member is plus where they've been — profile and visit history in one view.

# User passport

**Goal:** Build a passport-style view that pairs a member's identity and standing
with the places they've checked in.\
**Prep time:** \~10 minutes

A passport has two halves: who the member is (profile, level, progress) and
where they've been (their check-in history). Both read from the member's OAuth
token.

## Off the shelf

Two components from `@flynetdev/react` cover both halves. `UserPassport` renders
profile, level, and progress; `CheckInFeed` renders the member's check-ins,
newest first. Wrap them in one `FlynetProvider` with a `FlynetMemberClient`
built from the member's OAuth token — they fetch client-side under the
`read:profile` and `read:user_checkins` scopes.

```tsx app/passport.tsx theme={null}
"use client";
import { FlynetMemberClient } from "@flynetdev/core";
import { FlynetProvider, UserPassport, CheckInFeed } from "@flynetdev/react";

export function Passport({ accessToken }: { accessToken: string }) {
  const member = new FlynetMemberClient({ accessToken });
  return (
    <FlynetProvider member={member}>
      <UserPassport />
      <CheckInFeed />
    </FlynetProvider>
  );
}
```

## From scratch

To assemble the passport rows yourself — or build them outside React — read both
halves from `FlynetMemberClient` directly. The check-in feed embeds full venue
context, so you rarely need a second call.

## What you will use

* `GET /flynet/v1/users/me` - profile (name, email, account status)
* `GET /flynet/v1/users/me/status` - tier, level, and progress
* `GET /flynet/v1/users/me/check_ins` - the member's check-ins with embedded venue context

## Code

```typescript theme={null}
import { FlynetMemberClient } from "@flynetdev/core";

const member = new FlynetMemberClient({ accessToken: process.env.ACCESS_TOKEN! });

const profile = await member.getProfile(); // name, email, accountStatus
const status = await member.getStatus(); // tier, level, progress
const { checkIns } = await member.listCheckIns({ pageSize: 50 });

const passport = {
  member: `${profile.firstName} ${profile.lastName}`,
  tier: status.tier,
  level: status.level,
  visits: checkIns.map((checkIn) => ({
    visitedAt: checkIn.createdAt,
    brand: checkIn.location.restaurant.name,
    neighborhood: checkIn.location.neighborhood?.name,
  })),
};

console.log(passport);
```

<Tip>
  **From the kitchen** - Use the embedded `location.restaurant` from check-ins
  first. Only fetch a restaurant by id (with your `X-API-Key`) when you need
  brand fields the embedded object doesn't carry.
</Tip>

<Warning>
  **Chef's warning** - Profile and check-ins both use the OAuth bearer token.
  Restaurant detail calls use `X-API-Key` instead — the two credentials don't
  cross route families.
</Warning>

**Next:** [Wallet badge](/recipes/mains/flylevel-badge) - show wallet
context alongside the passport.
