Gateway ARQ API

Complete API Reference v1.5.0 - 44 Endpoints

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

Introduction

Gateway ARQ is a real-time data ingestion system for WebCom TLC, WebTV CDN, and Centralino (jPBX). This API provides access to call data, system metrics, blacklist management, 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-2026 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" },
    "webtv": { "status": "healthy", "last_run": "2025-11-15T13:30:00Z" }
  },
  "calls": {
    "webcom_active": 3,
    "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)'
    }]
  }
});

📊 WebCom Statistics

GET /api/webcom/stats/today

Get call statistics for today (total calls, duration, cost)

Response

{
  "date": "2025-12-09",
  "total_calls": 245,
  "total_duration_seconds": 45600,
  "total_cost": 125.50,
  "by_line_type": {
    "Green": { "calls": 120, "cost": 0 },
    "Vas": { "calls": 125, "cost": 125.50 }
  }
}
GET /api/webcom/stats/daily

Get daily call statistics for the last 7 days

Query Parameters

  • days (optional) - Number of days (default: 7, max: 30)

Response

{
  "days": [
    { "date": "2025-12-09", "calls": 245, "cost": 125.50 },
    { "date": "2025-12-08", "calls": 230, "cost": 118.25 },
    ...
  ]
}
GET /api/webcom/stats/hourly

Get hourly call statistics for today

Query Parameters

  • date (optional) - Date in YYYY-MM-DD format (default: today)

Response

{
  "date": "2025-12-09",
  "hours": [
    { "hour": 0, "calls": 5, "cost": 2.50 },
    { "hour": 1, "calls": 3, "cost": 1.50 },
    ...
  ]
}
GET /api/webcom/stats/5min

Get WebCom 5-minute call samples for last 3 hours (36 samples)

Response

{
  "samples": [
    { "time": "19:05", "calls": 2 },
    { "time": "19:10", "calls": 3 },
    ...
    { "time": "22:05", "calls": 5 }
  ],
  "count": 36,
  "timestamp": "2025-11-18T22:05:00Z"
}

Examples

cURL
curl -H "X-API-Key: YOUR_API_KEY" \
  http://localhost:8000/api/webcom/stats/5min
JavaScript (Fetch)
const response = await fetch('http://localhost:8000/api/webcom/stats/5min', {
  headers: { 'X-API-Key': 'YOUR_API_KEY' }
});
const data = await response.json();
console.log(`Last 3h samples: ${data.count}`);
GET /api/webtv/hourly

Get WebTV 5-minute samples for last 3 hours (3-hour trend chart)

Response

{
  "samples": [
    { "time": "19:05", "viewers": 142 },
    { "time": "19:10", "viewers": 145 },
    ...
    { "time": "22:05", "viewers": 150 }
  ],
  "count": 36,
  "timestamp": "2025-11-16T22:05:00Z"
}

Examples

cURL
curl -H "X-API-Key: YOUR_API_KEY" \
  http://localhost:8000/api/webtv/hourly

🎰 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 },
    ...
  ]
}
GET /api/ocr/config

Get OCR configuration (non-sensitive settings)

Response

{
  "ai": {
    "enabled": true,
    "default_model": "anthropic/claude-sonnet-4.5"
  },
  "telegram": { "enabled": true },
  "upload": { "enabled": true },
  "timestamp": "2025-12-09T10:00:00Z"
}
GET /api/ocr/autobot/config

Get AutoBOT configuration (stream URL, schedule, feature flags)

Response

{
  "stream_url": "https://cdn.example.com/stream.m3u8",
  "default_stream_url": "https://cdn.example.com/stream.m3u8",
  "schedule": "20:01 daily",
  "config": {
    "ai_validation": true,
    "auto_upload": true,
    "telegram_notify": true,
    "save_to_db": true
  },
  "timestamp": "2025-12-09T10:00:00Z"
}
PUT /api/ocr/autobot/config

Update AutoBOT configuration. Stream URL is persisted in Redis.

Request Body

