Bloomerang Constituents API

Create, retrieve, search, and update constituent records - the individuals, households, and organizations tracked in a Bloomerang donor database - including addresses, emails, phone numbers, and communication preferences.

OpenAPI Specification

bloomerang-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Bloomerang REST API v2
  description: >-
    The Bloomerang REST API v2 is a private-key, server-to-server API for
    reading and writing data in a Bloomerang donor management CRM account -
    constituents, transactions (donations, pledges, recurring donations),
    interactions, notes, relationships, and webhook subscriptions. Requests
    are authenticated with either a private API key sent in the X-Api-Key
    header (generated by an Administrator user under User Settings) or an
    OAuth 2.0 access token for third-party applications. Bloomerang does not
    offer a sandbox environment - all requests operate against production
    data. Endpoints for Constituents, Transactions, and Interactions are
    directly confirmed in Bloomerang's public documentation and third-party
    integration guides; endpoints for Households, Notes, Relationships,
    Custom Fields, Webhooks, Users, Funds, Campaigns, and Appeals are modeled
    from Bloomerang's REST API v1 resource parity, community client libraries,
    and CRM feature documentation, since Bloomerang does not publish a
    complete, versioned OpenAPI/Swagger document for v2. See review.yml in
    this repository for the endpointsConfirmed vs endpointsModeled
    breakdown.
  version: '2.0'
  contact:
    name: Bloomerang
    url: https://bloomerang.com/api/rest-api
servers:
  - url: https://api.bloomerang.co/v2
    description: Bloomerang REST API v2 (production - no sandbox is offered)
security:
  - apiKeyAuth: []
  - oauth2Bearer: []
tags:
  - name: Constituents
    description: Individuals, households, and organizations tracked as donors and contacts.
  - name: Households
    description: Family-unit grouping of individual constituents.
  - name: Transactions
    description: Donations, pledges, pledge payments, and recurring donation designations.
  - name: Interactions
    description: Logged touches between the organization and a constituent.
  - name: Notes
    description: Freeform notes attached to a constituent record.
  - name: Relationships
    description: Relationships between two constituents.
  - name: Custom Fields
    description: Account-specific custom field definitions by object type.
  - name: Webhooks
    description: Webhook subscriptions for event notifications.
  - name: Reference Data
    description: Users, funds, campaigns, and appeals used as designations and attribution.
