Flowral Notifications API

The notifications API from Flowral — 4 operation(s) for notifications.

GitHub OpenAPI

Operations 7

GET /v1/notifications/preferences What a person is subscribed to #
PUT /v1/notifications/preferences Change what a person is subscribed to #
GET /v1/notifications/preferences/flows/{flowId} What a person is subscribed to on one flow #
PUT /v1/notifications/preferences/flows/{flowId} Override a person's settings for one flow #
DELETE /v1/notifications/preferences/flows/{flowId} Remove a flow override #
GET /v1/notifications/log What was actually sent #
GET /v1/notifications/digest This person's digest, without sending it #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/flowral-app:flowral-app-notifications-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

flowral-app-notifications-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Flowral Notifications API
  version: 1.0.0
  summary: Client projects as dependency graphs — over HTTP.
  description: 'The Flowral public API: flows, the tasks in them, and the derived state that

    makes a dependency planner useful — what is ready, what is blocked, and when a

    project actually lands.


    **Authentication.** Every request carries a credential created in the app under

    **API & AI**. Either send an API key as a bearer token, or exchange a client id

    and secret for a short-lived token at `POST /v1/oauth/token`. A credential

    belongs to a workspace and carries its own role: it can never do more than that

    role allows, and it cannot move between workspaces.


    **Errors** are `{ "error": { "code", "message" } }`. Switch on `code`; the

    message is for humans and may change.


    **Lists** are `{ "total", "items" }` and take `size` and `from`.


    **Rate limit** 120 requests/minute per credential, burst 240. Exceeding it

    returns `429` with `Retry-After`.


    **Stability.** This is v1. Fields get added; nothing that exists is removed or

    repurposed without a new major version. The platform API the web app uses is a

    different, unversioned surface — it is not this, and it will change without

    notice.'
  contact:
    name: Flowral
    email: hello@flowral.app
    url: https://flowral.app/api
  license:
    name: Proprietary
    url: https://flowral.app/terms
servers:
- url: https://api.flowral.app
  description: Production
