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.
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/flowral-app:flowral-app-auth-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
openapi: 3.2.0
info:
title: Flowral Auth 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: Auth
description: Getting a token.
paths:
/v1/oauth/authorize:
get:
operationId: auth.authorize
summary: Start a first-party sign-in (authorization code + PKCE)
description: 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.
tags:
- Auth
parameters:
- name: client_id
in: query
required: true
schema:
type: string
- name: redirect_uri
in: query
required: true
description: A loopback address, e.g. `http://127.0.0.1:<port>/callback`.
schema:
type: string
description: A loopback address, e.g. `http://127.0.0.1:<port>/callback`.
- name: response_type
in: query
required: true
description: Must be `code`.
schema:
type: string
description: Must be `code`.
- name: code_challenge
in: query
required: true
description: PKCE, S256 of a code_verifier the client keeps.
schema:
type: string
description: PKCE, S256 of a code_verifier the client keeps.
- name: code_challenge_method
in: query
required: true
description: Must be `S256`.
schema:
type: string
description: Must be `S256`.
- name: state
in: query
required: false
schema:
type: string
- name: scope
in: query
required: false
description: Space-separated. Defaults to everything the signed-in person can do; naming scopes here can only narrow it.
schema:
type: string
description: Space-separated. Defaults to everything the signed-in person can do; naming scopes here can only narrow it.
responses:
'302':
description: Redirects to the app's sign-in screen.
security: []
/v1/oauth/token:
post:
operationId: auth.token
summary: Exchange credentials for an access token
description: '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.'
tags:
- Auth
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
grant_type:
type: string
description: '`client_credentials`, `authorization_code`, or `refresh_token`.'
client_id:
type: string
description: Required for client_credentials and authorization_code.
client_secret:
type: string
description: client_credentials only.
code:
type: string
description: authorization_code only — from /oauth/authorize.
code_verifier:
type: string
description: authorization_code only — PKCE.
redirect_uri:
type: string
description: authorization_code only — must match the value sent to /oauth/authorize.
refresh_token:
type: string
description: refresh_token only.
org_id:
type: string
description: refresh_token only. Switch to a different workspace the person belongs to; omit to just refresh the current one.
scope:
type: string
description: Space-separated. Defaults to everything the credential (or, for authorization_code, the person) was granted; naming scopes here can only narrow it.
required:
- grant_type
responses:
'200':
description: SUCCESS
content:
application/json:
schema:
$ref: '#/components/schemas/Token'
'400':
description: UNSUPPORTED_GRANT_TYPE · INVALID_SCOPE · invalid_grant · invalid_request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: UNSUPPORTED_GRANT_TYPE
message: Human-readable explanation.
'401':
description: INVALID_CLIENT
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: INVALID_CLIENT
message: Human-readable explanation.
'403':
description: invalid_target
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: invalid_target
message: Human-readable explanation.
security: []
x-codeSamples:
- lang: cURL
source: "curl -X POST '{{API_URL}}/v1/oauth/token' \\\n -H 'Content-Type: application/x-www-form-urlencoded' \\\n -d 'grant_type=client_credentials&client_id={{CLIENT_ID}}&client_secret={{CLIENT_SECRET}}'"
x-examples:
- request:
curl: "curl -X POST '{{API_URL}}/v1/oauth/token' \\\n -H 'Content-Type: application/x-www-form-urlencoded' \\\n -d 'grant_type=client_credentials&client_id={{CLIENT_ID}}&client_secret={{CLIENT_SECRET}}'"
response:
status: 200
body:
access_token: fl_at_9c2f…
token_type: Bearer
expires_in: 3600
scope: flows:read flows:write work:write
/v1/oauth/revoke:
post:
operationId: auth.revoke
summary: Revoke an access token
description: RFC 7009. Kills one issued token immediately. To kill the credential itself, delete it in the app — that also invalidates every token it ever issued.
tags:
- Auth
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
token:
type: string
required:
- token
responses:
'200':
description: SUCCESS — also returned for a token that was already invalid, per the RFC.
'401':
description: INVALID_CLIENT
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: INVALID_CLIENT
message: Human-readable explanation.
security: []
components:
schemas:
Token:
type: object
properties:
access_token:
type: string
token_type:
type: string
examples:
- Bearer
expires_in:
type: integer
description: Seconds.
examples:
- 3600
scope:
type: string
description: Space-separated, and never more than the credential was granted.
required:
- access_token
- token_type
- expires_in
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