Flows API Guide
A comprehensive guide to setting up and using the external Flows API for third-party integrations.
Table of Contents
- API Key Management
- Authentication
- API Endpoints Overview
- Example Queries
- Error Handling
- Best Practices
Available Scopes
| Scope | Description |
|---|---|
flows:read | Read access to flow data endpoints |
flows:write | Write access to flow configuration |
snmp:read | Read access to SNMP metrics |
synthetic:read | Read access to synthetic monitoring results |
sql:read | Execute read-only SQL queries |
* | Full access to all endpoints |
API Key Management
Create an API Key
Request:
curl -X POST https://whiteowl.example.com/api/admin/api-keys \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-jwt-token>" \
-d '{
"name": "External SIEM Integration",
"scopes": ["flows:read"],
"expires_in_days": 365
}'
Response:
{
"success": true,
"data": {
"id": 1,
"name": "External SIEM Integration",
"key_prefix": "chompy_a1b2",
"scopes": ["flows:read"],
"created_at": "2025-01-24T10:30:00.000Z",
"expires_at": "2026-01-24T10:30:00.000Z",
"api_key": "chompy_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4"
},
"message": "Save this key now - it cannot be retrieved again"
}
The api_key value is only shown once. Store it securely immediately.
List All API Keys
curl -X GET https://whiteowl.example.com/api/admin/api-keys \
-H "Authorization: Bearer <your-jwt-token>"
Response:
{
"success": true,
"data": [
{
"id": 1,
"name": "External SIEM Integration",
"key_prefix": "chompy_a1b2",
"scopes": ["flows:read"],
"created_at": "2025-01-24T10:30:00.000Z",
"last_used_at": "2025-01-24T14:22:00.000Z",
"expires_at": "2026-01-24T10:30:00.000Z",
"is_active": true,
"created_by_username": "admin"
}
]
}
Update an API Key
curl -X PATCH https://whiteowl.example.com/api/admin/api-keys/1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-jwt-token>" \
-d '{
"name": "SIEM Integration - Production",
"scopes": ["flows:read", "snmp:read"]
}'
Revoke an API Key
curl -X DELETE https://whiteowl.example.com/api/admin/api-keys/1 \
-H "Authorization: Bearer <your-jwt-token>"
Get API Key Usage Stats
curl -X GET "https://whiteowl.example.com/api/admin/api-keys/1/usage?days=30" \
-H "Authorization: Bearer <your-jwt-token>"
Authentication
All /api/v1/flows endpoints require API key authentication.
Authentication Methods
Option 1: Authorization Header (Recommended)
curl -H "Authorization: Bearer chompy_your_api_key_here" \
https://whiteowl.example.com/api/v1/flows
Option 2: X-API-Key Header
curl -H "X-API-Key: chompy_your_api_key_here" \
https://whiteowl.example.com/api/v1/flows
Option 3: Query Parameter (Not recommended for production)
curl "https://whiteowl.example.com/api/v1/flows?api_key=chompy_your_api_key_here"
Authentication Errors
| Status Code | Error | Description |
|---|---|---|
| 401 | API key required | No API key provided |
| 401 | Invalid API key format | Key doesn't start with chompy_ |
| 401 | Invalid API key | Key not found in database |
| 401 | API key is disabled | Key has been revoked |
| 401 | API key has expired | Key past expiration date |
| 403 | Missing required scope | Key lacks permission for endpoint |
API Endpoints Overview
Base URL: https://whiteowl.example.com/api/v1/flows
Endpoints Summary
| Method | Endpoint | Description | Required Scope |
|---|---|---|---|
| GET | / | Query raw flow records | flows:read |
| GET | /aggregate | Aggregated statistics by dimension | flows:read |
| GET | /timeseries | Time-bucketed data for charts | flows:read |
| GET | /top-talkers | Top N hosts by traffic | flows:read |
| GET | /conversations | Top conversations (src/dst pairs) | flows:read |
| GET | /samplers | List available flow exporters | flows:read |
| GET | /schema | Field documentation | flows:read |
GET /api/v1/flows
Query raw flow records with filtering.
Parameters:
| Parameter | Type | Description | Example |
|---|---|---|---|
start | ISO datetime | Start of time range | 2025-01-24T00:00:00Z |
end | ISO datetime | End of time range | 2025-01-24T23:59:59Z |
src_addr | string | Source IP address | 10.1.1.5 |
dst_addr | string | Destination IP address | 8.8.8.8 |
either_addr | string | Match src OR dst | 10.1.1.5 |
src_cidr | string | Source subnet (CIDR) | 10.0.0.0/8 |
dst_cidr | string | Destination subnet (CIDR) | 192.168.0.0/16 |
src_port | integer | Source port | 443 |
dst_port | integer | Destination port | 80 |
either_port | integer | Match src OR dst port | 22 |
proto | string | Protocol | TCP, UDP, ICMP |
in_if | integer | Input interface SNMP index | 1 |
out_if | integer | Output interface SNMP index | 2 |
sampler_address | string | Flow exporter IP | 10.0.0.1 |
src_country | string | Source country name | United States |
dst_country | string | Destination country name | Germany |
src_as_org | string | Source ASN org (partial match) | Google |
dst_as_org | string | Destination ASN org | Amazon |
appid | string | Application ID | HTTPS, DNS, SSH |
src_tags_server | string | Source server tags (comma-sep) | web01,web02 |
src_tags_application | string | Source app tags | nginx,apache |
src_tags_owner | string | Source owner tags | team-a |
src_tags_environment | string | Source env tags | production |
dst_tags_* | string | Same as src_tags for destination | |
fields | string | Comma-separated field list | src_addr,dst_addr,bytes |
sort_by | string | Sort column | bytes, time_received |
sort_order | string | Sort direction | ASC, DESC |
limit | integer | Max rows (1-10000) | 1000 |
offset | integer | Pagination offset | 0 |
Response:
{
"success": true,
"data": [
{
"time_received": "2025-01-24T10:30:00.000Z",
"src_addr": "10.1.1.5",
"dst_addr": "8.8.8.8",
"src_port": 54321,
"dst_port": 53,
"proto": "UDP",
"bytes": 64,
"packets": 1,
"sampling_rate": 1,
"appid": "DNS",
"src_country_name": "United States",
"dst_country_name": "United States"
}
],
"meta": {
"count": 1,
"limit": 1000,
"offset": 0
}
}
GET /api/v1/flows/aggregate
Aggregated statistics grouped by one or more dimensions.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
group_by | string | Yes | Comma-separated grouping fields |
metric | string | No | bytes (default), packets, flows |
limit | integer | No | Max results (1-1000, default 100) |
sort_order | string | No | DESC (default), ASC |
include_names | boolean | No | Include device/site names (default true) |
Plus all filter parameters from /flows.
Valid group_by values:
src_addr,dst_addrsrc_port,dst_portprotoin_if,out_ifsampler_addresssrc_country_name,dst_country_namesrc_as_org,dst_as_orgappid
Response:
{
"success": true,
"data": [
{
"src_addr": "10.1.1.5",
"value": 1234567890,
"flow_count": 5432
}
],
"meta": {
"group_by": ["src_addr"],
"metric": "bytes",
"count": 100
}
}
GET /api/v1/flows/timeseries
Time-bucketed data for charts and graphs.
Parameters:
| Parameter | Type | Description |
|---|---|---|
interval | string | Bucket size: 1 second, 1 minute, 5 minute, 15 minute, 1 hour, 1 day |
metric | string | bytes, packets, flows, bps, pps |
group_by | string | Optional grouping for multi-series |
top_n | integer | Limit to top N series (1-20) |
include_names | boolean | Include device/site names |
Plus all filter parameters from /flows.
Response:
{
"success": true,
"data": [
{
"timestamp": "2025-01-24T10:00:00.000Z",
"value": 1234567890,
"flow_count": 5432
},
{
"timestamp": "2025-01-24T10:01:00.000Z",
"value": 1345678901,
"flow_count": 5678
}
],
"meta": {
"interval": "1 minute",
"metric": "bytes",
"group_by": null,
"points": 60
}
}
GET /api/v1/flows/top-talkers
Convenience endpoint for finding top traffic sources/destinations.
Parameters:
| Parameter | Type | Description |
|---|---|---|
direction | string | src, dst, both (default) |
metric | string | bytes (default), packets |
limit | integer | Max results (1-100, default 10) |
Plus all filter parameters from /flows.
Response:
{
"success": true,
"data": [
{
"ip": "10.1.1.5",
"value": 9876543210,
"flows": 12345
}
],
"meta": {
"direction": "both",
"metric": "bytes",
"count": 10
}
}
GET /api/v1/flows/conversations
Top conversations showing source/destination pairs.
Parameters:
| Parameter | Type | Description |
|---|---|---|
metric | string | bytes (default), packets |
limit | integer | Max results (1-100, default 20) |
Plus all filter parameters from /flows.
Response:
{
"success": true,
"data": [
{
"src_addr": "10.1.1.5",
"dst_addr": "8.8.8.8",
"dst_port": 443,
"proto": "TCP",
"appid": "HTTPS",
"value": 5678901234,
"flows": 9876
}
],
"meta": {
"metric": "bytes",
"count": 20
}
}
GET /api/v1/flows/samplers
List available flow exporters (routers, switches, firewalls).
Response:
{
"success": true,
"data": [
{
"sampler_address": "10.0.0.1",
"display_name": "core-rtr-01",
"type": "router",
"site_name": "DC1 - Primary"
}
]
}
GET /api/v1/flows/schema
Returns field documentation and endpoint reference.
Response:
{
"success": true,
"table": "flows_all",
"fields": {
"src_addr": {
"type": "String",
"description": "Source IP address",
"filterable": true
}
},
"endpoints": {
"GET /api/v1/flows": "Query raw flow records"
}
}
Example Queries
Set your API key variable for convenience:
export CHOMPY_API_KEY="chompy_your_api_key_here"
export CHOMPY_URL="https://whiteowl.example.com"
Basic Flow Queries
Get flows from the last hour:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows"
Get flows for specific time range:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?start=2025-01-24T00:00:00Z&end=2025-01-24T12:00:00Z"
Get flows for a specific IP:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?either_addr=10.1.1.5&limit=100"
Get flows for a subnet:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?src_cidr=10.0.0.0/8&limit=500"
Get DNS traffic only:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?dst_port=53&proto=UDP"
Get specific fields only:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?fields=src_addr,dst_addr,bytes,packets,appid"
Get flows sorted by bytes descending:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?sort_by=bytes&sort_order=DESC&limit=100"
Get flows from a specific exporter:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?sampler_address=10.0.0.1"
Get flows tagged as production web servers:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?src_tags_environment=production&src_tags_application=web"
Aggregation Queries
Top source IPs by bytes:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/aggregate?group_by=src_addr&metric=bytes&limit=20"
Top destination ports:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/aggregate?group_by=dst_port&metric=bytes&limit=20"
Traffic by application:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/aggregate?group_by=appid&metric=bytes"
Traffic by protocol:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/aggregate?group_by=proto&metric=bytes"
Traffic by destination country:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/aggregate?group_by=dst_country_name&metric=bytes&limit=50"
Traffic by ASN organization:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/aggregate?group_by=dst_as_org&metric=bytes&limit=30"
Multi-dimension grouping (source IP + destination port):
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/aggregate?group_by=src_addr,dst_port&metric=bytes&limit=50"
Traffic by flow exporter with device names:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/aggregate?group_by=sampler_address&include_names=true"
Filter + aggregate (top talkers to Google):
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/aggregate?group_by=src_addr&dst_as_org=Google&metric=bytes"
Timeseries Queries
Total traffic over time (1-minute buckets):
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/timeseries?interval=1%20minute&metric=bytes"
Traffic over time with custom range:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/timeseries?start=2025-01-24T00:00:00Z&end=2025-01-24T23:59:59Z&interval=5%20minute"
Packets per second over time:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/timeseries?metric=pps&interval=1%20minute"
Traffic by protocol over time (multi-series):
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/timeseries?group_by=proto&interval=5%20minute"
Top 5 applications over time:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/timeseries?group_by=appid&top_n=5&interval=5%20minute"
Traffic for specific IP over time:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/timeseries?either_addr=10.1.1.5&interval=1%20minute"
Hourly traffic for last week:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/timeseries?start=$(date -d '7 days ago' -Iseconds)&interval=1%20hour"
Top Talkers Queries
Top 10 hosts (combined src + dst):
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/top-talkers?limit=10"
Top 20 source IPs:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/top-talkers?direction=src&limit=20"
Top destination IPs by packets:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/top-talkers?direction=dst&metric=packets&limit=20"
Top talkers within a subnet:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/top-talkers?src_cidr=10.1.0.0/16&limit=10"
Top talkers for HTTP/HTTPS:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/top-talkers?appid=HTTPS&limit=10"
Conversation Queries
Top 20 conversations:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/conversations?limit=20"
Top conversations by packets:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/conversations?metric=packets&limit=20"
Conversations for a specific host:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/conversations?either_addr=10.1.1.5&limit=50"
Conversations to external destinations:
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/conversations?src_cidr=10.0.0.0/8&limit=50"
Integration Examples
Export to CSV (using jq):
curl -s -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?limit=1000&fields=time_received,src_addr,dst_addr,bytes" | \
jq -r '.data[] | [.time_received, .src_addr, .dst_addr, .bytes] | @csv' > flows.csv
Continuous polling (every 60 seconds):
while true; do
curl -s -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/top-talkers?limit=5" | jq '.data'
sleep 60
done
Alerting script (high traffic detection):
#!/bin/bash
THRESHOLD=10000000000 # 10 GB
BYTES=$(curl -s -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows/aggregate?group_by=src_addr&limit=1" | \
jq -r '.data[0].value // 0')
if [ "$BYTES" -gt "$THRESHOLD" ]; then
echo "ALERT: Top talker exceeded threshold: $BYTES bytes"
fi
Python example:
import requests
API_KEY = "chompy_your_api_key_here"
BASE_URL = "https://whiteowl.example.com/api/v1/flows"
headers = {"Authorization": f"Bearer {API_KEY}"}
# Get top talkers
response = requests.get(
f"{BASE_URL}/top-talkers",
headers=headers,
params={"limit": 10, "metric": "bytes"}
)
data = response.json()
for host in data["data"]:
print(f"{host['ip']}: {host['value']:,} bytes")
Error Handling
Standard Error Response Format
{
"success": false,
"error": "Error message here"
}
Common Errors
| Status | Error | Cause |
|---|---|---|
| 400 | group_by parameter is required | Missing required parameter |
| 400 | Invalid group_by | Invalid grouping field |
| 401 | API key required | No authentication provided |
| 401 | Invalid API key | Key not found or incorrect |
| 401 | API key has expired | Key past expiration date |
| 403 | Missing required scope: flows:read | Key lacks permission |
| 500 | Query execution error | ClickHouse query failed |
Handling Errors in Code
response = requests.get(url, headers=headers)
if response.status_code == 401:
print("Authentication failed - check API key")
elif response.status_code == 403:
print("Permission denied - check scopes")
elif response.status_code >= 500:
print("Server error - retry later")
elif response.status_code == 200:
data = response.json()
if data.get("success"):
process_data(data["data"])
else:
print(f"API error: {data.get('error')}")
Best Practices
Query Optimization
- Always specify a time range — Queries without time bounds scan all data
- Use the narrowest time range possible — Smaller ranges = faster queries
- Limit results — Don't request 10,000 rows if you only need 100
- Select only needed fields — Use
fieldsparameter to reduce payload - Use aggregation endpoints —
/aggregateand/timeseriesare faster than/flowsfor analytics
Rate Limiting
- The API has a 30-second query timeout
- Limit is 10,000 rows per request
- For large exports, use pagination with offset
- Consider caching responses for dashboards
Security
- Never expose API keys in client-side code
- Use HTTPS only
- Rotate keys periodically (set
expires_in_days) - Use minimum required scopes
- Monitor key usage via
/api/admin/api-keys/:id/usage
Pagination Example
# Page 1
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?limit=1000&offset=0"
# Page 2
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?limit=1000&offset=1000"
# Page 3
curl -H "Authorization: Bearer $CHOMPY_API_KEY" \
"$CHOMPY_URL/api/v1/flows?limit=1000&offset=2000"
Quick Reference Card
# Authenticate
-H "Authorization: Bearer chompy_xxx"
# Endpoints
GET /api/v1/flows # Raw flows
GET /api/v1/flows/aggregate # Grouped stats (requires group_by)
GET /api/v1/flows/timeseries # Time-bucketed data
GET /api/v1/flows/top-talkers # Top hosts
GET /api/v1/flows/conversations # Top src/dst pairs
GET /api/v1/flows/samplers # List exporters
GET /api/v1/flows/schema # Field docs
# Common filters
?start=2025-01-24T00:00:00Z # Time range start
?end=2025-01-24T23:59:59Z # Time range end
?src_addr=10.1.1.5 # Source IP
?dst_addr=8.8.8.8 # Destination IP
?either_addr=10.1.1.5 # Either src or dst
?src_cidr=10.0.0.0/8 # Source subnet
?proto=TCP # Protocol
?appid=HTTPS # Application
?limit=100 # Max results