security:
- apiKey: []
- oauth2: []
tags:
- name: Notifications
paths:
  /v1/notifications/preferences:
    get:
      operationId: notifications.preferences.get
      summary: What a person is subscribed to
      description: The settings that actually apply, after the account defaults and any flow overrides have been resolved. This is the answer, not the stored row — a `true` here means mail will be sent.
      tags:
      - Notifications
      parameters:
      - name: memberId
        in: query
        required: true
        description: The person these settings belong to. A credential has no inbox, so this is never optional.
        schema:
          type: string
          description: The person these settings belong to. A credential has no inbox, so this is never optional.
      responses:
        '200':
          description: SUCCESS
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationPreferences'
        '400':
          description: VALIDATION_FAILED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: VALIDATION_FAILED
                  message: Human-readable explanation.
        '401':
          description: UNAUTHORIZED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: UNAUTHORIZED
                  message: Human-readable explanation.
        '403':
          description: FORBIDDEN · PLAN_REQUIRED · INSUFFICIENT_SCOPE
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: FORBIDDEN
                  message: Human-readable explanation.
        '404':
          description: MEMBER_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: MEMBER_NOT_FOUND
                  message: Human-readable explanation.
        '429':
          description: RATE_LIMITED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: RATE_LIMITED
                  message: Human-readable explanation.
      security:
      - apiKey: []
      - oauth2:
        - notifications:read
      x-codeSamples:
      - lang: cURL
        source: "curl '{{API_URL}}/v1/notifications/preferences?memberId=usr_41' \\\n  -H 'Authorization: Bearer {{API_KEY}}'"
      x-examples:
      - request:
          curl: "curl '{{API_URL}}/v1/notifications/preferences?memberId=usr_41' \\\n  -H 'Authorization: Bearer {{API_KEY}}'"
        response:
          status: 200
          body:
            memberId: usr_41
            flowId: null
            email: true
            muted: false
            events:
              assigned: true
              unlocked: true
              digest: true
            timezone: Europe/Paris
            digestHour: 8
    put:
      operationId: notifications.preferences.set
      summary: Change what a person is subscribed to
      description: Sets the account defaults. Only the keys you send are changed; sending `null` for one resets it to the built-in default rather than turning it off.
      tags:
      - Notifications
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                memberId:
                  type: string
                  description: The person these settings belong to.
                email:
                  type: boolean
                  description: The master switch for this scope. `null` means "inherit".
                muted:
                  type: boolean
                  description: 'Flow scope only: silence everything about this flow.'
                events:
                  type: object
                  description: 'Per-event switches: `assigned`, `unlocked`, `digest`. Omit a key to leave it alone; send `null` to reset it to inherited.'
                timezone:
                  type: string
                  description: Account scope only. IANA zone name — the digest is sent in this person's morning, not the server's.
                digestHour:
                  type: integer
                  description: Account scope only. 0–23, local. Default 8.
              required:
              - memberId
      responses:
        '200':
          description: SUCCESS
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationPreferences'
        '400':
          description: VALIDATION_FAILED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: VALIDATION_FAILED
                  message: Human-readable explanation.
        '401':
          description: UNAUTHORIZED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: UNAUTHORIZED
                  message: Human-readable explanation.
        '403':
          description: FORBIDDEN · INSUFFICIENT_SCOPE
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: FORBIDDEN
                  message: Human-readable explanation.
        '404':
          description: MEMBER_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: MEMBER_NOT_FOUND
                  message: Human-readable explanation.
        '429':
          description: RATE_LIMITED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: RATE_LIMITED
                  message: Human-readable explanation.
      security:
      - apiKey: []
      - oauth2:
        - notifications:write
      x-minRole: admin
      x-codeSamples:
      - lang: cURL
        source: "curl -X PUT '{{API_URL}}/v1/notifications/preferences' \\\n  -H 'Authorization: Bearer {{API_KEY}}' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"memberId\":\"usr_41\",\"timezone\":\"America/New_York\",\"digestHour\":7}'"
      x-examples:
      - request:
          curl: "curl -X PUT '{{API_URL}}/v1/notifications/preferences' \\\n  -H 'Authorization: Bearer {{API_KEY}}' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"memberId\":\"usr_41\",\"timezone\":\"America/New_York\",\"digestHour\":7}'"
        response:
          status: 200
          body:
            memberId: usr_41
            flowId: null
            email: true
            muted: false
            events:
              assigned: true
              unlocked: true
              digest: true
            timezone: America/New_York
            digestHour: 7
  /v1/notifications/preferences/flows/{flowId}:
    get:
      operationId: notifications.preferences.flow.get
      summary: What a person is subscribed to on one flow
      description: The account settings with this flow's override applied.
      tags:
      - Notifications
      parameters:
      - name: flowId
        in: path
        required: true
        schema:
          type: string
      - name: memberId
        in: query
        required: true
        description: The person these settings belong to. A credential has no inbox, so this is never optional.
        schema:
          type: string
          description: The person these settings belong to. A credential has no inbox, so this is never optional.
      responses:
        '200':
          description: SUCCESS
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationPreferences'
        '400':
          description: VALIDATION_FAILED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: VALIDATION_FAILED
                  message: Human-readable explanation.
        '401':
          description: UNAUTHORIZED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: UNAUTHORIZED
                  message: Human-readable explanation.
        '403':
          description: FORBIDDEN · PLAN_REQUIRED · INSUFFICIENT_SCOPE
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: FORBIDDEN
                  message: Human-readable explanation.
        '404':
          description: NOT_FOUND · MEMBER_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: NOT_FOUND
                  message: Human-readable explanation.
        '429':
          description: RATE_LIMITED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: RATE_LIMITED
                  message: Human-readable explanation.
      security:
      - apiKey: []
      - oauth2:
        - notifications:read
    put:
      operationId: notifications.preferences.flow.set
      summary: Override a person's settings for one flow
      description: 'The usual use is `{"muted": true}` — silence one noisy flow without touching anything else this person gets.'
      tags:
      - Notifications
      parameters:
      - name: flowId
        in: path
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                memberId:
                  type: string
                  description: The person these settings belong to.
                email:
                  type: boolean
                  description: The master switch for this scope. `null` means "inherit".
                muted:
                  type: boolean
                  description: 'Flow scope only: silence everything about this flow.'
                events:
                  type: object
                  description: 'Per-event switches: `assigned`, `unlocked`, `digest`. Omit a key to leave it alone; send `null` to reset it to inherited.'
                timezone:
                  type: string
                  description: Account scope only. IANA zone name — the digest is sent in this person's morning, not the server's.
                digestHour:
                  type: integer
                  description: Account scope only. 0–23, local. Default 8.
              required:
              - memberId
      responses:
        '200':
          description: SUCCESS
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationPreferences'
        '400':
          description: VALIDATION_FAILED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: VALIDATION_FAILED
                  message: Human-readable explanation.
        '401':
          description: UNAUTHORIZED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: UNAUTHORIZED
                  message: Human-readable explanation.
        '403':
          description: FORBIDDEN · INSUFFICIENT_SCOPE
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: FORBIDDEN
                  message: Human-readable explanation.
        '404':
          description: NOT_FOUND · MEMBER_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: NOT_FOUND
                  message: Human-readable explanation.
        '429':
          description: RATE_LIMITED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: RATE_LIMITED
                  message: Human-readable explanation.
      security:
      - apiKey: []
      - oauth2:
        - notifications:write
      x-minRole: admin
    delete:
      operationId: notifications.preferences.flow.clear
      summary: Remove a flow override
      description: The flow follows the person's account settings again. Not the same as turning everything off for it.
      tags:
      - Notifications
      parameters:
      - name: flowId
        in: path
        required: true
        schema:
          type: string
      - name: memberId
        in: query
        required: true
        description: The person these settings belong to. A credential has no inbox, so this is never optional.
        schema:
          type: string
          description: The person these settings belong to. A credential has no inbox, so this is never optional.
      responses:
        '200':
          description: SUCCESS
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationPreferences'
        '401':
          description: UNAUTHORIZED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: UNAUTHORIZED
                  message: Human-readable explanation.
        '403':
          description: FORBIDDEN · INSUFFICIENT_SCOPE
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: FORBIDDEN
                  message: Human-readable explanation.
        '404':
          description: NOT_FOUND · MEMBER_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: NOT_FOUND
                  message: Human-readable explanation.
        '429':
          description: RATE_LIMITED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: RATE_LIMITED
                  message: Human-readable explanation.
      security:
      - apiKey: []
      - oauth2:
        - notifications:write
      x-minRole: admin
  /v1/notifications/log:
    get:
      operationId: notifications.log
      summary: What was actually sent
      description: One row per email that left the building, newest first — batches and digests alike. Use it to answer "did they get told", and to see what was suppressed because they had unsubscribed.
      tags:
      - Notifications
      parameters:
      - name: size
        in: query
        required: false
        schema:
          type: integer
          default: 25
      - name: memberId
        in: query
        required: true
        description: The person these settings belong to. A credential has no inbox, so this is never optional.
        schema:
          type: string
          description: The person these settings belong to. A credential has no inbox, so this is never optional.
      responses:
        '200':
          description: SUCCESS
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    description: Total matching, not the length of `items`.
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/NotificationDelivery'
                required:
                - total
                - items
        '401':
          description: UNAUTHORIZED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: UNAUTHORIZED
                  message: Human-readable explanation.
        '403':
          description: FORBIDDEN · PLAN_REQUIRED · INSUFFICIENT_SCOPE
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: FORBIDDEN
                  message: Human-readable explanation.
        '404':
          description: MEMBER_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: MEMBER_NOT_FOUND
                  message: Human-readable explanation.
        '429':
          description: RATE_LIMITED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: RATE_LIMITED
                  message: Human-readable explanation.
      security:
      - apiKey: []
      - oauth2:
        - notifications:read
  /v1/notifications/digest:
    get:
      operationId: notifications.digest.preview
      summary: This person's digest, without sending it
      description: What tomorrow morning's mail would say, built by the real builder and delivered to nobody. Also the cleanest per-person view of "what should I work on today" across every flow they can see — `/v1/work/available` answers that per workspace, this answers it per person.
      tags:
      - Notifications
      parameters:
      - name: memberId
        in: query
        required: true
        description: The person these settings belong to. A credential has no inbox, so this is never optional.
        schema:
          type: string
          description: The person these settings belong to. A credential has no inbox, so this is never optional.
      responses:
        '200':
          description: SUCCESS
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationDigest'
        '401':
          description: UNAUTHORIZED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: UNAUTHORIZED
                  message: Human-readable explanation.
        '403':
          description: FORBIDDEN · PLAN_REQUIRED · INSUFFICIENT_SCOPE
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: FORBIDDEN
                  message: Human-readable explanation.
        '404':
          description: MEMBER_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: MEMBER_NOT_FOUND
                  message: Human-readable explanation.
        '429':
          description: RATE_LIMITED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: RATE_LIMITED
                  message: Human-readable explanation.
      security:
      - apiKey: []
      - oauth2:
        - notifications:read
      x-codeSamples:
      - lang: cURL
        source: "curl '{{API_URL}}/v1/notifications/digest?memberId=usr_41' \\\n  -H 'Authorization: Bearer {{API_KEY}}'"
      x-examples:
      - request:
          curl: "curl '{{API_URL}}/v1/notifications/digest?memberId=usr_41' \\\n  -H 'Authorization: Bearer {{API_KEY}}'"
        response:
          status: 200
          body:
            memberId: usr_41
            wouldSend: true
            counts:
              ready: 2
              inProgress: 1
              blocked: 1
              available: 3
              doneByMe: 1
              doneByTeam: 4
              atRisk: 1
              flows: 3
            ready:
            - questId: flw_2b8e10
              questName: 'Acme: Website relaunch'
              nodeId: tsk_9
              nodeTitle: Write launch copy
              hours: 8
              criticalPath: true
            atRisk:
            - questId: flw_2b8e10
              questName: 'Acme: Website relaunch'
              dueDate: '2026-09-14'
              projectedFinish: '2026-09-21'
              workdaysOver: 5
