API Documentation

The On Air Proof API gives you programmatic access to your broadcast monitoring data — detections, schedules, off-air dubs and compliance reports.

Available on: Veteran Plan only. Generate your API key in Portal → Developer API.

Base URL: https://onairproof.com/api/v1

All responses are JSON. List endpoints are paginated — pass ?page= and ?limit= (max 100, default 50). Rate limit: 120 requests per minute.


Authentication

All requests require a personal API key, sent as a Bearer token. Generate and revoke keys in your portal under Developer API.

Include the API key in every request:

Authorization: Bearer YOUR_API_KEY
Accept: application/json
                
⚠️ Keep your API key secret! Never share it publicly or commit it to version control. If a key leaks, revoke it immediately from your portal.

Requests without a valid key return 401 Unauthorized. Requests from accounts that are not on the Veteran plan return 403 with {"error": "api_access_required"}.


API Endpoints

Method Endpoint Description
GET /me Your account and current plan
GET /stations Monitored stations — filters: state, search
GET /adverts Your uploaded adverts and fingerprint status
GET /detections Airplay detections — filters: station_id, advert_id, from, to
GET /schedules Your ad schedules — filters: station_id, status
POST /schedules Create a schedule for one of your adverts
GET /dubs Off-air dub recordings — filter: station_id
GET /reports Compliance summary — start_date, end_date (defaults to last 30 days)

Detections

Every confirmed airing of one of your adverts, with station, timestamp and match confidence.

Request:

GET /api/v1/detections?station_id=12&from=2026-07-01&to=2026-07-12
Authorization: Bearer YOUR_API_KEY
                
Response (paginated):

{
  "current_page": 1,
  "data": [
    {
      "id": 4102,
      "advert": { "id": 88, "title": "MegaBank Q3 Jingle" },
      "station": { "id": 12, "name": "Fresh FM", "frequency": "105.9", "state": "Oyo" },
      "played_at": "2026-07-12T14:03:21+01:00",
      "duration_seconds": 30,
      "confidence_score": 92,
      "status": "matched"
    }
  ],
  "per_page": 50,
  "total": 245
}
                

Schedules

Read your booked spots, or create new ones directly from your traffic system.

Create a schedule:

POST /api/v1/schedules
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "advert_id": 88,
  "station_id": 12,
  "scheduled_at": "2026-07-15 08:30:00",
  "duration_seconds": 30,
  "notes": "Morning drive slot"
}
                

The advert must belong to your account. Returns 201 with the created schedule, or 422 on validation errors.


Reports

Aggregate compliance summary for any date range.

Request:

GET /api/v1/reports?start_date=2026-06-01&end_date=2026-06-30
Authorization: Bearer YOUR_API_KEY
                
Response:

{
  "period": { "from": "2026-06-01", "to": "2026-06-30" },
  "total_detections": 245,
  "total_scheduled": 250,
  "by_station": [
    { "station": "Fresh FM", "detections": 120 },
    { "station": "Splash FM", "detections": 125 }
  ],
  "schedule_status": { "aired": 245, "missed": 3, "pending": 2 }
}
                

Webhooks

Instead of polling, register an HTTPS webhook URL in Portal → Developer API and we'll push events to your server the moment they happen.

Events:
EventFires when
detection.createdOne of your adverts is detected on air
webhook.testYou click "Send Test Event" in the portal
Payload:

POST https://your-server.com/oap-webhook
Content-Type: application/json
X-OAP-Event: detection.created
X-OAP-Signature: 3f1a9c…   (HMAC-SHA256 of the raw body)

{
  "event": "detection.created",
  "data": {
    "detection_id": 4102,
    "advert": { "id": 88, "title": "MegaBank Q3 Jingle" },
    "station": { "id": 12, "name": "Fresh FM 105.9" },
    "played_at": "2026-07-12T14:03:21+01:00",
    "confidence_score": 92
  },
  "sent_at": "2026-07-12T14:03:24+01:00"
}
                
Verify the signature (PHP):

$body      = file_get_contents('php://input');
$expected  = hash_hmac('sha256', $body, $yourSigningSecret);
$received  = $_SERVER['HTTP_X_OAP_SIGNATURE'] ?? '';

if (!hash_equals($expected, $received)) {
    http_response_code(401);
    exit('Invalid signature');
}
                

Your signing secret is shown in Portal → Developer API. Deliveries time out after 6 seconds — respond with 200 quickly and process asynchronously.


Code Examples

JavaScript/Node.js

const apiKey = 'YOUR_API_KEY';
const baseUrl = 'https://onairproof.com/api/v1';

async function getDetections() {
  const response = await fetch(`${baseUrl}/detections?limit=100`, {
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Accept': 'application/json'
    }
  });

  const data = await response.json();
  console.log(data);
}

getDetections();
                
Python

import requests

API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://onairproof.com/api/v1'

headers = {
    'Authorization': f'Bearer {API_KEY}',
    'Accept': 'application/json'
}

response = requests.get(f'{BASE_URL}/detections', headers=headers)
data = response.json()
print(data)
                
cURL

curl "https://onairproof.com/api/v1/detections" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
                

Need Help?

For API support, contact support@onairproof.com.

💬 Chat with us!