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 · 39 paths ·
generated from the service, not written by hand
auth
Getting a token.
POST/v1/oauth/tokenauth.token
Exchange client credentials for an access token
Standard OAuth 2.0 client-credentials grant (application/x-www-form-urlencoded). Credentials may also be sent as HTTP Basic. 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
Must be client_credentials.
client_idrequired
string
client_secretrequired
string
scope
string
Space-separated. Defaults to everything the credential was granted; naming scopes here can only narrow it.
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
TaskInput[]
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.
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.
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.
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
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.
One task on the critical-path pass. Dates are computed from estimates and dependencies; nothing here is stored.
taskIdrequired
string
taskNamerequired
string
earliestStart
string
Working day, YYYY-MM-DD.
earliestFinish
string
Working day, YYYY-MM-DD.
criticalPathrequired
boolean
On the chain that decides the finish date — no slack.
estimated
boolean
False when the span is a one-day guess because nothing was estimated.
Report
The delivery health of a flow: what is done, what is left, what is holding it up, and who is carrying it.
flowIdrequired
string
flowName
string
completionrequired
number
0–1.
tasksTotalrequired
integer
tasksDone
integer
tasksReady
integer
tasksBlocked
integer
hoursEstimated
number | null
hoursRemaining
number | null
unestimatedTasks
string[]
Task ids with no estimate — the reason a projection is soft.
orphanedTasks
string[]
Tasks nothing depends on and that depend on nothing.
workload
object[]
topBlockers
object[]
Comment
idrequired
string
taskIdrequired
string
authorId
string
authorName
string
bodyrequired
string
createdAtrequired
string · date-time
Attachment
idrequired
string
namerequired
string
mimeType
string
sizeBytes
integer
kindrequired
reference | deliverable
referencedeliverable
uploadedAt
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.