Introduction

PLAY'A API was made to unify and simplify the delivery of video content. This document describes the workflow of the API and is divided into three main chapters:

General information

Authorization

API authorization is based on JSON Web Tokens (you can find more information about JWT you can find here: https://jwt.io/introduction/).
There are two common ways to receive authorization tokens. The first one assumes that you have valid credentials to access all the content with user tokens. The second way grants you access to free content with guest tokens.
Most of the endpoints have a mandatory Header:

"Authorization: Bearer <access_token>"
where <access_token> is an access token received from the endpoint of the authentication. It can be either a user access token or a guest access token.
If the provided token expires or is invalid, API will respond with the following message:
{
    "status": {
        "code": 401,
        "message": "Unauthorized"
    }
}

Headers

Each request to PLAY'A API typically contains the following headers:

Content-Type: application/json
Accept: application/json
Authorization: Bearer <access_token>

HTTP status code

For all requests, API responds with the following http status codes:

  • 200 Ok - successfully processed;
  • >=500 - server error;
  • 404 - incorrect address or request format;

Responses

PLAYA service generates a json object as a response on each request. It has a specific format described in this chapter. Correct response can be parsed only from response with the HTTP status code 200 Ok.
The simplest json object (also called a skeleton) is being generated for every request. It looks like this:

{
    status: {
        code: <status code>,
        message: <detailed message>
    }
}

The skeleton contains a status object with properties "code" and "message". Every request has a status code and message which describes this code. Table 1 explains the individual status codes.

Table 1: Status codes

CodeStatus
1Authorization failed
2Ok
3General error (see details in status message)
4User is expired
5User is inactive
6User is blocked
7Successful registry
8Registration: email exists
10Registration: email not sent
11Registration: invalid email
401Unauthorized
404Not found

Besides the status object, the response may contain other objects described in this chapter.

{
    status: {
        code: 2,
        message: “Ok”
    },
    data: {
        <...>,
        <...>
    }
}
where <...> is any object generated by endpoint. Additional objects may be added to the response depending on the result of the processing of the request and the request type. Detailed definition of endpoint’s responses can be found in the chapter “Requests”.

Response objects

Status object

status: {
    code: <code> ,
    message: <string>
}

Announcement object

announcement: {
    newslink: <string>
}

Announcements array

announcements: [
    <announcement>,
    <announcement>,
    ...
]

Configuration object

configuration: {
    "site_logo": <string>,
    "site_name": <string>,
    "lobby_logo": <string>,
    "theme": <int>,
    "categories": <bool>,
    "announcements": <bool>,
    "free_videos": <bool>,
    "free_video_category_logo": <string>,
    "registry": <bool>
}
where:
  • site_logo: a logo of the website (PNG with alpha channel - 256 px width, 256 px height)
  • site_name: a name of the website
  • lobby_logo: a logo of the lobby (PNG with alpha channel - 546 px width, 100 px height)
  • theme: a identifier of the theme (0 - red (default), 1 - blue, 2 - orange)
  • categories: enables/disables categories' UI
  • announcements: enables/disables announcements' UI
  • free_videos: enables/disables free videos' UI
  • free_video_category_logo: a logo of the free category (JPG - 526 px width, 524 px height)
  • registry: enables/disables the registry's UI

Category object

category: {
    id: <int>,
    name: <string>,
    image: <string>
}
where:
  • id: an identifier of the category
  • name: a name of the category
  • image: a link to the category's announce image

Favourites array

favorites: [
    <id>,
    <id>,
    ...
]
where <id> - is an identifier of the video

Video object

video: {
    id: <int>,
    date_gmt: <string>,
    title: <string>,
    status: <string>,
    content: <string>,
    video-category: [
        <category_id>,
        ...
    ],
    video-poster: <string>,
    video-preview-sprite: <string>,
    trailer-preview-sprite: <string>,
    video-links: {
        <type: string>: <link: string>,
        ...
    },
    trailer-links: {
        <type: string>: <link: string>,
        ...
    },
    video-positions: [
        <string>,
        ...
    ],
    video-rating: <int>,
    video-featured: <int>,
    video-duration: <string>,
    video-fps: <string>,
    video-starring: [
        <string>,
        ...
    ],
    video-tags: [
        <string>,
        ...
    ],
    timecodes_for_trailer: [
        <int>,
        ...
    ],
    timecodes_for_video: [
        <int>,
        ...
    ],
    automatic_camera_tilt: [
        <camera_tilt>,
        ...
    ],
    automatic_camera_tilt_trailer: [
        <camera_tilt>,
        ...
    ]
}
where:
  • id: an identifier of the video
  • date_gmt: a publishing date of the video, e.g. "2016-01-11T16:03:45"
  • title: a title of the video
  • status: a status of the video (publish, draft - available only for administrators and moderators)
  • content: a description of the video
  • video-category: an array of the video’s categories
  • video-poster: a link to the video’s poster
  • video-preview-sprite: a link to the video’s preview sprite
  • trailer-preview-sprite: a link to the trailer’s preview sprite
  • video-links: an array of the video’s links
  • trailer-links: an array of the trailer’s links
  • video-positions: an array with video’s positions ("Standing", "Sitting", "Lying", "Swivel")
  • video-rating: a rating of the video
  • video-featured: a feature rate of the video
  • video-duration: duration of the video (format HH:MM:SS)
  • video-fps: FPS value of the video
  • video-starring: an array with the video’s starring
  • video-tags: an array with the video’s tags
  • timecodes_for_trailer: an array of the trailer’s timecodes (in milliseconds)
  • timecodes_for_video: an array of the video’s timecodes (in milliseconds)
  • automatic_camera_tilt: an array of the video’s camera tilt objects:
camera_tilt: {
    camera_tilt: <float>,
    time_code: <int>
}
  • automatic_camera_tilt_trailer: an array of the trailer’s camera tilt objects:
camera_tilt: {
    camera_tilt: <float>,
    time_code: <int>
}

Videos array

videos: [
    <video>,
    <video>,
    ...
]
where <video> is a video object with empty field video-links.

Timestamps object

timestamps: {
    ts_announcements: <int>,
    ts_categories: <int>,
    ts_videos: <int>
}
where:
  • ts_announcements: timestamp of announcements' latest update
  • ts_categories: timestamp of categories' latest update
  • ts_videos: timestamp of videos' latest update

Token object

{
    access: <string>,
    refresh: <string>
}

User object

{
    is_guest: <boolean>,
    username: <string>,
    role: <int>,
    avatar: <int>
}
where:
  • is_guest: a guest's token indicator - if true, there will be no other fields
  • role: a role of the user (0 - user, 1 -moderator, 2 - administrator)
  • avatar: ID of the user’s avatar (0 to 15)
View avatars

Requests

Attention! All requests in this chapter have a prefix /api/playa/v1/

User registry

If a provided email address is not registered in the service, a registration email will be sent to the given email address. That email will contain a link to a "Join Now" page where user will be able to register.
An email option is mandatory.
An allow_marketing option will add email to the service's subscription list.
Response may contain the following status codes: 7, 8, 10, 11.

POST: auth/registry

{
    email: <email>,
    allow_marketing: <int>,
}

Response: {Status}

Request:

curl -X POST '<service_url>/api/playa/v1/auth/registry' -H 'Accept: application/json' -H 'Content-Type: application/json' --data-raw '{"email":"test@user.email","allow_marketing":1}'

Response:

{
    "status": {
        "code":7,
        "message":"Ok"
    }
}

User authentication

Returns a fresh pair of user tokens (access user token and refresh user token) if provided credentials are valid. The token pair may then be used to request the rest of the endpoints and to refresh the token pair when access token expires.

POST: auth/user

Request:

{
    email: <email>,
    password: <password>
}

Response: {Status, Token}

Request:

curl -X POST '<service_url>/api/playa/v1/auth/user' -H 'Accept: application/json' -H 'Content-Type: application/json' --data-raw '{"email":"user@mail.test","password":"userpassword"}'

Response:

{
    "status": {
        "code":2,
        "message":"Ok"
    },
    "data": {
        "token": {
            "access_token": "<a-user-access-token>",
            "refresh_token":"<a-user-refresh-token>"
        }
    }
}

Request:

curl -X POST '<service_url>/api/playa/v1/auth/user' -H 'Accept: application/json' -H 'Content-Type: application/json' --data-raw '{"email":"incorrect-user@mail.test","password":"orincorrectpassword"}'

Response:

{
    "status": {
        "code":1,
        "message":"Incorrect email or password."
    }
}

Guest authentication

Guest token pairs can be used in the same way as user token pairs - but responses will contain only public information. All private and personal information is inaccessible when using a guest token pair.

POST: auth/guest

Response: {Status, Token}

Request:

curl -X POST '<service_url>/api/playa/v1/auth/guest' -H 'Accept: application/json'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    },
    "data": {
        "token": {
            "access_token": "<a-guest-access-token>",
            "refresh_token": "<a-guest-refresh-token>"
        }
    }
}

