Gateway ARQ API

Complete API Reference v1.5.0 - 28 Endpoints

← Back to Dashboard | Base URL: http://localhost:8000

Introduction

Gateway ARQ is a real-time data ingestion system for WebCom TLC and Asterisk PBX. This API provides access to call data, system metrics, and real-time updates via WebSocket.

🔐 Authentication

⚠️ REQUIRED - All endpoints now require API key authentication

All API requests MUST include a valid API key in the X-API-Key header.

For WebSocket connections, use the ?api_key=xxx query parameter.

Example Request

curl -H "X-API-Key: sk_live_arq_2024_production_key_change_me" \
  http://localhost:8000/api/webcom/lines

Configure API Keys

Set keys in .env file:

API_KEY_1=sk_live_arq_2024_production_key_change_me
API_KEY_2=sk_live_arq_2024_dashboard_key_change_me
API_KEY_3=sk_live_arq_2024_monitoring_key_change_me

Authentication Errors

Missing or invalid API key returns 401 Unauthorized:

{
  "detail": "Missing X-API-Key header. Authentication required."
}

API Endpoints

GET /health

Health check endpoint - returns service status

Response

{
  "status": "healthy"
}

Examples

cURL
curl -X GET http://localhost:8000/health
JavaScript (Fetch)
fetch('http://localhost:8000/health')
  .then(res => res.json())
  .then(data => console.log(data));
Node.js (axios)
const axios = require('axios');

axios.get('http://localhost:8000/health')
  .then(response => console.log(response.data));
GET /version

Get API version and build information

Response

{
  "title": "Gateway ARQ",
  "version": "1.0.0",
  "description": "Real-time data ingestion system",
  "copyright": "© 2025 sanvil"
}

Examples

cURL
curl -X GET http://localhost:8000/version
JavaScript (Fetch)
fetch('http://localhost:8000/version')
  .then(res => res.json())
  .then(data => console.log(`Version: ${data.version}`));
GET /metrics

Get system metrics (workers, calls, costs)

Response

{
  "workers": {
    "webcom": { "status": "healthy", "last_run": "2025-11-15T13:30:00Z" },
    "asterisk": { "status": "healthy", "last_run": "2025-11-15T13:30:00Z" }
  },
  "calls": {
    "webcom_active": 3,
    "asterisk_active": 1,
    "total_today": 245
  },
  "webcom": {
    "line_ids": ["Sickprod90TLW", "Sickprod80FW", ...]
  },
  "costs": {
    "today": 45.50
  },
  "timestamp": "2025-11-15T13:30:00Z"
}

Examples

cURL
curl -X GET http://localhost:8000/metrics
Node.js (async/await)
const axios = require('axios');

async function getMetrics() {
  const { data } = await axios.get('http://localhost:8000/metrics');
  console.log(`Active calls: ${data.calls.webcom_active}`);
  console.log(`Cost today: €${data.costs.today}`);
}

getMetrics();
GET /api/webcom/lines

Get all WebCom line IDs and details

Response

{
  "count": 59,
  "lines": [
    {
      "lineId": "Sickprod28GN",
      "number": "800026028",
      "lineType": "Green",
      "group": "Green",
      "relations": ["Read", "Write", "Owner"],
      "name": null
    },
    ...
  ]
}

Examples

cURL
curl -X GET http://localhost:8000/api/webcom/lines
JavaScript (Fetch)
fetch('http://localhost:8000/api/webcom/lines')
  .then(res => res.json())
  .then(data => {
    console.log(`Total lines: ${data.count}`);
    data.lines.forEach(line => {
      console.log(`${line.number}: ${line.lineType}`);
    });
  });
Node.js (axios)
const axios = require('axios');

axios.get('http://localhost:8000/api/webcom/lines')
  .then(response => {
    console.log(`Total lines: ${response.data.count}`);
    console.log('Lines:', response.data.lines);
  });
GET /api/webcom/calls

Get active WebCom calls

Query Parameters

  • limit (optional) - Max number of calls to return (default: 50)

Response

{
  "count": 5,
  "calls": [
    {
      "id": "691880b00a5a19c9db354ac8",
      "lineID": "Sickprod90TLW",
      "state": "Pending",
      "direction": "Entering",
      "caller": "331234567",
      "called": "899748963",
      "callerOperator": "TIM",
      "cost": 0.15,
      "lineNumber": "899748963",
      "timestamp": 1731671400
    },
    ...
  ]
}

Examples

cURL
curl -X GET "http://localhost:8000/api/webcom/calls?limit=10"
JavaScript (Fetch)
fetch('http://localhost:8000/api/webcom/calls?limit=10')
  .then(res => res.json())
  .then(data => {
    console.log(`Active calls: ${data.count}`);
    data.calls.forEach(call => {
      console.log(`${call.id}: ${call.state} - ${call.caller} → ${call.called}`);
    });
  });
