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.
Import into Postman
Download the collection and drag it into Postman — or use Import → Link
with the spec URL, which stays current on its own.
Set the apiKey collection variable once and every request is signed.
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.
OpenAPI 3.1.0 · 52 paths ·
generated from the service, not written by hand
auth
Getting a token.
GET/v1/oauth/authorizeauth.authorize
Start a first-party sign-in (authorization code + PKCE)
Browser-facing, not meant to be called by anything but a user-agent. Validates the request and redirects to the Flowral app's own sign-in screen; once the person signs in and allows the connection there, the app redirects on to redirect_uri with a one-time code. POST /oauth/token's authorization_code grant exchanges it for a token. client_id must name a registered first-party client (currently flowral-vscode) and redirect_uri must be a loopback address it owns.
Query
client_idrequired
string
redirect_urirequired
string
A loopback address, e.g. http://127.0.0.1:<port>/callback.
response_typerequired
string
Must be code.
code_challengerequired
string
PKCE, S256 of a code_verifier the client keeps.
code_challenge_methodrequired
string
Must be S256.
state
string
scope
string
Space-separated. Defaults to everything the signed-in person can do; naming scopes here can only narrow it.
Responses
302Redirects to the app's sign-in screen.
POST/v1/oauth/tokenauth.token
Exchange credentials for an access token
Three grants, all application/x-www-form-urlencoded:
- client_credentials — a workspace credential's id/secret. May also be sent as HTTP Basic.
- authorization_code — the code from /oauth/authorize, with the PKCE code_verifier. Issues a token that acts as the person who signed in, not a workspace credential — plus a refresh_token, since a person has no secret to silently re-present an hour later.
- refresh_token — trades the refresh token from an authorization_code grant for a new access/refresh pair. Rotated: the old refresh token stops working the moment this succeeds. Pass org_id to move to a DIFFERENT workspace the same person belongs to, without a second trip through the browser — checked fresh against live membership, same as a new sign-in would be.
Either way the token is a bearer token for this API and nothing else — it is not a planner session and cannot be used against the app.
Body application/x-www-form-urlencoded
grant_typerequired
string
client_credentials, authorization_code, or refresh_token.
client_id
string
Required for client_credentials and authorization_code.
client_secret
string
client_credentials only.
code
string
authorization_code only — from /oauth/authorize.
code_verifier
string
authorization_code only — PKCE.
redirect_uri
string
authorization_code only — must match the value sent to /oauth/authorize.
refresh_token
string
refresh_token only.
org_id
string
refresh_token only. Switch to a different workspace the person belongs to; omit to just refresh the current one.
scope
string
Space-separated. Defaults to everything the credential (or, for authorization_code, the person) was granted; naming scopes here can only narrow it.
The workspace, the credential's role and scopes, and the plan. Cheap, and the right health check for an integration. For a person-token (authorization_code), also includes userId — the same id GET /team/members lists them under, for a client that wants "assign to me"/"my work" to work without asking the person to pick themselves out of their own team — and orgs: every workspace they belong to, for a client that wants to offer a "switch workspace" action (see POST /oauth/token's refresh_token grant). Unlike every other /v1 route, this one is NOT refused on a Free-plan workspace — it reports plan: "free" truthfully instead, which is what lets a client explain the refusal (or, for a person-token, offer switching to a different workspace) rather than just receiving one.
Creates a flow and, optionally, its whole task graph in one call. A task's after references other tasks by index in this request, so the dependency chain arrives with the flow rather than in follow-up calls. Cycles are refused outright.
Scopes: flows:write · Role: member or higher
Body application/json
namerequired
string
description
string
dueDate
string
ISO 8601. Used by the schedule and report endpoints to answer "is this on track".
tasks
object[]
Tasks to create, in order. Each: { name, description?, estimateHours?, assigneeId?, after?: [index] }, where after holds indexes into this same array.
Runs the critical-path pass: earliest and latest start and finish per task, slack, and the projected finish for the flow. Computed from estimates and dependencies — no dates are stored, so this is always current.
Completion, effort remaining, workload per member, the tasks blocking the most work, and what is unestimated or orphaned. The same figures the Reporting view shows.
Renders the flow through the same pipeline the app uses. pdf is the delivery document (diagram plus execution plan); png is the dependency diagram on its own. Responds with the bytes, Content-Disposition set.
Makes the flow readable by anyone with its link, with no account and nothing to accept. The public view never includes assignees, comments, uploaded files or task notes, and its items cannot be opened. Returns the flow, including its publicUrl.
Takes the flow off the internet. Immediate and total: the link stops working for everyone who already has it, including anyone with the page open. Embeds of it go dark at the same moment.
Creates a task and links it in the same call. after are the tasks that must finish first; before are the tasks that now wait on this one — use it to insert a step into an existing chain.
Name, description and estimate. Status is not settable here — see the transition endpoints. Refused once work has started, the same rule the canvas applies.
Bridges the gap it leaves: whatever depended on this task now depends on what it depended on, so removing a step from the middle leaves a plan that still runs end to end.
In progress → done, and the response says what that unblocked — which is the next question every time. Refused if sub-tasks are outstanding or a required deliverable has not been handed in.
Done → in progress. Refused once anything downstream has been started: undoing a completion that the next person already acted on would rewrite work that is under way.
Creates a brainstorm and, optionally, its whole starting idea tree in one call. An idea's parent references another idea by index in this request, so a shape arrives with the board rather than in follow-up calls.
Scopes: flows:write · Role: member or higher
Body application/json
namerequired
string
ideas
object[]
Ideas to create, in order. Each: { title, notes?, parent?: index }, where parent is an index into this same array — omit it for a root idea.
Archives rather than destroys, so it can be restored — with one exception, same rule the app applies: a brainstorm with no ideas on it yet is deleted outright, since there is nothing in it to recover.
Scopes: flows:write · Role: member or higher
Path
brainstormIdrequired
string
Responses
204ARCHIVED (or deleted outright, if it had no ideas)
Gives one person access to this brainstorm only — they see it from their own workspace and never join the squad. Only existing Flowral accounts can be shared with this way; the API does not send invitation emails.
Makes the board readable by anyone with its link, with no account and nothing to accept. The public view shows the boxes, their tree position and their tags — never assignees, comments, files or notes. Returns the brainstorm, including its publicUrl.
Bridges the gap it leaves: this idea's children are re-parented onto its own parent (or promoted to root ideas, if it had none), so removing a box from the middle of a branch doesn't orphan what nested under it. This cannot be undone.
Ready and in-progress work assigned to this credential's identity. For a service credential, pass assigneeId to /work/available instead — a credential is not a person and has nothing assigned to it.
Blocked work with the unfinished tasks holding it up, ranked so the task blocking the most appears first. This is the "where is delivery actually stalling" call.
Sends an invitation. A pending invite occupies a seat for the purposes of the plan limit, which is why this can be refused on a full workspace before anyone has accepted.
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.
Scopes: notifications:read
Query
memberIdrequired
string
The person these settings belong to. A credential has no inbox, so this is never optional.
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.
Scopes: notifications:read
Query
size
integer
default 25
memberIdrequired
string
The person these settings belong to. A credential has no inbox, so this is never optional.
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.
Scopes: notifications:read
Query
memberIdrequired
string
The person these settings belong to. A credential has no inbox, so this is never optional.
Who the credential is and what it may do — the first call to make when wiring an integration.
workspaceIdrequired
string
workspaceNamerequired
string
credentialId
string
The key or client this token belongs to.
credentialName
string
rolerequired
admin | member | viewer
The credential’s role in the workspace. It decides what every other call may do.adminmemberviewer
scopesrequired
string[]
planrequired
free | pro
freepro
Token
access_tokenrequired
string
token_typerequired
string
expires_inrequired
integer
Seconds.
scope
string
Space-separated, and never more than the credential was granted.
FlowSummary
A flow without its tasks — what list endpoints return.
idrequired
string
namerequired
string
description
string | null
archivedrequired
boolean
public
boolean
Whether this flow is published — readable by anyone with its link, with no account. Assignees, comments and files are never included in the public view.
publicUrl
string | null
The published link, or null when the flow is private.
dueDate
string · date-time
The date the flow is meant to land, if one is set.
taskCount
integer
doneCount
integer
readyCount
integer
Tasks that can be started right now.
createdAt
string · date-time
updatedAt
string · date-time
Flow
A flow with its full task graph and derived state.
A unit of work in a flow. Tasks are joined by dependencies: one is ready only when everything it depends on is done, and one with sub-tasks completes through them.
idrequired
string
flowIdrequired
string
parentIdrequired
string | null
Set when this is a sub-task — the objective it belongs to. Null for an objective itself.
namerequired
string
description
string | null
statusrequired
blocked | ready | in_progress | done
Derived from the graph on read, never stored. Work moves ready → in_progress → done; nothing jumps straight to done.blockedreadyin_progressdone
dependsOnrequired
string[]
Task ids that must be done first.
blockedBy
string[]
Of those, the ones not yet done. Empty when status is not "blocked".
assigneeId
string | null
estimateHours
number | null
criticalPath
boolean
True when this task is on the chain that decides the flow's finish date.
This objective's sub-tasks, if it has any. An objective with sub-tasks completes through them rather than directly — see the Task schema — so a client offering "start"/"complete" on this item should check here first.
blockedBy
object[]
On blocked work, the unfinished tasks holding it up, most-blocking first.
Schedule
flowIdrequired
string
dueDate
string | null
The day the flow is meant to land, YYYY-MM-DD.
projectedFinish
string | null
Working day it lands at the current shape and estimates, YYYY-MM-DD.
onTrack
boolean | null
Null when there is no due date to be on track against.
The idea this nests under, or null for a root idea.
titlerequired
string
notes
string | null
tags
string[]
assigneeId
string | null
commentCount
integer
fileCount
integer
createdAt
string · date-time
IdeaComment
idrequired
string
ideaIdrequired
string
authorId
string
authorName
string
bodyrequired
string
createdAtrequired
string · date-time
Member
idrequired
string
name
string
emailrequired
string · email
rolerequired
owner | admin | member | viewer
owneradminmemberviewer
Invite
idrequired
string
emailrequired
string · email
rolerequired
admin | member | viewer
adminmemberviewer
statusrequired
pending | accepted | revoked
pendingacceptedrevoked
createdAt
string · date-time
Share
A client or guest with access to one flow. Guests never occupy a seat.
idrequired
string
emailrequired
string · email
rolerequired
viewer | commenter
viewercommenter
flowIdrequired
string
createdAt
string · date-time
Template
A saved flow shape, ready to start a new flow from.
idrequired
string
namerequired
string
description
string | null
category
string | null
taskCount
integer
usedCount
integer
SearchResult
idrequired
string
typerequired
flow | task | template
flowtasktemplate
titlerequired
string
flowId
string | null
url
string
Where it lives in the app, for a link back.
NotificationPreferences
What one person is emailed about, resolved. When flowId is set, this is the account settings with that flow's override already applied.
memberIdrequired
string
flowId
string | null
Null for the account-level answer.
emailrequired
boolean
The master switch. False means no notification email at all, whatever the per-event flags say.
muted
boolean
Set by a flow-level override to silence one flow.
eventsrequired
object
Per-event switches.
timezone
string
IANA zone. The digest is sent in this person's morning.
digestHour
integer
0–23, local.
NotificationDelivery
One email that was sent — or deliberately not sent, which is recorded too.
idrequired
string
kindrequired
string
batch (assignments and unblocked work, grouped) or digest.
statusrequired
string
sent, failed, skipped, skipped-empty, or claimed while in flight.
sentAt
string · date-time
When the send was claimed.
subject
string | null
itemCount
integer
How many events one batch covered. Notifications are batched after a quiet period, so this is usually more than one.
flowIds
string[]
suppressed
integer
Events dropped because the person had unsubscribed since they were queued.
NotificationDigest
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.
memberIdrequired
string
generatedAt
string · date-time
When this was built.
wouldSendrequired
boolean
False when there is nothing worth mailing — an empty digest is never sent.
countsrequired
object
Totals BEFORE the per-section caps, so a truncated list still reports honestly.
ready
object[]
Assigned to them and unblocked.
inProgress
object[]
blocked
object[]
Theirs, waiting on someone else.
available
object[]
Unassigned and ready — anyone could pick it up.
completed
object[]
Finished in the last 24 hours, across their flows.