{
  "stream_url": "https://new-cdn.example.com/stream.m3u8",
  "ai_validation": true,
  "auto_upload": true,
  "telegram_notify": true,
  "save_to_db": true
}

Response

{
  "success": true,
  "config": { "ai_validation": true, "auto_upload": true, ... },
  "stream_url": "https://new-cdn.example.com/stream.m3u8",
  "message": "Configuration updated",
  "timestamp": "2025-12-09T10:00:00Z"
}
POST /api/ocr/autobot/stop

Stop AutoBOT processing gracefully

Response

{
  "success": true,
  "status": "idle",
  "previous_status": "capturing",
  "message": "AutoBOT stopped",
  "timestamp": "2025-12-09T10:00:00Z"
}
POST /api/ocr/ai/validate

Proxy endpoint for OpenRouter AI validation - sends image + prompt to AI vision model

Request Body

{
  "image_base64": "...",  // Base64 encoded image
  "prompt": "Verify these numbers...",  // Custom prompt
  "model": "anthropic/claude-sonnet-4.5"  // Optional
}

Response

{
  "success": true,
  "model": "anthropic/claude-sonnet-4.5",
  "response": "...",  // AI response text
  "usage": { "prompt_tokens": 100, "completion_tokens": 200 },
  "timestamp": "2025-12-09T10:00:00Z"
}
GET /api/ocr/ai/models

Get available AI vision models from OpenRouter

Response

{
  "models": [
    { "id": "anthropic/claude-sonnet-4.5", "name": "Claude Sonnet 4.5", ... },
    { "id": "openai/gpt-4-vision-preview", "name": "GPT-4 Vision", ... }
  ],
  "default": "anthropic/claude-sonnet-4.5",
  "count": 12,
  "timestamp": "2025-12-09T10:00:00Z"
}
GET /api/ocr/riscontri

Proxy per la pagina riscontri/vincite di lotto.sanvil.net (con Basic Auth)

Query Parameters

  • da (optional) - Pagination offset (default: 0)

Response

{
  "success": true,
  "html": "<html>...</html>",
  "current_offset": 0,
  "timestamp": "2025-12-09T10:00:00Z"
}
GET /api/ocr/riscontri2/dates

Get available extraction dates from legacy MySQL database

Query Parameters

  • limit (optional) - Number of dates to return (default: 10)

Response

{
  "status": "ok",
  "dates": [
    { "raw": "20251207", "formatted": "2025-12-07", "display": "07/12/2025" },
    ...
  ],
  "count": 10,
  "timestamp": "2025-12-09T10:00:00Z"
}
GET /api/ocr/riscontri2/extraction

Get current extraction from legacy MySQL database

Response

{
  "status": "ok",
  "extraction": {
    "BA": { "name": "BARI", "numbers": [12, 45, 67, 23, 89] },
    "CA": { "name": "CAGLIARI", "numbers": [4, 79, 80, 66, 84] },
    ...
  },
  "wheel_count": 11,
  "timestamp": "2025-12-09T10:00:00Z"
}
GET /api/ocr/riscontri2/riscontri

Calculate riscontri between current extraction and predictions

Query Parameters

  • by_dates (optional) - Number of extraction dates to load (default: 15)

Response

{
  "status": "ok",
  "extraction": { ... },
  "predictions": [ ... ],
  "stats": { "total": 100, "estratti": 25, "ambi": 5 },
  "stats_last3": { "total": 30, "estratti": 8 },
  "timestamp": "2025-12-09T10:00:00Z"
}
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
  • webtv_update - WebTV viewers update

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);
});

🎲 Lotto Database Endpoints

GET /api/lotto/stats

Get database statistics (total extractions, date range, per-wheel counts)

Response

{
  "total_records": 75845,
  "unique_dates": 6895,
  "first_date": "2001/01/02",
  "last_date": "2025/12/07",
  "by_wheel": {
    "BA": 6895, "CA": 6895, "FI": 6895,
    "GE": 6895, "MI": 6895, "NA": 6895,
    "PA": 6895, "RM": 6895, "TO": 6895,
    "VE": 6895, "RN": 6895
  }
}
GET /api/lotto/latest

