API reference
Every endpoint is authenticated with a bearer API key and lives under https://www.flowrelay.it/api/v1. Rate limit: 60 requests / minute / key.
openapi.json into Postman or Insomnia to generate a client.Finding IDs
Every id is a UUID you discover from a list endpoint – you never need to know one up front.
| You need | Get it from |
|---|---|
| project_id (and {id} in the path) | GET /projects |
| handoff_id | GET /handoffs |
| insight_id | GET /projects/{id}/insights |
| channel_id | GET /discord/channels |
| filter values (repos, branches, etc.) | GET /handoffs/filters?project_id=... |
| jobId | returned in the 202 response when you start a generation |
List accessible projects
/projectsReturns the tenant context for the key owner: account type, organization memberships, and every personal or organization project the key can access (role-scoped).
Request
curl "https://www.flowrelay.it/api/v1/projects" \
-H "Authorization: Bearer fr_your_api_key"Response
{
"account_type": "business",
"organizations": [
{
"id": "8c2b1a90-1234-4abc-9def-0123456789ab",
"name": "Acme",
"slug": "acme",
"role": "admin",
"is_temporary_admin": false
}
],
"projects": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Payments",
"slug": "payments",
"description": "Billing and checkout",
"organization_id": "8c2b1a90-1234-4abc-9def-0123456789ab",
"organization_name": "Acme",
"organization_slug": "acme",
"project_type": "organization",
"access_role": "admin",
"created_at": "2026-05-01T09:12:00Z",
"updated_at": "2026-06-20T14:03:00Z"
}
]
}| Status | When |
|---|---|
| 200 | Success |
| 401 | Missing or invalid API key. |
| 429 | Rate limit exceeded (60/min/key). |
List handoffs
/handoffsLists handoffs across accessible projects, newest first. Without project_id it spans every project the key can access.
Query parameters
| Name | Type | Description |
|---|---|---|
statusoptional | string | Filter by status.One of: active, archived, allDefault: active |
limitoptional | integer | Maximum rows to return (1–100).Default: 20 |
project_idoptional | string | Restrict to a single project. |
Request
curl "https://www.flowrelay.it/api/v1/handoffs" \
-H "Authorization: Bearer fr_your_api_key"Response
{
"handoffs": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"project_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"kind": "project",
"title": "Checkout refactor handoff",
"summary": "Migrated the checkout flow to the new pricing engine.",
"status": "active",
"sources": [
"github",
"linear"
],
"key_changes": [
"Replaced legacy tax calc"
],
"decisions": [
"Use flat per-artifact pricing"
],
"open_questions": [
"Backfill historical invoices?"
],
"next_steps": [
"Wire the new webhook"
],
"completion_percentage": null,
"related_event_ids": [
"d4e5f6a7-b8c9-0123-def4-23456789013a"
],
"scope_type": "project",
"project_name": "Payments",
"created_at": "2026-06-20T14:03:00Z",
"updated_at": "2026-06-20T14:03:00Z",
"markdown": "# Checkout refactor handoff\n\n> Migrated the checkout flow…"
}
]
}| Status | When |
|---|---|
| 200 | Success |
| 400 | The body or a query parameter is invalid: an unknown field, an unknown source, an unsupported filter dimension, or an out-of-range number. The response names the offending field and lists the allowed values. |
| 401 | Missing or invalid API key. |
| 404 | Project not found or not accessible by this key. |
Generate a handoff
/handoffsAsynchronous – returns 202 with a jobId. Poll GET /jobs/{jobId} until the job completes.
Enqueues a project handoff generation and returns a job id. Poll GET /jobs/{jobId} until status is completed. When sources/filters are omitted the project saved scope preferences are used.
Body parameters
| Name | Type | Description |
|---|---|---|
project_idrequired | string | Project UUID to generate the handoff for (from GET /projects). |
sourcesoptional | string[] | Restrict generation to these sources. Each must be a known source id; an unknown value is rejected with 400 (not silently ignored). Omit to use every connected source.One of: github, slack, discord, linear, notion, jira, gitlab, bitbucket, azure_devops, figma, confluence, microsoft_outlook, microsoft_teams, sentry, datadog, pagerduty, asana, gmail, buildkite, circleci, vercel |
filtersoptional | SourceFilter | Per-source projects / eventTypes / branches / priorities (AND-combined). Keys must be source ids (unknown keys are rejected with 400); the values are provider-driven and matched leniently – an unmatched value simply returns no events. Fetch GET /handoffs/filters for the set selectable on a project. |
Request
curl "https://www.flowrelay.it/api/v1/handoffs" \
-H "Authorization: Bearer fr_your_api_key" \
-X POST \
-H "Content-Type: application/json" \
-d '{ "project_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "sources": [ "github", "linear" ], "filters": { "github": { "branches": [ "main" ] } } }'Request body
{
"project_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"sources": [
"github",
"linear"
],
"filters": {
"github": {
"branches": [
"main"
]
}
}
}Response
{
"jobId": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"status": "pending"
}| Status | When |
|---|---|
| 202 | Job enqueued. Poll GET /jobs/{jobId} for the result. |
| 400 | project_id is missing or invalid, or the body failed validation (unknown field / source / filter value). The response names the field and lists allowed values. |
| 401 | Missing or invalid API key. |
| 404 | Project not found or not accessible by this key. |
| 429 | Rate limit exceeded (60/min/key). |
List selectable filter options
/handoffs/filtersReturns the real selectable filter values per connected source for a project: resources (repos / channels / boards / Figma files), branches, event types, and priorities. Use these to build a valid SourceFilter instead of guessing. The response also carries a "figma" availability block: Figma can be selected only on projects in the Global processing region, and selecting it attaches visual context (frame renders) at a flat 1-credit surcharge.
Query parameters
| Name | Type | Description |
|---|---|---|
project_idrequired | string | Project UUID (from GET /projects) to resolve filter options for. |
Request
curl "https://www.flowrelay.it/api/v1/handoffs/filters?project_id=PROJECT_ID" \
-H "Authorization: Bearer fr_your_api_key"Response
{
"filters": {
"github": {
"projects": [
{
"id": "acme/payments",
"label": "acme/payments"
}
],
"eventTypes": [
{
"value": "push",
"label": "Push"
}
],
"priorities": [],
"branches": [
{
"value": "main",
"label": "main"
}
]
},
"linear": {
"projects": [
{
"id": "f1e2d3c4-b5a6-7890-1234-567890abcdef",
"label": "Core"
}
],
"eventTypes": [
{
"value": "issue",
"label": "Issue"
}
],
"priorities": [
{
"value": "high",
"label": "High"
}
]
}
},
"figma": {
"selectable": true,
"region": "default",
"scope": "personal",
"canManageResidency": true,
"residencyHref": "/projects/3fa85f64-5717-4562-b3fc-2c963f66afa6#data-residency"
}
}| Status | When |
|---|---|
| 200 | Success |
| 400 | project_id is missing or not a valid UUID. |
| 401 | Missing or invalid API key. |
| 404 | Project not found or not accessible by this key. |
List project insights
/projects/{id}/insightsLists AI insights for a project, newest first. Optionally filter by kind and status.
Path parameters
| Name | Type | Description |
|---|---|---|
idrequired | string | Project UUID (from GET /projects). |
Query parameters
| Name | Type | Description |
|---|---|---|
kindoptional | string | Filter by insight kind.One of: cross_source_correlation, onboarding_brief, architecture_insight |
statusoptional | string | Filter by status.One of: active, archived, allDefault: active |
limitoptional | integer | Maximum rows to return (1–100).Default: 20 |
Request
curl "https://www.flowrelay.it/api/v1/projects/3fa85f64-5717-4562-b3fc-2c963f66afa6/insights" \
-H "Authorization: Bearer fr_your_api_key"Response
{
"insights": [
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"project_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"kind": "architecture_insight",
"title": "Pricing engine trade-offs",
"summary": "Flat per-artifact pricing simplifies billing at the cost of margin variance.",
"data": {
"tradeOffs": [],
"risks": [],
"patterns": [],
"recommendations": []
},
"model_used": "gemini-2.5-flash",
"status": "active",
"related_event_ids": [
"d4e5f6a7-b8c9-0123-def4-23456789013a"
],
"sources": [
"github"
],
"created_at": "2026-06-21T08:00:00Z",
"updated_at": "2026-06-21T08:00:00Z",
"markdown": "# Pricing engine trade-offs\n\n> Flat per-artifact pricing…"
}
]
}| Status | When |
|---|---|
| 200 | Success |
| 400 | The body or a query parameter is invalid: an unknown field, an unknown source, an unsupported filter dimension, or an out-of-range number. The response names the offending field and lists the allowed values. |
| 401 | Missing or invalid API key. |
| 404 | Project not found or not accessible by this key. |
Generate an insight
/projects/{id}/insights/{kind}Asynchronous – returns 202 with a jobId. Poll GET /jobs/{jobId} until the job completes.
Enqueues an insight generation for the project and returns a job id. The accepted body fields depend on kind. Poll GET /jobs/{jobId} for the result.
Path parameters
| Name | Type | Description |
|---|---|---|
idrequired | string | Project UUID (from GET /projects). |
kindrequired | string | Insight kind.One of: correlation, onboarding, architecture |
Body parameters
| Name | Type | Description |
|---|---|---|
lookbackHoursoptional | integer | correlation only – window in hours (1–2160, default 168). Rejected on other kinds. |
lookbackDaysoptional | integer | onboarding / architecture – window in days (1–365, default 30 / 14). Rejected on correlation. |
newMemberRoleoptional | string | onboarding only – role of the person being onboarded. |
focusAreaoptional | string | onboarding only – area to emphasise. |
focusQuestionoptional | string | architecture only – the question to investigate. |
sourcesoptional | string[] | Restrict to these sources. Unknown values are rejected with 400.One of: github, slack, discord, linear, notion, jira, gitlab, bitbucket, azure_devops, figma, confluence, microsoft_outlook, microsoft_teams, sentry, datadog, pagerduty, asana, gmail, buildkite, circleci, vercel |
filtersoptional | SourceFilter | Per-source filters (AND-combined). Keys must be source ids (unknown keys are rejected with 400); values are matched leniently (see GET /handoffs/filters). |
maxEventsoptional | integer | Cap the events fed to the model (1–1000). |
Request
curl "https://www.flowrelay.it/api/v1/projects/3fa85f64-5717-4562-b3fc-2c963f66afa6/insights/architecture" \
-H "Authorization: Bearer fr_your_api_key" \
-X POST \
-H "Content-Type: application/json" \
-d '{ "focusQuestion": "Is the pricing engine coupling billing to providers?", "lookbackDays": 14 }'Request body
{
"focusQuestion": "Is the pricing engine coupling billing to providers?",
"lookbackDays": 14
}Response
{
"jobId": "e7f8a9b0-1c2d-3e4f-5a6b-7c8d9e0f1a2b",
"status": "pending"
}| Status | When |
|---|---|
| 202 | Job enqueued. Poll GET /jobs/{jobId} for the result. |
| 400 | Unsupported insight kind, or the body failed validation (unknown field / source / filter value, or a field that does not apply to this kind). The response names the field and lists allowed values. |
| 401 | Missing or invalid API key. |
| 404 | Project not found or not accessible by this key. |
| 429 | Rate limit exceeded (60/min/key). |
List context events
/eventsLists recent context events, newest first. With project_id it spans the project members and scoped sources; without it returns the key owner personal-stream events.
Query parameters
| Name | Type | Description |
|---|---|---|
sourceoptional | string | Filter by source. Unknown values are rejected with 400.One of: github, slack, discord, linear, notion, jira, gitlab, bitbucket, azure_devops, figma, confluence, microsoft_outlook, microsoft_teams, sentry, datadog, pagerduty, asana, gmail, buildkite, circleci, vercel |
limitoptional | integer | Maximum rows to return (1–200).Default: 50 |
project_idoptional | string | Restrict to a project scope. |
Request
curl "https://www.flowrelay.it/api/v1/events" \
-H "Authorization: Bearer fr_your_api_key"Response
{
"events": [
{
"id": "d4e5f6a7-b8c9-0123-def4-23456789013a",
"user_id": "0a9b8c7d-6e5f-4a3b-2c1d-0e9f8a7b6c5d",
"source": "github",
"event_type": "push",
"title": "Push to acme/payments",
"content": "3 commits on main",
"created_at": "2026-06-20T13:55:00Z"
}
]
}| Status | When |
|---|---|
| 200 | Success |
| 400 | The body or a query parameter is invalid: an unknown field, an unknown source, an unsupported filter dimension, or an out-of-range number. The response names the offending field and lists the allowed values. |
| 401 | Missing or invalid API key. |
| 404 | Project not found or not accessible by this key. |
List integrations
/integrationsLists connected integrations. With project_id it returns the project-scoped resources with health and provider coverage; without it returns the key owner connected sources.
Query parameters
| Name | Type | Description |
|---|---|---|
project_idoptional | string | Return project-scoped integrations instead of personal ones. |
Request
curl "https://www.flowrelay.it/api/v1/integrations" \
-H "Authorization: Bearer fr_your_api_key"Response
{
"integrations": [
{
"source": "github",
"workspace_id": "acme",
"workspace_name": "Acme",
"connected_at": "2026-05-01T09:00:00Z",
"scope": "project",
"resource_type": "repository",
"connection_status": "active",
"providers_connected": 2,
"last_validated_at": "2026-06-20T10:00:00Z"
}
]
}| Status | When |
|---|---|
| 200 | Success |
| 401 | Missing or invalid API key. |
| 404 | Project not found or not accessible by this key. |
List untracked resources
/integrations/untrackedReturns active resources (last 30 days) that produced events but are not yet assigned to any project. The response is a bare array, sorted by most recent activity.
Request
curl "https://www.flowrelay.it/api/v1/integrations/untracked" \
-H "Authorization: Bearer fr_your_api_key"Response
[
{
"source": "slack",
"resource_id": "C0123",
"resource_name": "#incidents",
"resource_type": "channel",
"event_count": 42,
"last_event_at": "2026-06-20T12:00:00Z"
}
]| Status | When |
|---|---|
| 200 | Success |
| 401 | Missing or invalid API key. |
| 500 | Discovery failed for a connected source. |
Poll an async job
/jobs/{jobId}Returns the job record and, once completed, the generated artifact (handoff or insight). The artifact carries a `markdown` field with the canonical rendering – identical to the dashboard copy button. Poll this after any 202 response until status is completed or failed.
Path parameters
| Name | Type | Description |
|---|---|---|
jobIdrequired | string | UUID of the job returned in a prior 202 (POST /handoffs or POST /projects/{id}/insights/{kind}). Project-scoped: only readable if you can access the job's project. |
Request
curl "https://www.flowrelay.it/api/v1/jobs/c3d4e5f6-a7b8-9012-cdef-123456789012" \
-H "Authorization: Bearer fr_your_api_key"Response
{
"job": {
"id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"project_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"kind": "project_handoff",
"status": "completed",
"result_kind": "handoff",
"result_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"error": null,
"error_code": null,
"created_at": "2026-06-20T14:02:00Z",
"updated_at": "2026-06-20T14:03:00Z"
},
"result": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "Checkout refactor handoff",
"markdown": "# Checkout refactor handoff\n\n> Migrated the checkout flow…"
}
}| Status | When |
|---|---|
| 200 | Success |
| 400 | jobId is not a valid UUID. |
| 401 | Missing or invalid API key. |
| 404 | Job not found or not accessible. |
List Discord channels
/discord/channelsLists the text channels in the Discord guild connected to the key owner.
Request
curl "https://www.flowrelay.it/api/v1/discord/channels" \
-H "Authorization: Bearer fr_your_api_key"Response
{
"channels": [
{
"id": "987654",
"name": "general",
"type": 0
}
]
}| Status | When |
|---|---|
| 200 | Success |
| 401 | Missing or invalid API key. |
| 404 | Discord not connected. |
| 400 | No guild associated with this integration. |
Send a Discord message
/discord/sendSends to a channel in the connected guild. Provide exactly one of: content (inline text); handoff_id or insight_id (renders that artifact to Markdown and attaches it as a .md file); or artifact (last_handoff / last_correlation / last_onboarding / last_architecture, with project_id) to send the latest active artifact of that kind. Rendered artifacts use the same Markdown as the dashboard copy button and are always delivered as a .md attachment. The channel must belong to the connected guild (cross-tenant posts are rejected).
Body parameters
| Name | Type | Description |
|---|---|---|
channel_idrequired | string | Target channel id – a Discord snowflake from GET /discord/channels. |
contentoptional | string | Inline message text. Mutually exclusive with handoff_id / insight_id / artifact. |
handoff_idoptional | string | UUID of a handoff (from GET /handoffs). Rendered to Markdown and sent as a .md attachment. |
insight_idoptional | string | UUID of an insight (from GET /projects/{id}/insights). Sent as a .md attachment. |
artifactoptional | string | Send the latest active artifact of a kind. Requires project_id.One of: last_handoff, last_correlation, last_onboarding, last_architecture |
project_idoptional | string | Project UUID. Required only when artifact is set. |
Request
curl "https://www.flowrelay.it/api/v1/discord/send" \
-H "Authorization: Bearer fr_your_api_key" \
-X POST \
-H "Content-Type: application/json" \
-d '{ "channel_id": "987654321098765432", "artifact": "last_handoff", "project_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6" }'Request body
{
"channel_id": "987654321098765432",
"artifact": "last_handoff",
"project_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}Response
{
"ok": true,
"message_id": "111222333444555666"
}| Status | When |
|---|---|
| 200 | Success |
| 400 | channel_id missing, or no content / artifact provided. |
| 401 | Missing or invalid API key. |
| 403 | Channel does not belong to the connected guild. |
| 404 | Discord not connected, or the requested artifact does not exist / is not accessible. |
| 502 | Discord rejected the message. |