Token refreshing

When the service receives an expired access token, it sends the response with status code 401 (Unauthorized) for all requests where the access token is mandatory. In this case, a token pair must be refreshed by sending the request with a refresh token. The service will respond with a new pair of access and refresh tokens if the provided refresh token is valid and not expired. Otherwise, the service will also respond with the status code 401 and the status message will contain the information that the supplied refresh token is invalid or expired – in this case, a new authentication must be initiated. After refreshing, all previous token pairs become invalid. This endpoint doesn’t require an authorization header.

POST: auth/refresh

Request:

{
    refresh_token: <string>
}

Response: {Status, Token}

Request:

curl -X POST '<service_url>/api/playa/v1/auth/refresh' -H 'Accept: application/json' -H 'Content-Type: application/json' --data-raw '{"refresh_token":"<a-guest-refresh-token;"}'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    },
    "data": {
        "token": {
            "access_token": "<a-guest-access-token>",
            "refresh_token": "<a-guest-refresh-token>"
        }
    }
}

User information

This endpoint responds with a user object. This object contains user fields only when the access user token is provided in the authorization header. When a guest access token is provided, the user object contains only a guest indicator field. More information about that can be found in the “Responses” chapter.

GET: account/info

Response: {Status, User}

Request:

curl -X GET '<service_url>/api/playa/v1/account/info' -H 'Accept: application/json' -H 'Content-Type: application/json' --data-raw '{"access_token":"<a-user-access-token>"}'