Get latest extractions (grouped by date)

Query Parameters

  • limit (optional) - Number of dates (default: 10)

Response

{
  "dates": [
    {
      "date": "2025/12/07",
      "wheels": {
        "BA": [12, 45, 67, 23, 89],
        "CA": [4, 79, 80, 66, 84],
        ...
      }
    }
  ]
}
GET /api/lotto/date/{data}

Get all wheels for a specific extraction date

Path Parameters

  • data - Date in YYYY/MM/DD format (e.g., 2025/12/07)

Response

{
  "success": true,
  "date": "2025/12/07",
  "wheels": {
    "BA": [12, 45, 67, 23, 89],
    "CA": [4, 79, 80, 66, 84],
    "FI": [15, 33, 42, 58, 71],
    ...
  },
  "timestamp": "2025-12-09T10:00:00Z"
}
GET /api/lotto/date/{data}/{ruota}

Get single extraction by date and wheel

Path Parameters

  • data - Date in YYYY/MM/DD format
  • ruota - Wheel code (BA, CA, FI, GE, MI, NA, PA, RM, TO, VE, RN)

Response

{
  "success": true,
  "data": "2025/12/07",
  "ruota": "BA",
  "numeri": [12, 45, 67, 23, 89],
  "source": "sync",
  "timestamp": "2025-12-09T10:00:00Z"
}
GET /api/lotto/range

Get extractions in date range

Query Parameters

  • from_date (required) - Start date (YYYY/MM/DD)
  • to_date (required) - End date (YYYY/MM/DD)
  • ruota (optional) - Wheel filter (2-letter code)
  • limit (optional) - Max results (default: 100, max: 1000)
  • offset (optional) - Pagination offset (default: 0)

Response

{
  "success": true,
  "count": 50,
  "results": [
    { "data": "2025/12/01", "ruota": "BA", "numeri": [12, 45, 67, 23, 89] },
    ...
  ],
  "timestamp": "2025-12-09T10:00:00Z"
}
GET /api/lotto/export

Export database to TSV file

Query Parameters

  • filename (optional) - Output filename (default: lotto_export.tsv)

Response

{
  "success": true,
  "exported": 75845,
  "file_path": "/tmp/lotto_exports/lotto_export.tsv",
  "timestamp": "2025-12-09T10:00:00Z"
}
POST /api/lotto/save

Save a single wheel extraction

Request Body

{
  "data": "2025/12/07",
  "ruota": "BA",
  "numeri": [12, 45, 67, 23, 89],
  "source": "manual"  // "manual", "ocr", "sync", "import"
}

Response

{
  "success": true,
  "data": "2025/12/07",
  "ruota": "BA",
  "numeri": [12, 45, 67, 23, 89],
  "timestamp": "2025-12-09T10:00:00Z"
}
POST /api/lotto/save-full

Save complete extraction (all wheels) to database

Request Body

{
  "data": "2025/12/07",
  "wheels": {
    "BARI": [12, 45, 67, 23, 89],
    "CAGLIARI": [4, 79, 80, 66, 84],
    ...
  },
  "source": "ocr"
}

Response

{
  "success": true,
  "data": "2025/12/07",
  "saved": 11,
  "total": 11,
  "errors": null,
  "timestamp": "2025-12-09T10:00:00Z"
}
POST /api/lotto/import

Import historical data from TSV file. Expected format: YYYY/MM/DD\tRUOTA\tn1\tn2\tn3\tn4\tn5

Request Body

{
  "file_path": "/path/to/storico.tsv"
}

Response

{
  "success": true,
  "inserted": 1234,
  "skipped": 500,
  "errors": [],
  "duration_seconds": 2.5,
  "timestamp": "2025-12-09T10:00:00Z"
}
POST /api/lotto/sync

Sync database from brightstarlottery.it (downloads ZIP, imports missing dates)

Response

