API Documentation

Integrate OmniView into your event app. Submit fan-filmed videos via the API and get a synchronized multi-camera viewer automatically.

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

Authentication

API requests are authenticated using an API key tied to a specific event. Include the key in the X-API-Key header.

Each event has its own API key. You get the first one when you create an event in the dashboard; events you then create via the API return their own key.

curl -H "X-API-Key: your-api-key" \
     https://holossystems.com/api/v1/events

The sync job status endpoint is the one exception — it's keyless, since public upload pages poll it without holding an API key. Every other endpoint below requires the X-API-Key header (or api_key form field for file uploads).

Submit a Video (B2B Intake)

The primary integration endpoint. Submit a video URL from your event app, optionally with GPS coordinates from the user's phone. The video is automatically synchronized against the reference.

POST /api/v1/intake
Submit a fan video URL for synchronization
X-API-Key required

Request Body (JSON)

ParameterTypeDescription
video_urlstring requiredFull URL to the video (YouTube, TikTok, Instagram, SoundCloud)
platformstring optionalyoutube, tiktok, instagram, soundcloud. Default: youtube
latitudefloat optionalGPS latitude of the recording location (-90 to 90)
longitudefloat optionalGPS longitude of the recording location (-180 to 180)
titlestring optionalDisplay title for the video (max 300 chars)
user_labelstring optionalLocation label from the user, e.g. "Front row left" (max 200 chars)

Example Request

curl -X POST https://holossystems.com/api/v1/intake \
  -H "X-API-Key: 29c3d488-98fa-4ee9-a179-593754d7d0bf" \
  -H "Content-Type: application/json" \
  -d '{
    "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "platform": "youtube",
    "latitude": 52.3676,
    "longitude": 4.9041,
    "title": "Main stage opening",
    "user_label": "Front row center"
  }'

Response

{
  "job_id": "a1b2c3d4-...",
  "status": "pending",
  "video_id": "dQw4w9WgXcQ",
  "message": "Video submitted for synchronization"
}

The first video submitted to an event automatically becomes the reference video. All subsequent videos are synchronized against it. Duplicate submissions return status: "duplicate" instead of an error.

Upload a Video File

Upload a video file directly instead of submitting a URL. GPS coordinates and compass heading are automatically extracted from the video metadata when available. Use multipart/form-data.

POST /api/v1/events/{event_id}/upload
Upload a video file for synchronization
api_key form field required

Form Fields

ParameterTypeDescription
filefile requiredVideo file (mp4, mov, webm, m4v, avi, mkv)
api_keystring requiredEvent API key
titlestring optionalDisplay title
latitudefloat optionalGPS latitude (overrides video metadata)
longitudefloat optionalGPS longitude (overrides video metadata)
compass_headingfloat optionalCompass heading in degrees (0-360)
device_timestampstring optionalISO 8601 timestamp from the recording device
location_namestring optionalLocation label, e.g. "Main Stage"

Example Request

curl -X POST https://holossystems.com/api/v1/events/{event_id}/upload \
  -F "file=@concert.mov" \
  -F "api_key=29c3d488-98fa-4ee9-a179-593754d7d0bf" \
  -F "title=Main stage opening"

Response

{
  "status": "ok",
  "video_id": "abc123",
  "job_id": "def456",
  "stage": "Main Stage",
  "session_date": "2026-04-27"
}

Events

POST /api/v1/events
Create a new event on your account
X-API-Key of an existing event on your account required

Create your first event in the dashboard; use its API key to create further events via the API. New events belong to the same account and count towards your plan's event limit.

Request Body (JSON)

{
  "name": "Kingsday 2026",
  "date": "2026-04-27",
  "location": {
    "name": "Museumplein",
    "city": "Amsterdam",
    "country": "NL",
    "lat": 52.3580,
    "lon": 4.8828
  }
}

Response

{
  "id": "9a869d24-...",
  "name": "Kingsday 2026",
  "date": "2026-04-27",
  "api_key": "29c3d488-...",
  "status": "active",
  "viewer_url": "/view/9a869d24-...",
  "videos": []
}

The api_key is only returned on creation. Store it — you'll need it for all subsequent requests.

GET /api/v1/events/{event_id}
Get event details including all videos
X-API-Key required
GET /api/v1/events/{event_id}/manifest
Get the sync manifest with timing data for all videos
X-API-Key required

Videos

GET /api/v1/events/{event_id}/videos
List all videos for an event with sync status
X-API-Key required
POST /api/v1/events/{event_id}/videos
Submit a video URL for synchronization (alternative to /intake)
X-API-Key required

Request Body (JSON)

ParameterTypeDescription
source_urlstring requiredFull URL to the video
platformstring optionalyoutube, tiktok, instagram, soundcloud
latfloat optionalLatitude
lonfloat optionalLongitude
location_namestring optionalLocation label
titlestring optionalDisplay title
DELETE /api/v1/events/{event_id}/videos/{video_id}
Remove a video from the event
X-API-Key required

Sync Jobs

When you submit a video, you get a job_id back. Poll this endpoint to check if synchronization is complete.

GET /api/v1/jobs/{job_id}
Get sync job status

Response

{
  "id": "a1b2c3d4-...",
  "status": "done",
  "result": {
    "offset_ms": -2340.5,
    "confidence": 0.92,
    "method": "audio_fingerprint"
  }
}

Job Statuses

StatusMeaning
pendingQueued, waiting for processing
doneSuccessfully synchronized
failedSync failed — check result.error

Errors & Rate Limits

HTTP Status Codes

CodeMeaning
200Success
201Created
400Invalid request (bad URL, unsupported platform)
401Missing or invalid API key
403Event inactive or tier limit reached
404Event or video not found
409Duplicate video
429Rate limit exceeded

Rate Limits

API intake requests are limited to 30 requests per minute per IP address. If you exceed this limit, you'll receive a 429 response. Wait and retry.

Error Response Format

{
  "detail": "Invalid API key"
}