Node.js (async/await)
const axios = require('axios');

async function getCalls() {
  const { data } = await axios.get('http://localhost:8000/api/webcom/calls', {
    params: { limit: 10 }
  });

  console.log(`Found ${data.count} calls`);
  return data.calls;
}

getCalls();
GET /api/webcom/calls/{call_id}

Get specific WebCom call by ID

Path Parameters

  • call_id - Call identifier (e.g., "691880b00a5a19c9db354ac8")

Response (Success)

{
  "id": "691880b00a5a19c9db354ac8",
  "lineID": "Sickprod90TLW",
  "state": "Ok",
  "direction": "Entering",
  "caller": "331234567",
  "called": "899748963",
  "callerOperator": "TIM",
  "cost": 0.15,
  "duration": 45,
  "timestamp": 1731671400
}

Response (Not Found)

{
  "error": "Call not found"
}

Examples

cURL
curl -X GET http://localhost:8000/api/webcom/calls/691880b00a5a19c9db354ac8
JavaScript (Fetch)
const callId = '691880b00a5a19c9db354ac8';

fetch(`http://localhost:8000/api/webcom/calls/${callId}`)
  .then(res => res.json())
  .then(call => {
    if (call.error) {
      console.error('Call not found');
    } else {
      console.log(`Call ${call.id}: ${call.state}`);
      console.log(`Duration: ${call.duration}s, Cost: €${call.cost}`);
    }
  });
Node.js (axios)
const axios = require('axios');

async function getCall(callId) {
  try {
    const { data } = await axios.get(
      `http://localhost:8000/api/webcom/calls/${callId}`
    );
    return data;
  } catch (error) {
    console.error('Error fetching call:', error.message);
  }
}

getCall('691880b00a5a19c9db354ac8');
GET /api/webcom/rebates

Get WebCom rebates for a specific month

Query Parameters

  • month (optional) - Month in YYYY-MM format (default: current month)

Response

{
  "month": "2025-11",
  "count": 5,
  "updated_at": "1731671400",
  "rebates": [
    {
      "type": "Vas",
      "operator": "TIMG",
      "cost": 2092.68,
      "counter": 923
    },
    {
      "type": "Green",
      "operator": "WIND",
      "cost": -0.07,
      "counter": 8
    },
    ...
  ]
}

Examples

cURL (Current month)
curl -X GET http://localhost:8000/api/webcom/rebates
cURL (Specific month)
curl -X GET "http://localhost:8000/api/webcom/rebates?month=2025-10"
JavaScript (Fetch)
fetch('http://localhost:8000/api/webcom/rebates?month=2025-11')
  .then(res => res.json())
  .then(data => {
    console.log(`Rebates for ${data.month}`);

    let totalCost = 0;
    data.rebates.forEach(rebate => {
      console.log(`${rebate.operator} (${rebate.type}): €${rebate.cost}`);
      totalCost += rebate.cost;
    });

    console.log(`Total: €${totalCost.toFixed(2)}`);
  });
Node.js (axios)
const axios = require('axios');

async function getRebates(month = null) {
  const params = month ? { month } : {};

  const { data } = await axios.get(
    'http://localhost:8000/api/webcom/rebates',
    { params }
  );

  console.log(`Rebates for ${data.month}: ${data.count} entries`);
  return data.rebates;
}

// Get current month
getRebates();

// Get specific month
getRebates('2025-10');
GET /

Root endpoint - returns API information and available endpoints

Response

{
  "message": "Gateway ARQ API",
  "version": "1.0.0",
  "status": "healthy",
  "endpoints": {
    "health": "/health",
    "version": "/version",
    "metrics": "/metrics",
    "webcom": "/api/webcom/*",
    "webtv": "/api/webtv/*",
    "websocket": "/ws"
  }
}

Examples

cURL
curl -H "X-API-Key: sk_live_arq_2024_production_key_change_me" \
  http://localhost:8000/
GET 📺 /api/webtv/viewers

Get current WebTV CDN viewers count (real-time)

Response

{
  "viewers": 23,
  "timestamp": "2025-11-15T18:57:08.177349+00:00"
}

Response Fields

  • viewers - Current number of viewers (integer)
  • timestamp - Timestamp of data fetch (ISO 8601)

Update Frequency

Data is updated every 5 seconds by the WebTV worker.

Examples

cURL
curl -H "X-API-Key: sk_live_arq_2024_production_key_change_me" \
  http://localhost:8000/api/webtv/viewers
JavaScript (Fetch)
const response = await fetch('http://localhost:8000/api/webtv/viewers', {
  headers: { 'X-API-Key': 'sk_live_arq_2024_production_key_change_me' }
});
const data = await response.json();
console.log(`Current viewers: ${data.viewers}`);
Python
import requests

