Blackbird Memberships API
Per-(member, restaurant) loyalty records carrying check-in counts and tiers.
Per-(member, restaurant) loyalty records carrying check-in counts and tiers.
openapi: 3.0.3
info:
title: Flynet App Memberships API
version: '1.0'
description: 'Flynet''s partner API. Read access to member context, restaurants,
locations, check-ins, and memberships; write access for payment
intents.
**Base URL:** staging `https://api.staging.blackbird.xyz/flynet/v1`.
**Auth:** Two schemes — OAuth bearer (`Authorization: Bearer ...`) for
member-scoped routes, API key (`X-API-Key`) for restaurant and
location discovery. See Concepts → Authentication.
**Pagination:** `page` is zero-indexed (default `0`); `page_size`
default `50`. List responses include a `pagination` wrapper except
`GET /locations/{id}/open_hours`.
**Errors:** see Concepts → Pagination + errors. Three envelope shapes
are documented there.
'
servers:
- url: https://api.staging.blackbird.xyz/flynet/v1
description: Staging
security:
- oauthBearer: []
tags:
- name: Memberships
description: Per-(member, restaurant) loyalty records carrying check-in counts and tiers.
paths:
/users/me/memberships:
get:
tags:
- Memberships
summary: List the authenticated member's memberships
operationId: listMemberships
description: 'Returns the authenticated member''s paginated membership records —
one per restaurant — each carrying a `check_in_count` and the
member''s `membership_tier` at that restaurant. The subject is
resolved from the access token, so there is no member ID in the
path. This is the canonical source for the member''s per-restaurant
check-in totals: filter by `restaurant` and sum `check_in_count`
across the result.
Accessible with a token carrying `read:memberships`.
There is no `GET /users/me/memberships/{id}` — the list, with
filters, is the only accessor. Server-side sorting is not applied:
`sort` and related parameters are silently ignored, so sort
client-side.
'
security:
- oauthBearer: []
parameters:
- name: restaurant
in: query
description: 'Restaurant UUID to filter by. Note the asymmetry: the filter
key is `restaurant`, but the field on each record is
`restaurant_id`. Passing `restaurant_id` is silently ignored
and returns the full unfiltered list.
'
schema:
type: string
format: uuid
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PageSize'
responses:
'200':
description: Paginated memberships.
content:
application/json:
schema:
$ref: '#/components/schemas/MembershipList'
example:
memberships:
- id: 011ac10e-7f27-4355-847a-c51e2e7e5625
object: membership
restaurant_id: 2cb56d03-4417-4b60-afe3-be819ecde8ac
check_in_count: 1
last_check_in_date: '2026-05-26T16:30:45.825827Z'
membership_tier:
id: 8a71471b-c07c-4e05-9888-7ecd8e1bc609
object: membership_tier
name: Member
artist: Andrew Braswell
asset:
preview_1x: https://images.blackbird.xyz/.../343_490.png
web_2x: https://images.blackbird.xyz/.../343_490.png
full_3x: https://images.blackbird.xyz/.../343_490.png
pagination:
total_count: 875
total_pages: 18
current_page: 0
next_page: 1
page_size: 50
'401':
description: Missing or invalid token. Empty body.
'403':
description: Token lacks the required scope. Empty body; reason in the `WWW-Authenticate` header.
components:
schemas:
Membership:
type: object
required:
- id
- object
- restaurant_id
- check_in_count
- membership_tier
properties:
id:
type: string
format: uuid
object:
type: string
enum:
- membership
restaurant_id:
type: string
format: uuid
description: The restaurant this membership belongs to. (The filter param is `restaurant`, not `restaurant_id`.)
check_in_count:
type: integer
description: This member's check-ins at this restaurant. Sum across a filtered list for the per-restaurant total.
last_check_in_date:
type: string
format: date-time
nullable: true
membership_tier:
type: object
required:
- id
- object
- name
properties:
id:
type: string
format: uuid
object:
type: string
enum:
- membership_tier
name:
type: string
description: Open string (e.g. Member, VIP, Friend), not a fixed enum.
artist:
type: string
nullable: true
description: Card-art creator.
asset:
type: object
nullable: true
properties:
preview_1x:
type: string
format: uri
nullable: true
web_2x:
type: string
format: uri
nullable: true
full_3x:
type: string
format: uri
nullable: true
Pagination:
type: object
required:
- total_count
- total_pages
- current_page
- next_page
- page_size
properties:
total_count:
type: integer
total_pages:
type: integer
current_page:
type: integer
next_page:
type: integer
nullable: true
page_size:
type: integer
MembershipList:
type: object
required:
- memberships
- pagination
properties:
memberships:
type: array
items:
$ref: '#/components/schemas/Membership'
pagination:
$ref: '#/components/schemas/Pagination'
parameters:
PageSize:
name: page_size
in: query
schema:
type: integer
default: 50
description: Items per page. Default `50`.
Page:
name: page
in: query
schema:
type: integer
default: 0
minimum: 0
description: Zero-indexed page number.
securitySchemes:
oauthBearer:
type: http
scheme: bearer
bearerFormat: JWT
description: 'OAuth 2.0 access token. Required for the `/users/me/*` routes
(profile, status, wallets, tags, check-ins, memberships) and all
payment intent routes.
'
apiKey:
type: apiKey
in: header
name: X-API-Key
description: 'Server-to-server API key prefixed `fly_live_...` (production) or
`fly_test_...` (staging/dev). Required on restaurant and location
Discovery routes and on the `/check_ins` venue feed (key minted
with `read:checkins`).
'