JMV Public API
REST API for managing VOD videos, live events, playlists, streams and uploading files directly to S3/MinIO storage.
Base URLs
Errors
The API uses standard HTTP status codes. Error responses return an object with a message key.
| Code | Meaning |
|---|---|
400 | Invalid or missing parameters |
401 | Missing, expired or invalid token |
404 | Resource not found |
507 | No storage space available |
500 | Internal server error |
// Example error response
{
"message": "not allowed, token is expired"
}
Authentication
Generates a JWT token using only the plan UUID (resource). Official endpoint — no user credentials required.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| resource | string (UUID) | yes | Customer plan UUID |
Request
POST /v2/authenticate
Content-Type: application/json
{
"resource": "eeba7244-e850-4064-aa61-008718b6e4b0"
}
Response — 200 OK
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Using the token
Include the token in every authenticated request via the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
401 — not allowed, token is expired. Generate a new token with the authentication endpoint.
JWT payload (decoded)
{
"planId": 123,
"planUuid": "eeba7244-e850-4064-aa61-008718b6e4b0",
"planType": "od",
"planDescription": "VOD Enterprise Plan",
"id_customers": 456,
"sub": {
"id_customers": 456,
"email": "admin@company.com"
},
"iat": 1750870000,
"exp": 1750884400
}
Videos
All video routes require authentication via Bearer token.
Returns the paginated list of videos in the plan, with filtering and sorting options.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | number | 1 | Current page |
| perPage | number | 10 | Items per page (max. 50) |
| sort | ASC | DESC | ASC | Sort direction |
| orderBy | string | name | Sort field |
| name | string | — | Filter by name (like) |
| initialDate | YYYY-MM-DD | — | Filter start date |
| endDate | YYYY-MM-DD | — | Filter end date |
Returns a single video formatted with the plan secret for generating signed URLs.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| hash | string | Unique video hash (15 alphanumeric chars) |
Deletes a video from the plan. Deletion is processed asynchronously — the video becomes unavailable immediately, but physically removing the file may take a few moments to complete.
Moves a video to a different gallery.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| gallery | string (UUID) | yes | Destination gallery UUID |
Updates a video's display name.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | New video name |
Uploads a thumbnail via multipart/form-data. Limited to 1 MB. The image is sent to the Static API and the video's thumb field is updated.
multipart/form-data, not application/json.Returns the list of videos with conversion jobs in progress for the specified plan.
Returns the normalized status of a video's conversion job.
Return values
| Status | Condition |
|---|---|
COMPLETED | progress ≥ 100 |
CONVERTING | status = converting or progress > 0 |
ERROR | status = ERROR or FAILED |
AWAIT_CONVERSION | all other cases |
Galleries
Returns the plan's gallery tree, including child galleries (children).
{
"folders": [
{
"id": 1,
"uuid": "a1b2c3d4-...",
"name": "Training",
"description": "Internal training videos",
"children": []
}
]
}
Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Gallery name |
| description | string | no | Description |
| parent | string (UUID) | no | Parent gallery UUID (to create a subgallery) |
Updates the name and/or description of an existing gallery.
Deletes a gallery. Galleries with associated videos cannot be deleted.
Live Events
Creates a new event with the initial status WAITING_LIVE.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | yes | Event title |
| scheduledDate | string (ISO 8601) | yes | Scheduled date and time |
Returns a paginated list of the plan's events.
Changes the status of a live event. The lifecycle follows the sequence:
WAITING_LIVE → LIVE → ON_DEMAND
Deletes one or more events. Accepts an array of IDs in the body.
Body
{
"ids": [42, 43, 44]
}
Playlist
Playlist management for AVJ plans. Lets you order and control the content displayed.
Returns all videos in a plan's playlist in the configured order.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| videoId | number | yes | ID of the video to add |
Changes the position of a video in the playlist.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| position | number | yes | New position (1-based) |
Removes a video from the playlist without deleting it from the system.
Returns the video currently playing in the player. Queries the Webtv database (real-time read).
Streams v2
Proxy to the Stream Gateway. All operations are forwarded to the internal service via X-API-KEY. The stream_id is generated automatically in the format OT-NORMAL-{name}-{stream_key}.
Creates a new stream target on the Stream Gateway.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Stream identifier name |
| stream_key | string | yes | Unique stream key |
Returns the current broadcast status directly from the Stream Gateway.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| action | enable | disable | yes | Action to run on the broadcast |
Removes the broadcast from the Stream Gateway. This operation is irreversible.
S3 Upload v2
Upload videos directly to MinIO (S3-compatible) using presigned URLs. File content never passes through the API — the client sends it straight to storage. Supports files up to 5 TB.
POST /v2/upload/multipart/s3 → get presigned URLs2. PUT each URL directly to MinIO (client-side) → collect ETags
3.
POST /v2/upload/multipart/complete → finalize and process
Strategies by file size
| Size | Strategy | Chunk Size |
|---|---|---|
| < 100 MB | direct_upload | Full file (1 part) |
| 100 MB – 1 GB | medium_chunks | 16 MB |
| 1 GB – 100 GB | large_chunks | 64 MB |
| 100 GB – 5 TB | huge_chunks | Dynamic (max. 10,000 parts) |
Creates a multipart upload in MinIO and returns all presigned URLs at once. Each URL is valid for 6 hours.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| fileName | string | yes | Original file name (with extension) |
| fileSize | number | yes | File size in bytes |
| totalParts | number | yes | Total number of parts to send |
| chunkSize | number | yes | Size of each chunk in bytes |
Request
POST /v2/upload/multipart/s3
Authorization: Bearer <token>
Content-Type: application/json
{
"fileName": "training-video.mp4",
"fileSize": 1073741824,
"totalParts": 16,
"chunkSize": 67108864
}
Response — 200 OK
{
"uploadId": "minio-upload-id-xyz",
"objectName": "uploads/vod123/a8f3k2m9x1q4p.mp4",
"video_hash": "a8f3k2m9x1q4p",
"totalParts": 16,
"presignedUrls": [
{ "partNumber": 1, "url": "https://minio.../upload?partNumber=1&uploadId=..." },
{ "partNumber": 2, "url": "https://minio.../upload?partNumber=2&uploadId=..." }
]
}
Sending the parts (client-side)
For each presigned URL, make a PUT directly to MinIO with the corresponding chunk:
// JavaScript — send each part
const uploadedParts = [];
for (let i = 0; i < presignedUrls.length; i++) {
const { partNumber, url } = presignedUrls[i];
const start = i * chunkSize;
const chunk = file.slice(start, start + chunkSize);
const res = await fetch(url, {
method: 'PUT',
body: chunk,
headers: { 'Content-Type': 'application/octet-stream' }
});
uploadedParts.push({
partNumber,
etag: res.headers.get('ETag')
});
}
Completes the multipart upload in MinIO, registers the video in the database and queues the processing job on the s3-upload-queue queue.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| filename | string | yes | Original file name |
| size | number | yes | Size in bytes |
| video_hash | string | yes | Hash returned by init |
| objectName | string | yes | Object name returned by init |
| uploadId | string | yes | Upload ID returned by init |
| parts | array | yes | Array of { partNumber, etag } collected during upload |
| gallery | string (UUID) | no | Destination gallery UUID |
Request
{
"filename": "training-video.mp4",
"size": 1073741824,
"video_hash": "a8f3k2m9x1q4p",
"objectName": "uploads/vod123/a8f3k2m9x1q4p.mp4",
"uploadId": "minio-upload-id-xyz",
"gallery": "a1b2c3d4-e5f6-...",
"parts": [
{ "partNumber": 1, "etag": "\"abc123\"" },
{ "partNumber": 2, "etag": "\"def456\"" }
]
}
Generates a presigned URL to upload a file in a single PUT request. Valid for 24 hours. Recommended for files smaller than 100 MB.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| filename | string | yes | File name with extension |
| fileSize | number | yes | Size in bytes |
| gallery | string (UUID) | no | Destination gallery UUID |
Confirms that the file was uploaded to MinIO via PUT, validates that the object exists (headObject), registers the video and queues the processing job.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| hash | string | yes | Hash returned by the create endpoint |
| gallery | string (UUID) | no | Destination gallery UUID |