headers = {'X-API-Key': 'sk_live_arq_2024_production_key_change_me'}
response = requests.get('http://localhost:8000/api/webtv/viewers', headers=headers)
data = response.json()
print(f"Current viewers: {data['viewers']}")
GET 📺 /api/webtv/stats

Get WebTV statistics (today + yesterday + comparison)

Response

{
  "today": {
    "date": "2025-11-15",
    "min": 5,
    "max": 23,
    "avg": 10,
    "current": 23,
    "hourly": [0, 0, 0, ..., 12, 23, 0, ...]  // 24 values
  },
  "yesterday": {
    "date": "2025-11-14",
    "min": 0,
    "max": 0,
    "avg": 0,
    "hourly": [0, 0, 0, ...]
  },
  "comparison": {
    "min_change_pct": 0.0,
    "max_change_pct": 0.0,
    "avg_change_pct": 0.0
  },
  "timestamp": "2025-11-15T18:57:08.381807+00:00"
}

Response Fields

  • today.date - Current date (YYYY-MM-DD)
  • today.min - Minimum viewers today
  • today.max - Maximum viewers today
  • today.avg - Average viewers today (rounded)
  • today.current - Current viewers
  • today.hourly - Array of 24 hourly samples
  • yesterday.* - Same structure for yesterday
  • comparison.*_change_pct - Percentage change vs yesterday

Data Retention

Hourly samples and daily stats are stored for 7 days.

Examples

cURL
curl -H "X-API-Key: sk_live_arq_2024_production_key_change_me" \
  http://localhost:8000/api/webtv/stats
JavaScript (Chart.js Integration)
const response = await fetch('http://localhost:8000/api/webtv/stats', {
  headers: { 'X-API-Key': 'sk_live_arq_2024_production_key_change_me' }
});
const data = await response.json();

// Create Chart.js graph
const chart = new Chart(ctx, {
  type: 'line',
  data: {
    labels: Array.from({length: 24}, (_, i) => `${i}:00`),
    datasets: [{
      label: 'Today',
      data: data.today.hourly,
      borderColor: 'rgb(59, 130, 246)'
    }]
  }
});

🎰 OCR Lotto Endpoints

POST /api/ocr/process

Process image with OCR and extract Italian Lotto numbers. Includes AI validation for error correction.

Request Body

{
  "image_base64": "...",           // Base64 encoded JPEG/PNG
  "data_estrazione": "2025-12-02", // Extraction date
  "ai_validation": true,           // Enable AI error correction
  "send_telegram": false,          // Send result to Telegram
  "auto_upload": false             // Upload to lotto.sanvil.net
}

Response

{
  "success": true,
  "wheels": {
    "BARI": ["50", "29", "12", "47", "73"],
    "CAGLIARI": ["04", "79", "80", "66", "84"],
    ...
    "NAZIONALE": ["16", "25", "48", "81", "88"]
  },
  "wheels_count": 11,
  "confidence": 100.0,
  "ai_validation": { "corrections": 5, "confidence": 98 },
  "telegram": { "success": true },
  "upload": { "success": true, "wheels_uploaded": 11 }
}
GET /api/ocr/autobot/status

Get AutoBOT worker status (scheduled OCR extraction at 20:01)

Response

{
  "status": "idle",  // idle|capturing|ocr|validating|completed|error
  "wheels_completed": 0,
  "total_wheels": 11,
  "last_run": "2025-12-02T20:01:00Z"
}
POST /api/ocr/autobot/start

Manually start AutoBOT OCR extraction from live stream

Request Body

{
  "ai_validation": true,
  "telegram_notify": true,
  "auto_upload": false
}
POST /api/ocr/telegram/send

Send OCR results to configured Telegram chat

Request Body

{
  "message": "ESTRAZIONE LOTTO...",
  "parse_mode": "HTML",
  "image_base64": "..."  // Optional: attach image
}
POST /api/ocr/lotto/upload

Upload extracted numbers to lotto.sanvil.net

Request Body

{
  "wheels": {
    "BARI": ["50", "29", "12", "47", "73"],
    ...
  },
  "data_estrazione": "2025-12-02"
}

Response

{
  "success": true,
  "wheels_uploaded": 11,
  "results": [
    { "wheel": "BARI", "success": true },
    ...
  ]
}
WS /ws

WebSocket endpoint for real-time call updates

Connection URL

ws://localhost:8000/ws

Event Types

  • system - Connection established
  • heartbeat - Keep-alive ping (every 30s)
  • call_event_realtime - WebCom call update
  • rebates_updated - Rebates data updated
  • asterisk_event - Asterisk AMI event (Newchannel, Hangup, etc.)