components:
  schemas:
    NotificationDelivery:
      type: object
      description: One email that was sent — or deliberately not sent, which is recorded too.
      properties:
        id:
          type: string
        kind:
          type: string
          description: '`batch` (assignments and unblocked work, grouped) or `digest`.'
        status:
          type: string
          description: '`sent`, `failed`, `skipped`, `skipped-empty`, or `claimed` while in flight.'
        sentAt:
          type: string
          format: date-time
          description: When the send was claimed.
        subject:
          type:
          - string
          - 'null'
        itemCount:
          type: integer
          description: How many events one batch covered. Notifications are batched after a quiet period, so this is usually more than one.
        flowIds:
          type: array
          items:
            type: string
        suppressed:
          type: integer
          description: Events dropped because the person had unsubscribed since they were queued.
      required:
      - id
      - kind
      - status
    NotificationDigest:
      type: object
      description: 'One person''s day: what is on them, what is free to pick up, what moved. Spans every flow they can see, including flows shared with them from workspaces they are not a member of.'
      properties:
        memberId:
          type: string
        generatedAt:
          type: string
          format: date-time
          description: When this was built.
        wouldSend:
          type: boolean
          description: False when there is nothing worth mailing — an empty digest is never sent.
        counts:
          type: object
          additionalProperties:
            type: integer
          description: Totals BEFORE the per-section caps, so a truncated list still reports honestly.
        ready:
          type: array
          items:
            type: object
            properties:
              questId:
                type: string
                description: The flow id.
              questName:
                type: string
              nodeId:
                type: string
                description: The task id.
              nodeTitle:
                type: string
              hours:
                type:
                - number
                - 'null'
              criticalPath:
                type: boolean
          description: Assigned to them and unblocked.
        inProgress:
          type: array
          items:
            type: object
            properties:
              questId:
                type: string
                description: The flow id.
              questName:
                type: string
              nodeId:
                type: string
                description: The task id.
              nodeTitle:
                type: string
              hours:
                type:
                - number
                - 'null'
              criticalPath:
                type: boolean
        blocked:
          type: array
          items:
            type: object
            properties:
              questId:
                type: string
                description: The flow id.
              questName:
                type: string
              nodeId:
                type: string
                description: The task id.
              nodeTitle:
                type: string
              hours:
                type:
                - number
                - 'null'
              criticalPath:
                type: boolean
          description: Theirs, waiting on someone else.
        available:
          type: array
          items:
            type: object
            properties:
              questId:
                type: string
                description: The flow id.
              questName:
                type: string
              nodeId:
                type: string
                description: The task id.
              nodeTitle:
                type: string
              hours:
                type:
                - number
                - 'null'
              criticalPath:
                type: boolean
          description: Unassigned and ready — anyone could pick it up.
        completed:
          type: array
          items:
            type: object
          description: Finished in the last 24 hours, across their flows.
        atRisk:
          type: array
          items:
            type: object
          description: Flows projected to finish after their due date.
      required:
      - memberId
      - wouldSend
      - counts
    NotificationPreferences:
      type: object
      description: What one person is emailed about, resolved. When `flowId` is set, this is the account settings with that flow's override already applied.
      properties:
        memberId:
          type: string
        flowId:
          type:
          - string
          - 'null'
          description: Null for the account-level answer.
        email:
          type: boolean
          description: The master switch. False means no notification email at all, whatever the per-event flags say.
        muted:
          type: boolean
          description: Set by a flow-level override to silence one flow.
        events:
          type: object
          description: Per-event switches.
          properties:
            assigned:
              type: boolean
              description: A task was assigned to them.
            unlocked:
              type: boolean
              description: A task of theirs stopped being blocked.
            digest:
              type: boolean
              description: The morning summary. Account level only.
        timezone:
          type: string
          description: IANA zone. The digest is sent in this person's morning.
          examples:
          - Europe/Paris
        digestHour:
          type: integer
          description: 0–23, local.
      required:
      - memberId
      - email
      - events
    Error:
      type: object
      description: Every non-2xx response has this shape.
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: Stable, machine-readable. Switch on this, not on the message.
              examples:
              - NOT_FOUND
            message:
              type: string
              description: Human-readable. May change; never parse it.
            details:
              type: object
              additionalProperties: true
              description: Present when the code alone is not actionable — which task blocked, which deliverable is missing, which limit was hit.
          required:
          - code
          - message
      required:
      - error
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: 'An API key from the app: `Authorization: Bearer fl_sk_live_…`.'
    oauth2:
      type: oauth2
      description: Client credentials, for anything long-lived.
      flows:
        clientCredentials:
          tokenUrl: https://api.flowral.app/v1/oauth/token
          scopes:
            flows:read: Read flows, tasks, schedules and reports
            flows:write: Create and change flows and tasks
            work:write: Start, complete, assign and comment on work
            team:read: Read members and invitations
            team:write: Invite people and change roles
            templates:read: Read templates and start flows from them
            notifications:read: Read what people are emailed about
            notifications:write: Change what people are emailed about