{
  "success": true,
  "imported": 55,
  "skipped": 75790,
  "message": "Sync completed: 55 new records imported",
  "timestamp": "2025-12-09T10:00:00Z"
}
DELETE /api/lotto/date/{data}/{ruota}

Delete single extraction by date and wheel

Path Parameters

  • data - Date in YYYY/MM/DD format
  • ruota - Wheel code (BA, CA, FI, etc.)

Response

{
  "success": true,
  "message": "Deleted 2025/12/07 BA",
  "timestamp": "2025-12-09T10:00:00Z"
}

Examples

cURL
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
  "http://localhost:8000/api/lotto/date/2025/12/07/BA"
DELETE /api/lotto/date/{data}

Delete all extractions for a date (all 11 wheels)

Path Parameters

  • data - Date in YYYY/MM/DD format

Response

{
  "success": true,
  "deleted": 11,
  "message": "Deleted 11 extractions for 2025/12/07",
  "timestamp": "2025-12-09T10:00:00Z"
}

Examples

cURL
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
  "http://localhost:8000/api/lotto/date/2025/12/07"

📞 Centralino (jPBX) API

API per l'integrazione con il centralino telefonico (asterisk-monitor). Questi endpoint sono proxied attraverso nginx a /jpbx-api/.

GET /jpbx-api/api/calls

Ottiene le chiamate attive sul centralino

Response

{
  "active_calls": [
    {
      "channel_id": "asterisk-pbx-1765265705.475",
      "name": "PJSIP/clouditalia-endpoint-000000ab",
      "state": "Up",
      "caller": "3478893084",
      "caller_name": "3478893084",
      "extension": "s",
      "context": "post-stasis",
      "application": "Queue",
      "duration": "2025-12-09T08:35:05.936+0100"
    }
  ],
  "count": 1
}
GET /jpbx-api/api/blacklist

Ottiene la lista dei numeri in blacklist

Response

{
  "blacklist": [
    {
      "number": "3883666427",
      "reason": "answered-24h",
      "created_at": "2025-12-09 07:48:07",
      "expires_at": "2025-12-10 08:48:07",
      "permanent": 0
    },
    {
      "number": "3408564246",
      "reason": "manual-permanent",
      "created_at": "2025-12-08 07:18:32",
      "expires_at": "2099-12-31 23:59:59",
      "permanent": 1
    }
  ],
  "count": 25
}
POST /jpbx-api/api/blacklist

Aggiunge un numero alla blacklist

Request Body

{
  "number": "3331234567",
  "hours": 24,           // Durata in ore (default: 24, ignorato se permanent=true)
  "permanent": false     // Se true, ban permanente
}

Response

{
  "success": true,
  "number": "3331234567",
  "expires_at": "2025-12-10 11:30:00"
}
DELETE /jpbx-api/api/blacklist/{number}

Rimuove un numero dalla blacklist

Response

{
  "success": true,
  "message": "Number removed from blacklist"
}
GET /jpbx-api/api/ari/endpoints

Ottiene lo stato degli interni (extensions)

Response

[
  {
    "resource": "105",
    "state": "online",
    "channel_ids": ["asterisk-pbx-123.456"]
  },
  {
    "resource": "100",
    "state": "offline",
    "channel_ids": []
  }
]
GET /jpbx-api/api/status

Ottiene lo stato del monitor centralino

Response

{
  "status": "running",
  "websocket": "connected",
  "stasis_calls": 0,
  "blacklisted_this_session": 15,
  "ws_clients": 1,
  "timestamp": "2025-12-09T10:33:27.464463",
  "active_calls": 3
}
WS /jpbx-ws?api_key=xxx

WebSocket per eventi real-time del centralino

Eventi

  • ari_event - Eventi ARI raw (ChannelCreated, ChannelDestroyed, etc.)
  • call_passed - Chiamata passata controllo anti-spam
  • call_blocked - Chiamata bloccata (anonimo/blacklist)
  • blacklist_added - Numero aggiunto a blacklist

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-2026 sanvil