Blackbird Memberships API

Per-(member, restaurant) loyalty records carrying check-in counts and tiers.

OpenAPI Specification

blackbird-memberships-api-openapi.yml Raw ↑
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`).

        '