Skip to main content

Flows API Guide

A comprehensive guide to setting up and using the external Flows API for third-party integrations.

Table of Contents

  1. API Key Management
  2. Authentication
  3. API Endpoints Overview
  4. Example Queries
  5. Error Handling
  6. Best Practices

Available Scopes

ScopeDescription
flows:readRead access to flow data endpoints
flows:writeWrite access to flow configuration
snmp:readRead access to SNMP metrics
synthetic:readRead access to synthetic monitoring results
sql:readExecute 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"
}
warning

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 CodeErrorDescription
401API key requiredNo API key provided
401Invalid API key formatKey doesn't start with chompy_
401Invalid API keyKey not found in database
401API key is disabledKey has been revoked
401API key has expiredKey past expiration date
403Missing required scopeKey lacks permission for endpoint

API Endpoints Overview

Base URL: https://whiteowl.example.com/api/v1/flows

Endpoints Summary

MethodEndpointDescriptionRequired Scope
GET/Query raw flow recordsflows:read
GET/aggregateAggregated statistics by dimensionflows:read
GET/timeseriesTime-bucketed data for chartsflows:read
GET/top-talkersTop N hosts by trafficflows:read
GET/conversationsTop conversations (src/dst pairs)flows:read
GET/samplersList available flow exportersflows:read
GET/schemaField documentationflows:read

GET /api/v1/flows

Query raw flow records with filtering.

Parameters:

ParameterTypeDescriptionExample
startISO datetimeStart of time range2025-01-24T00:00:00Z
endISO datetimeEnd of time range2025-01-24T23:59:59Z
src_addrstringSource IP address10.1.1.5
dst_addrstringDestination IP address8.8.8.8
either_addrstringMatch src OR dst10.1.1.5
src_cidrstringSource subnet (CIDR)10.0.0.0/8
dst_cidrstringDestination subnet (CIDR)192.168.0.0/16
src_portintegerSource port443
dst_portintegerDestination port80
either_portintegerMatch src OR dst port22
protostringProtocolTCP, UDP, ICMP
in_ifintegerInput interface SNMP index1
out_ifintegerOutput interface SNMP index2
sampler_addressstringFlow exporter IP10.0.0.1
src_countrystringSource country nameUnited States
dst_countrystringDestination country nameGermany
src_as_orgstringSource ASN org (partial match)Google
dst_as_orgstringDestination ASN orgAmazon
appidstringApplication IDHTTPS, DNS, SSH
src_tags_serverstringSource server tags (comma-sep)web01,web02
src_tags_applicationstringSource app tagsnginx,apache
src_tags_ownerstringSource owner tagsteam-a
src_tags_environmentstringSource env tagsproduction
dst_tags_*stringSame as src_tags for destination
fieldsstringComma-separated field listsrc_addr,dst_addr,bytes
sort_bystringSort columnbytes, time_received
sort_orderstringSort directionASC, DESC
limitintegerMax rows (1-10000)1000
offsetintegerPagination offset0

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:

ParameterTypeRequiredDescription
group_bystringYesComma-separated grouping fields
metricstringNobytes (default), packets, flows
limitintegerNoMax results (1-1000, default 100)
sort_orderstringNoDESC (default), ASC
include_namesbooleanNoInclude device/site names (default true)

Plus all filter parameters from /flows.

Valid group_by values:

  • src_addr, dst_addr
  • src_port, dst_port
  • proto
  • in_if, out_if
  • sampler_address
  • src_country_name, dst_country_name
  • src_as_org, dst_as_org
  • appid

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:

ParameterTypeDescription
intervalstringBucket size: 1 second, 1 minute, 5 minute, 15 minute, 1 hour, 1 day
metricstringbytes, packets, flows, bps, pps
group_bystringOptional grouping for multi-series
top_nintegerLimit to top N series (1-20)
include_namesbooleanInclude 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:

ParameterTypeDescription
directionstringsrc, dst, both (default)
metricstringbytes (default), packets
limitintegerMax 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:

ParameterTypeDescription
metricstringbytes (default), packets
limitintegerMax 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

StatusErrorCause
400group_by parameter is requiredMissing required parameter
400Invalid group_byInvalid grouping field
401API key requiredNo authentication provided
401Invalid API keyKey not found or incorrect
401API key has expiredKey past expiration date
403Missing required scope: flows:readKey lacks permission
500Query execution errorClickHouse 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 fields parameter to reduce payload
  • Use aggregation endpoints/aggregate and /timeseries are faster than /flows for 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