paths:
  /constituents:
    get:
      operationId: listConstituents
      tags:
        - Constituents
      summary: List constituents
      description: Lists constituents, paginated with skip/take parameters.
      parameters:
        - $ref: '#/components/parameters/Skip'
        - $ref: '#/components/parameters/Take'
      responses:
        '200':
          description: A page of constituents.
          content:
            application/json:
              schema:
                type: object
                properties:
                  Results:
                    type: array
                    items:
                      $ref: '#/components/schemas/Constituent'
                  Total:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createConstituent
      tags:
        - Constituents
      summary: Create a constituent
      description: Creates a new constituent record.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConstituentInput'
      responses:
        '200':
          description: The created constituent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Constituent'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
  /constituents/search:
    get:
      operationId: searchConstituents
      tags:
        - Constituents
      summary: Search constituents
      description: Full-text search across constituent names and identifying fields.
      parameters:
        - name: search
          in: query
          required: true
          description: Search term, e.g. a constituent's name.
          schema:
            type: string
        - $ref: '#/components/parameters/Skip'
        - $ref: '#/components/parameters/Take'
      responses:
        '200':
          description: Matching constituents.
          content:
            application/json:
              schema:
                type: object
                properties:
                  Results:
                    type: array
                    items:
                      $ref: '#/components/schemas/Constituent'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /constituents/{id}:
    parameters:
      - $ref: '#/components/parameters/ConstituentId'
    get:
      operationId: getConstituent
      tags:
        - Constituents
      summary: Retrieve a constituent
      description: Retrieves a constituent by ID.
      responses:
        '200':
          description: The requested constituent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Constituent'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateConstituent
      tags:
        - Constituents
      summary: Update a constituent
      description: Updates fields on an existing constituent.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConstituentInput'
      responses:
        '200':
          description: The updated constituent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Constituent'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
  /constituents/{id}/timeline:
    parameters:
      - $ref: '#/components/parameters/ConstituentId'
    get:
      operationId: getConstituentTimeline
      tags:
        - Constituents
      summary: Get a constituent's timeline
      description: >-
        Retrieves the combined engagement timeline for a constituent -
        notes, interactions, donations, recurring donations, recurring
        donation payments, pledges, pledge payments, and tasks.
      responses:
        '200':
          description: The constituent timeline.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConstituentTimeline'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /constituents/{id}/relationships:
    parameters:
      - $ref: '#/components/parameters/ConstituentId'
    get:
      operationId: listConstituentRelationships
      tags:
        - Relationships
      summary: List a constituent's relationships
      description: Lists the relationships a constituent has to other constituents.
      responses:
        '200':
          description: A list of relationships.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Relationship'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    post:
      operationId: createConstituentRelationship
      tags:
        - Relationships
      summary: Create a relationship
      description: Creates a relationship between the given constituent and another constituent.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RelationshipInput'
      responses:
        '200':
          description: The created relationship.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Relationship'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
  /households:
    post:
      operationId: createHousehold
      tags:
        - Households
      summary: Create a household
      description: >-
        Creates a household constituent grouping one or more individual
        constituent members. Endpoint modeled from Bloomerang REST API v1
        household resource parity; not independently confirmed for v2 - see
        review.yml.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HouseholdInput'
      responses:
        '200':
          description: The created household.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Household'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
  /households/{id}:
    parameters:
      - name: id
        in: path
        required: true
        description: The ID of the household constituent.
        schema:
          type: integer
    get:
      operationId: getHousehold
      tags:
        - Households
      summary: Retrieve a household
      description: >-
        Retrieves a household by ID. Endpoint modeled from Bloomerang REST
        API v1 household resource parity - see review.yml.
      responses:
        '200':
          description: The requested household.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Household'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateHousehold
      tags:
        - Households
      summary: Update a household
      description: >-
        Updates household membership or details. Endpoint modeled from
        Bloomerang REST API v1 household resource parity - see review.yml.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HouseholdInput'
      responses:
        '200':
          description: The updated household.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Household'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /transactions:
    get:
      operationId: listTransactions
      tags:
        - Transactions
      summary: List transactions
      description: Lists transactions, paginated with skip/take parameters.
      parameters:
        - $ref: '#/components/parameters/Skip'
        - $ref: '#/components/parameters/Take'
      responses:
        '200':
          description: A page of transactions.
          content:
            application/json:
              schema:
                type: object
                properties:
                  Results:
                    type: array
                    items:
                      $ref: '#/components/schemas/Transaction'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createTransaction
      tags:
        - Transactions
      summary: Create a transaction
      description: >-
        Creates a transaction - the total amount of a payment - split into
        one or more designations (Donation, Pledge, PledgePayment,
        RecurringDonation, RecurringDonationPayment) against a fund and
        constituent.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TransactionInput'
      responses:
        '200':
          description: The created transaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Transaction'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
  /transactions/{id}:
    parameters:
      - name: id
        in: path
        required: true
        description: The ID of the transaction.
        schema:
          type: integer
    get:
      operationId: getTransaction
      tags:
        - Transactions
      summary: Retrieve a transaction
      description: Retrieves a transaction by ID.
      responses:
        '200':
          description: The requested transaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Transaction'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /interactions:
    get:
      operationId: listInteractions
      tags:
        - Interactions
      summary: List interactions
      description: Lists interactions, paginated with skip/take parameters.
      parameters:
        - $ref: '#/components/parameters/Skip'
        - $ref: '#/components/parameters/Take'
      responses:
        '200':
          description: A page of interactions.
          content:
            application/json:
              schema:
                type: object
                properties:
                  Results:
                    type: array
                    items:
                      $ref: '#/components/schemas/Interaction'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createInteraction
      tags:
        - Interactions
      summary: Create an interaction
      description: >-
        Creates an interaction - a logged touch (call, meeting, letter,
        email) between the organization and a constituent.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InteractionInput'
      responses:
        '200':
          description: The created interaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Interaction'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
  /interactions/{id}:
    parameters:
      - name: id
        in: path
        required: true
        description: The ID of the interaction.
        schema:
          type: integer
    get:
      operationId: getInteraction
      tags:
        - Interactions
      summary: Retrieve an interaction
      description: Retrieves an interaction by ID.
      responses:
        '200':
          description: The requested interaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Interaction'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /notes:
    post:
      operationId: createNote
      tags:
        - Notes
      summary: Create a note
      description: >-
        Creates a freeform note attached to a constituent, optionally with
        file attachment IDs. Endpoint path modeled from Bloomerang's
        documented Note object and AttachmentIds property - see review.yml.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NoteInput'
      responses:
        '200':
          description: The created note.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Note'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
  /notes/{id}:
    parameters:
      - name: id
        in: path
        required: true
        description: The ID of the note.
        schema:
          type: integer
    get:
      operationId: getNote
      tags:
        - Notes
      summary: Retrieve a note
      description: >-
        Retrieves a note by ID. Endpoint modeled from Bloomerang's documented
        Note object - see review.yml.
      responses:
        '200':
          description: The requested note.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Note'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /customFields/{type}:
    parameters:
      - name: type
        in: path
        required: true
        description: >-
          The object type to fetch custom field definitions for, e.g.
          Constituent, Transaction, Interaction, or Note.
        schema:
          type: string
          enum:
            - Constituent
            - Transaction
            - Interaction
            - Note
    get:
      operationId: listCustomFields
      tags:
        - Custom Fields
      summary: List custom field definitions
      description: Lists the custom field definitions configured for a given object type.
      responses:
        '200':
          description: A list of custom field definitions.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CustomFieldDefinition'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /webhooks:
    get:
      operationId: listWebhooks
      tags:
        - Webhooks
      summary: List webhook subscriptions
      description: Lists the webhook subscriptions registered for the account.
      responses:
        '200':
          description: A list of webhook subscriptions.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Webhook'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createWebhook
      tags:
        - Webhooks
      summary: Register a webhook subscription
      description: >-
        Registers a webhook subscription that receives an HTTP callback,
        signed with an x-bloomerang-signature header, when the given event
        occurs.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookInput'
      responses:
        '200':
          description: The created webhook subscription.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
  /webhooks/{id}:
    parameters:
      - name: id
        in: path
        required: true
        description: The ID of the webhook subscription.
        schema:
          type: string
    delete:
      operationId: deleteWebhook
      tags:
        - Webhooks
      summary: Delete a webhook subscription
      description: Removes a webhook subscription.
      responses:
        '200':
          description: Deletion confirmation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /users:
    get:
      operationId: listUsers
      tags:
        - Reference Data
      summary: List CRM users
      description: >-
        Lists the CRM users on the account, for attributing interactions and
        tasks. Endpoint modeled from Bloomerang REST API v1 User resource
        parity - see review.yml.
      responses:
        '200':
          description: A list of users.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /funds:
    get:
      operationId: listFunds
      tags:
        - Reference Data
      summary: List funds
      description: >-
        Lists the funds available as transaction designations. Endpoint
        modeled from Bloomerang REST API v1 Fund resource parity - see
        review.yml.
      responses:
        '200':
          description: A list of funds.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Fund'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /campaigns:
    get:
      operationId: listCampaigns
      tags:
        - Reference Data
      summary: List campaigns
      description: >-
        Lists fundraising campaigns. Endpoint modeled from Bloomerang REST
        API v1 Campaign resource parity - see review.yml.
      responses:
        '200':
          description: A list of campaigns.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Campaign'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /appeals:
    get:
      operationId: listAppeals
      tags:
        - Reference Data
      summary: List appeals
      description: >-
        Lists fundraising appeals. Endpoint modeled from Bloomerang REST API
        v1 Appeal resource parity - see review.yml.
      responses:
        '200':
          description: A list of appeals.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Appeal'
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
      description: >-
        Private API key generated by an Administrator user in Bloomerang
        under User Settings > Edit My User. Grants full read/write access -
        keep it secret.
    oauth2Bearer:
      type: oauth2
      description: >-
        OAuth 2.0 access token for third-party applications, presented as
        `Authorization: Bearer {access_token}`.
      flows:
        authorizationCode:
          authorizationUrl: https://crm.bloomerang.co/oauth/authorize
          tokenUrl: https://api.bloomerang.co/v2/oauth/token
          scopes:
            api: Full read/write access to account data.
  parameters:
    Skip:
      name: skip
      in: query
      required: false
      description: Number of records to skip, for pagination.
      schema:
        type: integer
        default: 0
    Take:
      name: take
      in: query
      required: false
      description: Number of records to return, for pagination.
      schema:
        type: integer
        default: 50
    ConstituentId:
      name: id
      in: path
      required: true
      description: The ID of the constituent.
      schema:
        type: integer
  responses:
    Unauthorized:
      description: Missing or invalid API key / access token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: The requested resource was not found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ValidationError:
      description: The request payload failed validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    Error:
      type: object
      properties:
        Message:
          type: string
        Errors:
          type: array
          items:
            type: string
    DeleteResponse:
      type: object
      properties:
        Id:
          type: string
        Deleted:
          type: boolean
    ConstituentInput:
      type: object
      properties:
        Type:
          type: string
          enum:
            - Individual
            - Organization
            - Household
        FirstName:
          type: string
        LastName:
          type: string
        FullName:
          type: string
        Status:
          type: string
          enum:
            - Active
            - Inactive
            - Deceased
        EmailAddress:
          type: object
          properties:
            Value:
              type: string
              format: email
            Type:
              type: string
        PhoneNumber:
          type: object
          properties:
            Number:
              type: string
            Type:
              type: string
        Address:
          type: object
          properties:
            Street:
              type: string
            City:
              type: string
            State:
              type: string
            PostalCode:
              type: string
            Country:
              type: string
        CustomValues:
          type: array
          items:
            type: object
            additionalProperties: true
    Constituent:
      allOf:
        - $ref: '#/components/schemas/ConstituentInput'
        - type: object
          properties:
            Id:
              type: integer
            AccountNumber:
              type: string
            CreatedDate:
              type: string
              format: date-time
            LastModifiedDate:
              type: string
              format: date-time
    ConstituentTimeline:
      type: object
      properties:
        Id:
          type: integer
        Notes:
          type: array
          items:
            $ref: '#/components/schemas/Note'
        Interactions:
          type: array
          items:
            $ref: '#/components/schemas/Interaction'
        Donations:
          type: array
          items:
            $ref: '#/components/schemas/Transaction'
        RecurringDonations:
          type: array
          items:
            type: object
            additionalProperties: true
        RecurringDonationPayments:
          type: array
          items:
            type: object
            additionalProperties: true
        Pledges:
          type: array
          items:
            type: object
            additionalProperties: true
        PledgePayments:
          type: array
          items:
            type: object
            additionalProperties: true
        Tasks:
          type: array
          items:
            type: object
            additionalProperties: true
    HouseholdInput:
      type: object
      required:
        - Name
      properties:
        Name:
          type: string
        MemberIds:
          type: array
          description: Constituent IDs of the individuals belonging to this household.
          items:
            type: integer
        Address:
          type: object
          properties:
            Street:
              type: string
            City:
              type: string
            State:
              type: string
            PostalCode:
              type: string
            Country:
              type: string
    Household:
      allOf:
        - $ref: '#/components/schemas/HouseholdInput'
        - type: object
          properties:
            Id:
              type: integer
    RelationshipInput:
      type: object
      required:
        - AccountId2
        - RelationshipRole1
        - RelationshipRole2
      properties:
        AccountId2:
          type: integer
          description: The constituent ID on the other side of the relationship.
        RelationshipRole1:
          type: string
          description: The role of the source constituent in the relationship, e.g. Spouse.
        RelationshipRole2:
          type: string
          description: The role of the related constituent in the relationship, e.g. Spouse.
        Note:
          type: string
    Relationship:
      allOf:
        - $ref: '#/components/schemas/RelationshipInput'
        - type: object
          properties:
            Id:
              type: integer
            AccountId1:
              type: integer
    TransactionInput:
      type: object
      required:
        - AccountId
        - Date
        - Designations
      properties:
        AccountId:
          type: integer
          description: The constituent ID this transaction is attributed to.
        Date:
          type: string
          format: date
        Method:
          type: string
          enum:
            - Cash
            - Check
            - CreditCard
            - AchDebit
            - Other
        Designations:
          type: array
          items:
            type: object
            properties:
              Type:
                type: string
                enum:
                  - Donation
                  - Pledge
                  - PledgePayment
                  - RecurringDonation
                  - RecurringDonationPayment
              FundId:
                type: integer
              CampaignId:
                type: integer
              AppealId:
                type: integer
              Amount:
                type: number
                format: double
    Transaction:
      allOf:
        - $ref: '#/components/schemas/TransactionInput'
        - type: object
          properties:
            Id:
              type: integer
            CreatedDate:
              type: string
              format: date-time
    InteractionInput:
      type: object
      required:
        - AccountId
        - Date
        - Channel
      properties:
        AccountId:
          type: integer
        Date:
          type: string
          format: date
        Channel:
          type: string
          enum:
            - Call
            - Email
            - InPerson
            - Letter
            - Other
        Purpose:
          type: string
        Note:
          type: string
        UserId:
          type: integer
    Interaction:
      allOf:
        - $ref: '#/components/schemas/InteractionInput'
        - type: object
          properties:
            Id:
              type: integer
    NoteInput:
      type: object
      required:
        - AccountId
        - Note
      properties:
        AccountId:
          type: integer
        Note:
          type: string
        Date:
          type: string
          format: date
        AttachmentIds:
          type: array
          items:
            type: integer
    Note:
      allOf:
        - $ref: '#/components/schemas/NoteInput'
        - type: object
          properties:
            Id:
              type: integer
    CustomFieldDefinition:
      type: object
      properties:
        Id:
          type: integer
        Name:
          type: string
        FieldType:
          type: string
          enum:
            - Text
            - Number
            - Date
            - PickList
            - MultiSelectPickList
        PossibleValues:
          type: array
          items:
            type: string
    WebhookInput:
      type: object
      required:
        - url
        - event
      properties:
        url:
          type: string
          format: uri
          description: The HTTPS endpoint Bloomerang will POST the event payload to.
        event:
          type: string
          description: The event type to subscribe to, e.g. constituent.created.
          enum:
            - constituent.created
            - constituent.updated
            - transaction.created
            - interaction.created
        active:
          type: boolean
          default: true
    Webhook:
      allOf:
        - $ref: '#/components/schemas/WebhookInput'
        - type: object
          properties:
            id:
              type: string
    User:
      type: object
      properties:
        Id:
          typ

# --- truncated at 32 KB (32 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/bloomerang/refs/heads/main/openapi/bloomerang-openapi.yml