REST API v1 · Developers · API reference
Flows API reference
All 3 Flows endpoints of the BotGG REST API v1: scopes, parameters, fields, errors and ready-to-run curl, JavaScript and Python examples.
Developer docs
On this page
Endpoints
Paths are relative to https://console.botgg.app/api/v1. Send your API key as Authorization: Bearer botgg_…; IDs are strings.
| Endpoint | Scope | Description |
|---|---|---|
GET/guilds/{guildId}/flows | flows:read | List flows |
GET/guilds/{guildId}/flows/runs/{executionId} | flows:read | Get a flow run |
POST/guilds/{guildId}/flows/{workflowId}/runs | flows:run | Run a flow |
Besides its own errors below, every endpoint can return these common ones:
List flows
GET/guilds/{guildId}/flows
Needs this feature enabled on the server: Flows
| Name | In | Type | Required | Description |
|---|---|---|---|---|
guildId | path | string | Yes | Your server’s ID · Discord ID (string) |
Response
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object | Yes | |
items[].id | integer | Yes | |
items[].name | string | Yes | |
items[].description | string | null | Yes | |
items[].enabled | boolean | Yes | |
items[].triggerType | string | null | Yes | e.g. trigger.manual, trigger.webhook, trigger.discord.messageCreated |
items[].runnable | boolean | Yes | Can be run with POST …/runs (enabled + Manual or Webhook trigger) |
items[].updatedAt | string | null | Yes |
{
"items": [
{
"id": 98765,
"name": "Example",
"description": "example",
"enabled": true,
"triggerType": "example",
"runnable": true,
"updatedAt": "2026-10-07T12:00:00.000Z"
}
]
}Examples
curl -s "https://console.botgg.app/api/v1/guilds/123456789012345678/flows" \
-H "Authorization: Bearer $BOTGG_API_KEY"// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/flows', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);import os
import requests
res = requests.get(
"https://console.botgg.app/api/v1/guilds/123456789012345678/flows",
headers={
"Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
},
timeout=10,
)
data = res.json()
if not res.ok:
raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)Errors
| HTTP | Codes |
|---|---|
| 409 | FEATURE_DISABLED |
| 503 | SERVICE_UNAVAILABLE |
Get a flow run
GET/guilds/{guildId}/flows/runs/{executionId}
Status of a run (any run of this server’s flows); output is the last node’s output once it finished.
Needs this feature enabled on the server: Flows
| Name | In | Type | Required | Description |
|---|---|---|---|---|
guildId | path | string | Yes | Your server’s ID · Discord ID (string) |
executionId | path | string | Yes |
Response
| Field | Type | Required | Description |
|---|---|---|---|
executionId | integer | Yes | |
workflowId | integer | Yes | |
status | string | Yes | running | success | error | stopped | cancelled |
output | any | null | Yes | The last node’s output (finished runs only) |
error | string | null | Yes | |
startedAt | string | null | Yes | |
finishedAt | string | null | Yes | |
durationMs | integer | null | Yes |
{
"executionId": 98765,
"workflowId": 98765,
"status": "example",
"output": null,
"error": "example",
"startedAt": "2026-10-07T12:00:00.000Z",
"finishedAt": "2026-10-07T12:00:00.000Z",
"durationMs": 10
}Examples
curl -s "https://console.botgg.app/api/v1/guilds/123456789012345678/flows/runs/234567890123456789" \
-H "Authorization: Bearer $BOTGG_API_KEY"// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/flows/runs/234567890123456789', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);import os
import requests
res = requests.get(
"https://console.botgg.app/api/v1/guilds/123456789012345678/flows/runs/234567890123456789",
headers={
"Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
},
timeout=10,
)
data = res.json()
if not res.ok:
raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)Errors
| HTTP | Codes |
|---|---|
| 404 | FLOW_EXECUTION_NOT_FOUND |
| 409 | FEATURE_DISABLED |
| 503 | SERVICE_UNAVAILABLE |
Run a flow
POST/guilds/{guildId}/flows/{workflowId}/runs
Only enabled flows with a Manual or Webhook trigger. A Webhook flow runs as if its webhook URL was called with input as the JSON body. Counts toward the plan’s daily runs. 202 { executionId, status: "running" }, or with wait: true 200 with the final status and output (202 when it is still running after the timeout — poll GET …/flows/runs/{executionId}).
Needs this feature enabled on the server: Flows
| Name | In | Type | Required | Description |
|---|---|---|---|---|
guildId | path | string | Yes | Your server’s ID · Discord ID (string) |
workflowId | path | string | Yes | |
Idempotency-Key | header | string | No | Optional. Send a unique value (a UUID) and reuse it when you retry: the change happens only once. How it works |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
input | any | No | Trigger data (any JSON): $trigger for Manual flows, $trigger.body for Webhook flows |
wait | boolean | No | Wait for the run to finish (default false → 202 right after it started) |
timeoutSeconds | integer | No | Longest wait; default = the flow timeout + 5 s 1–120 |
Response
| Field | Type | Required | Description |
|---|---|---|---|
executionId | integer | Yes | |
workflowId | integer | Yes | |
status | string | Yes | running | success | error | stopped | cancelled |
output | any | null | Yes | The last node’s output (finished runs only) |
error | string | null | Yes | |
startedAt | string | null | Yes | |
finishedAt | string | null | Yes | |
durationMs | integer | null | Yes |
{
"executionId": 98765,
"workflowId": 98765,
"status": "example",
"output": null,
"error": "example",
"startedAt": "2026-10-07T12:00:00.000Z",
"finishedAt": "2026-10-07T12:00:00.000Z",
"durationMs": 10
}Examples
curl -s -X POST "https://console.botgg.app/api/v1/guilds/123456789012345678/flows/234567890123456789/runs" \
-H "Authorization: Bearer $BOTGG_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"input":null,"wait":true,"timeoutSeconds":3600}'// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/flows/234567890123456789/runs', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(), // reuse it when you retry this request
},
body: JSON.stringify({
input: null,
wait: true,
timeoutSeconds: 3600,
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);import os, uuid
import requests
res = requests.post(
"https://console.botgg.app/api/v1/guilds/123456789012345678/flows/234567890123456789/runs",
headers={
"Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()), # reuse it when you retry this request
},
json={
"input": None,
"wait": True,
"timeoutSeconds": 3600,
},
timeout=10,
)
data = res.json()
if not res.ok:
raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)Errors
| HTTP | Codes |
|---|---|
| 400 | INVALID_JSON |
| 402 | PLAN_LIMIT |
| 404 | FLOW_NOT_FOUND |
| 409 | FEATURE_DISABLED, FLOW_NOT_RUNNABLE, FLOW_DISABLED |
| 413 | PAYLOAD_TOO_LARGE |
| 415 | UNSUPPORTED_MEDIA_TYPE |
| 422 | IDEMPOTENCY_KEY_REUSED |
| 503 | SERVICE_UNAVAILABLE |