openapi: 3.0.0
info:
  version: 1.0.2
  title: Star Community API
  description: Provides live data from Hubble Community Café in Eindhoven
servers:
- url: "https://api.test.starcommunity.app"
  description: Upcoming API features (testing ground)
- url: "https://api.starcommunity.app"
  description: Production Environment
paths:
  /profile:
    get:
      description: |
        Gets the user profile information from both Star Accounts and the cash register. Includes general user information, such as names and email, but also information about the balance, credit limit and discount applied to this user.
      operationId: profile-get
      summary: Get user profile
      tags:
      - User
      security:
      - OpenID-AuthCode:
        - profile
      responses:
        "200":
          description: User profile data
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/UserProfile"
        "401":
          description: Unauthorized
        "500":
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
    patch:
      description: |-
        Updates the user profile information, only a limited subset of fields is available. You can add any of these fields while leaving the others null. Only partial updates are supported.

        If you update the email field, the user will receive a verification request by email that they have to click to confirm their new email address. Until then, the email_verified field will be false.
      operationId: profile-post
      summary: Update user profile
      tags:
      - User
      security:
      - OpenID-AuthCode:
        - profile
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UserProfileUpdate"
      responses:
        "200":
          description: Updated user profile with all changes processed as requested
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserProfile"
        "400":
          description: "Bad Request, you sent values that were wrong"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Unauthorized
        "500":
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /cards:
    get:
      summary: List all registered cards for this user
      tags:
      - Cards
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  cards:
                    type: array
                    items:
                      $ref: "#/components/schemas/Card"
              examples:
                One NFC + one bar code:
                  value:
                    cards:
                    - type: barcode
                      id: b6df6c1f-6f86-41e6-b95d-e0b864c31e1c
                      value: "123456789"
                    - type: nfc-id
                      id: 1f3c4d4b-b43b-4cd0-ac52-0b21179b959f
                      display_name: OV-chipkaart
                      value: "04:4f:71:32:21:4b:80"
        "401":
          description: Unauthorized
        "500":
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      operationId: get-cards
      description: "Gives a list of cards linked to this user, of any type, such as NFC or barcode"
      security:
      - OpenID-AuthCode:
        - profile.cards
    post:
      summary: Add a card to a user
      operationId: post-cards
      responses:
        "201":
          description: "Created, returns the resulted card"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Card"
        "400":
          description: "Bad Request, might occur when submitting the values wrong (or if your NFC ID is not unique)"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Unauthorized
        "403":
          description: "Forbidden, triggered when the card is already linked"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "500":
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      tags:
      - Cards
      security:
      - OpenID-AuthCode:
        - profile.cards
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Card"
            examples:
              Barcode:
                value:
                  type: barcode
                  display_name: Pietje Puk Card
              NFC:
                value:
                  type: nfc-id
                  display_name: OV-chipkaart
                  value: "04:4f:71:32:21:4b:80"
        description: ""
      description: |-
        Registers a new card for this user, based on the specification submitted.

        When submitting an NFC card, you need to fill the type & value fields. 
        When submitting a barcode, only fill the type field, the value will be autogenerated.

        You may submit display_name for both types, but that is optional.
  "/cards/{id}":
    get:
      summary: Get specific card information
      tags:
      - Cards
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Card"
              examples:
                NFC:
                  value:
                    type: nfc-id
                    id: 1f3c4d4b-b43b-4cd0-ac52-0b21179b959f
                    display_name: null
                    value: "04:4f:71:32:21:4b:80"
                Barcode:
                  value:
                    type: barcode
                    id: b6df6c1f-6f86-41e6-b95d-e0b864c31e1c
                    display_name: Example name
                    value: "123456789"
        "401":
          description: Unauthorized
        "404":
          description: Not Found
        "500":
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      operationId: "get-cards-:id"
      security:
      - OpenID-AuthCode:
        - profile.cards
      description: Get a single card by its ID
    parameters:
    - schema:
        type: string
      name: id
      in: path
      required: true
      description: ID of the card (UUID)
    delete:
      summary: Delete a card from your account
      operationId: delete-cards-id
      responses:
        "204":
          description: "No Content, sent when it is successfully deleted"
        "401":
          description: Unauthorized
        "404":
          description: Not Found
        "500":
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      description: Remove a card from this user to allow linking it to another user
      tags:
      - Cards
      security:
      - OpenID-AuthCode:
        - profile.cards
  /organisations:
    get:
      summary: List all organisations this user is part of
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  organisations:
                    type: array
                    items:
                      $ref: "#/components/schemas/UserOrganisation"
        "401":
          description: Unauthorized
        "500":
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      operationId: get-associations
      description: "Gets a list of all organisations that this user is linked to, including their state (active or not)."
      security:
      - OpenID-AuthCode:
        - organisations.all
      tags:
      - Organisations
    parameters: []
  /example:
    get:
      deprecated: true
      description: |
        Example endpoint that returns the data saved about your user in MplusKASSA, including your balance.
      operationId: example
      summary: Example Endpoint
      security:
      - OpenID-AuthCode:
        - profile
      responses:
        "200":
          description: API response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Relation"
        default:
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      tags:
      - Deprecated
  /organisations/available:
    get:
      summary: List all available organisations to join
      tags:
      - Organisations
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  organisations:
                    $ref: "#/components/schemas/Organisation"
        "401":
          description: Unauthorized
        "500":
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      operationId: get-organisations-enrollable
      description: Get a list of all organisations that this user could possibly apply to join
    parameters: []
  "/financial-reports/{id}":
    parameters:
    - schema:
        type: string
      name: id
      in: path
      required: true
    get:
      summary: Obtain a generated financial report
      tags:
      - Financial Reports
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FinancialReportResponse"
        "401":
          description: Unauthorized
        "403":
          description: Forbidden. Might be returned if missing scopes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "404":
          description: "Not Found. Will be returned if the report has not yet finished generating, has encountered an error while generating or has already been removed from the cache after 2 hours."
        "500":
          description: Internal Server Error
      operationId: get-financial-reports-id
      description: Gets a previously generated financial report (for up to 2 hours after generation)
      security:
      - OpenID-ClientCredentials:
        - financial-reports
  /financial-reports/relations:
    post:
      summary: Generate a financial report grouped by relations
      operationId: post-financial-reports-relations
      tags:
      - Financial Reports
      responses:
        "202":
          description: Returned when the report is being created. You will have to wait a little bit until the report is actually available. Until then the given URL will return a 404 response.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    description: Informative status message.
                  url:
                    type: string
                    description: Relative URL at which the report will be available after generation.
        "400":
          description: Bad Request
          headers: {}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Unauthorized
        "403":
          description: "Forbidden, for instance when missing required scopes"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "500":
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      description: Generates a financial turnover report with totals and totals per relation (user/association)
      security:
      - OpenID-ClientCredentials:
        - financial-reports
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                start_date:
                  type: string
                  description: Start date for the report
                end_date:
                  type: string
                  description: End date of the report (inclusive)
                branch:
                  type: string
                  description: Branch that you would like the report for (see /branches for options)
              required:
              - start_date
              - end_date
              - branch
        description: ""
  /branches:
    get:
      description: |
        Gets a list of all branches configured.
      operationId: branches-get
      summary: Get branches
      tags:
      - Branches
      responses:
        "200":
          description: List of branches
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                      description: Branch identifier
                    name:
                      type: string
                      description: Human friendly name of the branch
        "401":
          description: Unauthorized
        "500":
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
components:
  securitySchemes:
    OpenID-AuthCode:
      type: oauth2
      flows:
        authorizationCode:
          scopes:
            openid: Allow login through your Hubble Account
            profile: View your name
            email: View your email address
            organisations.all: View all linked organisations
            profile.cards: View all linked cards
    OpenID-ClientCredentials:
      type: oauth2
      flows:
        clientCredentials:
          scopes:
            financial-reports: Create and view financial reports
  schemas:
    Relation:
      type: object
      required:
      - id
      - name
      - email
      - balance
      properties:
        id:
          type: number
        name:
          type: string
        email:
          type: string
        balance:
          type: number
    UserProfile:
      type: object
      description: Corresponds to the combination of the Star Account data & MplusKASSA Relation resource for this user
      properties:
        given_name:
          type: string
          description: 'Name given to you by your parents, usually the "first name" in Western cultures'
        family_name:
          type: string
          description: 'Name given to your family, usually the "surname" in Western cultures'
          nullable: true
        name:
          type: string
          description: "Full name, can only be read, not written"
        discount:
          type: string
          enum:
          - none
          - student
          - community
          - svh
          - board
          description: Indicates which discount this user receives at the cash register
          default: none
        email:
          type: string
          description: Email as registered to your account
          format: email
        email_verified:
          type: boolean
          description: "Indicates if the email address was validated. If it isn't, you should show a banner indicating that the user should check their email and click the link sent to them. If they do not verify, accounts will not be automatically linked by SSO."
        balance:
          type: number
          description: "Balance, if any balance (may be negative to indicate that there is an outstanding balance)"
        credit_limit:
          type: number
          description: "Credit limit set for this user, may be negative to indicate that the user can 'borrow' up to a certain amount. Will be null if the credit limit doesn't matter and the user needs to add money first."
          nullable: true
    UserProfileUpdate:
      type: object
      description: "Data that can be updated using the PATCH call on user profile. If you patch the email address, you will need to reaffirm your email address using a verification email."
      properties:
        given_name:
          type: string
          description: 'Name given to you by your parents, usually the "first name" in Western cultures'
          nullable: true
        family_name:
          type: string
          description: 'Name given to your family, usually the "surname" in Western cultures'
          nullable: true
        email:
          type: string
          description: Email as registered to your account
          format: email
          nullable: true
    Error:
      type: object
      description: Error thrown by the server.
      properties:
        error:
          type: string
          description: Error code given to indicate the problem to the user. You can use these for your translations.
        error_description:
          type: string
          description: Human readable error description.
      required:
      - error
    Card:
      title: Card
      x-stoplight:
        id: jtftik5sj1upx
      type: object
      description: Object representing a card linked to a user
      x-examples:
        Barcode:
          type: barcode
          id: b6df6c1f-6f86-41e6-b95d-e0b864c31e1c
          value: "123456789"
        NFC:
          type: nfc-id
          id: 1f3c4d4b-b43b-4cd0-ac52-0b21179b959f
          value: 044F7132214B80
      properties:
        type:
          type: string
          default: barcode
          enum:
          - barcode
          - nfc-id
          description: Type of card
        id:
          type: string
          description: "Internal identifier of the card, usually a UUID"
        display_name:
          type:
          - "null"
          - string
          description: "User-chosen friendly name for the card, may be left empty"
        value:
          type: string
          description: "Value of the card. In the case of a barcode, this is the barcode itself, in case of NFC-ID, this is the NFC id of the physical card/sticker/tag. Required when submitting type NFC-ID."
      required:
      - type
    Organisation:
      title: Organisation
      x-stoplight:
        id: 4g09503x6a1vu
      type: object
      description: Organisation that can be linked to a user
      properties:
        id:
          type: string
          description: UUID identifying this organisation
        name:
          type: string
          description: Display friendly name for this organisation
        logo:
          type: string
          description: "Logo of the organisation, if available"
          nullable: true
    UserOrganisation:
      title: UserOrganisation
      x-stoplight:
        id: lvjwtotuaushw
      type: object
      description: User organisation relationship
      properties:
        organisation:
          $ref: "#/components/schemas/Organisation"
        active:
          type: boolean
          description: Are we considered 'active' at this organisation?
        registered_since:
          type: string
          format: date-time
          description: When did this user first apply to be in this organisation?
        type:
          type: string
          enum:
          - manual
          - automatic
          description: Indicates if this user was registered by an admin/the association (manual) or through SSO (automatic)
    FinancialReportResponse:
      title: FinancialReportResponse
      x-stoplight:
        id: m1kwg7xaa135u
      type: object
      properties:
        id:
          type: string
          description: ID of the report
        start_date:
          type: string
          description: "Start date of the report, in ISO date format"
        end_date:
          type: string
          description: "End date of the report, in ISO date format (day inclusive)"
        generated_at:
          type: string
          description: ISO datetime string of report generation
        turnover_groups:
          type: array
          items:
            type: object
            properties:
              id:
                type: number
                description: Group ID
              name:
                type: string
                description: Human readable name of the turnover group
        turnover_group_totals:
          type: array
          items:
            type: object
            properties:
              id:
                type: number
                description: Turnover group ID
              total_incl_amount:
                type: number
                description: Total sales of this turnover group (including BTW/VAT)
              total_excl_amount:
                type: number
                description: Total sales of this turnover group (excluding BTW/VAT)
        relations:
          type: array
          items:
            type: object
            properties:
              id:
                type: number
                description: Relation ID
              name:
                type: string
                description: Human readable name of this relation
              turnover_group_totals:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: number
                      description: Turnover group ID
                    total_incl_amount:
                      type: number
                      description: Total sales of this turnover group for this relation (including BTW/VAT)
                    total_excl_amount:
                      type: number
                      description: Total sales of this turnover group for this relation (excluding BTW/VAT)
      description: ""