Response:

{
        "status": {
            "code": 2,
            "message": "Ok"
        },
        "data": {
            "user": {
                "is_guest": false,
                "username": "user@email.test",
                "role": 0,
                "avatar": 0
            }
        }
    }

Request:

curl -X GET '<service_url>/api/playa/v1/account/info' -H 'Accept: application/json' -H 'Content-Type: application/json' --data-raw '{"access_token":"<a-guest-access-token>"}'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    },
    "data": {
        "user": {
            "is_guest": true
        }
    }
}

Avatar set

Sets a new avatar for the current user.

PUT: account/avatar

{
    avatar: <int>
}

Response: {Status}

Request:

curl -X PUT '/api/playa/v1/account/avatar' -H 'authorization: bearer ' -H 'Accept: application/json' -H 'Content-Type: application/json' --data-raw '{"avatar":0}'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    }
}

Favourites

Returns a list of favourite videos for the current user.

GET: account/favorites

Response: {Status, Favourites}

Request:

curl -X GET '<service_url>/api/playa/v1/account/favorites' -H 'authorization: bearer <a-user-access-token>' -H 'Accept: application/json' -H 'Content-Type: application/json'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    },
    "data": {
        "favorites": [98949, 99234, 97514, 97996, 97702, 98619, 98221, 95902, 96224, 117975, 113903]
    }
}

Add a favourite

Adds a new favourite video id to the current user’s favourite video list.

PUT: account/favorites/{id}

Response: {Status}

Request:

curl -X PUT '<service_url>/api/playa/v1/account/favorites/121115' -H 'authorization: bearer <a-user-access-token>' -H 'Accept: application/json' -H 'Content-Type: application/json'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    }
}

Remove a favourite

Removes a favourite video id from the current user’s favourite video list.

DELETE: account/favorites/{id}

Response: {Status}

Request:

curl -X DELETE '<service_url>/api/playa/v1/account/favorites/121115' -H 'authorization: bearer <a-user-access-token' -H 'Accept: application/json' -H 'Content-Type: application/json'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    }
}

Configuration

Returns detailed information about the website’s configuration. Configuration explains which entities are available on the service. This endpoint requires authorization.

GET: configuration

Response: {Status, Configuration}