Call Event Example

{
  "id": "691880b00a5a19c9db354ac8",
  "lineID": "Sickprod90TLW",
  "state": "Pending",
  "direction": "Entering",
  "caller": "331234567",
  "called": "899748963",
  "callerOperator": "TIM",
  "cost": 0.15,
  "lineNumber": "899748963"
}

Examples

JavaScript (Browser)
const ws = new WebSocket('ws://localhost:8000/ws');

ws.onopen = () => {
  console.log('Connected to Gateway ARQ');
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Event received:', data);

  if (data.id && data.state) {
    console.log(`Call ${data.id}: ${data.state}`);
  }
};

ws.onerror = (error) => {
  console.error('WebSocket error:', error);
};

ws.onclose = () => {
  console.log('Disconnected');
};
Node.js (ws library)
const WebSocket = require('ws');

const ws = new WebSocket('ws://localhost:8000/ws');

ws.on('open', () => {
  console.log('Connected to Gateway ARQ');
});

ws.on('message', (data) => {
  const event = JSON.parse(data);

  if (event.id && event.state) {
    console.log(`Call ${event.id}: ${event.state}`);
    console.log(`  Caller: ${event.caller}`);
    console.log(`  Cost: €${event.cost}`);
  }
});

ws.on('error', (error) => {
  console.error('Error:', error);
});

📞 Asterisk PBX Integration

✅ ACTIVE - Asterisk worker is running via SSH tunnel

Gateway ARQ monitors Asterisk PBX servers in real-time through the Asterisk Manager Interface (AMI). The integration uses SSH tunneling for secure connections to remote PBX servers.

Connection Details

Server: astpbx.sanvil.net
SSH Port: 9022
AMI Port: 5038
Tunnel: localhost:65532 → astpbx.sanvil.net:9022 → localhost:5038
Status: 🟢 Connected

Data Access

⚠️ NOTE: Asterisk data is available ONLY via WebSocket

Unlike WebCom (which has REST endpoints), Asterisk events are streamed in real-time exclusively through WebSocket. There are no dedicated REST API endpoints for Asterisk call data.

WebSocket Event Format

{
  "type": "asterisk_event",
  "event": "Newchannel",
  "server": "asterisk_1",
  "channel": "SIP/trunk-00000042",
  "uniqueid": "1731671400.123",
  "calleridnum": "331234567",
  "calleridname": "John Doe",
  "context": "from-trunk",
  "exten": "100",
  "state": "Ring",
  "timestamp": 1731671400
}

AMI Event Types

  • Newchannel - New call channel created
  • Newstate - Channel state changed (Ring, Up, etc.)
  • Hangup - Call terminated
  • DialBegin - Outbound dial initiated
  • DialEnd - Outbound dial completed

Worker Status (via /metrics)

Check Asterisk worker health through the metrics endpoint:

curl -H "X-API-Key: sk_live_arq_2024_production_key_change_me" \
  http://localhost:8000/metrics

Response includes Asterisk worker status:

{
  "workers": {
    "asterisk": {
      "status": "healthy",
      "last_run": "2025-11-15T14:30:00Z"
    }
  },
  "stats": {
    "asterisk_active": 5
  }
}

WebSocket Example (Asterisk Events)

JavaScript (Browser)
const ws = new WebSocket('ws://localhost:8000/ws?api_key=sk_live_arq_2024_production_key_change_me');

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  // Filter Asterisk events
  if (data.type === 'asterisk_event') {
    console.log(`[Asterisk] ${data.event} on ${data.server}`);
    console.log(`  Channel: ${data.channel}`);
    console.log(`  CallerID: ${data.calleridnum} (${data.calleridname})`);
    console.log(`  State: ${data.state}`);
  }
};
Node.js (ws library)
const WebSocket = require('ws');

const ws = new WebSocket('ws://localhost:8000/ws?api_key=sk_live_arq_2024_production_key_change_me');

ws.on('message', (data) => {
  const event = JSON.parse(data);

  if (event.type === 'asterisk_event') {
    if (event.event === 'Newchannel') {
      console.log(`📞 New call on ${event.server}: ${event.calleridnum}`);
    } else if (event.event === 'Hangup') {
      console.log(`📴 Call ended: ${event.channel}`);
    }
  }
});

Rate Limiting

Currently no rate limiting is enforced. Future versions will implement:

  • 100 requests/minute per IP address
  • Rate limit headers in responses
  • HTTP 429 (Too Many Requests) when exceeded

Error Codes

Code Description
200 OK - Request successful
400 Bad Request - Invalid parameters
404 Not Found - Endpoint does not exist
500 Internal Server Error - Server error

Gateway ARQ API Documentation v1.5.0

© 2025 sanvil