Request:

curl -X DELETE '<service_url>/api/playa/v1/configuration' -H 'authorization: bearer <a-user-access-token>' -H 'Accept: application/json'

Response:

{
    "status": {
        "code": 2,
        "message": "ok"
    },
    "data": {
        "configuration": {
            "categories": true,
            "announcements": false,
            "free_videos": false
        }
    }
}

Video

Returns detailed information about video with specified id. If the authorization header will contain a guest access token, a video-links field will be empty.

GET: video/{id}

Response: {Status, Video}

Request:

curl -X GET '<service_url>/api/playa/v1/video/101435' -H 'authorization: bearer <a-user-access-token>' -H 'Accept: application/json'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    },
    "data": {
        "video": {
            "id": 101435,
            "date_gmt": "2019-09-13T08:03:53",
            "title": "A title",
            "status": "publish",
            "video_category": [260, 262, 482, 72, 440],
            "video-poster": "<link>",
            "video-preview-sprite": "<link>",
            "trailer-preview-sprite": "",
            "video-links": {
                "3D 180 HQ": "<link>",
                "3D 180 HD": "<link>",
                "3D 180 4K": "<link>",
                "3D 180 5K": "<link>",
                "3D 180 6K": "<link>"
            },
            "trailer-links": {
                "3D 180 HQ_trailer": "<link>",
                "3D 180 HD_trailer": "<link>",
                "3D 180 4K_trailer": "<link>",
                "3D 180 5K_trailer": "<link>",
                "3D 180 6K_trailer": "<link>"
            },
            "video-positions": ["Sitting", "Standing"],
            "video-rating": 26,
            "video-featured": 0,
            "video-duration": "49:41",
            "video-fps": "60",
            "video-starring": ["Actor 1", "Actor 2"],
            "video-tags": ["Tag 1", "Tag 2", "Tag5", "Tag14", "Tag 21", "Tag24", "Tag27"],
            "seek_markers_full": [],
            "seek_markers_trailer": [],
            "timecodes_for_trailer": [76183],
            "timecodes_for_video": [127667, 245417, 580717, 1000700, 1304883, 1531300, 1751817, 1991033, 2282450, 2614050, 2927867],
            "automatic_camera_tilt": [{
                "camera_tilt": -0.22,
                "time_code": 49350
            }, {
                "camera_tilt": 0,
                "time_code": 1745583
            }, {
                "camera_tilt": 0.68,
                "time_code": 1751600
            }, {
                "camera_tilt": 0,
                "time_code": 2273700
            }, {
                "camera_tilt": 0.39,
                "time_code": 2279717
            }],
            "automatic_camera_tilt_trailer": [{
                "camera_tilt": -0.22,
                "time_code": 33733
            }, {
                "camera_tilt": 0,
                "time_code": 38333
            }, {
                "camera_tilt": -0.22,
                "time_code": 40383
            }, {
                "camera_tilt": 0,
                "time_code": 48117
            }, {
                "camera_tilt": -0.22,
                "time_code": 50533
            }, {
                "camera_tilt": 0,
                "time_code": 58100
            }, {
                "camera_tilt": -0.22,
                "time_code": 60517
            }, {
                "camera_tilt": 0,
                "time_code": 67200
            }, {
                "camera_tilt": -0.22,
                "time_code": 69617
            }, {
                "camera_tilt": 0.68,
                "time_code": 71683
            }, {
                "camera_tilt": 0.39,
                "time_code": 73717
            }, {
                "camera_tilt": 0,
                "time_code": 78700
            }],
            "description": "A long text description <…>"
        }
    }
}

Videos

Returns a list of all videos. This endpoint supports pagination parameters page (optional page number – default 1) and per_page (optional video count per page – default 500).

GET: videos?page={page}&per_page={per_page}

Response: {Status, Videos}

Request:

curl -X GET '<service_url>/api/playa/v1/videos?page=50&per_page=2' -H 'authorization: bearer <a-user-access-token>' -H 'Accept: application/json'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    },
    "data": {
        "videos": [{
            "id": 67833,
            "date_gmt": "2018-12-18T08:17:50",
            "title": "A title",
            "status": "publish",
            "video_category": [257, 266, 263, 482, 440],
            "video-poster": "<link>",
            "video-preview-sprite": "<link>",
            "trailer-preview-sprite": "",
            "trailer-links": {
                "3D 180 HQ_trailer": "<link>",
                "3D 180 HD_trailer": "<link>",
                "3D 180 4K_trailer": "<link>",
                "3D 180 5K_trailer": "<link>",
                "3D 180 6K_trailer": "<link>"
            },
            "video-positions": ["Sitting"],
            "video-rating": 8,
            "video-featured": 0,
            "video-duration": "42:50",
            "video-fps": "60",
            "video-starring": ["Actor 41"],
            "video-tags": ["Tag 4", "Tag 7", "Tag 8", "Tag 15", "Tag 21", "Tag 22", "Tag 24"],
            "seek_markers_full": [],
            "seek_markers_trailer": [],
            "timecodes_for_trailer": [0, 0, 0, 0, 0, 0, 0],
            "timecodes_for_video": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            "automatic_camera_tilt": [],
            "automatic_camera_tilt_trailer": [],
            "description": "A long text description <…>"
        }, {
            "id": 67013,
            "date_gmt": "2018-12-13T11:21:48",
            "title": "A title",
            "status": "publish",
            "video_category": [257, 139, 74, 262, 440],
            "video-poster": "<link>",
            "video-preview-sprite": "<link>",
            "trailer-preview-sprite": "",
            "trailer-links": {
                "3D 180 HQ_trailer": "<link>",
                "3D 180 HD_trailer": "<link>",
                "3D 180 4K_trailer": "<link>",
                "3D 180 5K_trailer": "<link>",
                "3D 180 6K_trailer": "<link>"
            },
            "video-positions": ["Sitting"],
            "video-rating": 13,
            "video-featured": 0,
            "video-duration": "47:23",
            "video-fps": "60",
            "video-starring": ["Actor 6"],
            "video-tags": ["Tag 9", "Tag 16", "Tag 29", "Tag 33", "Tag 36", "Tag 41"],
            "seek_markers_full": [],
            "seek_markers_trailer": [],
            "timecodes_for_trailer": [0, 0, 0, 0, 0, 0, 0, 0],
            "timecodes_for_video": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            "automatic_camera_tilt": [],
            "automatic_camera_tilt_trailer": [],
            "description": "A long text description <…>"
        }]
    }
}

Free videos

Returns a list of free videos. Requests with a guest access token in the authorization header are supported.

GET: videos/free

Response: {Status, Videos}

Request:

curl -X GET '<service_url>/api/playa/v1/videos/free' -H 'authorization: bearer <a-user-access-token>' -H 'Accept: application/json'

Response:

(See videos response)

Categories

Returns a list of the video’s categories.

GET: videos/categories

Response: {Status, Category[]}

Request:

curl -X GET '<service_url>/api/playa/v1/videos/categories' -H 'authorization: bearer <a-user-access-token>' -H 'Accept: application/json'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    },
    "data": {
        "categories": [{
            "id": 64,
            "name": "First category",
            "cat-image": "<link>"
        }, {
            "id": 65,
            "name": "Second category",
            "cat-image": "<link>"
        }, {
            "id": 134,
            "name": "Third category",
            "cat-image": "<link>"
        }]
    }
}

Announcements

Returns a list of announcements with image links.

GET: announcements

Response: {Status, Announcements}

Request:

curl -X GET '<service_url>/api/playa/v1/announcements' -H 'authorization: bearer <a-user-access-token>' -H 'Accept: application/json'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    },
    "data": {
        "announcements": [{
            "caption": "Caption 1",
            "newslink": "<link>"
        }, {
            "caption": "Caption 2",
            "newslink": "<link>"
        }]
    }
}

Timestamps

Returns the last updated timestamps for the entities: announcements, categories, and videos. These timestamps should be used to build a request workflow – update only the entities that have changed.

GET: timestamps

Response: {Status, Timestamps}

Request:

curl -X GET '<service_url>/api/playa/v1/timestamps' -H 'authorization: bearer <a-user-access-token>' -H 'Accept: application/json'

Response:

{
    "status": {
        "code": 2,
        "message": "Ok"
    },
    "data": {
        "timestamps": {
            "ts_categories": 1584525289,
            "ts_videos": 1584544393,
            "ts_announcements": 1574235871
        }
    }
}