General

General information

Getting API keys

Send email to API-manager Aleksi Rossi (firstname.lastname@yle.fi)

Getting help

This service provides documention for Yle API. We welcome your feedback, improvement suggestions, comments and questions! In other words, if something does not feel right, could be improved or bugs you, please contact Aleksi.

Articles API v2

Data model

Articles posted to Articles API v2 must conform to a schema, which is documented with JSON schema. See the following links:

Articles requested from Articles API are guaranteed to conform to a schema, which is a superset of the schema for inbound articles. This is because when article data is requested from Articles API v2, some fields of the article data are enriched with detailed data originating from other APIs. For example, when a list of concepts related to an article is included in inbound article data, the list is allowed to contain only the concept IDs, but when the article is requested from the API, the list contains also a title, a description and other information for which the master data is located in Meta API.

This schema is also documented with JSON schema. See the following links:

GET /v2/articles.json Search articles

Lists articles matching the given search criteria.

Parameters

Filtering

Name Description
id Comma-separated list of article IDs. Other filtering parameters will be ignored.
language Comma-separated list of article languages (fi, sv, ru, en, se).
publisher Only return articles from these publishers. Allows comma separated list of publisher names. (Yle Uutiset, Yle Urheilu, …)
published_after Only return articles published after this date (inclusive).
published_before Only return articles published before this date (inclusive).
author Filter articles by author (search covers author id, name, organization, and twitter account name).
q Free text search. Supports Lucene Query Parser syntax.
coverage Only articles with these coverages (national, local - supports comma separated list)
subject Comma-separated list of article subjects. Expects concept IDs. The query is OR by default: if any of the subjects match the article, the article is returned
subject_operator OR by default, use AND if you want all the listed subjects to match the article
primary_subject Search with primary (first) subject. The query is OR.

Other

Name Description
offset Return results starting from this index.
limit Limit to this many results.
fields Comma-separated list of top-level field names to return. If not given, all article fields will be included.
orderby Defines sort order of results. Defaults to published desc, but can also be set to one of: published asc, relevance desc, relevance asc or readcount.{30min,1h,6h,12h,24h,2d,week,month} desc (asc not supported)

NOTE: When using id parameter, orderby will be ignored, and articles will be returned in the same order that the IDs were given in.

Response

{
  "meta": {
    "offset": Integer,      // value of the offset parameter
    "limit": Integer,       // value of the limit parameter
    "count": Integer,       // number of articles in the response
    "total": Integer,       // total number of articles matching the search criteria
    "remaining": Integer    // number of articles after this result set
  },
  "data": Array[Article]      // articles of this result set
  "notifications": [
    { "message": "Query executed successfully." }
  ]
}

Examples

Get multiple articles by IDs

https://articles.api.yle.fi/v2/articles.json?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY&id=3-8103169,3-8104234

Find all articles published after 2015-06-25 12:00:00 (Finnish local time)

curl -XGET https://articles.api.yle.fi/v2/articles.json?published_after=2015-06-25T12:00:00+0300&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY

The returned articles are ordered by the publish date in descending order.

Find IDs of all articles authored by ‘Yle Lahti’

curl -XGET https://articles.api.yle.fi/v2/articles.json?author=Yle%20Lahti&fields=id&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY

The fields=id parameter instructs Articles API to include only the article ID in the results.

Find all articles using free text search for ‘“Sauli Niinistö”’

curl -XGET https://articles.api.yle.fi/v2/articles.json?q=%22Sauli%20Niinist%C3%B6%22&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY

POST /v2/articles.json Publish article

Publishes a new article, or updates existing one.

NOTE: Access to this API is restricted to select partners only.

Request

Request does not take query parameters apart from app_id and app_key.

Clients should add Content-Type: application/json; charset=utf-8 header.

Example:

curl -H 'Content-Type: application/json; charset=utf-8' -XPOST https://articles.api.yle.fi/v2/articles.json?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY -d '{
    "article" : {
        // full article body -- see data model for more details,
        // or browse examples of real articles with the search API
    },
    "labels": {
      "yle_contenttype" : "article",
      "yle_language" : "fi"
    }
}'

Response

200 OK when article was published successfully

{
  "meta": {
    "count": 1
  },
  "data": [
    // full body of published article
  ],
  "notifications": [
    {
      "message": "Article saved successfully."
    }
  ]
}

After successful publish request, the article will be available from /v2/articles.json?id={id}.

400 Bad Request when request body is empty, not JSON, or does not contain a valid article

{
    "notifications":
    [
        {
            "message": "Invalid request body"
        }
    ]
}

DELETE /v2/articles.json Remove article

Removes an existing article.

NOTE: Access to this API is restricted to select partners only.

Request

Parameters

Name Description
id ID of the article to remove.

Response

200 OK when article was removed successfully

{
    "meta": {
        "id": "3-123", // ID of article that was removed
        "count": 1
    },
    "data": [ {
            "id": "3-123"
    } ],
    "notifications": [ {
            "message": "Article deleted successfully."
    } ]
}

400 Bad Request when parameter ‘id’ is missing from request

{
    "notifications": [ {
            "message": "Required parameter 'id' is missing from request."
    } ]
}

404 Not Found when article with given ID was not found

{
    "notifications": [ {
            "message": "No matching articles found."
    } ]
}

RabbitMQ changes messages

NOTE: The payload formats here are due to deprecation at the time Articles API v2 is moved to AWS. Queue owners will be contacted when this happens.

Articles API v2 publishes article change messages in exchange.api.internal with routing key articlesapi-v2.article.changes.

A change happens when article is either created, updated or deleted.

  • create and updated event is sent after POST articles.json call
  • delete event is sent after DELETE articles.json call

The message headers will contain event_type header that can have a value of create, update or delete

Message payload for create and update messages will be like this:

{
    "data": [ ArticleObject ]
}

NOTE: You might get updated event even if the json content of the article did not change in POST.

NOTE: Updated event is not sent when article subjects are changed via concept combine. So, if there originally was concept 18-1 which was combined to 18-2, there won’t be an updated message for articles with 18-1 in subject.

NOTE: In payload, subjects contains only { id: CONCEPT_ID } objects. Only GET articles.json calls substitute those with concept data.

For delete message, the payload will contain only the following:

{
    "found": true,
    "_id": ArticleId
}

Auth API

General information

Auth API implements OAuth 2.0 for Yle Tunnus. It supports Authorization Code and Implicit grant types.

Applications can use Auth API to establish the user’s identity, obtain certain data about the user (for example, email address), or to gain user’s permission about using his/her data resources at a given scope (for a predefined time period).

Access tokens provided by Auth API are used to authorize user actions in many Yle APIs (in OAuth 2.0 terms, these APIs are resource servers). Most of the time, access tokens are passed in Authorization header of HTTP requests. Follow the instructions provided for the API in question.

Registering client applications

Before you can start to use Auth API, you must register your application as an Auth API client.

To register your application, contact Yle API support and provide them with the following information about your application:

  1. API proxy app_id of your application. This will be used as Auth API client id.
  2. Whether your application is a client-side (browser) or a server-side (backend) application. This determines the grant type that will be used (Authorization Grant or Implicit).
  3. One or more redirect URIs in your application that accept OAuth 2.0 authorization responses. (It is strongly recommended that these URIs are secured with HTTPS.)
  4. A set of scope specifiers that your application requests from Auth API, e.g. sub email user_segments.

Upon registration, API support will provide you with a client secret that your server-side application shall use when requesting access tokens. For client-side applications, client secret is not used. Keep your secret safe! It must never be transmitted within browser.

GET /v1/authorize Authorization request

By redirecting browser to this endpoint, a registered client application requests Auth API:

  • To establish user’s Yle Tunnus identity (by either verifying the Yle Tunnus login cookie already present in the request, or by redirecting the browser to Yle Tunnus login dialog and obtaining the login cookie after successful login).

  • To gain user’s consent to the registered client application to use user’s data resources at a given scope for a predefined time period. This step can be skipped for Yle internal applications that operate within Yle Tunnus terms of service.

Query parameters

Name Description
client_id Client id of your application.
response_type Requested grant type, either code or token. You can only use values configured for your application.
redirect_uri Redirect URI where the browser will be redirected after processing the authorization request. Must match one of the configured redirect URIs for your application.
scope Requested scope(s), delimited by spaces. This must contain only scopes that have been configured for your application.
state A string representing the state of your application at the time of the request. This value is returned to your application (appended to the redirect URI), so it can be used to reconstruct the state of your application after the authorization. It can also be used to protect against cross-site request forgeries. The values should be rather unique, but be careful to not leak out sensitive information!

Response

302 Found on success

After receiving the request, Auth API proceeds to authenticate the user (if necessary), and obtain consent from the user for the requested scopes (again, if necessary - the consent may have already been granted explicitly or implicitly). Then, the browser is redirected to your application’s redirect URI.

When authorization was successful, and requested response_type was code, the redirect URI is appended with the following query parameters:

Name Description
code Authorization code
state The state that was included in the original request (unchanged).

Your application can then proceed to request an access token with the authorization code.

If response_type was token instead, the redirect URI is appended with these parameters in the URI fragment:

Name Description
access_token Base64-encoded access token.
token_type Type of token. Always jwt (access tokens are in JSON Web Token format).
state The state that was included in the original request (unchanged).

Your application should parse the URI fragment, and then validate the access token and the state. It is your application’s responsibility to ensure that it only operates with valid access tokens! See About access tokens for more information about the access token.

302 Found on failures

If authorization request failed for some reason, the browser is still redirected to your application’s redirect URI (unless there was a problem with the redirect_uri parameter itself), but this time the redirect URI is appended with the following information. As with success response, these are appended as query parameters when response_type was code, and in URI fragment when response_type was token.

Name Description
error Error code. Consult the OAuth 2.0 specification for information about different codes.
error_description Human-readable description of the error.
state The state that was included in the original request (unchanged).

Your application should handle these failures in authorization gracefully, to ensure that the user experience remains pleasant.

400 Bad Request on failures with redirect URI

If the authorization failed because of a problem with the redirect_uri parameter itself, Auth API will not redirect browser to that URI. Instead, it responds with status code 400. The abovementioned error and error description are provided in response body as a JSON object like this:

{
  "error": invalid_request",
  "error_description": "Missing or invalid redirect_uri."
}

If the request included a redirect URI but you can’t figure out what the problem is, remember that each redirect URI has to be configured in the client configuration of your application. Otherwise it is rejected. Contact API support to check the configuration, if necessary.

POST /v1/token Access token request

Exchanges an authorization code obtained from an authorization request to an access token. Used by server-side applications as the second step of an “Authorization Grant” type of authorization.

Form parameters

Parameters must be sent using application/x-www-form-urlencoded content type.

Name Description
client_id Client id of your application.
client_secret Client secret of your application.
grant_type Set this to "authorization_code".
code Authorization code received from a successful authorization request.
redirect_uri Redirect URI of your application. This must match with the redirect URI used in the authorization request.

Response

200 OK on success

Response body is a JSON object with the following attributes:

Name Description
access_token Base64-encoded access token.
token_type Type of token. Always bearer in this case.
expires_in Lifetime of the access token in seconds.

Your application can now use the access token to perform authorized operations.

400 Bad Request on failure

If the operation failed, response body is a JSON object containing the error code and description like this:

{
  "error": invalid_grant",
  "error_description": "Missing authorization code."
}

GET /v1/tokeninfo Access token validation

Validates provided access token, and responds with JSON object that contains basic information about the token.

Query parameters

Name Description
access_token Access token to validate.

Response

200 OK when access token is valid

This response indicates that the token is valid and has not expired yet. Response is a JSON object with the following attributes:

Name Description
accessToken Validated access token itself.
expiresIn Token’s TTL in seconds.
userKey Surrogate id of the Yle Tunnus user who authorized the access token.
clientId Client id of the application that requested the authorization.
scope Scope(s) of the access token, delimited by space.

Token can be used until it expires.

400 Bad Request when access token is not valid

This response indicates that the token is not valid, or that it has expired. Token must not be used.

About access tokens

Access tokens provided by Auth API are in JSON Web Token format. JSON Web Tokens contain a header, a payload, and a signature. Tokens must always be verified and validated before they can be trusted. Auth API provides online functionality for this purpose.

Here is an example of the payload of a valid JWT token, and a description of its fields (known as claims):

{
  "aud": "f82hf3dv",
  "iss": "https://auth.api.yle.fi",
  "sub": "56e1423bc95162266a5e2469",
  "exp": 1457607854,
  "iat": 1457604254,
  "scopes": "sub"
}
Field Description
aud Audience the token is created for. Valid tokens always contain the client id of your application here.
iss Issuer of the token (always https://auth.api.yle.fi).
sub Surrogate id of the Yle Tunnus user who authorized the access token.
email Email address of the user. Only included if scope email was requested.
exp Expiration time of the token in Unix time.
iat Issued at time of the token in Unix time.
scopes List of scopes the token was issued with.

GET /v1/subjects/removed?client_id={client_id}&start_time={start_time}&end_time={end_time} List removed users

Returns a list of subject keys of users removed between a given time range and client sector. It is recommended to use a short time range, for example, between 5 to 15 minutes.

Parameters

client_id, start_time and end_time are all mandatory parameters. start_time and end_time must conform to full ISO 8601 format. start_time and end_time must be no more than 30 days apart, and start_time must occur before end_time.

Example query (without app_id and app_key parameters):

curl 'https://auth.api.yle.fi/v1/subjects/removed?client_id=ylefiapp&start_time=2018-01-01T10:00:00Z&end_time=2018-01-01T10:05:00Z'

Response

200 OK when request was successful

Body contains a JSON object with a list of removed user IDs, in the attribute removed_user_ids:

{
  "removed_user_ids": ["cf088b65e4b72b7c8381089a", "31ebf9cd8db642aa26e4ec93"]
}

400 Bad Request when client_id is missing

400 Bad Request when start_time is greater than end_time, either time is invalid or missing, or the time difference is over 30 days

Comments API

General information

Comments API provides commenting related functionality. Commenting always requires a topic, which the users can then comment. Topics can be registered, modified etc. as described in topics section.

After commenting of a topic is open, anybody can post comments and notices as documented in comments and notices. (Also, see Yle Comments plugin which is a JavaScript library that provides the client UI and functionality.)

Users can post new comments on a topic as well as respond to earlier comments.

Comments may be published immediately, or require moderation before publishing, depending on topic’s settings. Moderators can accept and reject comments, leave replies to comments, and close notices left for a comment. It is also possible to enable automatic moderation of comments.

Users section describes how to register new users, how to grant them moderator privileges, and more.

In addition to API-level moderator privileges, moderation actions are also authorized based on tags, which can (and should) be assigned to topics. See tags on how to set up tags, and topics on how to assign tags to topics, and finally users on how to grant and revoke permissions to tags for users.

Users can also be subscribed to receive notifications when new comments are posted to a certain topic. These operations are documented under notification subscriptions.

heading Comments and notices

Anyone is allowed to fetch accepted comments of a non-hidden topic, post new comments, and leave notices for comments.

Moderators are allowed to accept and reject comments, to leave a moderator reply to a comment, and to close a notice left for a comment. Also, moderators are allowed to fetch a listing of all comments of a topic, and all notices of a topic.

GET /v1/topics/{topicId}/comments/accepted Get accepted comments of a topic

Retrieves accepted comments of the given topic.

Note: retrieving comments via this API supports threaded comment trees.

Legacy API for older client without threading support exists, too: Get accepted comments of a topic (legacy version).

API returns new or old style responses depending on the max_hierarchy_depth query parameter. Including it in the request triggers the new API response, leaving it out invokes legacy response.

Note on threading

Comment support for threading will be limited to n levels. Comments Plugin will show two levels (n = 2) of comments, but callers of the API can choose how many levels they want to see.

Users can reply to comments on all levels and API will store the relationship between original comment and its replies. Plugin UI will display comment threads limited to two levels: all replies to second-level replies (and further) will be shown on level two, sorted by creation time (earliest first).

The comments API handles the comment tree formatting to limit tree depth to max_hierarchy_depth.

URL parameters

Name Type Description
topicId string Internal or external ID of the topic.

Query parameters

Name Description
max_hierarchy_depth Limits hierarchy depth. Suggested value = 2. Responses on deeper levels are flattened to the deepest allowed level. Required parameter: omitting it triggers the legacy format response.
order Defines the order in which comments should be returned. Supported values are parent_created_at:asc (default) and parent_created_at:desc
parent_limit Limits the number of root level comments that should be returned. Allows values from 1 to 100. Default is 10.
from_parent_id If this parameter is used, it must contain an id of a comment. When given, only comments whose parent comment’s creation date is after this comment’s creation time.

Response

200 OK on success

Threaded response will contain an array of top-level comments under key data:

{
  "data": [{
    "id": "99c3f086-20fd-4f6d-821d-89cea8f7f8bb",
    ...
    }, {
    "id": "6b68cc3a-5b6e-4b03-810b-4f9c094a4e9f",
    ...
  }]
}

Each comment will have a children element, containing comments to be displayed as replies to this comment. Child comments may in turn contain children, within the limits of requested max_hierarchy_depth.

{
  "id": "99c3f086-20fd-4f6d-821d-89cea8f7f8bb",
  "children": [{
                 "id": "8b716535-370a-401c-bc11-2bb787ee40ba",
                 "parentId": "99c3f086-20fd-4f6d-821d-89cea8f7f8bb",
                 "children": [...]}],
                 ...
              }, {
                 "id": "ee3b6974-d708-4394-bd2b-c5e57881ba60",
                 "parentId": "99c3f086-20fd-4f6d-821d-89cea8f7f8bb",
                 "children": [...]}],
                 ...
              }]
 }

Each response comment will also contain a parentId element identifying the parent comment for which this comment is a response.

Note the difference: parentId refers to stored comment-reply relationship while the children array construction is for display purposes and obeys the requested max_hierarchy_depth.

400 Bad Request when request contains invalid parameter values

Examples:

{ "notifications": [
    { "message": "Invalid value provided for 'from_parent_id'." }
]}

{ "notifications": [
    { "message": "Illegal parameter value for 'order' provided. The allowed options are parent_created_at:asc or parent_created_at:desc" }
]}

{ "notifications": [
    { "message": "Illegal parameter value for 'parent_limit' provided. The allowed range is 1-100" }
]}

404 Not Found when topic is not found

{ "notifications": [
    { "message": "Requested topic not found" }
]}

cURL example

curl -X GET -H 'Content-Type: application/json' \
    "https://comments.api.yle.fi/v1/topics/1-1234567/comments/accepted?max_hierarchy_depth=2&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

GET /v1/topics/{topicId}/comments/accepted Get accepted comments of a topic (legacy version)

Retrieves accepted comments of the given topic.

Note: this page documents the old API, prior to threading support in comments. Use this only API only if you need to.

Adding query parameter max_hierarchy_depth to query invokes the new API version. See Get accepted comments of a topic.

URL parameters

Name Type Description
topicId string Internal or external ID of the topic.

Query parameters

Name Description
order Defines the order in which comments should be returned. Supported values are parent_created_at:asc (default) and parent_created_at:desc
parent_limit Limits the number of root level comments that should be returned. Allows values from 1 to 100. Default is 10.
from_parent_id If this parameter is used, it must contain an id of a comment. When given, only comments whose parent comment’s creation date is after this comment’s creation time.

Response

200 OK on success

Response body is a JSON array that contains the accepted comments of the topic that match the search criteria.

400 Bad Request when request contains invalid parameter values

Examples:

{ "notifications": [
    { "message": "Invalid value provided for 'from_parent_id'." }
]}

{ "notifications": [
    { "message": "Illegal parameter value for 'order' provided. The allowed options are parent_created_at:asc or parent_created_at:desc" }
]}

{ "notifications": [
    { "message": "Illegal parameter value for 'parent_limit' provided. The allowed range is 1-100" }
]}

404 Not Found when topic is not found

{ "notifications": [
    { "message": "Requested topic not found" }
]}

cURL example

curl -X GET -H 'Content-Type: application/json' \
    "https://comments.api.yle.fi/v1/topics/1-1234567/comments/accepted?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

POST /v1/topics/{topicId}/comments Post a new comment

Posts a new comment to a topic. Topic must not be locked.

Request body must contain the comment as a JSON object.

Comment can be posted without authorization, or be authorized with Yle Tunnus (via Tunnus session cookie).

Depending on topic’s settings and authorized user’s privileges, the comment may be approved and published instantly, or it may be left waiting for a moderator’s approval before being published. The comment may also be automatically moderated, in which case it should be accepted or rejected very shortly in most cases.

If this operation is successful (endpoint returns 200 OK), a notification email is sent to all users subscribed to the topic (regardless of whether the comment was instantly approved or not), to let them know that a new comment has been added.

URL parameters

Name Type Description
topicId string Internal or external id of the topic.

Body parameters

Request body must contain a JSON object with the following attributes.

Name Type Required Description
content string Yes The comment text.
anonymousComment boolean Yes Defines whether the comment is posted without authorization or not.
author string No Name of the author. Required when comment is posted without authorization (when anonymousComment is true).
parentId string No If the new comment is a reply to another comment: the id of comment replied on.

Response

200 OK when comment was added successfully

Response body contains a JSON object with the newly added comment. See example below.

400 Bad Request if required values were missing from comment

403 Forbidden when commenting is not allowed

Commenting on a topic is denied if the topic is locked, or if the user is an inactive trusted comment author trying to post in a post-moderated topic, or if the user tries to post without authorization (anonymousComment is true) in a topic where anonymous commenting is not allowed (allowAnonymousCommenting is false)

404 Not Found if topic was not found

Example request

curl -X POST \
     -H 'Content-Type: application/json' \
     "https://comments.api.yle.fi/v1/topics/7-123456/comments?app_id=YOUR_APP_KEY&app_key=YOUR_APP_ID" \
     --data '{"content": "Kiinnostava artikkeli! Lisää tällaista!", "anonymousComment": true, "author": "Kaisa Kansalainen"}'

{
  "id": "33-783d80c3-5c34-4a2b-89bb-c696ab5dc207",
  "parentId": null,
  "topicId": "33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9",
  "topicExternalId": "7-123456",
  "content": "Kiinnostava artikkeli! Lisää tällaista!",
  "author": "Kaisa Kansalainen",
  "anonymousComment": true,
  "createdAt": "2017-04-18T10:01:23+03:00",
  "acceptedAt": null,
  "rejectedAt": null,
  "moderatedBy": null,
  "createdByModerator": false,
  "createdByTrustedCommentAuthor": false
}

POST /v1/topics/{topicId}/comments/{commentId}/notices Add notice to a comment

Adds a notice for a comment (in other words, flags it as a possible case of abuse or rules violation).

Notice must include a textual explanation (reason). This explanation is sent in request body as a JSON object, in an attribute named content. You can also include information of the user reporting the notice.

URL parameters

Name Type Description
topicId string External id of the topic.
commentId string Id of the comment.

Body parameters

Request body must contain a JSON object with the following attributes.

Name Type Required Description
content string Yes Reason for the notice
reporterEmail string No Email of the user reporting the notice
reporterName string No Name of the user reporting the notice

Response

200 OK when notice was added successfully

Response body contains a JSON object with the newly added notice. (See example below.)

400 Bad Request if request body is not valid JSON, notice content is missing, or topic does not have a public comment with the given id

404 Not Found if topic was not found

Example request

curl -X POST \
     -H 'Content-Type: application/json' \
     "https://comments.api.yle.fi/v1/topics/7-123456/comments/33-783d80c3-5c34-4a2b-89bb-c696ab5dc207/notices?app_id=YOUR_APP_KEY&app_key=YOUR_APP_ID" \
     --data '{"content": "Asiaton kommentti", "reporterName": "Maija Mallikansalainen", "reporterEmail": "maija.mallikansalainen@suomi.fi"}'

{
  "id": "33-d2269ec3-f495-48d4-95b1-e706302eb811",
  "topicId": "33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9",
  "commentId": "33-783d80c3-5c34-4a2b-89bb-c696ab5dc207",
  "reporterName": "Maija Mallikansalainen",
  "reporterEmail": "maija.mallikansalainen@suomi.fi",
  "content": "Asiaton kommentti",
  "createdAt": "2017-04-19T12:35:57+03:00",
  "status": "open",
  "closedBy": null
}

GET /v1/topics/{topicId}/comments Get comments for a topic

RESERVED FOR MODERATOR USE

Get all comments for a topic.

Note that this endpoint returns all comments, including unpublished comments that have not been moderated yet. Do not display these for all users!

This operation requires moderator privileges. The moderator must also be authorized to moderate the topic in question.

URL parameters

Name Description
topicId ID of topic which comments to get

Response

200 OK on success

400 Bad Request if the topic does not exist

{ "notifications": [
    { "message": "Topic does not exist." }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have moderator rights, is not active, or has not been authorized to moderate the topic

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

Example request

curl --header 'Cookie: ylelogin=YOUR_VALID_LOGIN_COOKIE' \
"https://comments.api.yle.fi/v1/topics/33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9/comments?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"
[
  {
    "rejectedAt": "2017-04-18T13:39:20+03:00",
    "content": "hähää",
    "moderatedBy": "Juha",
    "acceptedAt": null,
    "createdByModerator": false,
    "author": "Juha",
    "topicExternalId": "7-740449",
    "id": "33-fe950a7b-7c74-4f48-9a33-aed2ba1986d1",
    "parentId": null,
    "topicId": "33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9",
    "anonymousComment": true,
    "createdAt": "2016-06-02T16:11:30+03:00",
    "createdByTrustedCommentAuthor": false
  }
]

GET /v1/comments Get comments for all topics

RESERVED FOR MODERATOR USE

Get comments (including unpublished ones!) for all topics that the authenticated user is authorized to moderate.

Note: For perfomance reasons, accessing comments this way is limited to comments created in last 7 days.

Authenticated user must have moderator rights.

URL parameters

Name Required Type Description
created_after No ISO 8601 timestamp Return only comments that were posted after this time. Remember to encode + sign as %2B.
created_after_id No String Return only comments created after the comment with this id. Ignored if created_after is given.
limit No Number Maximum number of comments to return. Allows values between 1 and 100 (default is 30).
is_auto_moderated No Boolean Return only comments that have been moderated by automatic moderation (true), or the opposite (false).

When neither created_after nor created_after_id are defined, the endpoint just returns the latest comments.

Response

200 OK on success

Response body is a JSON object with a data attribute. The data is an array of comments, sorted from oldest to newest (by creation time). See examples below for a detailed listing of attributes returned for each comment.

400 Bad Request if given parameter values were not valid

{ "notifications": [
    { "message": "Limit must be a number between 1 and 100." }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have moderator rights, or the user account has been inactivated

{ "notifications": [
  { "message": "user123456 (yle-tunnus/xxx) has insufficient rights to perform this action." }
]}

Example requests

Use case: present a list of latest automatically moderated comments to human moderators, and then update the list with new comments that have been posted and automatically moderated after the initial request.

First, fetch a list of latest 2 comments to keep the example size suitably small:

curl --header 'Cookie: ylelogin=YOUR_VALID_LOGIN_COOKIE' \
"https://comments.api.yle.fi/v1/comments?is_auto_moderated=true&limit=2&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
  "data": [
    {
      "acceptedAt": "2018-05-17T11:33:04+03:00",
      "anonymousComment": true,
      "author": "Anne",
      "content": "Kaikki ihmiset syntyvät vapaina ja tasavertaisina arvoltaan ja oikeuksiltaan.",
      "createdAt": "2018-05-11T11:33:03+03:00",
      "createdByModerator": false,
      "createdByTrustedCommentAuthor": false,
      "id": "33-dd50c506-d555-4350-ab5a-9bed308e004c",
      "moderatedBy": "Automatic Moderator",
      "parentId": null,
      "rejectedAt": null,
      "topicExternalId": "7-65467548",
      "topicId": "33-796d453d-f23b-4b48-af34-75b507294542",
      "autoModerationCategory": "PROBABLY_GOOD",
      "autoModerationProbabilityBad": 0.2
    },
    {
      "acceptedAt": null,
      "anonymousComment": false,
      "author": "Lasse",
      "content": "Blergh!",
      "createdAt": "2018-05-17T11:34:56+03:00",
      "createdByModerator": false,
      "createdByTrustedCommentAuthor": false,
      "id": "33-9f7eaf8f-57d6-4bfc-bb9e-4fb7e793507e",
      "moderatedBy": "Automatic Moderator",
      "parentId": null,
      "rejectedAt": "2018-05-17T11:34:57+03:00",
      "topicExternalId": "7-76334353",
      "topicId": "33-796d453d-f23b-4b48-af34-75b507236842",
      "autoModerationCategory": "PROBABLY_BAD",
      "autoModerationProbabilityBad": 0.95
    }
  ]
}

Note the "id": "33-9f7eaf8f-57d6-4bfc-bb9e-4fb7e793507e" attribute on the last ( = most recent) comment.

Now, let’s make another request a little later, to see if there are new comments. The created_after_id parameter is set to the value taken from the last comment’s id:

curl --header 'Cookie: ylelogin=YOUR_VALID_LOGIN_COOKIE' \
"https://comments.api.yle.fi/v1/comments?is_auto_moderated=true&created_after_id=33-9f7eaf8f-57d6-4bfc-bb9e-4fb7e793507e&limit=2&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
  "data": [
    {
      "acceptedAt": "2018-05-17T11:35:03+03:00",
      "anonymousComment": false,
      "author": "Paavo",
      "content": "Heille on annettu järki ja omatunto, ja heidän on toimittava toisiaan kohtaan veljeyden hengessä.",
      "createdAt": "2018-05-11T11:35:02+03:00",
      "createdByModerator": false,
      "createdByTrustedCommentAuthor": false,
      "id": "33-03f51218-4c64-450c-9c1c-08bb18056f9a",
      "moderatedBy": "Automatic Moderator",
      "parentId": null,
      "rejectedAt": null,
      "topicExternalId": "7-65467548",
      "topicId": "33-796d453d-f23b-4b48-af34-75b507294542",
      "autoModerationCategory": "PROBABLY_GOOD",
      "autoModerationProbabilityBad": 0.15
    },
    ...
  ]
}

To fetch new comments again later, you’d just pick up the id value from the last comment, and include it in your request as the created_after_id parameter. And so on.

PUT /v1/topics/{topicId}/comments/{commentId}/accept Accept a comment

Accepts a comment. The comment will be immediately published.

This operation requires moderator privileges. The moderator must also be authorized to moderate the topic in question.

URL parameters

Name Description
topicId ID of topic that contains the comment
commentId ID of comment to accept

Response

200 OK on success

400 Bad Request if the topic does not exist

{ "notifications": [
    { "message": "Topic does not exist." }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have moderator rights, is not active, or has not been authorized to moderate the topic

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

Example request

curl --request PUT --header 'Cookie: yletestlogin=YOUR_VALID_LOGIN_COOKIE' \
"https://comments.api-test.yle.fi/v1/topics/33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9/comments/33-9cc9b160-ba66-438d-aadb-fe665760fdc8/accept?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"
{
  "rejectedAt": null,
  "content": "accept me pls",
  "moderatedBy": "pva",
  "acceptedAt": "2017-05-08T15:15:35+03:00",
  "createdByModerator": true,
  "author": "pva",
  "topicExternalId": "7-740449",
  "id": "33-9cc9b160-ba66-438d-aadb-fe665760fdc8",
  "parentId": null,
  "topicId": "33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9",
  "anonymousComment": false,
  "createdAt": "2017-05-08T15:13:54+03:00",
  "createdByTrustedCommentAuthor": false
}

PUT /v1/topics/{topicId}/comments/{commentId}/reject Reject a comment

Rejects a comment. The comment will not appear in topic’s list of comments (and will be hidden if it was previously accepted and published).

This operation requires moderator privileges. The moderator must also be authorized to moderate the topic in question.

URL parameters

Name Description
topicId ID of topic that contains the comment
commentId ID of comment to reject

Response

200 OK on success

400 Bad Request if the topic does not exist

{ "notifications": [
    { "message": "Topic does not exist." }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have moderator rights, is not active, or has not been authorized to moderate the topic

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

Example request

curl --request PUT --header 'Cookie: yletestlogin=YOUR_VALID_LOGIN_COOKIE' \
"https://comments.api-test.yle.fi/v1/topics/33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9/comments/33-9cc9b160-ba66-438d-aadb-fe665760fdc8/reject?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"
{
  "rejectedAt": "2017-05-09T09:50:08+03:00",
  "content": "accept me pls",
  "moderatedBy": "pva",
  "acceptedAt": null,
  "createdByModerator": true,
  "author": "pva",
  "topicExternalId": "7-740449",
  "id": "33-9cc9b160-ba66-438d-aadb-fe665760fdc8",
  "parentId": null,
  "topicId": "33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9",
  "anonymousComment": false,
  "createdAt": "2017-05-08T15:13:54+03:00",
  "createdByTrustedCommentAuthor": false
}

POST /v1/topics/{topicId}/comments/{commentId}/reply Add moderator reply to a comment

Post a new moderator’s reply to a comment. The reply will be immediately published in the topic’s comment thread. (The parent comment is identified by the parentId attribute returned in the response. This can be used to render the response next to its parent in client UIs.)

This operation requires moderator privileges. The moderator must also be authorized to moderate the topic in question.

URL parameters

Name Description
topicId ID of topic containing the comment
commentId ID of comment to reply to

Response

200 OK on success

400 Bad Request if the topic does not exist

{ "notifications": [
    { "message": "Topic does not exist." }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have moderator rights, is not active, or has not been authorized to moderate the topic

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

Example request

curl --request POST \
--header 'Cookie: yletestlogin=YOUR_VALID_LOGIN_COOKIE' \
--header 'Content-Type: application/json' \
--data '{"content": "Reply content"}'
"https://comments.api-test.yle.fi/v1/topics/33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9/comments/33-9cc9b160-ba66-438d-aadb-fe665760fdc8/reply?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"
{
  "rejectedAt": null,
  "content": "Reply content",
  "moderatedBy": null,
  "acceptedAt": "2017-05-09T15:40:09+03:00",
  "createdByModerator": true,
  "author": "pva",
  "topicExternalId": "7-740449",
  "id": "33-c1bcece4-b648-4580-ae0a-e6370c2107ed",
  "parentId": "33-9cc9b160-ba66-438d-aadb-fe665760fdc8",
  "topicId": "33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9",
  "anonymousComment": false,
  "createdAt": "2017-05-09T12:40:09+03:00",
  "createdByTrustedCommentAuthor": false
}

GET /v1/topics/{topicId}/notices?status={status} Get notices for a topic

Get all open notices for a topic.

This operation requires moderator privileges. The moderator must also be authorized to moderate the topic in question.

URL parameters

Name Description
topicId ID of topic which notices to get
status Status of the notices to get (currently only open is supported)

Response

200 OK on success

400 Bad Request if the topic does not exist

{ "notifications": [
    { "message": "Topic does not exist." }
]}

400 Bad Request if the status of the comments is not open

{ "notifications": [
    { "message": "Unsupported status" }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have moderator rights, is not active, or has not been authorized to moderate the topic

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

Example request

curl --request GET --header 'Cookie: yletestlogin=YOUR_VALID_LOGIN_COOKIE' \
"https://comments.api-test.yle.fi/v1/topics/33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9/notices?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"
[
  {
    "content": "Asiaton kommentti",
    "reporterEmail": "ella.esimerkki@yle.fi",
    "closedBy": null,
    "status": "open",
    "id": "33-a164fe2d-e4d3-4cc4-9bb9-9179e720f0a1",
    "topicId": "33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9",
    "commentId": "33-9cc9b160-ba66-438d-aadb-fe665760fdc8",
    "closedAt": null,
    "createdAt": "2017-05-09T10:46:53+03:00",
    "reporterName": "Ella Esimerkki"
  }
]

PUT /v1/topics/{topicId}/comments/{commentId}/notices/{noticeId}/close Close a notice

Close a notice attached to a comment.

A moderator will close a notice when they have reviewed it. After closing, the notice will no longer be included in the list of (open) notices returned by the GET endpoint.

This operation requires moderator privileges. The moderator must also be authorized to moderate the topic in question.

URL parameters

Name Description
topicId ID of topic containing the comment
commentId ID of comment the notice is attached to
noticeId ID of notice to close

Response

200 OK on success

400 Bad Request if the topic does not exist

{ "notifications": [
    { "message": "Topic does not exist." }
]}

400 Bad Request if the topic does not have the notice identified by the notice ID

400 Bad Request when trying to close a notification with the wrong comment or notice ID

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have moderator rights, is not active, or has not been authorized to moderate the topic

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

Example request

curl --request PUT --header 'Cookie: yletestlogin=YOUR_VALID_LOGIN_COOKIE' \
"https://comments.api-test.yle.fi/v1/topics/33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9/comments/33-9cc9b160-ba66-438d-aadb-fe665760fdc8/notices/33-a164fe2d-e4d3-4cc4-9bb9-9179e720f0a1/close?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"
{
  "content": "Asiaton kommentti",
  "reporterEmail": "ella.esimerkki@yle.fi",
  "closedBy": "pva",
  "status": "closed",
  "id": "33-a164fe2d-e4d3-4cc4-9bb9-9179e720f0a1",
  "topicId": "33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9",
  "commentId": "33-9cc9b160-ba66-438d-aadb-fe665760fdc8",
  "closedAt": "2017-05-09T12:02:43+03:00",
  "createdAt": "2017-05-09T10:46:53+03:00",
  "reporterName": "Ella Esimerkki"
}

POST /v1/topics/{topicId}/comments/{commentId}/like Like a comment

Likes a comment. If the comment has already been liked by the current user, the request succeeds without doing anything.

This operation requires the user to be authorized with Yle Tunnus (via Tunnus session cookie).

URL parameters

Name Description
topicId Internal or external id of topic that contains the comment
commentId ID of comment to like

Response

200 OK on success

400 Bad Request if the topic does not have the comment identified by the comment ID

404 Not Found if the topic does not exist

{ "notifications": [
    { "message": "Topic does not exist." }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

Example request

curl --request POST --header 'Cookie: yletestlogin=YOUR_VALID_LOGIN_COOKIE' \
"https://comments.api-test.yle.fi/v1/topics/33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9/comments/33-9cc9b160-ba66-438d-aadb-fe665760fdc8/like?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

POST /v1/topics/{topicId}/comments/{commentId}/unlike Unlike a comment

Removes a like from previously liked comment. If the comment hasn’t been liked by the current user, the request succeeds without doing anything.

This operation requires the user to be authorized with Yle Tunnus (via Tunnus session cookie).

URL parameters

Name Description
topicId Internal or external id of topic that contains the comment
commentId ID of comment to like

Response

200 OK on success

400 Bad Request if the topic does not have the comment identified by the comment ID

404 Not Found if the topic does not exist

{ "notifications": [
    { "message": "Topic does not exist." }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

Example request

curl --request POST --header 'Cookie: yletestlogin=YOUR_VALID_LOGIN_COOKIE' \
"https://comments.api-test.yle.fi/v1/topics/33-3c9c2d2e-25cf-48ff-9715-8fb43459aff9/comments/33-9cc9b160-ba66-438d-aadb-fe665760fdc8/unlike?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

GET /v1/topics/{topicId}/comments/liked Get liked comments of a topic

Retrieves IDs of comments in the given topic that the current user has liked.

URL parameters

Name Type Description
topicId string Internal or external ID of the topic.

Response

200 OK on success

Response will contain an array of comment ids. [ “99c3f086-20fd-4f6d-821d-89cea8f7f8bb”, “6b68cc3a-5b6e-4b03-810b-4f9c094a4e9f”, … ]

If the request isn’t authenticated, an empty array is returned.

404 Not Found when topic is not found

{ "notifications": [
    { "message": "Requested topic not found" }
]}

cURL example

curl -X GET --header 'Cookie: yletestlogin=YOUR_VALID_LOGIN_COOKIE' \
    "https://comments.api.yle.fi/v1/topics/1-1234567/comments/liked?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

heading Topics

Topic operations include the registration of new topics, updating topics, retrieving existing topics, and assigning and removing tags from a topic.

Commenting always requires a topic, so at least one must be registered before commenting can start.

Updating a topic is typically used to unlock or lock commenting, or hiding / opening it altogether, but it can also be used to fix the url or title of the topic, for example.

Topic operations require operator privileges.

POST /v1/topics Create new topic

Body parameters

Name Type Description
url string URL of a target site containing the Yle Comments Plugin
title string Title of the target article containing Yle Comments Plugin. Max length is 255 characters.
externalId string optional
isLocked boolean optional (default false) - Locked topic does not allow new comments
isHidden boolean optional (default false) - Topic is not shown to public
postModerateComments boolean optional (default false) - Comments to this topic are published immediately (true) or need premoderation before publishing (false).
allowAnonymousCommenting boolean optional (default true) - Anonymous commenting is allowed on this topic. When set to false, commenting requires YLE Tunnus authentication.

Previously used parameters “autoModerateComments” and “autoModerationPlatform” are no longer used in the api, but are allowed in the request. Key “autoModerateComments” is also present in the response payloads.

Body

Request body should be with ContentType application/json.

{
  "url": "http://svenska.yle.fi/artikel/2016/03/20/radiohuset-fragar-vad-far-ett-museibesok-kosta",
  "title": "Radiohuset frågar: Vad får ett museibesök kosta?",
  "externalId": "3-1234"
}

Response

200 OK on success

{
  "title": "Radiohuset frågar: Vad får ett museibesök kosta?",
  "acceptedCommentsCount": 0,
  "id": "c3628d2e-1df2-41fc-986e-47dbf3105606",
  "url": "http://svenska.yle.fi/artikel/2016/03/20/radiohuset-fragar-vad-far-ett-museibesok-kosta",
  "isLocked": false,
  "isHidden": false,
  "externalId": 3-1234",
  "unprocessedNoticesCount": 0,
  "unmoderatedCommentsCount": 0,
  "postModerateComments": false,
  "autoModerateComments": false,
  "allowAnonymousCommenting": true,
  "tags": []
}

400 Bad Request url or title missing

Both parameters are required.

cURL example

curl -X POST -H 'Content-Type: application/json' https://comments.api.yle.fi/v1/topics?app_id=YOUR_APP_ID_HERE&app_key=YOUR_APP_KEY_HERE --data '{"title": "Radiohuset frågar: Vad får ett museibesök kosta?", "url": "http://svenska.yle.fi/artikel/2016/03/20/radiohuset-fragar-vad-far-ett-museibesok-kosta"}'

PATCH /v1/topics/{id or externalId} Update topic's fields

Body parameters (updateable fields)

Name Type Description
url string Optional - URL of a target site containing the Yle Comments Plugin
title string Optional - Title of the target article containing Yle Comments Plugin
isLocked boolean Optional - Locked topic does not allow new comments
isHidden boolean Optional - Topic is not shown to public
postModerateComments boolean Optional - Comments to this topic are published immediately (true) or need premoderation before publishing (false). If autoModerateComments is true, this must be false.
allowAnonymousCommenting boolean Optional - Anonymous commenting is allowed on this topic. When set to false, commenting requires YLE Tunnus authentication.
autoModerateComments boolean Optional - Attempt to moderate comments automatically. See “Create new topic” documentation for more details.
autoModerationPlatform string Optional - Identifies the commenting platform (site) where the topic is hosted at.

Body

Request body should be with ContentType application/json.

{
  "isLocked": true,
  "isHidden": false
}

Response

200 OK on success

{
  "title": "Radiohuset frågar: Vad får ett museibesök kosta?",
  "acceptedCommentsCount": 0,
  "id": "c3628d2e-1df2-41fc-986e-47dbf3105606",
  "url": "http://svenska.yle.fi/artikel/2016/03/20/radiohuset-fragar-vad-far-ett-museibesok-kosta",
  "isLocked": false,
  "isHidden": false,
  "externalId": 3-1234",
  "unprocessedNoticesCount": 0,
  "unmoderatedCommentsCount": 0,
  "postModerateComments": false,
  "autoModerateComments": false,
  "tags": [],
  "allowAnonymousCommenting": true
}

GET /v1/topics Get topics

Request parameters

Name Type Description
url string Optional - topic url
externalIds string Optional - comma separated list of externalIds, like “3-123456,3-765432”. Note! Response is wrapped in data field when this parameter is used.
commented_by string Optional - only ‘me’ is supported. Returns topics that the current user has commented
is_locked boolean Optional - return only topics that have isLocked set to given value (either true or false). For example, to return only topics where commenting is open, set is_locked=false. Must not be used when url, externalIds, or commented_by are given. When this parameter is not given, topics are returned regardless of their isLocked attribute.
is_hidden boolean Optional - return only topics that have isHidden set to given value, similarly to is_locked parameter. When not given, topics are returned regardless of isHidden attribute. Must not be used when url, externalIds, or commented_by are given.
fields string Optional - comma separated list of fields to include in the response. When not given, all fields are returned.
limit number Optional - maximum number of topics that shall be returned. Default value (and maximum allowed value) is 100.

Note

Caller’s Yle Tunnus session is used to filter results if both url and externalIds parameters are omitted.

Response

200 OK on success

[
    {
      "tags": [{"id": "33-b694c439-c648-43a7-811d-30c8e10c0693", "externalId": "svenska", "name": "Svenska"}],
      "oldestOpenModerationTaskCreatedAt": "2018-07-20T17:01:21+03:00",
      "title": "Radiohuset frågar: Vad får ett museibesök kosta?",
      "acceptedCommentsCount": 0,
      "id": "c3628d2e-1df2-41fc-986e-47dbf3105606",
      "latestModerationTaskFinishedAt": "2018-07-20T17:20:07+03:00",
      "url": "http://svenska.yle.fi/artikel/2016/03/20/radiohuset-fragar-vad-far-ett-museibesok-kosta",
      "isLocked": false,
      "isHidden": false,
      "externalId": 3-1234",
      "unprocessedNoticesCount": 0,
      "unmoderatedCommentsCount": 0,
      "postModerateComments": false,
      "autoModerateComments": false,
      "allowAnonymousCommenting": true
    }
]

OR when using externalIds parameter

{
    "data": [
        {
            "allowAnonymousCommenting": false,
            "tags": [{"id": "33-dd8cbebc-7035-4b2a-92a1-4dda9031f0c4", "externalId": "uutiset-prod", "name": "Uutiset"}],
            "oldestOpenModerationTaskCreatedAt": null,
            "postModerateComments": false,
            "title": "Itä-Suomen kaupungit lämpenevät ennätysvauhtia – vuotuinen keskilämpötilan muutos on toiseksi suurin Euroopassa",
            "externalId": "3-10419721",
            "autoModerationPlatform": "uutiset",
            "isLocked": false,
            "id": "33-2206b6b5-6ade-430c-a1d9-84999f92285c",
            "latestModerationTaskFinishedAt": "2018-09-24T13:54:47+03:00",
            "isHidden": false,
            "unmoderatedCommentsCount": 0,
            "url": "https://yle.fi/uutiset/3-10419721",
            "unprocessedNoticesCount": 0,
            "acceptedCommentsCount": 6
        }
    ]
}

GET /v1/topics/{id or externalId} Get single topic

Response

200 OK on success

{
  "tags": [{"id": "33-b694c439-c648-43a7-811d-30c8e10c0693", "externalId": "svenska", "name": "Svenska"}],
  "title": "Radiohuset frågar: Vad får ett museibesök kosta?",
  "acceptedCommentsCount": 0,
  "id": "c3628d2e-1df2-41fc-986e-47dbf3105606",
  "url": "http://svenska.yle.fi/artikel/2016/03/20/radiohuset-fragar-vad-far-ett-museibesok-kosta",
  "isLocked": false,
  "isHidden": false,
  "externalId": 3-1234",
  "unprocessedNoticesCount": 0,
  "unmoderatedCommentsCount": 0,
  "postModerateComments": false,
  "autoModerateComments": false,
  "allowAnonymousCommenting": true
}

cURL example

curl -X GET -H 'Content-Type: application/json' "https://comments.api.yle.fi/v1/topics/275eb144-8bf0-401b-9597-da7e33056faa?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

POST /v1/topics/{topicId}/tags/{tagId} Assign tag to a topic

Add a tag to a topic. Users that have been granted permissions to a tag are allowed to view (and moderate) topics that have been tagged with it. This operation requires operator privileges.

Path parameters

Parameter Description
topicId Internal or external ID of the topic.
tagId Internal or external ID of the tag.

Response

200 OK on success

[{"topic_id":"33-82a23a87-6631-4c3e-b937-ded991b7985e","tag_id":"33-9507503f-2454-4570-bab1-efede32c4f5c"}]

400 Bad Request if the given topic does not exist

{"notifications":[{"message":"Topic does not exist."}]}

400 Bad Request if the given tag does not exist

{"notifications":[{"message":"Tag with id '33-f5fce2af-0b16-432d-8d27-67634de76c37' does not exist."}]}

403 Forbidden when authenticated user does not have operator privileges, or is not active

Examples

$ curl -X POST -H 'Content-Type: application/json' \
  "https://comments.api.yle.fi/v1/topics/33-82a23a87-6631-4c3e-b937-ded991b7985e/tags/33-9507503f-2454-4570-bab1-efede32c4f5c?app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"
  [{"topic_id":"33-82a23a87-6631-4c3e-b937-ded991b7985e","tag_id":"33-9507503f-2454-4570-bab1-efede32c4f5c"}]

DELETE /v1/topics/{topicId}/tags/{tagId} Remove tag from a topic

Remove a tag from a topic. This operation requires operator privileges.

Path parameters

Parameter Description
topicId Internal or external ID of the topic.
tagId Internal or external ID of the tag.

Response

200 OK on success

{"status": "Removed tag from 1 topic(s)."}

400 Bad Request if the given topic does not exist

{"notifications":[{"message":"Topic does not exist."}]}

400 Bad Request if the given tag does not exist

{"notifications":[{"message":"Tag with id '33-f5fce2af-0b16-432d-8d27-67634de76c37' does not exist."}]}

403 Forbidden when authenticated user does not have operator privileges, or is not active

Examples

$ curl -X DELETE -H 'Content-Type: application/json' \
  "https://comments.api.yle.fi/v1/topics/33-82a23a87-6631-4c3e-b937-ded991b7985e/tags/33-9507503f-2454-4570-bab1-efede32c4f5c?app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"
  {"status": "Removed tag from 1 topic(s)."}

GET /v1/topics/{topicId}/tags Get tags of a topic

Get tags of the topic. This operation requires operator privileges.

Path parameters

Parameter Description
topicId Internal or external ID of the topic.

Response

200 OK on success

[
    {
      "id": "33-d6cf70ba-5a61-4167-aeae-234e7a02a849"
      "name": "Lasten areena",
      "externalId": "lasten areena",
    },
    {
      "id": "33-22hf8r33-438h-vs98d-03jf-98gjdn3cg89"
      "name": "Ulkomaat",
      "externalId": "ulkomaat",
    }
]

400 Bad Request if the given topic does not exist

{"notifications":[{"message":"Topic does not exist."}]}

403 Forbidden when authenticated user does not have operator privileges, or is not active

Examples

$ curl -X GET -H 'Content-Type: application/json' \
  "https://comments.api.yle.fi/v1/topics/33-82a23a87-6631-4c3e-b937-ded991b7985e/tags?app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"

heading Tags

Tag operations are used for creating, updating, and retrieving tags. They require operator privileges.

POST /v1/tags Create new tag

Body parameters

Name Type Description
name string Human readable name for tag
externalId string Optional - Needs to be unique within comments api

Body

Request

Request body should be with ContentType application/json.

{
  "name": "Lasten areena",
  "externalId": "lasten areena",
}

Response

200 OK on success

{
  "id": "33-d6cf70ba-5a61-4167-aeae-234e7a02a849"
  "name": "Lasten areena",
  "externalId": "lasten areena",
}

PUT /v1/tags/{tagId} Rename a tag

Renames a tag. New name must be sent in request body as a JSON object, in attribute "name".

URL parameters

Name Type Description
tagId string External or internal id of the tag.

Response

200 OK when tag is renamed successfully

Response body contains the renamed tag as a JSON object. (See example below.)

400 Bad Request if name is missing from request body, or tag with the given id does not exist

Example request

curl -X PUT \
     -H 'Content-Type: application/json' \
     "https://comments.api.yle.fi/v1/tags/33-d6cf70ba-5a61-4167-aeae-234e7a02a849?app_id=YOUR_APP_KEY&app_key=YOUR_APP_ID" \
     --data '{"name": "Areena Lapsille"}'

{
  "id": "33-d6cf70ba-5a61-4167-aeae-234e7a02a849",
  "externalId": "lasten areena",
  "name": "Areena Lapsille"
}

GET /v1/tags Get all tags

Response

200 OK on success

[
    {
      "id": "33-d6cf70ba-5a61-4167-aeae-234e7a02a849"
      "name": "Lasten areena",
      "externalId": "lasten areena",
    },
    {
      "id": "33-22hf8r33-438h-vs98d-03jf-98gjdn3cg89"
      "name": "Ulkomaat",
      "externalId": "ulkomaat",
    }
]

cURL example

curl -X GET -H 'Content-Type: application/json' 'https://comments.api.yle.fi/v1/tags?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY'

GET /v1/tags?name={name} Get single tag

Request parameters

Name Type Description
name string Human readable name of a tag

Response

200 OK on success

[
    {
      "id": "33-d6cf70ba-5a61-4167-aeae-234e7a02a849"
      "name": "Lasten areena",
      "externalId": "lasten areena",
    }
]

404 Not Found when a tag could not be found

{ "notifications": [
    { "message": "Could not find tag with name 'Not there'." }
]}

cURL example

curl -X GET -H 'Content-Type: application/json' 'https://comments.api.yle.fi/v1/tags?name=Lasten%20areena&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY'

heading Users

User operations are used for creating new users (either “from scratch” or based on an email address of a registered Yle Tunnus user), updating users information, and granting and revoking users’ permissions to tags.

These operations require operator privileges.

POST /v1/users Create new user

Creates a new user. User data must be sent as JSON object in request body. See example request and table below for more details.

This endpoint supports (and requires) authentication either with Yle Tunnus session or 4scale app_id and app_key.

Clients should add Content-Type: application/json header. Request does not take query parameters apart from app_id and app_key.

Example:

curl -X POST -H 'Content-Type: application/json' "https://comments.api.yle.fi/v1/users?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
     --data '{"nick": "heebo", "externalId": "5499aa14f4b0b721913fbe34", "externalIdSource": "yle-tunnus", "isModerator": true}'

Body parameters

Name Type Required Description
externalId string Yes Yle Tunnus user surrogate key or 4scale app_id.
externalIdSource string Yes yle-tunnus or 4scale
nick string Yes User nick
isTrustedCommentAuthor boolean   When true, user can comment as Yle representative. Default is false.
isModerator boolean   When true, user can moderate topics. Default is false.
isOperator boolean   When true, user can assign roles. Default is false.
isActive boolean   When true, user is allowed to perform API operations based on his role. Default is true.

Note: The isActive attribute also has an effect on notifications (see notification subscriptions). Notifications are only sent to active users.

Response

200 OK on success

{ "nick": "Juha",
  "createdAt": "2016-07-19T16:46:25+03:00",
  "externalId": "5499aa14f4b0b721913fbe34",
  "externalIdSource": "yle-tunnus",
  "id": "1351b15-ceee-41ec-b4fb-da6f3e219d0e",
  "isModerator": true,
  "isTrustedCommentAuthor": false,
  "isOperator": false,
  "isActive": true,
  "createdBy": null,
  "tags": [
    { "name": "Svenska",
      "externalId": "svenska-yle-fi",
      "id": "33-778f7cdf-c829-4c87-9eb9-1a093231d07c",
      "assignedAt": "2016-07-19T16:46:25+03:00",
      "assignedBy": "admin"
    }
  ]
}

400 Bad Request when user data is not valid

{ "notifications": [
  { "message": "Required key 'externalIdSource' is missing." }
]}

400 Bad Request when user already exists

{ "notifications": [
  { "message": "User with externalId '5499aa14f4b0b721913fbe34' already exists." }
]}

401 Unauthenticated when not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have operator rights, or is not active

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

POST /v1/users/{yleTunnusEmail} Create new user based on Yle Tunnus email

Creates a new user using given Yle Tunnus email. User roles data must be sent as JSON object in request body. See example request and table below for more details.

This endpoint supports (and requires) authentication either with Yle Tunnus session or 4scale app_id and app_key.

Clients should add Content-Type: application/json header.

Example:

curl -X POST -H 'Content-Type: application/json' "https://comments.api.yle.fi/v1/users/mikko.mallikas@gmail.com?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
     --data '{"isTrustedCommentAuthor": true}'

URL Parameter

Name Type Required Description
yleTunnusEmail string Yes Yle Tunnus user’s email

Body parameters

Name Type Required Description
isTrustedCommentAuthor boolean   When true, user can comment as Yle representative. Default is false.
isModerator boolean   When true, user can moderate topics. Default is false.
isOperator boolean   When true, user can assign roles. Default is false.
isActive boolean   When true, user is allowed to perform API operations based on his role. Default is true.

Note: The isActive attribute also has an effect on notifications (see notification subscriptions). Notifications are only sent to active users.

Response

200 OK on success

{ "nick": "Juha",
  "createdAt": "2016-07-19T16:46:25+03:00",
  "externalId": "5499aa14f4b0b721913fbe34",
  "externalIdSource": "yle-tunnus",
  "id": "1351b15-ceee-41ec-b4fb-da6f3e219d0e",
  "isModerator": true,
  "isTrustedCommentAuthor": false,
  "isOperator": false,
  "isActive": true,
  "createdBy": null,
  "tags": [
    { "name": "Svenska",
      "externalId": "svenska-yle-fi",
      "id": "33-778f7cdf-c829-4c87-9eb9-1a093231d07c",
      "assignedAt": "2016-07-19T16:46:25+03:00",
      "assignedBy": "admin"
    }
  ]
}

400 Bad Request when user roles are not valid

{ "notifications": [
  { "message": "'isTrustedCommentAuthor' must be boolean." }
]}

400 Bad Request when user already exists

{ "notifications": [
  { "message": "User with externalId '5499aa14f4b0b721913fbe34' already exists." }
]}

401 Unauthenticated when not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have operator rights, or is not active

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

404 Not Found when user with given email is not found from Yle Tunnus

{ "notifications": [
  { "message": "Could not find Yle Tunnus user with email 'mode.rator@yle.fi'." }
]}

503 Service Unavailable when Yle Tunnus is not available

{ "notifications": [
  { "message": "Could not connect to Login API. Try again later." }
]}

PUT /v1/users/{externalIdSource}/{externalId} Update user

Updates the data of a single user with given Yle Tunnus surrogate ID or 4scale id. User data must be sent as JSON object in request body. See example request and table below for more details.

This endpoint supports (and requires) authentication either with Yle Tunnus session or 4scale app_id and app_key.

Clients should add Content-Type: application/json header.

Example:

curl -X PUT -H 'Content-Type: application/json' "https://comments.api.yle.fi/v1/users/yle-tunnus/5499aa14f4b0b721913fbe34?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
     --data '{"nick": "uusi nimimerkki", "isTrustedCommentAuthor": true}'

URL Parameter

Name Type Required Description
externalIdSource string yes yle-tunnus or 4scale
externalId string yes YLE Tunnus user surrogate key or 4scale app_id

Body parameters

All parameters are optional. Update only affects fields that are included.

Name Type Description
nick string User nick
isTrustedCommentAuthor boolean When true, user can comment as Yle representative.
isModerator boolean When true, user can moderate topics.
isOperator boolean When true, user can assign roles.
isActive boolean When true, user is allowed to perform API operations based on his role.

Note: The isActive attribute also has an effect on notifications (see notification subscriptions). Notifications are only sent to active users.

Response

200 OK on success

{ "nick": "Juha",
  "createdAt": "2016-07-19T16:46:25+03:00",
  "externalId": "5499aa14f4b0b721913fbe34",
  "externalIdSource": "yle-tunnus",
  "id": "1351b15-ceee-41ec-b4fb-da6f3e219d0e",
  "isModerator": true,
  "isTrustedCommentAuthor": false,
  "isOperator": false,
  "isActive": true,
  "createdBy": null,
  "tags": [
    { "name": "Svenska",
      "externalId": "svenska-yle-fi",
      "id": "33-778f7cdf-c829-4c87-9eb9-1a093231d07c",
      "assignedAt": "2016-07-19T16:46:25+03:00",
      "assignedBy": "admin"
    }
  ]
}

400 Bad Request when user data is not valid

{ "notifications": [
  { "message": "'isTrustedCommentAuthor' must be boolean." }
]}

401 Unauthenticated when not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have operator rights, or is not active

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

404 Not Found when user is not found

{ "notifications": [
  { "message": "Could not find user with external id 'xyz123'." }
]}

PUT /v1/users/{externalIdSource}/{userExternalId}/tags/{tagId} Grant permission to tag for a user

Grants permission to a tag for a user. Users that have been granted permission to a tag are allowed to perform moderation operations on topics that have been tagged with it. Permissions are inclusive - if user has permission to at least one tag of a topic, the user is allowed to moderate the topic.

If the user already had permission to the tag, this operation does nothing, but is still considered successful.

Using this endpoint requires operator privileges.

URL parameters

Name Description
externalIdSource yle-tunnus or 4scale
externalId YLE Tunnus user surrogate key, or 4scale app_id
tagId id of the tag

Response

200 OK when permission to a tag has been granted, or was already granted

400 Bad Request if external id source is not valid, or a tag with given id does not exist

401 Unauthorized when authorization information is missing from request

403 Forbidden when authorized user does not have operator privileges

404 Not Found if user was not found

Example request

curl -X PUT \
     "https://comments.api.yle.fi/yle-tunnus/5499aa14f4b0b721913fbe34/tags/33-b0a844a4-0fdc-478e-aae2-e75b374e5b73?app_id=YOUR_APP_KEY&app_key=YOUR_APP_ID"

DELETE /v1/users/{externalIdSource}/{userExternalId}/tags/{tagId} Revoke permission to tag from a user

Revokes permission to a tag from a user. The user will no longer be allowed to perform moderation operations on topics based on this tag (but permission to moderate the topic may still be granted by some other tag of the topic, since permissions are inclusive).

It is safe to use this endpoint to ensure that user does not have permission to a tag - if user does not have the permission, this operation does nothing, but is still considered successful.

Using this endpoint requires operator privileges.

URL parameters

Name Description
externalIdSource yle-tunnus or 4scale
externalId YLE Tunnus user surrogate key, or 4scale app_id
tagId id of the tag

Response

200 OK when permission to a tag has been revoked, or was already revoked

400 Bad Request if external id source is not valid, or a tag with given id does not exist

401 Unauthorized when authorization information is missing from request

403 Forbidden when authorized user does not have operator privileges

404 Not Found if user was not found

Example request

curl -X DELETE \
     "https://comments.api.yle.fi/yle-tunnus/5499aa14f4b0b721913fbe34/tags/33-b0a844a4-0fdc-478e-aae2-e75b374e5b73?app_id=YOUR_APP_KEY&app_key=YOUR_APP_ID"

GET /v1/users/{externalIdSource}/{externalId} Get user by external id

Retrieves the data of a single user with given Yle Tunnus surrogate ID or 4scale id.

This endpoint supports (and requires) authentication either with Yle Tunnus session or 4scale app_id and app_key.

URL Parameter

Name Type Required Description
externalIdSource string yes yle-tunnus or 4scale
externalId string yes YLE Tunnus user surrogate key or 4scale app_id

Response

200 OK on success

{ "nick": "Juha",
  "createdAt": "2016-07-19T16:46:25+03:00",
  "externalId": "5499aa14f4b0b721913fbe34",
  "externalIdSource": "yle-tunnus",
  "id": "1351b15-ceee-41ec-b4fb-da6f3e219d0e",
  "isModerator": true,
  "isTrustedCommentAuthor": false,
  "isOperator": false,
  "isActive": true,
  "createdBy": null,
  "tags": [
    { "name": "Svenska",
      "externalId": "svenska-yle-fi",
      "id": "33-778f7cdf-c829-4c87-9eb9-1a093231d07c",
      "assignedAt": "2016-07-19T16:46:25+03:00",
      "assignedBy": "admin"
    }
  ]
}

400 Bad Request when externalIdSource is not valid

{ "notifications": [
  { "message": "Illegal value in key 'externalIdSource'. The allowed values are '4scale', 'yle-tunnus'." }
]}

401 Unauthenticated when not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have operator rights, or is not active

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

404 Not Found when user is not found

{ "notifications": [
  { "message": "Could not find user with external id 'xyz123'." }
]}

cURL example

curl -X GET -H 'Content-Type: application/json' "https://comments.api.yle.fi/v1/users/yle-tunnus/5499aa14f4b0b721913fbe34?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

GET /v1/users?email={email} Get user by email

Retrieves the data of a single user by its Yle Tunnus email.

This endpoint supports (and requires) authentication either with Yle Tunnus session or 4scale app_id and app_key.

Query Parameter

Name Type Required
email string Yes

Response

200 OK on success

{ "nick": "Juha",
  "createdAt": "2016-07-19T16:46:25+03:00",
  "externalId": "5499aa14f4b0b721913fbe34",
  "externalIdSource": "yle-tunnus",
  "id": "1351b15-ceee-41ec-b4fb-da6f3e219d0e",
  "isModerator": true,
  "isTrustedCommentAuthor": false,
  "isOperator": false,
  "isActive": true,
  "createdBy": null,
  "tags": [
    { "name": "Svenska",
      "externalId": "svenska-yle-fi",
      "id": "33-778f7cdf-c829-4c87-9eb9-1a093231d07c",
      "assignedAt": "2016-07-19T16:46:25+03:00",
      "assignedBy": "admin"
    }
  ]
}

401 Unauthenticated when not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have operator rights, or is not active

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

404 Not Found when user with given email is not found from Yle Tunnus

{ "notifications": [
  { "message": "Could not find Yle Tunnus user with email 'mode.rator@yle.fi'." }
]}

404 Not Found when Yle Tunnus user is not found from Comments API

{ "notifications": [
  { "message": "Could not find user with external id 'xyz123'." }
]}

503 Service Unavailable when Yle Tunnus is not available

{ "notifications": [
  { "message": "Could not connect to Login API. Try again later." }
]}

cURL example

curl -X GET -H 'Content-Type: application/json' "https://comments.api.yle.fi/v1/users?email=mikko.mallikas@gmail.com?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

GET /v1/users/me Get currently authenticated user's information

Retrieves the authenticated user’s own information.

This endpoint supports (and requires) authentication either with Yle Tunnus session or 4scale app_id and app_key.

Response

200 OK on success

{ "nick": "Juha",
  "createdAt": "2016-07-19T16:46:25+03:00",
  "externalId": "5499aa14f4b0b721913fbe34",
  "externalIdSource": "yle-tunnus",
  "id": "1351b15-ceee-41ec-b4fb-da6f3e219d0e",
  "isModerator": true,
  "isTrustedCommentAuthor": false,
  "isOperator": false,
  "isActive": true,
  "createdBy": null,
  "isBanned": false,
  "tags": [
    { "name": "Svenska",
      "externalId": "svenska-yle-fi",
      "id": "33-778f7cdf-c829-4c87-9eb9-1a093231d07c",
      "assignedAt": "2016-07-19T16:46:25+03:00",
      "assignedBy": "admin"
    }
  ]
}

401 Unauthenticated when not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

cURL example

curl -X GET -H 'Content-Type: application/json' -H 'Cookie: ylelogin=YOUR_YLE_SESSION_TOKEN' "https://comments.api.yle.fi/v1/users/me?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

heading Banning users

Sometimes it is necessary to ban users - block them from writing comments.

Currently a ban is permanent: user cannot write comments until ban is removed.

Banning a user does not currently inform the user about the block.

GET /v1/block/{nickName} Find out if user is banned or not

Look up a user based on his/her current nickname to find out whether he/she is blocked or not.

This operation requires moderator rights.

This not an operation that is meant to be performed often: DB access is unoptimized, for example.

URL parameters

Name Description
nickName user’s chosen nick

Response

200 OK on success

Example when user is not banned:

{
    "user": {
        "id": "0e81355d-b222-3c76-4b4d-b222-21c546fad41d",
        "isBanned": false,
        "nick":"Risto Reipas"
    },
    "block": null
}

Example when user is banned:

{
    "user": {
        "id": "0e81355d-b222-3c76-4b4d-b222-21c546fad41d",
        "isBanned": false,
        "nick":"Risto Reipas"
    },
    "block": {
        "blockedUserId": "0e81355d-b222-3c76-4b4d-b222-21c546fad41d",
        "reason": "Spämännyt keskusteluja jatkuvasti. \n\nPäättäjä: Aino            Admin, 10.12.2018.",
        "blockingUserId":"0e81355d-b222-3c76-4b4d-b222-21c546faaaaa",
        "createdAt": "2018-12-11T09:25:26+02:00"
    }
}

400 Bad Request when request does not include nickName

401 Unauthenticated when request is not authenticated

403 Forbidden when authenticated user does not have moderator rights, or is not active

404 Not Found when user with the given nickname is not found

POST /v1/block/ Ban user

Create a ban/block for user.

This operation requires moderator rights.

Body parameters

Body is a JSON object with fields:

Name Type Description
blocked-user-id string Users id (as returned by earlier nick look-up)
reaseon-description boolean Reason for banning the user

Example body:

{
    "blocked-user-id": "0e81355d-b222-3c76-4b4d-b222-21c546fad41d",
    "reason-description":"Spämännyt keskusteluja jatkuvasti.           \n\nPäättäjä: Aino Admin, 10.12.2018."
}

Response

200 OK on success

User is now banned until further notice.

Response body contains a description of updated blocking status for user. See get-blocking-info.

400 Bad Request when request does not include user id or reason description; or if user is already blocked.

401 Unauthenticated when request is not authenticated

403 Forbidden when authenticated user does not have moderator rights, or is not active

404 Not Found when user with the given id is not found

DELETE /v1/block/{nickName} Un-Ban user

Remove a previously created ban/block for user.

This operation requires moderator rights.

URL parameters

Name Description
nickName user’s chosen nick

Response

200 OK on success

User is no longer banned.

Response body contains a description of updated blocking status for user. See get-blocking-info.

400 Bad Request when request does not include nickName.

401 Unauthenticated when request is not authenticated

403 Forbidden when authenticated user does not have moderator rights, or is not active

404 Not Found when user with the given id is not found or is not banned.

heading Notification subscriptions

These operations are used for managing users’ subscriptions to receive notifications for topics. Notifications are sent when new comments are posted to a topic.

Notifications are only sent to active users.

These operations require operator privileges.

PUT /v1/users//{externalIdSource}/{userExternalId}/subscriptions/topic/{topicId} Add notification subscription for a user

Create a notification subscription to a topic for a user. Subscribed users receive a notification each time a new comment is added to the topic. Notifications are only sent to active users (isActive = true).

Subscriptions can only be added to Yle Tunnus users.

URL parameters

Name Description
externalIdSource yle-tunnus
userExternalId YLE Tunnus user surrogate key
topicId Internal or external id of the topic

Response

200 OK when successful

User is now subscribed to the topic, or was already subscribed. Notifications will now be sent to the user whenever new comments are added to the topic (unless user’s isActive attribute is set to false).

400 Bad Request when user’s external id source is not ‘yle-tunnus’

{ "notifications": [
  { "message": "Illegal value in key 'externalIdSource'. The only allowed value is 'yle-tunnus'." }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have operator rights, or is not active

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

404 Not Found when user with the given external id is not found

{ "notifications": [
  { "message": "Could not find user with external id 'xyz123'." }
]}

404 Not Found when topic is not found

Example request

curl -X PUT \
     "https://comments.api.yle.fi/v1/users/yle-tunnus/5499aa14f4b0b721913fbe34/subscriptions/topic/7-123456?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
    "subscriptionId": "0b5698b7-8f79-4d41-802b-fc4d713a6f25",
    "topicExternalId": "7-123456",
    "topicId": "33-796d453d-f23b-4b48-af34-75b507294542",
    "userId": "58184a3ae4b0660154dfe37b"
}

GET /v1/users/{externalIdSource}/{userExternalId}/subscriptions Get notification subscriptions of a user

Get all notification subscriptions of a user. For every subscription, both the internal and external id of the topic is returned.

URL parameters

Name Description
externalIdSource yle-tunnus
userExternalId YLE Tunnus user surrogate key

Response

200 OK on success

400 Bad Request when user’s external id source is not ‘yle-tunnus’

{ "notifications": [
  { "message": "Illegal value in key 'externalIdSource'. The only allowed value is 'yle-tunnus'." }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have operator rights, or is not active

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

404 Not Found when user with the given external id is not found

{ "notifications": [
  { "message": "Could not find user with external id 'xyz123'." }
]}

Example request

curl -X GET \
     "https://comments.api.yle.fi/v1/users/yle-tunnus/5499aa14f4b0b721913fbe34/subscriptions?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{"subscriptions": [
  {
    "topicExternalId": "7-123456",
    "topicId": "33-796d453d-f23b-4b48-af34-75b507294542"
  }
]}

DELETE /v1/users/{externalIdSource}/{userExternalId}/subscriptions/topic/{topicId} Remove a notification subscription from user

Remove a notification subscription for a topic from a user.

URL parameters

Name Description
externalIdSource yle-tunnus
userExternalId YLE Tunnus user surrogate key
topicId Internal or external id of the topic

Response

200 OK when successful

Notification subscription to the topic was removed from the user, if there was one. The user will no longer receive notifications about new comments of the topic.

400 Bad Request when user’s external id source is not ‘yle-tunnus’

{ "notifications": [
  { "message": "Illegal value in key 'externalIdSource'. The only allowed value is 'yle-tunnus'." }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have operator rights, or is not active

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

404 Not Found when user with the given external id is not found

{ "notifications": [
  { "message": "Could not find user with external id 'xyz123'." }
]}

Example request

curl -X DELETE \
     "https://comments.api.yle.fi/v1/users/yle-tunnus/5499aa14f4b0b721913fbe34/subscriptions/topic/7-123456?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
  "status": "Unsubscribed from 1 topic(s)."
}

DELETE /v1/users/{externalIdSource}/{userExternalId}/subscriptions Remove all notification subscriptions from user

Remove all notification subscriptions from a user.

URL parameters

Name Description
externalIdSource yle-tunnus
userExternalId YLE Tunnus user surrogate key

Response

200 OK when successful

All notification subscriptions were removed from the user, if there were any. The user will no longer receive notifications about new comments of any topic.

400 Bad Request when user’s external id source is not ‘yle-tunnus’

{ "notifications": [
  { "message": "Illegal value in key 'externalIdSource'. The only allowed value is 'yle-tunnus'." }
]}

401 Unauthenticated when request is not authenticated

{ "notifications": [
  { "message": "This endpoint requires authentication." }
]}

403 Forbidden when authenticated user does not have operator rights, or is not active

{ "notifications": [
  { "message": "user123456 (yle-tunnus/577e23e8e4a085db86ddeb43) has insufficient rights to perform this action." }
]}

404 Not Found when user with the given external id is not found

{ "notifications": [
  { "message": "Could not find user with external id 'xyz123'." }
]}

Example request

curl -X DELETE \
     "https://comments.api.yle.fi/v1/users/yle-tunnus/5499aa14f4b0b721913fbe34/subscriptions?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
  "status": "Unsubscribed from 18 topic(s)."
}

Consume topic changes using a queue - REST MQ API

Comments API publishes changes to topics through REST MQ API. A message is published when topic is created, updated or its comments change. You can consume these events by registering your application as a consumer to comments-api.topic queue.

Registering a consumer in REST MQ API

To register a consumer come up with an id for your consumer. Then issue an HTTP PUT request to the following URI:

https://rest-mq.api.yle.fi/v1/queue/comments-api.topic/consumer/{consumer-id}

Consumer id should be human readable and describe the consuming application (for example, uutisvahti-api).

Request body

Request body must contain a JSON object with callback attribute at its root. Callback object defines your application’s endpoint that will receive the Comments API topic events.

Callback attribute Description
url URI of the endpoint that will consume the events. For example, https://uutisvahti.api.yle.fi/v6/events/topic-changes?app_id=APP_ID&app_key=APP_KEY.
method HTTP method of your consuming endpoint. Must be either POST or PUT.

It is important to include API key parameters app_id and app_key in the callback url, if your application is authorized by 4scale. This API key must have access to the consuming endpoint - otherwise the events will not reach your application.

Response

200 OK consumer was registered successfully

400 Bad Request if required parameters were missing or invalid

Example request

$ curl -XPUT -H "Content-Type: application/json" \
  "https://rest-mq.api.yle.fi/v1/queue/comments-api.topic/consumer/uutisvahti-api?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --data '{"callback": { \
             "url": "https://uutisvahti.api.yle.fi/v6/events/topic-changes?app_id=APP_ID&app_key=APP_KEY", \
             "method": "post" \
           }}'

Receiving events from Comments API

After the consumer has been registered successfully, you will receive the events from Comments API in the consumer endpoint. These requests will contain JSON body with the following attributes:

Attribute Description
eventType create when the topic has just been created or update otherwise
topic Topic data

For example:

{ "eventType": "update"
  "topic": {
      "title": "Radiohuset frågar: Vad får ett museibesök kosta?",
      "acceptedCommentsCount": 1,
      "id": "c3628d2e-1df2-41fc-986e-47dbf3105606",
      "url": "http://svenska.yle.fi/artikel/2016/03/20/radiohuset-fragar-vad-far-ett-museibesok-kosta",
      "isLocked": false,
      "isHidden": false,
      "externalId": 3-1234",
      "unprocessedNoticesCount": 0,
      "unmoderatedCommentsCount": 0,
      "postModerateComments": false,
      "autoModerateComments": false,
      "allowAnonymousCommenting": true,
      "updatedAt": "2018-08-31T12:00:00+0300"
    }
}

With updatedAt timestamp consumer can ensure that only latest data is used.

Comments Plugin

General information

Comments Plugin is a JavaScript library that provides user interface for Comments API clients. It displays comments of a single topic in a paginated view, and provides a form for posting new comments (when allowed).

Comments Test Site

The Comments plugin can be tested on the deployed test site https://comments.test.yle.fi/versions/<VERSION>/test.html.

The latest stable version of the test site is as of 14.12.2020 0.2.808-develop.

Including the plugin on your site

These steps instruct you on including the plugin on your site.

Include the JavaScript file of the plugin

The JavaScript file can be found from this URL: https://comments.yle.fi/versions/<VERSION>/yle-comments-plugin.js

Check the latest stable version number from Vuorovaikutus team. As of 14.12.2020, it is 1.2.809.

Test version can be found from this URL:

https://comments.test.yle.fi/versions/<VERSION>/yle-comments-plugin.js

Include the CSS stylesheet of the plugin

The stylesheet can be found from the following URL: https://comments.yle.fi/versions/<VERSION>/css/comments.css.

The legacy stylesheet can still be retrieved from:
https://comments.yle.fi/versions/<VERSION>/yle-comments-plugin.css.

Be sure to use the same version number for both the JavaScript file and the stylesheet.

You can also override the styles, or provide your own stylesheet, if you wish.

Yle Tunnus SDK

Comments plugin also has a dependency to Yle Tunnus SDK (to provide user authentication.) Follow the instructions of Yle Tunnus SDK on how to include it on your site.

Initializing the plugin

To display the plugin on a web page, include a placeholder div with the id yle-comments-plugin on the page:

<div id="yle-comments-plugin"></div>

By default, the plugin listens to prefers-color-scheme from the browser. To disable dark theme in the plugin, add the class disable-dark-theme to the placeholder div. To force dark theme, add the class force-dark-theme.

<div id="yle-comments-plugin" class="disable-dark-theme"></div>

After the div has been loaded, initialize the plugin like this:

<script>comments.core.initialize('<Environment>', '<App id>', '<App key>', '<Language>');</script>

Initialization parameters

Name Description
Environment Environment where the plugin is used. Either "production" or "test". This determines which APIs the plugin will use.
App id 4scale app id of your application. The account must have Comments API access rights (and most likely Login API as well).
App key 4scale app key of your application.
Language Default language to be used by the plugin. Either "fi" or "sv". Note that custom translations can be used, too.

After the plugin is initialized, nothing is rendered yet, because the topic has not been set yet.

Binding user authentication events

Information about the authenticated user must be passed to Comments Plugin so that it can display the commenting form correctly. For example, in some topics anonymous commenting may be disabled.

In your page you will typically initialize Tunnus SDK and install event handlers to allow your users to log in and out with their YLE Account. Comments plugin will also need to know user’s login status and plugin will need to be able to launch the login dialog.

Passing information about Tunnus SDK to plugin

Pass information about tunnus SDK to the plugin with bindTunnus function:

<script>comments.core.bindTunnus(tunnus);</script>

Full working example

This code snippet demonstrates how to initialize Tunnus SDK and bind its state to Comments Plugin.

(async () => {
  const tunnus = await window.yleTunnus({
    trackingAppName: 'YOUR_APP_NAME',
    initiatingApp: 'YOUR_APP_ID',
    environment: 'test|production'
  })
  // add your own click handlers to implement logIn/logOut functionality in your UI
  // ...
  await comments.core.bindTunnus(tunnus);
})()

Displaying comments of a topic

Commenting is always based on some topic that the comments are posted on. The topic is typically an article, but it can be any content that has a fixed URL. Commenting on a topic is enabled by POSTing the topic data to Comments API, after which the topic will have a Comments API id.

The topic id is passed to Comments Plugin with the mount function:

<script>comments.core.mount(<Topic id>, <Initial number of comments>, <Number of comments>);</script>

Remember to initialize the plugin before mounting a topic!

Initialization parameters

Name Description
Topic id Comments API id of the topic to mount.
Initial number of comments Initial number of comments to fetch after user opens the commenting. This parameter is optional. Default value is 10.
Number of comments Number of comments to fetch during subsequent page loads. This parameter is optional. Default value is 30.

After the topic id has been set (and assuming that it is a valid and proper Comments API topic id), the plugin will be rendered. Initially only a button is displayed (with the total number of existing comments on the topic). Clicking on the button then displays the whole component, and renders the initial number of comments.

If the topic has been set as hidden in Comments API, the button will not be shown. This is also the case when the topic has been set as locked and has no accepted comments.

This function can be called multiple times to switch from one topic to another.

Unloading a topic

Currently selected topic can be unloaded from the plugin with the unmount function:

<script>comments.core.unmount();</script>

This will effectively hide the component. Calling unmount is not required when switching between topics with the mount function, but it can be used to unload the currently selected topic, when there is no need to display another topic immediately.

Translating the plugin

By default, Comments Plugin provides Finnish and Swedish translations for all of its visible texts. It is also possible to override any of these translations.

Translations are overridden with the setTranslations function:

<script>
  comments.core.setTranslations(
    {
      comments: 'Comments',
      sendComment: 'Send comment'
    }
  );
</script>

The function takes an object where each property defines one translatable text (property key defines the translation that is overridden, and property value is the text that will be shown).

Below table lists all translations that can be overridden. Any other properties in the passed object are ignored.

The object does not need to contain texts for all of the translations listed below. Default text will be used, if some translation is not included in the object.

Translatable texts

Key Finnish default translation Swedish default translation
accountBanned Yle Tunnustasi on käytetty keskusteluohjeen vastaiseen keskusteluun. Kommentointi Yle tunnuksellasi on toistaiseksi estetty. Ditt Yle-konto har använts till att diskutera på ett sätt som strider mot vår diskussionspolicy. Därför kan du inte kommentera just nu.
allFieldsAreMandatory Kaikki kentät ovat pakollisia. Alla fält är obligatoriska.
comment Kommentti Kommentar
commentAbuseReportSent Ilmoituksesi tästä kommentista on lähetetty tarkistettavaksi. Din anmälan av den här kommentaren har skickats till redaktionen för granskning.
commentAnonymously Kommentoi anonyymisti Kommentera anonymt
commentIsBeingReviewed Kommenttisi tarkistetaan ja julkaistaan, kun se on hyväksytty. Din kommentar granskas och kommer att publiceras efter godkännande.
commentWithYleTunnus Kommentoi Yle Tunnuksella Kommentera med Yle Profil
comments Kommentit Kommentarer
commentsClosed Kommentointi on suljettu. Kommentarsfunktionen är stängd.
commentsPolicy Keskusteluohje Diskussionspolicy
commentsPolicyAfterText    
commentsPolicyBeforeText    
commentsPolicyUrl https://yle.fi/aihe/keskusteluohje https://svenska.yle.fi/sida/diskussionspolicy
email Sähköpostiosoite E-postadress
loadMore Lataa lisää Visa fler
loginWithYleTunnusToComment Kirjaudu Yle Tunnuksella kommentoidaksesi Logga in med Yle Profil för att kommentera
nameMandatory Nimi* Namn*
nameOfUser Nimesi Ditt namn
noticeCause Syy Orsak
noticeCauseIsMandatory Ilmoitukselle on annettava syy. Det krävs en orsak om du anmäler kommentaren.
moderateComment Moderoi kommentti Moderera kommentaren
reportComment Ilmoita kommentti Anmäl kommentaren
reportCommentAbuse Ilmoita asiaton kommentti Anmäl kommentaren
reportCommentAbuseLink Ilmoita Anmäl
reportCommentBeforeText    
reportCommentClose Sulje Stäng
reverseComments Käänteinen järjestys Ändra ordningsföljd
sendComment Lähetä kommentti Skicka kommentaren
submittingComment Kommenttiasi lähetetään… Din kommentar skickas…
timestampNotAvailable Aikaleima ei saatavilla Ingen tidsstämpel tillgänglig
today Tänään I dag
yesterday Eilen I går

Notes

Some translations like commentsPolicyAfterText and commentsPolicyBeforeText are empty by default, but they can be set to display some text for example before and/or after the comments policy link.

Translation commentsPolicyUrl is a special case. Its value should contain an URL of a page that describes the commenting policy. This URL must be in yle.fi domain and use HTTPS protocol.

Analytics

This feature was enabled in comments plugin version 1.2.433.

The comments plugin will send events for common user interactions if the yle analytics sdk has been initialized. Check the analytics sdk for details

Type of analytics events sent by the comments plugin:

"comments.comments_opened"    
"comments.comments_sent"    
"comments.comments_order_changed_to_asc"    
"comments.comments_order_changed_to_desc"    
"comments.report_sent"    

Consumer Events API

GET /v2/articles/pageviews/delta.json Get number of page views during time period

Get the amount of page views for an article during the requested time period.

Parameters

Name Required? Description
yle_id yes The Yle ID of the article
period yes Time period, one of following: 30min, 1h, 6h, 12h, 24h, 2d, week, month

Response

200 OK on success

400 Bad Request if the yle_id or period parameters are missing or invalid

404 Not Found if the requested article does not exist

Examples

$ curl "https://consumer-events.api.yle.fi/v2/articles/pageviews/delta.json?yle_id=3-7961541&period=1h&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" |python -mjson.tool
{
    "data": [
        {
            "pageViews": 1373,
            "yleId": "3-7961541"
        }
    ],
    "meta": {
        "app_id": "YOUR_APP_ID",
        "app_key": "YOUR_APP_KEY",
        "count": 1,
        "origin": "Consumer Events API",
        "period": "1h",
        "yle_id": "3-7961541"
    },
    "notifications": []
}

GET /v2/articles/pageviews/top.json Get most read articles during a time period

Get top 50 most read articles for given time period by publication & language

Parameters

Name Required? Description
period yes Time period, one of following: 30min, 1h, 6h, 12h, 24h, 2d, week, month
language yes Content language, for example: fi, sv, en, krl, ru, se
section.publication yes Articles API v1 publication, see more info from Articles API v1 documentation
section.uname no Comma sepatated list of Articles API v1 uname, see more info from Articles API v1 documentation

Response

200 OK on success

400 Bad Request Missing or invalid required parameter value

Example

$ curl -XGET "https://consumer-events.api.yle.fi/v2/articles/pageviews/top.json?period=6h&language=fi&section.publication=urheilu&section.uname=nhl&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" |python -mjson.tool
{
    "data": [
        {
            "score": 8850,
            "yleId": "3-7947199"
        },
        {
            "score": 5205,
            "yleId": "3-7947143"
        },
        {
            "score": 4013,
            "yleId": "3-7960844"
        },
        ...
    ],
    "meta": {
        "app_id": "YOUR_APP_ID",
        "app_key": "YOUR_APP_KEY",
        "count": 50,
        "origin": "Consumer Events API",
        "language": "fi",
        "period": "6h",
        "section.publication": "urheilu",
        "section.uname": "nhl"
    },
    "notifications": []
}

GET /v2/articles/pageviews/total.json Get total number of page views for an article

Get all time page views for any number of articles

Parameters

Name Required? Description
yle_id yes Comma separated list of yle ids (for example 3-123456,3-234567,3-345678)

Note! Multiple ids can be also given like this yle_id=3-123456&yle_id=3-234567&yle_id=3-345678

Response

200 OK on success

400 Bad Request if yle_id is missing or has invalid yle ids in it

404 Not Found if the document does not exist

Examples

$ curl -XGET "https://consumer-events.api.yle.fi/v2/articles/pageviews/total.json?yle_id=3-7961541&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" |python -mjson.tool
{
    "data": [
        {
            "pageViews": 2190,
            "yleId": "3-7961541"
        }
    ],
    "meta": {
        "app_id": "YOUR_APP_ID",
        "app_key": "YOUR_APP_KEY",
        "count": 1,
        "origin": "Consumer Events API",
        "yle_id": "3-7961541"
    },
    "notifications": []
}

GET /v2/programs/streamstarts/delta.json Get number of stream starts during time period

Get the amount of stream starts for a program during the requested time period.

Parameters

Name Required? Description
yle_id yes The Yle ID of the article
period yes Time period, one of following: 30min, 1h, 6h, 12h, 24h, 2d, week, month

Response

200 OK on success

400 Bad Request if the yle_id or period parameters are missing or invalid

404 Not Found if the requested program does not exist

Examples

$ curl "https://consumer-events.api.yle.fi/v2/programs/streamstarts/delta.json?yle_id=1-4226378&period=30min&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" |python -mjson.tool
{
    "data": [
        {
            "streamStarts": 10,
            "yleId": "1-4226378"
        }
    ],
    "meta": {
        "app_id": "YOUR_APP_ID",
        "app_key": "YOUR_APP_KEY",
        "count": 1,
        "origin": "Consumer Events API",
        "period": "30min",
        "yle_id": "1-4226378"
    },
    "notifications": []
}

GET /v2/programs/streamstarts/top.json Get most watched programs during a time period

Get top 50 most watched programs for given time period

Parameters

Name Required? Description
period yes Time period, one of following: 30min, 1h, 6h, 12h, 24h, 2d, week, month

Response

200 OK on success

400 Bad Request Missing or invalid required parameter value

$ curl -XGET "https://consumer-events.api.yle.fi/v2/programs/streamstarts/top.json?period=6h&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" |python -mjson.tool
{
    "data": [
        {
          "score": 7357,
          "yleId": "1-2351406"
        },
        {
          "score": 4430,
          "yleId": "1-2213834"
        },
        {
          "score": 3624,
          "yleId": "1-2449145"
        }
        ...
    ],
    "meta": {
        "app_id": "YOUR_APP_ID",
        "app_key": "YOUR_APP_KEY",
        "count": 50,
        "origin": "Consumer Events API",
        "period": "6h"
    },
    "notifications": []
}

GET /v2/programs/streamstarts/total.json Get total number of stream starts for a program

Get all time stream starts for any number of programs

Parameters

Name Required? Description
yle_id yes Comma separated list of yle ids (for example 1-123456,1-234567,1-345678)

Response

200 OK on success

400 Bad Request if yle_id is missing or has invalid yle ids in it

404 Not Found if the document does not exist

Examples

$ curl -XGET "https://consumer-events.api.yle.fi/v2/programs/streamstarts/total.json?yle_id=1-2163411&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" |python -mjson.tool
{
    "data": [
        {
            "streamStarts": 7942,
            "yleId": "1-2163411"
        }
    ],
    "meta": {
        "app_id": "YOUR_APP_ID",
        "app_key": "YOUR_APP_KEY",
        "count": 1,
        "origin": "Consumer Events API",
        "yle_id": "1-2163411"
    },
    "notifications": []
}

PUT /v1/content-attributes/batch Update content attributes (as a batch)

Updates content attributes as a batch. Operation overrides possible previous attributes for a content. Attributes that are not included will be set as empty.

JSON body parameters

Request body must be a JSON object with a data attribute. Value of that attribute must be a JSON array that may contain a maximum of 1000 objects with the following attributes.

Name Required Description
yleId Yes Yle ID of the content for which the other attributes apply. One yleId value may appear only once in data.
language No Language of the content as a two-letter abbreviation. For example, "fi" or "sv".
origin No Origin of the content. For example, "uutiset".
topics No Topics of the content as an array. For example, ["linnut" "joutsenet" "varikset"]. Max 20 values, no duplicates allowed.

Response

200 OK when content attributes were updated successfully

400 Bad Request when request body was not valid

Example request

curl --request POST \
     --header 'Content-Type: application/json' \
     --data '{"data": [{"yleId": "3-123", "language": "fi"}, {"yleId": "3-456", "origin": "uutiset"}]}' \
     "https://consumer-events.api.yle.fi/v1/content-attributes/batch?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

Consuming content view batches

Consumer Events Bridge publishes content view batches to Rest MQ API every 5 minutes. These batches are published to the queue consumer-events.inbound-content-view-batches, and contain information about how many times a program has been watched or an article has been opened during a 5-minute time slice.

Content batch data

Each content view batch contains the field periodEnd, which indicates what time slice the content views originate from, spanning 5 minutes back from the end period. For example, if periodEnd is 2018-01-01T12:05:00+02:00, then the batch contains content views from 2018-01-01T12:00:00+02:00 up to, but not including 2018-01-01T12:05:00+02:00.

Each batch has the following fields:

Attribute Description
periodEnd End time of the 5-minute time slice the batch contains data from
data Array of content views
data.yleId Yle ID of an article/program
data.category page_view for article views, or stream_start for video plays
data.count Amount of views for this item during the 5-minute period indicated by periodEnd

Due to large volumes of data, several of these batches will be sent in bursts each 5 minutes and may contain up to 200KB of data. The batches are guaranteed to be in ascending order by their respective end periods, but there can be multiple subsequent batches with identical end periods.

GET /v3/articles/pageviews/delta.json Get number of page views during time period

Get the amount of page views for an article during the requested time period.

Parameters

Name Required? Description
yle_id yes The Yle ID of the article
period yes Time period, one of following: 30min, 1h, 6h, 12h, 24h, 2d, week, month

Response

200 OK on success

400 Bad Request if the yle_id or period parameters are missing or invalid

If no data is found, data will be empty, and notifications will contain a message indicating yle_id had no view data for the period.

Examples

$ curl "https://consumer-events.api.yle.fi/v3/articles/pageviews/delta.json?yle_id=3-7961541&period=1h&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" |python -mjson.tool
{
    "data": [
        {
            "pageViews": 1373,
            "yleId": "3-7961541"
        }
    ],
    "meta": {
        "app_id": "YOUR_APP_ID",
        "app_key": "YOUR_APP_KEY",
        "count": 1,
        "origin": "Consumer Events API",
        "period": "1h",
        "yle_id": "3-7961541"
    },
    "notifications": []
}

GET /v3/articles/pageviews/total.json Get total number of page views for an article

Get all time page views for any number of articles

Parameters

Name Required? Description
yle_id yes Comma separated list of yle ids (for example 3-123456,3-234567,3-345678)

Note! Multiple ids can be also given like this yle_id=3-123456&yle_id=3-234567&yle_id=3-345678

Response

200 OK on success

400 Bad Request if yle_id is missing or has invalid yle ids in it

If no data is found, data will be empty, and notifications will contain a message indicating the database found no logged view counts for the yle_id.

Examples

$ curl -XGET "https://consumer-events.api.yle.fi/v3/articles/pageviews/total.json?yle_id=3-7961541&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" |python -mjson.tool
{
    "data": [
        {
            "pageViews": 2190,
            "yleId": "3-7961541"
        }
    ],
    "meta": {
        "app_id": "YOUR_APP_ID",
        "app_key": "YOUR_APP_KEY",
        "count": 1,
        "origin": "Consumer Events API",
        "yle_id": "3-7961541"
    },
    "notifications": []
}

GET /v3/programs/streamstarts/delta.json Get number of stream starts during time period

Get the amount of stream starts for a program during the requested time period.

Parameters

Name Required? Description
yle_id yes The Yle ID of the article
period yes Time period, one of following: 30min, 1h, 6h, 12h, 24h, 2d, week, month

Response

200 OK on success

400 Bad Request if the yle_id or period parameters are missing or invalid

If no data is found, data will be empty, and notifications will contain a message indicating yle_id had no stream count data for the period.

Examples

$ curl "https://consumer-events.api.yle.fi/v3/programs/streamstarts/delta.json?yle_id=1-4226378&period=30min&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" |python -mjson.tool
{
    "data": [
        {
            "streamStarts": 10,
            "yleId": "1-4226378"
        }
    ],
    "meta": {
        "app_id": "YOUR_APP_ID",
        "app_key": "YOUR_APP_KEY",
        "count": 1,
        "origin": "Consumer Events API",
        "period": "30min",
        "yle_id": "1-4226378"
    },
    "notifications": []
}

GET /v3/programs/streamstarts/total.json Get total number of stream starts for a program

Get all time stream starts for any number of programs

Parameters

Name Required? Description
yle_id yes Comma separated list of yle ids (for example 1-123456,1-234567,1-345678)

Response

200 OK on success

400 Bad Request if yle_id is missing or has invalid yle ids in it

If no data is found, data will be empty, and notifications will contain a message indicating the database found no logged stream counts for the yle_id.

Examples

$ curl -XGET "https://consumer-events.api.yle.fi/v3/programs/streamstarts/total.json?yle_id=1-2163411&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" |python -mjson.tool
{
    "data": [
        {
            "streamStarts": 7942,
            "yleId": "1-2163411"
        }
    ],
    "meta": {
        "app_id": "YOUR_APP_ID",
        "app_key": "YOUR_APP_KEY",
        "count": 1,
        "origin": "Consumer Events API",
        "yle_id": "1-2163411"
    },
    "notifications": []
}

Email API

POST /v2/email/no-reply Send email to Yle Tunnus user without reply address

Send an email to a Yle Tunnus user without specifying an address to reply to.

Parameters must be sent as a JSON object in the request body. Clients should also add the Content-Type: application/json header.

Example request:

curl --request POST \
     --header 'Content-Type: application/json' \
     --data '{"subject": "YLE APIs", "recipientSurrogate": "5499aa14f4b0b721913fbe34", \
              "body": "<h1>YLE APIs are great!</h1>", "appId": "abcd1234", \
              "plaintextBody": "YLE APIs are great!", \
              "sendingApplication": "YLE verkkokehitys"}' \
     "https://email.api.yle.fi/v2/email/no-reply?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

Parameters

Name Required Description
subject Yes Subject of the message.
recipientSurrogate Yes Yle Tunnus surrogate key of the recipient.
body Yes Body of the message. Can contain HTML.
plaintextBody No Body of the message in plain text. If set, will be used as an alternative content alongside body. Using this lessens the chance that the mail is classified as spam.
appId Yes 4scale app id of the application which is requesting email to be sent. Used for gathering statistics.
sendingApplication Yes Name of the application which is requesting email to be sent. This will be displayed in the application logs.
useUnconfirmedEmail No boolean. Use the unconfirmed email of the profile. This is meant for changing user’s email.
usePreviousAddress No boolean. Use the previous email address of the profile. This is meant for post-notification after changing user’s email. Request will fail if user has not changed his address.

Response

200 OK on success

After receiving this response, the recipientSurrogate has been validated to belong to an active Yle Tunnus user, and an email is being delivered to that user. Receiving this response does NOT indicate that the message has actually been successfully delivered to the user.

400 Bad Request when recipientSurrogate is not found from Yle Tunnus

An active user was not found from Yle Tunnus with the given surrogate key.

400 Bad Request when sent data is not valid

Sent data was invalid in some way. Details are in response body.

400 Bad Request when email address is malformed

Email address might contain whitespace or control characters.

409 Conflict when recipient’s email address is marked as blocked

User’s email address is marked as blocked in Email API’s DB

500 Internal server error when the attempt to deliver the message failed

The attempt to deliver the email failed for some reason. Contact Yle API support for more details.

POST /v2/email Send email to Yle Tunnus user on behalf of another user

Send an email to a Yle Tunnus user on behalf of another user (using the From field).

Using this endpoint requires Google authentication by a user belonging to yle.fi organization. Acquire the user’s ID token and include it in Authorization header in format Bearer <id-token>.

Clients should also add the Content-Type: application/json header.

Parameters must be sent as a JSON object in the request body.

Example request:

curl --request POST \
     --header 'Content-Type: application/json' \
     --header 'Authorization: Bearer XYZ123456' \
     --data '{"subject": "YLE APIs", "recipientSurrogate": "5499aa14f4b0b721913fbe34", \
              "body": "<h1>YLE APIs are great!</h1>", "appId": "abcd1234", \
              "plaintextBody": "YLE APIs are great!", \
              "sendingApplication": "YLE verkkokehitys", \
              "fromAddress": "tanja.toimittaja@yle.fi"}' \
     "https://email.api.yle.fi/v2/email?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

Parameters

Name Required Description
subject Yes Subject of the message.
recipientSurrogate Yes Yle Tunnus surrogate key of the recipient.
body Yes Body of the message. Can contain HTML.
plaintextBody No Body of the message in plain text. If set, will be used as an alternative content alongside body. Using this lessens the chance that the mail is classified as spam.
appId Yes 4scale app id of the application which is requesting email to be sent. Used for gathering statistics.
sendingApplication Yes Name of the application which is requesting email to be sent. This will be displayed in the application logs.
fromAddress Yes The email address from which the email will appear to be sent from (the From field). The address must belong to the yle.fi domain.

Response

200 OK on success

After receiving this response, the recipientSurrogate has been validated to belong to an active Yle Tunnus user, and an email is being delivered to that user. Receiving this response does NOT indicate that the message has actually been successfully delivered to the user.

400 Bad Request when the fromAddress doesn’t belong to the yle.fi domain

The fromAddress doesn’t belong to the yle.fi domain.

400 Bad Request when recipientSurrogate is not found from Yle Tunnus

An active user was not found from Yle Tunnus with the given surrogate key.

400 Bad Request when sent data is not valid

Sent data was invalid in some way. Details are in response body.

400 Bad Request when email address is malformed

Email address might contain whitespace or control characters.

401 Unauthorized when Google ID token is not present in Authorization header

403 Forbidden when provided Google ID token verification failed

409 Conflict when recipient’s email address is marked as blocked

User’s email address is marked as blocked in Email API’s DB

500 Internal server error when the attempt to deliver the message failed

The attempt to deliver the email failed for some reason. Contact Yle API support for more details.

Event Reporting API

POST /v1/report_event.json Report event without media ID

Parameters

Name Description
operator Operator ID (dna, elisa, finnpanel, sonera, telia)
broadcastStartTime Original broadcast start time
channel Original broadcast TV channel (yle-tv1, yle-tv2, yle-teema, yle-fem, yle-teema-fem)
programName Program name as a string
startTime When user started to watch the program
deviceId Unique anonymous device identifier
duration Time spent on the program in seconds
streamType Type of the program stream (livetv, npvr)

Timestamps are formatted as ISO-8601 eg. 2014-06-12T07:50:00+0300

Body

NOTE: Access to this API is restricted to select partners only.

Does not take parameters apart from app_id and app_key

Requesters should add Content-Type: application/json; charset=utf-8 header.

Example:

curl -H 'Content-Type: application/json; charset=utf-8' -XPOST https://ev-report.api.yle.fi/v1/report-event.json?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY -d '{
  "channel": "yle-fem",
  "programName": "Tuntematon sotilas",
  "broadcastStartTime": "2016-02-08T10:00:10+0300",
  "streamType":"npvr",
  "startTime":"2016-02-08T10:10:10+0300",
  "deviceId":"ab34sdf43094nsd093fmksdaowe349vf",
  "duration": 123,
  "operator": "dna"
}'

Response

200 OK on success

{
    "notifications": [
        {
            "message": "Event information accepted."
        }
    ]
}

400 Bad request on invalid input

{
    "notifications": [
        {
            "message": "Missing required key 'streamType' from {\"channel\":\"yle-tv1\",\"programName\":\"Nousuvesi\",\"broadcastStartTime\":\"2016-09-15T23:15:00+0300\"}"
        }
    ]
}

Program info

More info about programs can be queried from Programs API

POST /v1/report_event.json Report event with media ID

It is also possible to submit events using media and publication event IDs from public Yle APIs. In this case the broadcast time, channel and program name are not needed.

Parameters

Name Description
operator Operator ID (dna, elisa, finnpanel, sonera, telia)
mediaId The Yle ID of the specific media content
publicationEventId The Yle ID of the publication event, which identifies the exact broadcast time and channel
startTime When user started to watch the program
deviceId Unique anonymous device identifier
duration Time spent on the program in seconds
streamType Type of the program stream (livetv, npvr)

Timestamps are formatted as ISO­8601 eg. 2014-06-12T07:50:00+0300

Body

NOTE: Access to this API is restricted to select partners only.

Does not take parameters apart from app_id and app_key

Requesters should add Content-Type: application/json; charset=utf-8 header.

Example:

curl -H 'Content-Type: application/json; charset=utf-8' -XPOST https://ev-report.api.yle.fi/v1/report-event.json?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY -d '{
  "mediaId": "1-2620819",
  "publicationEventId": "1-3067063",
  "streamType":"npvr",
  "startTime":"2016-02-08T10:10:10+0300",
  "deviceId":"ab34sdf43094nsd093fmksdaowe349vf",
  "duration": 123,
  "operator": "dna"
}'

Response

200 OK on success

{
    "notifications": [
        {
            "message": "Event information accepted."
        }
    ]
}

400 Bad request on invalid input

{
    "notifications": [
        {
            "message": "Missing required key 'streamType' from {\"channel\":\"yle-tv1\",\"programName\":\"Nousuvesi\",\"broadcastStartTime\":\"2016-09-15T23:15:00+0300\"}"
        }
    ]
}

Program info

More info about programs can be queried from Programs API

Identification API

General information

Identification API provides strong authentication for Yle Tunnus users.

Services

The API has endpoints for:

  • initiating an identification process
  • querying the status of an identification process
  • receiving authentication assertions from the identity provider

Terminology

  • an identification process spans from the beginning (where we have no information about a user) to the end (where we know the status of their residence)
  • an Identification ID refers to a unique identification process

GET /v1/authenticate Initiate user identification

Request to this endpoint initiates an identification process for the currently logged in Yle Tunnus user, by strongly authenticating the user via an identity prodivder. This endpoint is meant to be used from a browser context.

Yle Tunnus user is identified by Yle login cookie, which must be present in the request.

Performance test results for this endpoint can be found here.

URL Parameters

Name Type Required Description
returnToUrl string yes An URL where the user should be redirected to, after identification completes (either successfully or with a failure). The URL protocol must be either https:// or yleareena://, and domain must be either tunnus.yle.fi or areena.yle.fi
language string yes The language to use in authentication flow, must be fi or sv.

Response

200 OK on success

Response body is a JSON object that contains a redirectTo attribute.

  • redirectTo is an URL that points to the identity provider. To continue with the identification process, browser should be redirected to this URL. The URL must not be modified by the client.

Redirect URI is not provided as a regular 302 Redirect to allow the client to display some information to the end user, before the redirect takes place.

Example response body
{
  "redirectTo": "https://my-identity-provider.fi/SAML2/foobar"
}

400 Bad Request when returnToUrl is missing or invalid

GET /v1/identification/{identificationId} Get identification process status

Request to this endpoint returns the status of an identification process that was initiated by calling the /v1/authenticate endpoint.

Yle Tunnus user is identified by Yle login cookie, which must be present in the request.

Performance test results for this endpoint can be found here.

Path parameters

Name Description
identificationId ID of the identification process returned by the /v1/authenticate endpoint.

Response

200 OK on success

Response body is a JSON object that contains a status attribute and an optional residenceInFinland attribute.

  • status is one of the following:
    • "pending", if the identification process is still in progress
    • "failure", when the idenfication process did not complete successfully
    • "success", when the identification process has completed successfully
  • residenceInFinland attribute exists when the status attribute is "success", in which case it is either:
    • true when user’s home municipality was confirmed to be located in Finland
    • false when user’s home municipality was not in Finland
Example response bodies
{
  "status": "pending"
}
{
  "status": "success",
  "residenceInFinland": true
}
{
  "status": "failure"
}

404 Not Found when an identification process was not found with the given event ID

POST /v1/assertion Receive authentication assertion

Request to this endpoint indicates that an identification process has completed. This endpoint is meant to be used by the identity provider.

After the provided assertion has been processed, client is redirected to the logout endpoint of the identity provider, which calls the logout endpoint of Identification API.

Form parameters

Parameters should be sent within an application/x-www-form-urlencoded form.

Name Type Required Description
SAMLResponse string yes Authentication assertion that represent’s the user’s login security context.
RelayState string yes Matches with the identification_id which was established when the identification process was initiated.

Response

302 Found on success

On success, the redirect URL contains the following query parameters:

  • SAMLRequest, which is a logout request for the identity provider
  • RelayState, for tracking the identification flow
  • SigAlg, a reference to the signature algorithm
  • Signature, base64-encoded request signature

400 Bad Request when required parameter is missing or invalid, or processing of assertion failed

POST /v1/logout Receive Single Logout response

A request to this endpoint indicates that the Identity Provider (IdP) has initiated the Single Logout (SLO) process using the HTTP-POST binding.

Request

The request body must contain a SAML 2.0 LogoutRequest message and a RelayState query parameter, which matches with the identification_id which was established when the identification process was initiated.

Response

302 Found on success

The client is redirected to the returnToUrl, which was defined when identification process was initiated.

400 Bad Request when the LogoutRequest or RelayState values are missing or invalid

Images API

GET /v1/images/{id}.json Get image

Retrieves the data of a single image by its ID.

Parameters

Name Description
id The ID of the image

Response

200 OK on success

Response is a JSON document that contains the data of the requested image. Please refer to Cloudinary documentation (Browse Resources -> Details of a single resource) for more detailed description of the image attributes.

400 Bad Request if request was invalid or it could not be processed successfully

404 Not Found If an image is not found with the given id

POST /v1/upload/image.json Upload image from remote URL

Publishes a new image by its remote URL, or updates an existing one. In addition to storing the actual image, EXIF data and metadata is extracted from the image and stored for later use.

NOTE: Access to this API is restricted to select partners only.

Request

Request does not take query parameters apart from app_id and app_key.

Clients should add Content-Type: application/json header.

The following parameters should be included in request body in a JSON document.

Name Required? Description
public_id yes Public id of the image to be uploaded. ID should be prefixed with 13- (See Yle ID prefixes).
source_url yes Remote URL where the image is currently located.
no_cmyk no When set to “true”, adds an incoming transformation converting CMYK images to RGB in Cloudinary.

Response

200 OK on success

Response is a JSON document that contains the data of the requested image (including metadata, EXIF etc.).

400 Bad Request if request was invalid or the upload could not be completed successfully

If the request failed due to an error in the Cloudinary end, the response will contain a JSON document with the Cloudinary error message and HTTP status code.

{
  "message": String, // error message
  "http_code": Integer // HTTP status code
}

POST /v1/upload/image Upload image from binary file

Publishes a new image (or updates an existing one) from a binary file. In addition to storing the actual image, EXIF data and metadata is extracted from the image and stored for later use.

NOTE: Access to this API is restricted to select partners only.

Request

Request does not take query parameters apart from app_id and app_key.

The following parameters should be included in request.

Name Required? Description
public_id yes Public id of the image to be uploaded. ID should be prefixed with 13- (See Yle ID prefixes).
image yes The actual image file.
no_cmyk no When set to “true”, adds an incoming transformation converting CMYK images to RGB in Cloudinary.

Example:

curl -F "public_id=13-1-1234567890" \
  -F "image=@/home/your-local-image.png" \
  -X POST "https://images.api.yle.fi/v1/upload/image?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

Response

200 OK on success

Response is a JSON document that contains the data of the requested image (including metadata, EXIF etc.).

400 Bad Request if request was invalid or the upload could not be completed successfully

If the request failed due to an error in the Cloudinary end, the response will contain a JSON document with the Cloudinary error message and HTTP status code.

{
  "message": String, // error message
  "http_code": Integer // HTTP status code
}

DELETE /v1/images/{id}.json Remove image

Removes an existing image.

NOTE: Access to this API is restricted to select partners only.

Request

Parameters

Name Description
id ID of the image to be removed.

Response

200 OK when image was removed successfully

{
  "public_id": String // Public id of the removed image
}

400 Bad Request request was invalid or image could not be removed

Json storage API

General information

JSON Storage API allows you to store and retrieve JSON documents. It supports two use cases:

1) Single document storage, where you store a single JSON document, and optionally define a schema which the document must conform with.

2) Collection of multiple documents, where you define a schema, and store multiple documents which must conform with that schema.

In both use cases, everyone with access to JSON Storage API is allowed to retrieve the documents, but only the creator of the document can modify or delete the document or its schema. Thus, the API must not be used for storing confidential data.

Schemas are defined as JSON schemas. See JSON schema description for more information.

GET /v1/storage/{id} Get a single JSON document

Retrieve a single JSON document (that is not part of a collection).

If the document is an array, you can select a slice from it by using the limit and offset parameters.

Parameters

Name Required? Description
id yes The ID of the JSON document.
limit no Take the specified number of elements from the array. Can only be used when the document is an array.
offset no Drop the specified number of elements from the beginning of the array. Can only be used when the document is an array.

Response

200 OK on success

404 Not Found if the document doesn’t exist

Examples

Retrieve a stored JSON document

$ curl -XGET "https://json-storage.api.yle.fi/v1/storage/areenan-suosituimmat?app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"
["Docventures", "A-Studio", "Prisma", "Uutisvuoto", "Kioski"]

Retrieve a stored JSON document (with limit)

$ curl -XGET "https://json-storage.api.yle.fi/v1/storage/areenan-suosituimmat?limit=3&app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"
["Docventures", "A-Studio", "Prisma"]

Retrieve a stored JSON document (with limit and offset)

$ curl -XGET "https://json-storage.api.yle.fi/v1/storage/areenan-suosituimmat?limit=3&offset=1&app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"
["A-Studio", "Prisma", "Uutisvuoto"]

PUT /v1/storage/{id} Insert/update a single JSON document

Insert or update a single JSON document (that is not part of a collection). Upon document creation, the 4scale app_id from the request will be marked as the owner of the document. From then on, only the owner of the document will be allowed to modify or delete it. However, everyone with access to JSON Storage API will be able to retrieve the document, so do not use the API for storing confidential data.

Parameters

Name Description
id The ID of the JSON document
app_id 4scale app id

Body

The JSON document. Maximum allowed size of the document is 2048 Kb.

Response

200 OK document was inserted/updated successfully

400 Bad Request if the document is too large, doesn’t conform with its schema or contains invalid JSON data

401 Unauthorized if the document already exists, and is owned by a different app_id

Examples

Insert or update a JSON document

$ curl -XPUT -H "Content-Type: application/json" \
  --data '["Docventures", "A-Studio", "Prisma", "Uutisvuoto", "Kioski"]' \
  "https://json-storage.api.yle.fi/v1/storage/areenan-suosituimmat?app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"
{"msg":"Ok"}

DELETE /v1/storage/{id} Delete a single JSON document

Delete a single JSON document (that is not part of a collection).

This operation will not delete the schema of the document, if one exists.

Parameters

Name Description
id The ID of the JSON document

Response

200 OK document was deleted successfully

401 Unauthorized if the document is owned by a different app_id

404 Not Found if the document doesn’t exist

Examples

Delete a JSON document

$ curl -XDELETE "https://json-storage.api.yle.fi/v1/storage/areenan-suosituimmat?app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"
{"msg":"Ok"}

GET /v1/schema/{documentId} Get the JSON schema of a single JSON document

Retrieve the JSON Schema of a single stored JSON document (that is not part of a collection).

Parameters

Name Description
documentId The ID of the JSON document

Response

200 OK on success

Response is a JSON object with data attribute that contains the schema JSON.

404 Not Found if the schema doesn’t exist

cURL example

curl "https://json-storage.api-test.yle.fi/v1/schema/areenan-suosituimmat?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{"data":"{\"type\": \"array\"}"}

PUT /v1/schema/{documentId} Set the JSON schema for a single JSON document

Set a JSON Schema for a single stored JSON document (that is not part of a collection). The API guarentees that the document will always conform to the schema. If the document exists but doesn’t conform to the schema, the schema is rejected.

Parameters

Name Description
documentId The ID of the JSON document

Body

The JSON schema

Response

200 OK on success

400 Bad Request if the schema is invalid or the document doesn’t conform to the schema

401 Unauthorized if the document is owned by a different app_id.

cURL example

Enforce minimalistic schema (JSON root must be array)

curl -XPUT -H "Content-Type: application/json" \
  --data '{"type": "array"}' \
  "https://json-storage.api-test.yle.fi/v1/schema/areenan-suosituimmat?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

DELETE /v1/schema/{documentId} Delete the JSON schema of a single JSON document

Delete the JSON Schema of a single stored JSON document (that is not part of a collection). This operation will not delete the document itself.

Parameters

Name Description
documentId The ID of the JSON document

Response

200 OK on success

401 Unauthorized if the document is owned by a different app_id

404 Not Found if the schema doesn’t exist

cURL example

curl -XDELETE "https://json-storage.api-test.yle.fi/v1/schema/areenan-suosituimmat?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

POST /v1/collection/{collectionId} Create a collection

Create a new collection of documents.

Collection must have a schema that defines the structure of the documents to be stored. This schema is immutable - in other words, it cannot be altered after the collection has been created.

Upon collection creation, the parameter app_id from the request will be marked as the owner of the collection. Only the owner of the collection will be allowed to create, update, or delete documents of the collection. However, everyone with access to JSON Storage API will be able to retrieve the documents. This means that you must not use this API for storing confidential data.

Path parameters

Parameter Description
collectionId ID of the collection. It must be unique, between 3-50 characters in length, and contain only the following characters: a-z, 0-9, and -.

Query parameters

Name Description
app_id This will be the owner of the collection.

Request body

Request body must be a JSON object with the following attributes.

Name Description
schema JSON schema for documents to be stored in the collection

Response

200 OK collection was created successfully

400 Bad Request if the collection ID or its schema is invalid

409 Conflict if the collection already exists

Examples

Create a collection

$ curl -XPOST -H "Content-Type: application/json" \
  --data '{"schema": {"type": "object", "additionalProperties": false, "properties": {"id": {"type": "string"}}}}' \
  "https://json-storage.api.yle.fi/v1/collection/ims-images?app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"

GET /v1/collection/{collectionId} Retrieve information of a collection

Retrieves the information of a collection.

Path parameters

Parameter Description
collectionId ID of the collection

Response

200 OK collection was created successfully

Response body contains a JSON object describing the collection (see example request below).

404 Not Found if the collection does not exist

Example request

$ curl -XGET "https://json-storage.api.yle.fi/v1/collection/ims-images?app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"

{
  "documentCount": 1,
  "owner": "OTHER_APP_ID",
  "schema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "id": {
        "type": "string"
      }
    }
  }
}

GET /v1/collection/{collectionId}/document/{documentId} Get document from a collection

Retrieves document from a collection.

Path parameters

Name Description
collectionId ID of the collection
documentId ID of the document

Response

200 OK when successful

Response body contains the JSON document wrapped inside a data attribute.

404 Not Found if the document or collection does not exist

Examples

Get a JSON document

$ curl -XGET "https://json-storage.api.yle.fi/v1/collection/ims-images/document/33-123456?app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"

PUT /v1/collection/{collectionId}/document/{documentId} Create or update document in a collection

Creates or updates a document in a collection.

The document must conform with the schema defined at the collection level.

Path parameters

Name Description
collectionId ID of the collection
documentId ID of the document. It must be unique in the context of the collection, be between 3 to 50 characters in length, and contain only the following characters: a-z, 0-9, and -.

Body

Request body must contain the document, which must be a JSON object that conforms with the schema of the collection.

Response

200 OK document was updated successfully

400 Bad Request if the document does not conform with the schema or contains invalid JSON data

401 Unauthorized if the requester is not the owner of the collection

404 Not Found if the collection or the document does not exist

Examples

Add a new document to a collection

$ curl -XPUT -H "Content-Type: application/json" --data '{"width": 200, "height": 200}' \
  "https://json-storage.api.yle.fi/v1/collection/ims-images/document/33-123456?app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"

DELETE /v1/collection/{collectionId}/document/{documentId} Delete document from a collection

Deletes a document from a collection.

Path parameters

Name Description
collectionId ID of the collection
documentId ID of the document

Response

200 OK document was deleted successfully

401 Unauthorized if the requester is not the owner of the collection

404 Not Found if the collection or the document does not exist

Examples

Delete JSON document from a collection

$ curl -XDELETE "https://json-storage.api.yle.fi/v1/collection/ims-images/document/33-123456?app_id=YOUR_ADD_ID&app_key=YOUR_APP_KEY"

Consume collection using queue - REST MQ API

JSON Storage API publishes all create, update, and delete events for documents in collections to REST MQ API. You can consume these events by creating an HTTP endpoint in your application for receiving the data, and then registering a consumer in REST MQ API.

Registering a consumer in REST MQ API

To register a consumer, you need to know the id of the collection to be consumed, and come up with an id for your consumer. Then issue an HTTP PUT request to the following URI:

https://rest-mq.api.yle.fi/v1/queue/json-storage-api_{collection-id}/consumer/{consumer-id}

Parameters in URI are defined as follows:

Parameter Description
collection-id ID of the collection to be consumed
consumer-id ID of your consumer

Consumer id should be human readable and describe the consuming application (for example, articles-api-v2).

Request body

Request body must contain a JSON object with callback attribute at its root. Callback object defines your application’s endpoint that will receive the JSON Storage API collection events.

Callback attribute Description
url URI of the endpoint that will consume the events. For example, https://articles.api.yle.fi/v2/events/image-changes?app_id=APP_ID&app_key=APP_KEY.
method HTTP method of your consuming endpoint. Must be either POST or PUT.

It is important to include API key parameters app_id and app_key in the callback url, if your application is authorized by 4scale. This API key must have access to the consuming endpoint - otherwise the events will not reach your application.

Response

200 OK consumer was registered successfully

400 Bad Request if required parameters were missing or invalid

Example request

$ curl -XPUT -H "Content-Type: application/json" \
  "https://rest-mq.api.yle.fi/v1/queue/json-storage-api_ims-images/consumer/test-api?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --data '{"callback": { \
             "url": "https://articles.api.yle.fi/v2/events/image-changes?app_id=APP_ID&app_key=APP_KEY", \
             "method": "post" \
           }}'

Receiving events from JSON Storage API

After the consumer has been registered successfully, you will receive the events from JSON Storage API in the consumer endpoint. These requests will contain JSON body with the following attributes:

Attribute Description
eventType create, update, or delete
id Id of the document
document The related collection item from JSON Storage API

Consume collection using queue - RabbitMQ

JSON Storage API publishes all create, update, and delete events for documents in collections to Yle RabbitMQ. To consume these events, create a queue in RabbitMQ, and set up a binding for that queue with the following configuration:

Exchange Routing key
exchange.api.internal json-storage-api.{collection-id}.changes

For example, to consume events for collection ims-image, the routing key would be json-storage-api.ims-image.changes.

You will then receive the events in the queue with the following properties:

Message property Description
contentType application/json
header event_type create, update or delete
header json_storage_api_collection_id id of the collection in JSON Storage API
message payload the related JSON document

JSON Schema description

You can optionally use a JSON Schema to validate the structure of your JSON documents. For a detailed guide about how to write JSON Schemas, see this tutorial.

Example JSON Schema:

{"type": "array",
 "items": {"type": "object",
 "required": ["title", "meta"],
 "properties": {
    "someOptionalData": {
      "type": "integer",
      "minimum": 0,
      "exclusiveMinimum": true},
    "title": {"type": "string"},
    "meta": {
      "type": "object",
      "additionalProperties": false,
      "required": ["subject"],
      "properties": {"subject": {"type": "string"}}}}}}

Locations API

GET /v1/address/current Get location by current address (IP)

Can be used to get location information.

Response

Possible keys in a successful response body can be one or more from the following: continent, country_code, region_code, asnum, eu.

200 OK on success

  {
    continent: "EU",
    country_code: "FI",
    asnum: "719",
    eu: true
  }

200 OK with an empty body ( {} ) if no location is found

cURL example

Get your current location

curl -XGET https://locations.api.yle.fi/v1/address/current?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

GET /v1/address/{ipAddress} Get location by given address (IP)

Can be used to get location information by given IP address. Both IPv4 and IPv6 addresses are supported.

Response

Possible keys in a successful response body can be one or more from the following: country_code, continent, region_code, asnum, eu.

200 OK with a body containing location information on success

  {
    country_code: "FI",
    continent: "EU",
    asnum: "719",
    eu: true
  }

200 OK with an empty body ( {} ) if no location is found

400 Bad Request if the given IP address is invalid

cURL example

Get your current location

curl -XGET https://locations.api.yle.fi/v1/address/84.231.157.149?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

Logger API

General information

Log to YLE Kibana from browsers and native applications using Logger API.

To log you will need app_id and app_key. Each app_id will be limited to 7200 requests per day for now.

You can filter Kibana logs using the app_id and ecs_service

Example Kibana filter:

ecs_service:"logger-api" AND "App-id tunnusylefi_logging_prod"

POST /v1/errors Log errors to Yle Kibana

Use content type “application/json”.

Body parameters parameters

Body parameters are not required nor is there any logic attached to any body params.

Response

200 OK on success

cURL example

$ curl -v -XPOST "https://logger.api.yle.fi/v1/errors?app_id=APP_ID&app_key=APP_KEY" \
       --data '{"message": "Hello \n world!"}' -H "content-type: application/json"

POST /v1/warnings Log warnings to Yle Kibana

Use content type “application/json”.

Body parameters parameters

Body parameters are not required nor is there any logic attached to any body params.

Response

200 OK on success

cURL example

$ curl -v -XPOST "https://logger.api.yle.fi/v1/warnings?app_id=APP_ID&app_key=APP_KEY" \
       --data '{"message": "Hello \n world!"}' -H "content-type: application/json"

Login API

POST /v1/user/login Log in using email and password

Logs user in with email and password.

Parameters

These parameters should be transmitted in request body, not in query string. Remember to set Content-Type: application/x-www-form-urlencoded; charset=utf-8 header.

Name Required? Description
username yes Email address
password yes Password
accepted_tos_version no/yes The version number of accepted TOS in YYYYMMDD-<revision> format eg. 20180405-1. Required when user has not accepted the latest TOS and the TOS acceptance has been flagged as required in Login API. Response will be 409 Terms of service not accepted in this case. User should then be asked to accept ToS and try to login again with this parameter set.
with_token no If set, the response will include a temporary token that can be exchanged to a session token using GET /v1/user/session.

Response

OK responses set ylelogin cookie (secure, http-only). This is used to authenticate requests to Login API endpoints and to Profiles API.

Example response cookie header:

Set-Cookie: ylelogin=YmUyNDUxMDQtYWNkNS20Y2QULTlHODAtOTY1YzliOWRjADkz; Domain=.yle.fi; HttpOnly; path=/; expires=Tue, 10 May 2016 04:32:43 GMT; secure

200 OK if log in succeeded

{
  "userId": "USERID",
  "nick": "NICK",
  "nickUpdatedAt": "2018-08-22T09:58:09+0300",
  "latestTermsOfServiceAccepted": true | false,
  "token": "TEMPORARY TOKEN"
}

latestTermsOfServiceAccepted tells you if the user has accepted the latest Terms of Service. token is included only if with_token was set.

401 Unauthorized when submitted username or password is invalid

Login failed!

400 Bad Request if password is too short

{ "message": "Parameter password value '<password>' is too short. Value must be at least 6 chars", "errorCode": "password_value_was_is_too_short" }

409 Terms of service not accepted when TOS acceptance has been flagged as required and user has not accepted latest terms

{ "message": "Latest terms of service not accepted", "errorCode": "terms_of_service_not_accepted"}

User should be asked to accept the latest ToS and then try the login again this time with accepted_tos_version parameter. Or if that is not possible, they should be directed to https://tunnus.yle.fi to accept the terms.

Curl examples

curl -XPOST -c - -H "Content-Type: application/x-www-form-urlencoded; charset=utf-8" --data 'username=YOUR_EMAIL&password=YOUR_PASSWORD' "https://login.api.yle.fi/v1/user/login?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

This should set secure cookie with name ylelogin and show it on a terminal. You will need that cookie for further Login API calls.

GET /v1/user/login Check and refresh session

Checks whether user is logged in and if user has successfully completed verification (meaning that the user is not likely a bot). Please note that the session expires may also be updated when this endpoint is called unless the refreshSession parameter is set to false.

Parameters

Name Required? Description
refreshSession no default true

Request

The request must contain the ylelogin (or yletestlogin in the test environment) cookie to succeed.

Response

200 OK if user is logged in

{ "userId": "USERID",
  "username": "user@email.fi"
  "nick": "NICK",
  "nickUpdatedAt": "2018-08-22T09:58:09+0300",
  "verifications": [],
  "latestTermsOfServiceAccepted": true|false,
  "residenceInFinland": true|false,
  "initials": "US"}

verifications array contains a list of verification types that the user has successfully completed at some point. Currently the only supported verification type is 'sms'.

latestTermsOfServiceAccepted tells you if the latest Terms of Service has been accepted by the user.

The residenceInFinland attribute indicates whether the user’s municipality of residence is in Finland or not (as determined by Identification API). If the attribute is not present, the user has not verified their municipality of residence.

The initials attribute is generated from the username (email) and contains one or two letters. If for some reason initials cannot be generated from the email, the returned value will be “-“.

Note! If session has been created more than 24 hours ago and refreshSession is not set to false, session token will be updated using Set-Cookie header in response. Example:

Set-Cookie:ylelogin=YmUyNDUxMDQtYWNkNS20Y2QULTlHODAtOTY1YzliOWRjADkz; Domain=.yle.fi; HttpOnly; path=/; expires=Tue, 10 May 2016 04:32:43 GMT; secure

401 Unauthorized when user is not logged in

{"message": "The API call requires a valid session. Log in again", "errorCode": "no_session"}

Curl examples

$ curl --header 'Cookie: ylelogin=YOUR_VALID_LOGIN_COOKIE' "https://login.api.yle.fi/v1/user/login?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

DELETE /v1/user/login Log out

Logs out currently logged in user.

Request

The request must contain ylelogin cookie.

Response

200 OK

{ "status": "OK" }

401 Unauthorized when user is not logged in

{ "message": "The API call requires a valid session. Log in again", "errorCode": "no_session" }

GET /v1/account/checkNickAvailability?nick={nick} Check nick availability

Check if given nick is available.

Query parameters

These parameters should be transmitted in query string.

Name Required? Description
nick yes Nick to be checked

Nick must be at least 2 and at most 50 characters long. It must match pattern ^[\w \d \- äöåÄÖÅÀÂÆÇÈÉÊËÌÍÎÏÒÓÔØÙÚÛÜàâæçèéêëìíîïòóôøùúûüÿĄąĆćĘꣳŃńŒœŚŜŠśŝšŸŹźŻż_]+$. Also, it must not begin with words anonyymi or anonym (case-insensitive) which are reserved for automatically generated nicks.

Request

The request must contain ylelogin cookie.

Response

200 OK if nick is available

{ "status": "OK" }

401 Unauthorized Request when user is not logged in

{"message": "The API call requires a valid session. Log in again","errorCode": "no_session"}

400 Bad Request Errors

The endpoint will return 400 error with specific errorCode when nick is already reserved or not a valid nick.

Example response:

{ "message": "Missing parameter 'nick'", "errorCode": "parameter_nick_is_missing" }

Possible error codes in the table below.

Error code Description
parameter_nick_is_missing Nick to be checked is missing from the query parameters
nick_is_already_taken Nick is already in use by other user
nick_has_invalid_value Nick contains characters that are not allowed
nick_has_reserved_word Nick begins with a reserved word
nick_value_was_is_too_short Nick does not fulfill the requirement for minimum length
nick_value_was_is_too_long Nick exceeds the maximum allowed length

Examples

Check if a nick is available

curl -X GET --header 'Cookie: ylelogin=YOUR_VALID_LOGIN_COOKIE' 'https://login.api.yle.fi/v1/account/checkNickAvailability?nick=thisNickIsFree&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY'

POST /v1/account/nick Set user nick

Sets user nick

Parameters

These parameters should be transmitted in request body, not in query string. Remember to set Content-Type: application/x-www-form-urlencoded; charset=utf-8 header.

Name Required? Description
nick yes New nick for user
userid yes NEW: This parameter must contain the id of the user.

Nick must be at least 2 and at most 50 characters long. It must match pattern ^[\w \d \- äöåÄÖÅÀÂÆÇÈÉÊËÌÍÎÏÒÓÔØÙÚÛÜàâæçèéêëìíîïòóôøùúûüÿĄąĆćĘꣳŃńŒœŚŜŠśŝšŸŹźŻż_]+$. Also, it must not begin with words anonyymi or anonym (case-insensitive) which are reserved for automatically generated nicks.

Request

The request must contain ylelogin cookie.

Response

200 OK if everything works

{ "status": "OK" }

401 Unauthorized Request when user is not logged in

{"message": "The API call requires a valid session. Log in again","errorCode": "no_session"}
{"message": "Authentication failed","errorCode": "authentication_failed"}

400 Bad Request Reserved Nick

{ "message": "User nick '<nick>' is already taken", "errorCode": "nick_is_already_taken" }

400 Bad Request Missing Nick

{ "message": "Missing parameter 'nick'", "errorCode": "parameter_nick_is_missing" }

400 Bad Request Invalid Nick ( with nick that has not been trimmed, contains bad characters )

{ "message": "Parameter nick value '<nick>' was invalid", "errorCode": "nick_has_invalid_value" }

400 Bad Request Invalid Nick ( nick begins with a reserved word )

{ "message": "Parameter nick '<nick>' contains reserved word", "errorCode": "nick_has_reserved_word" }

POST /v1/account/password Change password

Changes user’s current password.

Requires an active session (ylelogin cookie must be present)

Parameters

These parameters should be transmitted as keys of json object in request body. Remember to set Content-Type: application/json; charset=utf-8 header.

Parameter name Required? Description
oldPassword yes Previous password
newPassword yes New password

New password must be at least 6 characters and at most 500 characters long. It may contain letters, numbers, spaces, and the following characters: !@$#%^&*()_-+={}[]|:;?,./<>§\"´`'€¨°~

Response

200 OK after password has been changed successfully

{ "status"  : "OK" }

400 Bad Request if the password did not meet the validation criteria

{ "errorCode" : "password_contains_unsupported_characters" }

400 Bad Request if requested for user that uses Facebook authentication

{ "errorCode" : "facebook_password_change_not_supported" }

401 Unauthorized when the old password does not match

{ "errorCode" : "authentication_failed" }

401 Unauthorized when user is not logged in or the session has been inactivated

{ "errorCode" : "no_session" }

POST /v1/account/requestChangePasswordEmail Request forgotten password

Requests change of forgotten password. This will send a link to the provided email address that can be used to reset password.

Note that 200 OK is returned even if there is no user with the provided email address. This is to prevent fishing of email addresses from the system.

Parameters

These parameters should be transmitted in request body, not in query string. Remember to set Content-Type: application/x-www-form-urlencoded; charset=utf-8 header.

Name Required? Description
email yes User’s email address
language no Preferred language of the email (fi or sv, defaults to fi)

Response

{ "status"  : "OK" }

400 Bad Request if the request parameters don’t pass validation

{ "errorCode" : "parameter_email_is_missing" }

GET /v1/stats/accounts Get number of registered users

Lists the number of registered users, as defined in the parameters.

Parameters

Filtering

Name Description
registered_after Take into account only those users who registered after this date (inclusive).
registered_before Take into account only those users who registered before this date (inclusive).

Dates must be in format yyyy-MM-dd.

Other

Name Description
group_by Comma-separated list of fields that the results should be grouped by. If not given, only the grand total number of users will be returned. Valid values are app_id (which means the service that the user originated from when registering), initiating_component (name of component where the registration action was initiated in), and registration_date.

Examples

Get total number of registered users

https://login.api.yle.fi/v1/stats/accounts?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY

Response:

{
    "data":
    [
        {
            "count": 155717
        }
    ]
}

Get number of registered users in a single month

https://login.api.yle.fi/v1/stats/accounts?registered_after=2015-12-01&registered_before=2015-12-31&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY

Response:

{
    "data":
    [
        {
            "count": 30614
        }
    ]
}

Get number of registered users by service

https://login.api.yle.fi/v1/stats/accounts?group_by=app_id&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY

Response:

{
    "data":
    [
        {
            "registeredAppId": "5rMM3hDK",
            "count": 2562
        },
        {
            "registeredAppId": "6BeEWqbT",
            "count": 473
        },
        {
            "registeredAppId": "9EsTfMhL",
            "count": 11
        },
        {
            "registeredAppId": "hJzAsh68",
            "count": 6532
        },
    ]
}

Get number of registered users by service and registration date

https://login.api.yle.fi/v1/stats/accounts?group_by=app_id,registration_date&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY

Response:

{
    "data":
    [
        {
            "registeredAppId": "5rMM3hDK",
            "data":
            [
                {
                    "registrationDate": "2015-12-01",
                    "count": 14
                },
                {
                    "registrationDate": "2015-12-02",
                    "count": 25
                },
                ...
            ]
        },
        ...
    ]
}

GET /v1/account/checkToken?token={token} Check token

Check if given token is valid and available.

Query parameters

These parameters should be transmitted in query string.

Name Required? Description
token yes Token to be checked

Response

200 OK if token is available

{ "status": "OK" }

400 Bad Token Errors

The endpoint will return 400 error with specific errorCode when token is not available or has been expired.

Example response:

{"message":"Not a valid token","errorCode":"bad_token"}

Example

curl -X GET 'https://login.api.yle.fi/v1/account/checkToken?token=abcd1234&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY'

heading Registration

Normal registration occurs by calling two endpoints, where the first one registers a user, and the second one activates it.

POST /v3/register/email Register user with email

Pay attention to the version number in the URL. This API endpoint has been upgraded to version 3.

Registers a new Yle Tunnus user. After this call, the email address will be validated by sending an activation link to the users email address.

After the user has opened the activation link, they will be redirected to return_to_url. In case return_to_url was not given, it will default to a welcome page under tunnus.yle.fi

Note that 200 OK is returned even if user with the same email address has already been registered. This is to prevent phishing of email addresses from the system.

NOTE: The specified return_to_url must have hostname yle.fi or hostname ending to .yle.fi. This is needed to prevent spamming users with arbitrary links.

Parameters

These parameters should be transmitted in request body, not in query string. Remember to set Content-Type: application/x-www-form-urlencoded; charset=utf-8 header.

Name Required? Description
email yes Email address
password yes Password. Max length 500 chars
birth_year yes Birth year in YYYY format
birth_month yes Birth month in M format
accepted_tos_version yes The version number of accepted TOS in YYYYMMDD-<revision> format eg. 20180405-1.
gender no male, female, other or prefer_not_to_say
return_to_url no URL to return to after user has successfully completed registration. Must be in yle.fi domain over HTTPS.
personal_recommendations no Allow sending personal recommendations to user’s email. If given, must be true or false
marketing_consent no This parameter is not in use anymore.
initiating_app no 4scale app_id of application which initiated the registration. This is collected for statistical purposes. Use this only when your application is initiating registration on behalf of another application. Otherwise this information is inferred from the app_id authentication parameter.
initiating_component no Name of the component where registration action was initiated in. Currently supported values are forum, header, oauth and survey. This is collected for statistical purposes. Contact API team or Yle Tunnus Support if you need a new component name for your use case.

The password must be at least 6 characters and at most 500 characters long. It may contain letters, numbers, and the following characters: !@$#%^&*()_-+={}[]|:;?,./<>§\"´`'€¨°~

Response

200 OK if registration succeeded:

{ "status" : 200 }

400 Bad Request when submitted parameters were invalid

{ "message" : "Error message", "errorCode" : "error_code" }

GET /v1/register/activate Activate user

This endpoint is used to activate and log in an inactive user that has been initialized with a normal registration flow.

Body parameters

These parameters must be transmitted in the request body (not as query parameters). Remember to set the Content-Type: application/x-www-form-urlencoded; charset=utf-8 header.

Name Required Description
token yes Token received in the verification link when starting a normal registration
language no User’s preferred language ("fi" or "sv")
returnToUrl no URL to return to after the user has successfully completed registration. Must be in yle.fi domain over HTTPS. If no URL is provided, user is redirected to Yle Tunnus site.

Response

200 OK with an HTML body describing successful activation, if everything went well.

Example body:

<html>
<head>
  <meta http-equiv="refresh" content="0; url=https://tunnus.yle.fi/tervetuloa" />
  <title>Yle Tunnus</title>
</head>
<body>
Yle Tunnuksesi on aktivoitu.
</body>
</html>

401 Unauthorized with an HTML body describing the error, if token has been already used or is not found.

Example body:

<html>
<head>
  <title>Yle Tunnus</title>
</head>
<body>
Aktivointilinkkisi Yle Tunnuksessa on joko käytetty tai vanhentunut.
</body>
</html>

POST /v1/register/activate Activate user

This endpoint is used to activate and log in an inactive user. There is also an older endpoint GET /v1/register/activate which was used by the old registration emails.

Query parameters

Name Required Description
token yes Token received in the verification link when starting a normal registration
language no User’s preferred language "sv" or "fi" (default).
returnToUrl no URL to return to after the user has successfully completed registration. Must be in yle.fi domain over HTTPS. If no URL is provided, user is redirected to Yle Tunnus site.

For example:

curl -v -X POST 'https://login.api.yle.fi/v1/register/activate?token=YOUR_TOKEN&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY'

NOTE: Alternatively app_key can be given in Authorization header -H 'Authorization: YOUR_APP_KEY'.

Response

200 OK with an returnToUrl

Example body:

{
  "returnToUrl": "https://tunnus.yle.fi/tervetuloa"
}

401 Unauthorized with an error message if token is not found

Example body:

{
  "message" : "Token not found",
  "errorCode" : "token_not_found"
}

heading Device pairing flow

Devices such as AppleTV can log their users in so that user don’t need to type their password. Instead of a password, a short lived token is created for the device, which user can use to link the device in https://tunnus.yle.fi/liita.

The device initiates the flow by posting JSON document to deviceToken -endpoint with deviceId and deviceName fields. deviceId has to be unique. For example posting a request:

curl -v -XPOST 'https://login.api.yle.fi/v1/deviceToken?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY' -H 'content-Type: application/json' -d '{"deviceId": "xxx", "deviceName": "yyy"}'

should yield a response such as this:

{"deviceToken":"243502","sessionId":"a7e49c4b-f6ac-4058-a414-35ba48b584d5"}

deviceToken should be displayed to user with instructions to navigate to https://tunnus.yle.fi/liita and submit the token to the form that is displayed.\ The token is valid for 10 minutes.

After the user has submitted the token, the site instructs user to return to the device and proceed to login from there.

The device can now log the user in using the sessionId from the first request:

curl -v -XPOST 'https://login.api.yle.fi/v1/deviceToken/a7e49c4b-f6ac-4058-a414-35ba48b584d5/login?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY'

Response contains ylelogin cookie which can be used to authenticate the user in subsequent requests.

POST /v1/deviceToken/ Creating device token

The request that initiates device pairing flow by creating deviceToken and sessionId. See device pairing tutorial for more details.

Parameters

Parameters are given in a JSON-document in the request body and content type has to be application/json.

Name Required? Description
deviceId yes Unique id for the device
deviceName yes Name of the device

For example:

curl -v -XPOST 'https://login.api.yle.fi/v1/deviceToken?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY' -H 'content-Type: application/json' -d '{"deviceId": "xxx", "deviceName": "yyy"}'

Response

200 OK

{ 
  "deviceToken" : "243502", 
  "sessionId" : "a7e49c4b-f6ac-4058-a414-35ba48b584d5"
}

The token is valid for 10 minutes.

400 Bad Request when one or both required parameters were missing

{ "message" : "Error message", "errorCode" : "error_code" }

500 Internal Server Error when creating new deviceToken failed

POST /v1/deviceToken/:deviceToken/activate Activate device token

Finalizes device pairing by activating deviceToken and makes logging in possible with sessionId associated to that deviceToken. See device pairing tutorial for more details.

Parameters

The request must contain a ylelogin cookie.

Name Required? Description
deviceToken yes Created device token

For example:

curl -v -XPOST --header 'Cookie: ylelogin=YOUR_VALID_LOGIN_COOKIE' 'https://login.api.yle.fi/v1/deviceToken/243502/activate?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY'

Response

200 OK

404 Not Found

POST /v1/deviceToken/:sessionId/login Device token login

Returns the ylelogin cookie if the deviceToken which is associated to given sessionId has been activated. See device pairing tutorial for more details.

Parameters

Name Required? Description
sessionId yes session id associated to created device token

For example:

curl -v -XPOST 'https://login.api.yle.fi/v1/deviceToken/a7e49c4b-f6ac-4058-a414-35ba48b584d5/login?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY'

Response

OK responses set a ylelogin cookie (secure, http-only). This is used to authenticate requests to Login API endpoints and to Profiles API.

Example response cookie header:

Set-Cookie:ylelogin=YmUyNDUxMDQtYWNkNS20Y2QULTlHODAtOTY1YzliOWRjADkz; Domain=.yle.fi; HttpOnly; path=/; expires=Tue, 10 May 2016 04:32:43 GMT; secure

200 OK

403 Unauthorized

GET /v1/device/ List devices

Returns list of users paired devices.

Parameters

The request must contain a ylelogin cookie.

For example:

curl -v -XGET --header 'Cookie: ylelogin=YOUR_VALID_LOGIN_COOKIE' 'https://login.api.yle.fi/v1/device?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY'

Response

200 OK

{
  "devices" : [{
    "id": "57baf0b1e4b016e39e4cfc86",
     "externalId": "8BF9BBE3-2EC8-4C82-A537-421184CC3F0A"
     "deviceName": "My AppleTV"
     "lastLogin": "2017-10-11T11:23:03Z"
  }]
}  

403 Unauthorized

DELETE /v1/device/:deviceId Removes paired device

Removes pairing of given device.

Parameters

The request must contain a ylelogin cookie.

Name Required? Description
deviceId yes Device to be removed

For example:

curl -v -XDELETE --header 'Cookie: ylelogin=YOUR_VALID_LOGIN_COOKIE' 'https://login.api.yle.fi/v1/device/1234567890?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY'

Response

200 OK

403 Unauthorized

heading Yle Tunnus user removals

Yle Tunnus users can choose to remove their accounts. When that happens, and you have stored the user’s Yle Tunnus identifier, email address, or other personal data in your system, that data needs to be removed as well (without undue delay). Login API provides several options for delivering information about removed Yle Tunnus accounts to integrated systems: RabbitMQ messages, REST MQ API messages, and a REST API for polling the data (as a last resort, if message queue integration is not possible).

RabbitMQ messages

Login API publishes messages to the exchange.api.internal exchange with the routing key tunnus.user.changes when Yle Tunnus accounts are created, updated, or removed.

Account removal messages have the following headers:

Header Value
content_type "tunnus.user"
event_type "delete"

The content type of the payload is application/json and the payload contains a JSON object with a single userId attribute. Example:

{
  "userId": "56e1423bc95162266a5e2469"
}

The userId value is the surrogate key of the removed Yle Tunnus user account. Upon receiving such a message, you should remove all personal data of that user from your system.

REST MQ API messages

Login API publishes messages to the tunnus.user.delete REST MQ API queue when Yle Tunnus accounts are removed.

These messages can be consumed by creating an HTTP endpoint in your system for receiving the messages, and then registering a consumer in REST MQ API.

Receiving user removal messages from Login API

After a consumer has been registered successfully, the consumer endpoint will start receiving messages from Login API. These messages have a JSON body that contains a JSON object with a single yleTunnusUserId attribute.

Example message:

{
  "yleTunnusUserId": "56e1423bc95162266a5e2469"
}

Upon receiving such a message, you should remove all personal data of that user from your system.

GET /v2/accounts/removed?start_time={start_time}&end_time={end_time} List removed users

DEPRECATED Will be removed in future versions. This endpoint is not in use, except by one auth-api client. Thus, a new similar endpoint has been implemented in auth-api that returns PPID sector specific ids. The new endpoint and its documentation have be found here

Returns a list of surrogate keys of users removed between a given time range. It is recommended to use a short time range, for example, between 5 to 15 minutes.

Parameters

Both start_time and end_time are mandatory parameters, and they must conform to full ISO 8601 format. They must be no more than 30 days apart, and start_time must occur before end_time.

Example query (without app_id and app_key parameters):

curl 'https://login.api.yle.fi/v2/accounts/removed?start_time=2018-01-01T10:00:00Z&end_time=2018-01-01T10:05:00Z'

Response

200 OK when request was successful

Body contains a JSON object with a list of removed user IDs, in the attribute removed_user_ids:

{
  "removed_user_ids": ["cf088b65e4b72b7c8381089a", "31ebf9cd8db642aa26e4ec93"]
}

400 Bad Request when start_time is greater than end_time, either time is invalid or missing, or the time difference is over 30 days

POST /v1/terms-of-service/accepted/{version} Accept Terms of Service

Accept a specific version of Terms of Service for the user.

Parameters

The request must contain a ylelogin cookie (or yletestlogin in the test environment).

version is mandatory, and must be in the format 20180423-1.

Response

200 OK when request was successful

401 Unauthorized

400 Bad Request when version is invalid

User change RabbitMQ message

Login API publishes messages to the exchange.api.internal exchange with the routing key tunnus.user.changes when Yle Tunnus accounts are created, updated, or removed.

Headers

Header Value
content_type "tunnus.user"
event_type "create" or "update" or "delete"

Content for create and update

The content type of the payload is application/json and the payload contains a JSON object with userId, contact and user attributes. For example:

{
  "userId": "56e1423bc95162266a5e2469",
  "contact": {"email": "<encrypted email>",
              "marketingConsent": true,
              "activationUrl": "<actionvationUrl>"}
  "user": {"registrationDate": "2018-01-01T00:00:00.000+02:00",
           "registeredAppId": "12345",
           "initiatingComponent": "header",
           "gender": "OTHER",
           "languagePreference": "fi",
           "yearOfBirth": 2000,
           "monthOfBirth": 1,
           "acceptedTosVersion": "20180405-1",
           "residenceInFinland": true},
  "active": true
}

The userId value is the surrogate key of the Yle Tunnus user account for which to event information is for. Change messages can have only partial data or a missing field does not mean it has been removed. Only if a field has a null value it was removed.

TOS-update

Currently TOS-update message content differs from the structure above. It looks like this:

{
  "userId": "56e1423bc95162266a5e2469",
  "email": "<encrypted email>",
  "active": true,
  "acceptedTosVersion": "20180405-1"
}

Content for delete

Delete message content has only userId:

{
  "userId": "56e1423bc95162266a5e2469"
}

heading Session token in header

It is possible to use Yle-Tunnus-Session header instead to the ylelogin session cookie.

Normally API calls are authenticated using a cookie that contains a session token. However, dealing with cookies has been a recurring source of problems on React Native. The support for transmitting the token in a header was added to solve these problems.

NOTE: The cookie is the preferred authentication mechanism. Please use cookies if possible. Not all APIs support header-based authentication.

Example

The cookie usually looks like this:

Cookie: ylelogin=YmUyNDUxMDQtYWNkNS20Y2QULTlHODAtOTY1YzliOWRjADkz

You can put the same token into a header:

Yle-Tunnus-Session: YmUyNDUxMDQtYWNkNS20Y2QULTlHODAtOTY1YzliOWRjADkz

The cookie has a different name in the test environment, but the header name is always the same.

GET /v1/user/session/{tempToken} Exchange a temporary token to a session token

Exchange a temporary token to a session token.

If you call /v1/user/login with with_token=true, the response includes a temporary token that can be exchanged to a session token. This is intended to be used by the mobile applications that need to use header-based authentication.

Parameters

Name Description
token The temporary token

Response

200 OK if token exchange succeeded

{ "yleTunnus": "SESSION TOKEN" }

401 Unauthorized if the temporary token is invalid or expired

{ "message": "Temp token invalid", "errorCode": "token_invalid_or_expired" }

Media API

GET /v1/{mediaId}/playouts.json Retrieving Stream URL for OnDemand program

Used to get stream URL for media. The urls returned from this API are encrypted using the secret key associated with your application.

How to use

First, you need a mediaId. You can get that from Programs API by finding the item’s current publication event. It’s the type == 'OnDemandPublication' and temporalStatus == 'currently' one

Then, query playouts.json:

https://media.api.yle.fi/v1/MEDIAID/playouts.json?protocol=[HLS|HDS|PMD|RTMPE]&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY

For example:

$ curl https://media.api.yle.fi/v1/6-35af958db127424fbf43694a14ece041/playouts.json?protocol=HLS&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY
{
  "notifications": {},
  "data": [
    {
          "multibitrate": true,
          "height": 396,
          "formatOf": "6-35af958db127424fbf43694a14ece041",
          "type": "VideoObject",
          "protectionType": "DEFAULT",
          "url": "CwAArk9txSGpZeJEf1PZV1+b9qt6Q65wtIr5UVINKzvV/GVYtYxGMCYnVkYYVocPWsDrk03trz91cdK9pXMbV5LdWi2/awoXyL64uHaZdeEWvU6fIZfnt1cGIWuHskl673ypyLUQAOJkViqo0D1UjOzthDn4GeupiuhT7mvY0Pjh1BxMZLssYQfjWfiWGshxjAHpZO1yL4fWqRwZcuo0Yd4t/dt0Kou2F/VjICkNtLQbx8vvw9vQe8HLjdp8hG+uo7qgyK2krhU7fIjRAuYgBp8ZEOQ/BsVaWu6MErSaVvc2WkWm1IGQrG08xppAG2BrNQ2nRHXGSOn65p2F86hEokiarINIrGzByVGfLjqL6A9GLE92D4NP2HV8jOKbHn85FRDYcaUXQzfnpk8uufPs69fUh2Cvv0c2MaMfwAoDNWs=",
          "subtitles": [],
          "protocol": "HLS",
          "live": false,
          "width": 704
        }
      ],
      "meta": {
        "id": "6-35af958db127424fbf43694a14ece041"
      }
    }
  ]
}

Now you can use your secret key to decrypt the url

$ node decrypt-url.js $SECRET $URL

To verify the URL works, you can copy paste it into QuickTime

NOTE: The URL decrypted from the above example response won’t work anymore. The links generated by Media API expire soon after they’ve been generated.

URL encryption

Media API encrypts stream URLs using a shared key associated with your application. You should have received the encryption key when you signed up as Media API user.

Decrypting URLs

We provide a reference script for decrypting the URLs. To use it, you need to have NodeJS installed. Also, you need to download the script to your computer. Then, you can use it like:

$ node decrypt-url.js $SECRET $URL

The process for decrypting is:

  1. First, decode the base64 url

  2. Then take the first 32 bytes of the decoded url as $IV and the rest as $MESSAGE

  3. Create a cipher with AES/CBC/PKC7Padding

  4. Initialize the cipher in decrypt mode with your $SECRET and $IV

  5. Decrypt the $MESSAGE

With JVM based languages you can use javax.crypto.Cipher#getInstance("AES/CBC/PKC7Padding") as the cipher

GET /v1/downloads.json Retrieving download URL for downloadable OnDemand program

This endpoint is used to get download URL’s for medias set to be downloadable. URL’s are not encrypted in any way, and are downloadable as long as the media is viewable in Areena. Media is always served in the format that it is encoded in Mediakanta. By default this means that videos are in mp4-format and audios in mp3-format.

How to use

First, you need at least one mediaId that is set to be downloadable. You can get that from Programs API by finding the item’s current publication event. This endpoint can handle multiple id requests at the same time. In these cases you have to submit a comma separated list as the ids-parameter. You can also specify if you want to have video files that have hard subtitles included. This can be done by specifying hardsubtitles=[true|false] parameter. Default value for this is ‘false’.

Then, query downloads.json:

https://media.api.yle.fi/v1/downloads.json?ids=[comma-separated-list-of-ids]&hardsubtitles=[true|false]&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY

For example:

$ curl https://media.api.yle.fi/v1/downloads.json?ids=6-f8b88966fd394e5a8ee9914465cf32bd,6-18b6cf6756234cbc99e3bab359ef4fd4&hardsubtitles=true&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY
{
  meta: {
    ids: "6-f8b88966fd394e5a8ee9914465cf32bd,6-18b6cf6756234cbc99e3bab359ef4fd4",
    count: 2
  },
  data: [
    {
      id: "6-f8b88966fd394e5a8ee9914465cf32bd",
      type: "VideoObject",
      mediaObjects: [
        {
          audioBitrateKbps: 128,
          videoBitrateKbps: 650,
          width: 640,
          height: 360,
          hardsubtitle: {
            lang: "fi",
            type: "translation"
          },
          downloadLink: "http://areena-pdl-world.edgesuite.net/be/be937cb9b231257ce9f55cc2b9475ad6_634880.mp4"
        },
        {
          audioBitrateKbps: 48,
          videoBitrateKbps: 400,
          width: 480,
          height: 270,
          hardsubtitle: {
            lang: "fi",
            type: "translation"
          },
          downloadLink: "http://areena-pdl-world.edgesuite.net/be/be937cb9b231257ce9f55cc2b9475ad6_14746.mp4"
        },
        {
          audioBitrateKbps: 48,
          videoBitrateKbps: 400,
          width: 480,
          height: 270,
          hardsubtitle: {
            lang: "fi",
            type: "translation"
          },
          downloadLink: "http://areena-pdl-world.edgesuite.net/be/be937cb9b231257ce9f55cc2b9475ad6_200704.mp4"
        },
        {
          audioBitrateKbps: 128,
          videoBitrateKbps: 650,
          width: 640,
          height: 360,
          downloadLink: "http://areena-pdl-world.edgesuite.net/e9/e9331dc82142449b9b6131c90b74460f.mp4"
        }
      ]
    },
    {
      id: "6-18b6cf6756234cbc99e3bab359ef4fd4",
      type: "VideoObject",
      mediaObjects: [
        {
          audioBitrateKbps: 128,
          videoBitrateKbps: 1000,
          width: 704,
          height: 396,
          downloadLink: "http://areena-pdl-world.edgesuite.net/b2/b252b810baeb7b8e70d45525bf16834f_1001472.mp4"
        },
        {
          audioBitrateKbps: 128,
          videoBitrateKbps: 650,
          width: 640,
          height: 360,
          downloadLink: "http://areena-pdl-world.edgesuite.net/b2/b252b810baeb7b8e70d45525bf16834f_661504.mp4"
        },
        {
          audioBitrateKbps: 128,
          videoBitrateKbps: 400,
          width: 480,
          height: 270,
          downloadLink: "http://areena-pdl-world.edgesuite.net/b2/b252b810baeb7b8e70d45525bf16834f_404480.mp4"
        },
        {
          audioBitrateKbps: 48,
          videoBitrateKbps: 400,
          width: 480,
          height: 270,
          downloadLink: "http://areena-pdl-world.edgesuite.net/b2/b252b810baeb7b8e70d45525bf16834f_143360.mp4"
        }
      ]
    }
  ],
  notifications: { }
}

NOTE

It is possible to define downloadable filename by setting a ‘filename’-parameter to the Akamai download URL. Like this: http://areena-pdl-world.edgesuite.net/b2/b252b810baeb7b8e70d45525bf16834f_143360.mp4?filename=renamedfile.mp4

Meta API

General information

Meta API is an API for managing Yle concepts and content-to-content links. For concept-to-content links, see Relations API.

Terminology

Term Finnish usage Description
Concept Käsite, asiasana Abstract notion, to which multiple contents may be linked.
Concept type Käsitetyyppi Used to categorize usage of concepts, but not much used for now.
Content Sisältö Articles, radio things, program things etc., where things are series, clips etc.
Description Kuvaus Definition of a concept, eg. snippet from Wikipedia or from a broader concept.
Exact match - Mapping from a concept in an external ontology to a local concept.
Combination Siltaus, yhdistäminen A link between concepts in distinct external ontologies, achieved with an exact match.
Ontology Ontologia Source of concepts, such as Yle, Wikidata, Freebase etc., with different priorities.
Relation Suhde Links from concept to content, or from content to content.
Relation type Suhdetyyppi Type of relation between concept and content, such as being a subject of some content.
Section Osasto (aihe in S/FYND) A department where content belongs, such as Yle Urheilu, Yle Talous etc.
Title Nimitys Name assigned to a concept, with possibly varying languages (Finnish, Swedish, English).

For documentation about relation types, see Relations API general information.

GET /v1/content.json Get content

Parameters

Name Description
language Required - (only return content in this language) (example “fi”)
subject Optional* - concept yle ID (example “18-1”)
related_content Optional* - content yle ID (example “7-849353”)
  • Please note that exactly one of the parameters “subject” or “related_content” is required.

Response

200 OK on success

{
  "meta": {
    "subject": "18-4498",
    "language": "sv",
    "count": 222
  },
  "data":[
    { "type": "Article", "id": "7-849353" },
    { "type": "Article", "id": "7-848623" },
    ...
  ]
}

To get title and other details for a piece of content, query the API correspondingto content type. For example, in the above example, you could query Articles API for IDs 7-849353 and 7-848623.

400 Bad Request if required parameters are missing

You need to specify language. It is currently not possible to list content in all languages.

cURL example

List all Swedish content about Formula 1 (concept id 18-4498)

curl -XGET https://meta.api.yle.fi/v1/content.json?subject=18-4498&language=sv&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

GET /v1/concepts.json Find concepts

Finds concepts from Meta-api only (concept_search.json searches also external ontology services)

Parameters

 Parameter Description
yle_id Find concept by concept yle id (for example 18-4431). This can be a comma-separated list of Yle IDs (max 200)
subjectof Find concepts that have a subject relation to content with this id
exactmatch Find concept by exact match (freebase:/m/xxxx, finto:url, …). This can be a comma-separated list of Yle IDs (max 100)
q Find concepts by their title with free text search in selected language
lang/language Provide language for free text search language, required when using free text search; fi, sv or en (N.B. the language parameter is deprecated and will be removed. Please use lang instead.)
ignore_accents Optional parameter that can be used with q and lang. When set to true accents are ignored in the search. Eg. vora will match Vörån hiihtokeskus, Jakub Voráček and Vorarlberg.

Either yle_id, subjectof, exactmatch or combination q with lang (or language) parameter is required.

Response

200 OK on success

{
  "meta": {
    "subjectof": "7-846362",
    "count": 4
  },
  "data": [
    {
      "id": "18-4428",
      "alternativeIds": ["18-5323", "18-3455"],
      "types": ["Concept"],
      "exactMatch": ["finto:http://www.yso.fi/onto/koko/p7135"],
      "title": { "fi": "autourheilu", "sv": "bilsport", "en": "car sport"},
      "description": {
        "fi": "Urho Kaleva Kekkonen oli suomalainen poliitikko",
        "sv": "Urho Kaleva Kekkonen, född 3 september 1900",
        "en": "Urho Kaleva Kekkonen was a Finnish politician"
      },
      "imageId": "13-18-4428-1",
      "updated": "2017-08-27T19:37:15+03:00"
    },
    {
      "id": "18-4431",
      "alternativeIds": [],
      "types": ["Organization", "Concept", "Agent"],
      "exactMatch": ["freebase:/m/02xz2"],
      "title": { "fi": "Formula 1", "sv": "Formel 1" },
      "description": {
        "fi": "formula",
        "sv": null
      },
      "updated": "2017-08-27T19:37:15+03:00"
    },
    ...
  ]
}

400 Bad Request when required parameters are missing

Exactly one of the parameters subjectof, exactmatch, q or yle_id must be provided, and language must be valid.

cURL example

List all concepts for svenska.yle.fi article 7-846362

https://meta.api.yle.fi/v1/concepts.json?subjectof=7-846362&app_key=YOUR_APP_ID&app_id=YOUR_APP_KEY

Known issues

This endpoint can suffer from increased response times nightly at 01:30 (Finnish time). This is because of a scheduled maintenance operation that is executed in the database at that time. Duration of this operation is usually about 20-30 seconds.

GET /v1/concept_search.json Search concepts by query

Search concepts from meta-api AND external ontology services using free-text search.

Currently concepts are queried from Finto, the Meta API database and Wikidata. Only concepts considered valid by Meta API are returned. Also returns the number of times (contentHits) the concept is used in Yle content (articles etc.). A score (a measure of how well the concept matches the query; on a scale of 0-1000) is included in the response when the debug parameter is set to true.

The optional lang parameter can be used to specify in which languages to query the external ontologies and the Meta API database. Please note that not all sources support all languages (Meta API currently only supports fi and sv, and Wikidata will only be queried in the first given language).

Parameters

 Parameter Required? Description
 q  Yes query
lang No comma-separated list of languages in preference order (defaults to fi,sv,en)
debug No true/false

Response

200 OK is success

{ "meta: {
  "q: "kekkonen",
  "timeout.secs": 3,
  "services": {
    "finto": {
      "requestStatus": "ok"
    },
    "wikidata": {
      "requestStatus": "ok"
    },
    "yle": {
      "requestStatus": "ok"
    }
  }
}, "data": [ {
  "type": "TagResult",
  "score": 25.197794,
  "title": "Urho Kekkonen",
  "disambiguationHint": "Poliitikko",
  "lang": "fi",
  "exactMatch": [
    "freebase:/m/07w5w"
  ],
  "types": [
    "Concept",
    "Person",
    "Agent"
  ],
  "contentHits": 14,
  "vocabulary": "freebase"
  }
...]}

400 Bad Request when required parameters are missing

cURL example

List all concepts for ‘Kekkonen’

https://meta.api.yle.fi/v1/concept_search.json?q=kekkonen&lang=fi&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

Known issues

This endpoint can suffer from increased response times nightly at 01:30 (Finnish time). This is because of a scheduled maintenance operation that is executed in the database at that time. Duration of this operation is usually about 20-30 seconds.

POST /v1/concepts_from_exact_match.json Create new concept using external id

Creates new concept from external ontology service (Wikidata, Finto, Escenic) to Meta API.

You may call this endpoint multiple times with the same parameters. The subsequent requests are no-ops.

Note: Creating new concepts from Leiki is no longer supported. For that purpose, use Text Analysis API’s POST /v1/concepts/leiki/{leikiConceptId}.json endpoint instead.

Body parameters

Parameter Required? Description
exactMatch Yes Array of external ontology system ids

example body: {"exactMatch": ["wikidata:Q179858", "escenic:kotimaa"]}

Response

200 OK is success

{ "meta": {},
  "data": [{"id": "18-5419",
            "alternativeIds": ["18-5323", "18-3455"],
            "types": ["Concept","Person","Agent"],
            "exactMatch": ["wikidata:Q179858"],
            "title": {"fi": "Urho Kekkonen","sv": "Urho Kekkonen"},
            "description": {
              "fi": "Urho Kaleva Kekkonen oli suomalainen poliitikko",
              "sv": "Urho Kaleva Kekkonen, född 3 september 1900"
            },
            "valid": true,
            "imageId": "13-18-5419-1"},
           {"id":"18-32499",
            "types":["Concept"],
            "exactMatch":["escenic:kotimaa"],
            "title":{"fi":"Kotimaa","sv":"inrikes"},
            "description": {
              "fi": null,
              "sv": null
            },
            "valid": true}]}

Note: If the concept is valid, other Meta API endpoints will return it. Technically, valid means that Meta API has successfully retrieved concept’s data from at least one of the external ontology services identified by exactMatch. It does not guarantee, for instance, that concept has both Swedish and Finnish title.

400 Bad Request when required parameters are missing

400 Bad Request when exactMatch has an unsupported ontology id

cURL example

Add wikidata and escenic concept ‘Kekkonen’ to meta-api

curl -XPOST -H "Content-Type:application/json" --data '{"exactMatch": [ "wikidata:Q179858", "escenic:kotimaa" ]}' \
    "https://meta.api.yle.fi/v1/concepts_from_exact_match.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

POST /v1/concepts.json Create new concept

Creates a new concept in Meta API using concept data (in JSON) from an external ontology. A concept is considered valid when it has at least a title and a description set in either Finnish, Swedish or English.

JSON body parameters

 Parameter Required? Description
title Yes Object containing Finnish (fi), Swedish (sv) and/or English (en) titles
description Yes Object containing Finnish (fi), Swedish (sv) and/or English (en) descriptions
types Yes Array of concept types
givenName No Given name of a Person type concept
familyName No Family name of a Person type concept
exactMatch   No Array of exact matches

Example body:

{
  "title": {
    "fi": "Urho Kekkonen",
    "sv": "Urho Kekkonen",
    "en": "Urho Kekkonen"
  },
  "description": {
    "fi": "Urho Kaleva Kekkonen oli suomalainen poliitikko",
    "sv": "Urho Kaleva Kekkonen, född 3 september 1900",
    "en": "Urho Kaleva Kekkonen was a Finnish politician"
  },
  "types": [
    "Concept",
    "Person",
    "Agent"
  ],
  "exactMatch": [
    "wikidata:Q179858",
    "escenic:kotimaa"
  ],
  "givenName": "Urho",
  "familyName": "Kekkonen"
}

Response

200 OK on success

{
  "data": {
    "id": "18-1",
    "alternativeIds": [],
    "types": [
      "Concept",
      "Person",
      "Agent"
    ],
    "exactMatch": [
      "wikidata:Q179858",
      "escenic:kotimaa"
    ],
    "title": {
      "fi": "Urho Kekkonen",
      "sv": "Urho Kekkonen",
      "en": "Urho Kekkonen"
    },
    "description": {
      "fi": "Urho Kaleva Kekkonen oli suomalainen poliitikko",
      "sv": "Urho Kaleva Kekkonen, född 3 september 1900",
      "en": "Urho Kaleva Kekkonen was a Finnish politician"
    },
    "givenName": "Urho",
    "familyName": "Kekkonen"
  }
}

400 Bad Request when required parameters are missing

400 Bad Request when given values for types or exact match(es) do not match the schema

400 Bad Request when given name or family name fields are set on a concept that is not of the Person type

409 Conflict when concept(s) with the given exact match(es) already exist(s). A human-readable error message is set in the notifications section, and the conflicting concept(s) stored in the DB are/is returned in data.

{
  "data": {
    "notifications": [
      {
        "message": "Concept with exact match(es) 'leiki:focus100k_na_7224' already exists."
      }
    ],
    "data": [
      {
        "id": "18-1",
        "alternativeIds": [],
        "types": [
          "Concept"
        ],
        "exactMatch": [
          "leiki:focus100k_na_7224"
        ],
        "title": {
          "fi": "luonnonmukainen viljely",
          "sv": "ekologisk odling",
          "en": "organic farming"
        },
        "description": {
          "fi": "vaihtoehtoiset viljelymenetelmät",
          "sv": null,
          "en": null
        }
      }
    ]
  }
}

cURL example

Create a Wikidata and Escenic concept ‘Urho Kekkonen’ in Meta API.

curl --request POST \
    --header "Content-Type:application/json" \
    --data '{"title": {"fi": "Urho Kekkonen","sv": "Urho Kekkonen","en": "Urho Kekkonen"}, "description": {"fi": "Urho Kaleva Kekkonen oli suomalainen poliitikko", "sv": "Urho Kaleva Kekkonen, född 3 september 1900", "en": "Urho Kekkonen was a Finnish politician"}, "types": ["Concept","Person","Agent"], "exactMatch": ["wikidata:Q179858", "escenic:kotimaa"], "givenName": "Urho", "familyName": "Kekkonen"}' \
    "https://meta.api.yle.fi/v1/concepts.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

PUT /v1/concepts/{id}.json Update existing concept

Updates one or more fields in an existing Meta API concept.

Path parameters

Parameter Required? Description
id Yes Yle ID of the concept to update

JSON body parameters

Parameter Required? Description
title Yes Object containing Finnish (fi), Swedish (sv) and/or English (en) titles
description Yes Object containing Finnish (fi), Swedish (sv) and/or English (en) descriptions
types No Array of concept types
givenName No Given name of a Person type concept
familyName No Family name of a Person type concept
exactMatch No Array of exact matches
updated Yes Last updated date (obtained from GET concept). This value is used to prevent data loss by concurrent editing.

Example body:

{
   "title": {
     "fi": "Kerho Ukkonen"
   },
   "description": {
     "fi": "Kerho Kaleva Ukkonen oli suomalainen poliitikko"
   },
   "givenName":"Kerho",
   "familyName":"Ukkonen",
   "updated": "2017-08-27T19:37:15+03:00"
}

Response

200 OK on success

{
    "meta": {
      "id": "18-1"
    },
    "data": {
      "id": "18-1",
      "alternativeIds": [],
      "types": [
        "Concept",
        "Person",
        "Agent"
      ],
      "exactMatch": [
        "wikidata:Q179858",
        "escenic:kotimaa"
      ],
      "title": {
        "fi": "Kerho Ukkonen",
        "sv": "Urho Kekkonen",
        "en": "Urho Kekkonen"
        },
      "description": {
        "fi": "Kerho Kaleva Ukkonen oli suomalainen poliitikko",
        "sv": "Urho Kaleva Kekkonen, född 3 september 1900",
        "en": "Urho Kaleva Kekkonen was a Finnish politician"
      },
      "givenName": "Kerho",
      "familyName": "Ukkonen",
      "updated": "2017-08-28T09:00:00+03:00"
    }
}

404 Not Found when a concept with the given Yle ID does not exist

400 Bad Request when given values for types or exact match(es) do not match the schema

400 Bad Request when given name or family name fields are set on a concept that is not of the Person type

409 Conflict when version is in conflict. Your changes are made to old version of this concept. Refresh the concept and redo your changes.

cURL example

Update the Finnish title, Finnish description, given name and family name of concept 18-1.

curl --request PUT \
    --header "Content-Type:application/json" \
    --data '{"title": {"fi": "Kerho Ukkonen"}, "description": {"fi": "Kerho Kaleva Ukkonen oli suomalainen poliitikko","givenName":"Kerho","familyName":"Ukkonen", "updated": "2017-08-27T19:37:15+03:00"}}' \
    "https://meta.api.yle.fi/v1/concepts.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

Metrics API

GET /v2/labels/stream/services/{serviceId}/{mediaId}.json Show tracking params for media by service

Can be used to produce needed tracking variable for media..

Parameters

Name Description
serviceId Required service ID
mediaId Required media ID

Response

200 OK on success

{
    "data": {
        "category": "nettiradio",
        "ns_st_dt": "20141201",
        "ns_st_ty": "liveradio",
        "ns_st_st": "yle x3m",
        "yle_ss_mediaid": "10-18",
        "yle_language": "sv",
        "ns_st_cl": "0",
        "ns_st_el": "0",
        "ns_st_li": "1",
        "yle_metrics_api_data_version": "v2.0",
        "ns_st_ep": "20141201",
        "content_type": "liveradio",
        "ns_st_pr": "nettiradio.liveradio.yle x3m.null",
        "countername": "nettiradio.liveradio.yle x3m.null",
        "ns_st_pl": "nettiradio.liveradio.yle x3m.null.20141201"
    }
}

400 Bad Request if required parameters are missing

cURL example

Get comScore params for service Yle X3m and media 10-18

curl -XGET https://metrics.api.yle.fi/v2/labels/stream/services/yle-x3m/10-18.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

Details about service

curl -XGET https://programs.api.yle.fi/v1/services/yle-x3m.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

GET /v2/labels/stream/services/{serviceId}/{mediaId}/comscore.json Show tracking params for media in comScore format by service

Can be used to produce needed tracking variable for media in comScore format.

Parameters

Name Description
serviceId Required service ID
mediaId Required media ID

Response

200 OK on success

{
    "data": {
        "category": "nettiradio",
        "ns_st_dt": "20141201",
        "ns_st_ty": "liveradio",
        "ns_st_st": "yle x3m",
        "yle_ss_mediaid": "10-18",
        "yle_language": "sv",
        "ns_st_cl": "0",
        "ns_st_el": "0",
        "ns_st_li": "1",
        "yle_metrics_api_data_version": "v2.0",
        "ns_st_ep": "20141201",
        "content_type": "liveradio",
        "ns_st_pr": "nettiradio.liveradio.yle x3m.null",
        "countername": "nettiradio.liveradio.yle x3m.null",
        "ns_st_pl": "nettiradio.liveradio.yle x3m.null.20141201"
    }
}

400 Bad Request if required parameters are missing

cURL example

Get comScore params for service Yle X3m and media 10-18

curl -XGET https://metrics.api.yle.fi/v2/labels/stream/services/yle-x3m/10-18/comscore.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

Details about service

curl -XGET https://programs.api.yle.fi/v1/services/yle-x3m.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

GET /v2/labels/stream/services/{serviceId}/{mediaId}/akamai-sola.json Show tracking params for media in Akamai Sola format by service

Can be used to produce needed tracking variable for media in Akamai Sola format.

Parameters

Name Description
serviceId Required service ID
mediaId Required media ID

Response

200 OK on success

{
    "data": {
        "title": "nettiradio.liveradio.yle x3m",
        "category": "nettiradio",
        "show": "20141201.yle x3m",
        "contentLength": "0",
        "contentType": "liveradio"
    }
}

400 Bad Request if required parameters are missing

cURL example

Get comScore params for service Yle X3m and media 10-18

curl -XGET https://metrics.api.yle.fi/v2/labels/stream/services/yle-x3m/10-18/akamai-sola.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

Details about service

curl -XGET https://programs.api.yle.fi/v1/services/yle-x3m.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

GET /v2/labels/stream/services/{serviceId}/{mediaId}/analytics.json Show tracking params for media by service in multiple formats

Can be used to produce needed tracking variable for media in multiple formats.

Parameters

Name Description
serviceId Required service ID
mediaId Required media ID

Query parameters

Name Description
formats Required comma separated list of formats

Response

200 OK on success

{
    "data": [
        {
            "comscore": {
                "category": "nettiradio",
                "ns_st_dt": "20141201",
                "ns_st_ty": "liveradio",
                "ns_st_st": "yle x3m",
                "yle_ss_mediaid": "10-18",
                "yle_language": "sv",
                "ns_st_cl": "0",
                "ns_st_el": "0",
                "ns_st_li": "1",
                "yle_metrics_api_data_version": "v2.0",
                "ns_st_ep": "20141201",
                "content_type": "liveradio",
                "ns_st_pr": "nettiradio.liveradio.yle x3m.null",
                "countername": "nettiradio.liveradio.yle x3m.null",
                "ns_st_pl": "nettiradio.liveradio.yle x3m.null.20141201"
                }
        },
        {
            "akamai-sola": {
                "title": "nettiradio.liveradio.yle x3m",
                "category": "nettiradio",
                "show": "20141201.yle x3m",
                "contentLength": "0",
                "contentType": "liveradio"
            }
        }
    }]
}

400 Bad Request if required parameters are missing

cURL example

Get comScore and akamai-sola params for service Yle X3m and media 10-18

curl -XGET https://metrics.api.yle.fi/v2/labels/stream/services/yle-x3m/10-18/analytics.json?formats=comscore,akamai-sola&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

Details about service

curl -XGET https://programs.api.yle.fi/v1/services/yle-x3m.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

GET /v2/labels/stream/programs/{programId}/{publicationEventId}.json Show tracking params for program

Can be used to produce needed tracking variables for media.

Parameters

Name Description
programId Required program ID
publicationEventId Required media ID

Response

200 OK on success

{
    "data": {
        "ns_st_pl": "draama.vod.yle tv1.top of the lake.20140212.4",
        "ns_st_ep": "20140212.4",
        "ns_st_pr": "draama.vod.yle tv1.top of the lake",
        "ns_st_dt": "20140212",
        "ns_st_ty": "vod",
        "ns_st_st": "yle tv1",
        "countername": "draama.vod.yle tv1.top of the lake",
        "content_type": "vod",
        "yle_dayssincepublish": "14",
        "yle_language": "en",
        "yle_ss_mediaid": "6-073b0b2f5352460da3ce21beac78ed5e",
        "yle_ss_ohjusid": "1-2127750",
        "yle_ss_prodnumber": "55162204000",
        "yle_title": "top of the lake",
        "yle_stickytitle": "top of the lake",
        "category": "draama",
        "ns_st_cl": "3508000",
        "ns_st_el": "3508000",
        "yle_truelength": "3508000",
        "ns_st_ci": "16-1-0798588",
        "yle_metrics_api_data_version": "v2.1",
        "ns_st_ge": "ulkomainen fiktio",
        "yle_genreid": "6",
        "yle_alternativeid": "16-1-0798588",
        "yle_category": "sarjatjaelokuvat;jannitys;ulkomaisetsarjat",
        "fp_bd": "20140212",
        "fp_ty": "video_tv_program",
        "fp_clnr": "20001",
        "fp_prod_id": "na",
        "fp_ch": "fp101",
        "yle_productfamily": "top of the lake"
    }
}

400 Bad Request if required parameters are missing

cURL example

Get comScore params for program Top Of The Lake and publication event 4-3245278

curl -XGET https://metrics.api.yle.fi/v2/labels/stream/programs/1-376/4-3245278.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

GET /v2/labels/stream/programs/{programId}/{publicationEventId}/comscore.json Show comScore tracking params for program by publication event

Can be used to produce needed tracking variables for media.

Parameters

Name Description
programId Required program ID
publicationEventId Required media ID

Response

200 OK on success

{
    "data": {
        "ns_st_pr": "viihde.vod.yle tv2.pasila",
        "ns_st_ep": "20140123",
        "ns_st_pl": "viihde.vod.yle tv2.pasila.20140123",
        "ns_st_dt": "20140123",
        "ns_st_ty": "vod",
        "ns_st_st": "yle tv2",
        "countername": "viihde.vod.yle tv2.pasila",
        "content_type": "vod",
        "yle_dayssincepublish": "312",
        "yle_language": "fi",
        "yle_ss_mediaid": "6-09c3f94215c046bfbab8515f5d2b23dc",
        "yle_ss_ohjusid": "1-376",
        "yle_ss_prodnumber": "54454005000",
        "yle_title": "pasila",
        "category": "viihde",
        "ns_st_cl": "1603000",
        "ns_st_el": "1603000",
        "yle_truelength": "1603000",
        "ns_st_ci": "1-376",
        "yle_metrics_api_data_version": "v2.1",
        "ns_st_ge": "viihde/kevyt musiikki/reality",
        "yle_genreid": "10",
        "yle_alternativeid": "16-1-0655053",
        "yle_productfamily": "pasila"
    }
}

400 Bad Request if required parameters are missing

cURL example

Get comScore params for program Pasila and publication event 4-3245278

curl -XGET https://metrics.api.yle.fi/v2/labels/stream/programs/1-376/4-3245278/comscore.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

GET /v2/labels/stream/programs/{programId}/{publicationEventId}/akamai-sola.json Show Akamai Sola tracking params for program by publication event

Can be used to produce needed tracking variables for media.

Parameters

Name Description
programId Required program ID
publicationEventId Required media ID

Response

200 OK on success

{
    "data": {
        "title": "20140123.viihde.n/a.yle tv2.pasila",
        "category": "viihde",
        "show": "viihde.n/a.yle tv2.",
        "contentLength": "1603000",
        "contentType": "n/a"
    }
}

400 Bad Request if required parameters are missing

cURL example

Get Akamai Sola params for program Pasila and publication event 4-3245278

curl -XGET https://metrics.api.yle.fi/v2/labels/stream/programs/1-376/4-3245278/akamai-sola.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

GET /v2/labels/stream/programs/{programId}/{publicationEventId}/analytics.json Show tracking params for program by publication event in multiple formats

Can be used to produce needed tracking variables for media in multiple formats.

Parameters

Name Description
programId Required program ID
publicationEventId Required media ID

Query parameters

Name Description
formats Required comma separated list of formats

Response

200 OK on success

{
    "data": [{
        "comscore": {
            "ns_st_pr": "viihde.vod.yle tv2.pasila",
            "ns_st_ep": "20140123",
            "ns_st_pl": "viihde.vod.yle tv2.pasila.20140123",
            "ns_st_dt": "20140123",
            "ns_st_ty": "vod",
            "ns_st_st": "yle tv2",
            "countername": "viihde.vod.yle tv2.pasila",
            "content_type": "vod",
            "yle_dayssincepublish": "312",
            "yle_language": "fi",
            "yle_ss_mediaid": "6-09c3f94215c046bfbab8515f5d2b23dc",
            "yle_ss_ohjusid": "1-376",
            "yle_ss_prodnumber": "54454005000",
            "yle_title": "pasila",
            "category": "viihde",
            "ns_st_cl": "1603000",
            "ns_st_el": "1603000",
            "yle_truelength": "1603000",
            "ns_st_ci": "1-376",
            "yle_metrics_api_data_version": "v2.1",
            "ns_st_ge": "viihde/kevyt musiikki/reality",
            "yle_genreid": "10",
            "yle_alternativeid": "16-1-0655053",
            "yle_productfamily": "pasila"
        }
    },
    {
        "akamai-sola": {
            "title": "20140123.viihde.n/a.yle tv2.pasila",
            "category": "viihde",
            "show": "viihde.n/a.yle tv2.",
            "contentLength": "1603000",
            "contentType": "n/a"
        }
    }]
}

400 Bad Request if required parameters are missing

cURL example

Get comScore and akaimai-sola params for program Pasila and publication event 4-3245278

curl -XGET https://metrics.api.yle.fi/v2/labels/stream/programs/1-376/4-3245278/analytics.json?formats=comscore,akamai-sola&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

GET /v2/labels/pageload/articles.json?id={articleIds} Show tracking params for article(s)

Can be used to produce needed tracking variables for an article or multiple articles.

Parameters

Name Description
articleIds Comma separated list of article IDs

Response

200 OK on success

{
    "data": {
        "3-9905944": {
            "yle_pubtime": "06-42",
            "yle_pubweek": "2017-43",
            "yle_language": "fi",
            "yle_contenttype": "article",
            "yle_organization": "1441-ajankohtaiset",
            "yle_pub": "2017-10-29",
            "yle_pagetype": "newscontent-news",
            "yle_mediatype": "image",
            "yle_articleid": "9905944",
            "countername": "tekniikka.posti_paljastaa_mainostajille_milloin_muutat_ja_trafi_sen_milloin_tarvitset_uuden_auton.sivu",
            "yle_stickytitle": "posti_paljastaa_mainostajille_milloin_muutat_ja_trafi_sen_milloin_tarvitset_uuden_auton",
            "yle_artby": "rigatsa",
            "yle_topic": "tekniikka",
            "yle_dayssincepublish": "1",
            "yle_system": "escenic",
            "yle_origin": "uutiset",
            "yle_id": "3-9905944",
            "yle_schemaid": "3"
        }
    }
}

400 Bad Request if required parameters are missing

cURL example

curl -XGET https://metrics.api.yle.fi/v2/labels/pageload/articles.json?id=3-9905944&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID

Recent changes to Metrics API

Previously, the Metrics API made HTTP calls to Programs API every time tracking parameters were requested. To reduce load on Programs API, the implementation was changed to use a message queue to listen for changes as they happen and store the information required for generating tracking parameters in a local database.

Because Meta API and Metrics API now receive the same change messages, the message format was changed into a form usable by both APIs. This has resulted in some small changes to tracking parameter generation logic.

List of changes

Title language

Program title and series title (used in fields such as title, ns_st_pr, yle_title, countername etc.) can now be in a language other than Finnish or Swedish if a Finnish or Swedish title cannot be found.

The previous version of the API ranked titles for selection in the following order: series title (fi), program title (fi), series title (sv), program title (sv). The new version, however, ranks the titles like this: series title (fi), series title (other language), program title (fi), program title (other language). As a result, e.g. a Swedish series title will be ranked higher than a Finnish program title. This only affects results when the program has a Finnish title but is for some reason missing a Finnish series title, which should be rare.

Language parameter

yle_language used to be either the audio language or the video language of the program. In the current implementation, if neither audio nor video language can be found, this parameter may also be the subtitle language.

OVP Search API

GET /v1/events/schedule.json List publications for event schedule

List publications for an event schedule. An event is defined by one or more concepts.
The requested concepts and other filtering criteria are given as request parameters.

This API is so called id-API meaning that the responses don’t contain rich data but basically only IDs of result objects.

OVP = online video platfrom for program meta data.

Parameters

Name Required Description
concept Yes The concepts ids.
Single value or a comma seprated list of values. Can have multiple values.
E.g. concept=1,2&concept=3 translates to ((1 && 2) || 3).
contentType No Single or comma separated list of different content type values.
start No Publication’s start time.
A comma separated list of two times in format YYYY-MM-ddTHH:mm:ss.
Finds publications where the start time is between the provided values.
start=2017-01-01T12:00:00,2017-01-01T16:00:00 - Finds publications where the start time is between (inclusive) 2017-01-01T12:00:00 and 2017-01-01T16:00:00
start=2017-01-01T12:00:00, - Finds publications where the start time is later than (inclusive) 2017-01-01T12:00:00
start=,2017-01-01T16:00:00 - Finds publications where the start time is earlier than (inclusive) 2017-01-01T16:00:00
end No Publication’s end time.
A comma separated list of two times in format YYYY-MM-ddTHH:mm:ss.
Finds publications where the end time is between the provided values.
end=2017-01-01T12:00:00,2017-01-01T16:00:00 - Finds publications where the end time is between (inclusive) 2017-01-01T12:00:00 and 2017-01-01T16:00:00
end=2017-01-01T12:00:00, - Finds publications where the end time is later than (inclusive) 2017-01-01T12:00:00
end=,2017-01-01T16:00:00 - Finds publications where the end time is earlier than (inclusive) 2017-01-01T16:00:00
order No The sort order of the results. Defaults to start:asc - by publication start time in ascending order.
offset No Number of items to skip. Default: 0.
limit No Maximum number of items in the results. Default: 25.

Response

200 OK on success

{
  "meta": {
    "count": "2"
  },
  "data": [
    {
      "id": "4-123",
      "type": "ScheduledTransmission",
      "content": {
        "id": "1-1456",
        "series": {
          "id": "1-1789"
        }
      }
    },
    {
      "id": "4-456",
      "type": "ScheduledTransmission",
      "content": {
        "id": "1-2456",
        "series": {
          "id": "1-2789"
        }
      }
    }
  ]
}

GET /v1/publications/current.json List current publications

List current publications by concept(s)
The requested concepts and other filtering criteria are given as request parameters.

This API is so called id-API meaning that the responses don’t contain rich data but basically only IDs of result objects.

OVP = online video platfrom for program meta data.

Parameters

Name Required Description
concept Yes The concepts ids.
Single value or a comma seprated list of values. Can have multiple values.
E.g. concept=1,2&concept=3 translates to ((1 && 2) || 3).
contentType No Single or comma separated list of different content type values. (Program Clip TVContent RadioContent TVProgram TVClip RadioProgram RadioClip)
type No Single or comma separated list of different publication type values. (OnDemandPublication ScheduledTransmission)
mediaAvailable No Boolean.
order No The sort order of the results. Defaults to start:desc - by publication start time in descending order. (start:desc start:asc end:desc end:asc playcounts.month:asc playcounts.month:desc playcounts.week:asc playcounts.week:desc playcounts.24h:asc playcounts.24h:desc playcounts.6h:asc playcounts.6h:desc)
offset No Number of items to skip. Default: 0.
limit No Maximum number of items in the results. Default: 25.

Response

200 OK on success

{
  "meta": {
    "count": "2"
  },
  "data": [
    {
      "id": "4-123",
      "type": "ScheduledTransmission",
      "content": {
        "id": "1-1456",
        "series": {
          "id": "1-1789"
        }
      }
    },
    {
      "id": "4-456",
      "type": "ScheduledTransmission",
      "content": {
        "id": "1-2456",
        "series": {
          "id": "1-2789"
        }
      }
    }
  ]
}

GET /v1/publications/future.json List future publications

List future publications by concept(s).
The requested concepts and other filtering criteria are given as request parameters.

This API is so called id-API meaning that the responses don’t contain rich data but basically only IDs of result objects.

OVP = online video platfrom for program meta data.

Parameters

Name Required Description
concept Yes The concepts ids.
Single value or a comma seprated list of values. Can have multiple values.
E.g. concept=1,2&concept=3 translates to ((1 && 2) || 3).
contentType No Single or comma separated list of different content type values. (Program Clip TVContent RadioContent TVProgram TVClip RadioProgram RadioClip)
type No Single or comma separated list of different publication type values. (OnDemandPublication ScheduledTransmission)
order No The sort order of the results. Defaults to start:asc - by publication start time in ascending order. (start:desc start:asc end:desc end:asc)
offset No Number of items to skip. Default: 0.
limit No Maximum number of items in the results. Default: 25.

Response

200 OK on success

{
  "meta": {
    "count": "2"
  },
  "data": [
    {
      "id": "4-123",
      "type": "ScheduledTransmission",
      "content": {
        "id": "1-1456",
        "series": {
          "id": "1-1789"
        }
      }
    },
    {
      "id": "4-456",
      "type": "ScheduledTransmission",
      "content": {
        "id": "1-2456",
        "series": {
          "id": "1-2789"
        }
      }
    }
  ]
}

Packages API

GET /v4/packages/{packageId}/ao.json Get items of package in alphabetical order

Returns series and single programs that belong to the package in alphabetical order, sorted by title.

Parameters

Check https://packages.api.yle.fi/swagger/index.html for details.

Name Description
packageId Id of the package
language Title language for sorting, fi/sv
media_language Language selection
limit Limit the number of returned items
geo_restricted Return only items that are geographically restricted
downloadable Return only downloadable items
offset Offsetting value

GET /v4/packages/{packageId}/expiring.json Get expiring items of package

Returns episodes and single programs that belong to package in order of expiry, i.e. earliest expiration date first.

Parameters

Check https://packages.api.yle.fi/swagger/index.html for details.

Name Description
packageId Id of the package
grouping Groups items in response by parameter
media_language Language selection
limit Limit the number of returned items
geo_restricted Return only items that are geographically restricted
downloadable Return only downloadable items
offset Offsetting value

GET /v4/packages/{packageId}/extended-recommendations.json Get extended recommendations of package

Returns package’s recommendations, followed by the package’s most popular series and single programs in popularity order, i.e. recommendations.json + popular.json without duplicates.

Parameters

Check https://packages.api.yle.fi/swagger/index.html for details.

Name Description
packageId Id of the package
limit Limit the number of returned items
offset Offsetting value
timeframe Calculate popularity in given timeframe: 6h, 24h, week or month.

GET /v4/packages/{packageId}/future.json Get future items of package

Returns package’s broadcasts and webcasts that start in the future, earliest first.

Parameters

Check https://packages.api.yle.fi/swagger/index.html for details.

Name Description
packageId Id of the package
grouping Groups items in response by parameter
limit Limit the number of returned items
offset Offsetting value

GET /v4/packages/{packageId}/latest.json Get latest items of package

Returns series and single programs that belong to package in reverse chronological order, i.e. latest first.

Parameters

Check https://packages.api.yle.fi/swagger/index.html for details.

Name Description
packageId Id of the package
grouping Groups items in response by parameter.
media_language Language selection
limit Limit the number of returned items
geo_restricted Return only items that are geographically restricted
downloadable Return only downloadable items
offset Offsetting value
episodes_as_series Return series objects instead of episodes where applicable

GET /v4/packages/{packageId}/popular.json Get most popular items of package

Returns the most popular programs and series that belong to package, most popular first.

Parameters

Check https://packages.api.yle.fi/swagger/index.html for details.

Name Description
packageId Id of the package
grouping Groups items in response by parameter.
media_language Language selection
limit Limit the number of returned items
geo_restricted Return only items that are geographically restricted
downloadable Return only downloadable items
offset Offsetting value
episodes_as_series Return series objects instead of episodes where applicable
exclude When “recommendations”, excludes recommendations for given package from results
timeframe Calculate popularity in given timeframe: 6h, 24h, week or month.

GET /v4/packages/{packageId}/recommendations.json Get recommendations of package

Returns package’s recommendations. Recommendations are hand-picked content that are most relevant to that package at any given moment.

Parameters

Check https://packages.api.yle.fi/swagger/index.html for details.

Name Description
packageId Id of the package
limit Limit the number of returned items
offset Offsetting value

GET /v4/{package}.json Get a package

General

Yle Areena uses packages for organizing content so that end users could find relevant content easily. Packages has few different ways content is attached to them.

Genres

Package might have one or more classifications attached to it. For example there might be Package for Forest. That package then could have classifications ‘nature’ and ‘animals’ included and maybe a ‘news content’ excluded from it. Then when you are requesting items that belong to that Package you get all content that have nature or animals classification in it but is not considered to be news.

Recommendations

There is also recommended content in most of the packages. Those recommendations are hand-picked by Yle staff. Picked items are most relevant content for that package at any time. Those recommendations might change or priorities between items might change multiple times a day depending how much new content is coming out.

Relations

Packages may also have seeAlso relations to other packages. So for example ‘Movie package’ could have a seeAlso relation to ‘Finnish movies’ and ‘Foreign movies’ packages.

GET Package by id.

Returns basic information about package by id.

Parameters and details.

Check https://packages.api.yle.fi/swagger/index.html for details.

Name Description
package Id of the package

GET /v4/packages/{packageId}/related.json Get relations of package

Returns package’s relations to other packages. Package might have different relation types (SeeAlso and Narrower). SeeAlso is used to relate similar packages to each other. Narrower is used to indicate a sub-package relation.

Parameters

Check https://packages.api.yle.fi/swagger/index.html for parameters.

Name Description
packageId Id of the package
predicate seeAlso or narrower. Defines what kind/type relation is.
refresh Refresh caches

Playlist API

General information

Playlist API returns information about songs played on the radio. The service parameter refers to station, such as ylex which is currently only supported service.

GET /v1/performers.json Get performers

Returns names of performers played in service.

Query parameters

Name Description Required
service Name of the service queried true
performer_prefix First letter(s) of the performer names searched for true
limit Default value 50. Max 100.  
offset Default value 0  
app_id Application id true
app_key Application key true

Response

200 OK on success

Everything went OK. Body contains all performer names in data array matching given performer_prefix.

Response example:

{
  "meta": {
    "service": "ylex",
    "limit": 50,
    "offset": 0,
    "performer_prefix": "pap"
  },
  "data": [
    "PAPA ROACH",
    "PAPERI T"
  ]
}

400 Bad Request invalid parameters

Invalid request parameters. Do not retry the request without fixing the problems with the request parameters.

500 Internal server error

Unexpected error occured. You can try retrying the request in a while.

cURL example

curl "http://playlist.api-test.yle.fi/v1/performers.json?service=ylex&performer_prefix=me&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"
{
  "meta": {
      "limit": 50,
      "offset": 0,
      "performer_prefix": "me",
      "service": "ylex"
  },
  "data": [
      "ME & MY",
      "MEANWHILE",
      "MEAT LOAF",
      "MEEK MILL",
      "MEGADETH",
      "MEGAPHONE STATE",
      "MEGHAN TRAINOR",
      "MELANIE C",
      "MELODIE MC",
      "MEREDITH BROOKS",
      "METALLICA",
      "METRO STATION",
      "MEW"
  ]
}

GET /v1/playout_events.json Get playout events

Returns playout events of service sorted descending by startTime.

Query parameters

Name Description Required
service Name of the service queried true
start yyyy-MM-dd’T’HH:mm:ssZ for example 2014-08-21T10:53:05+0300  
end yyyy-MM-dd’T’HH:mm:ssZ for example 2014-08-21T10:53:05+0300  
limit Default value 50. Max 100.  
offset Default value 0  
app_id Application id true
app_key Application key true

Response

200 OK on success

Everything went OK. Body contains all playout events in data array matching given service.

400 Bad Request invalid parameters

Invalid request parameters. Do not retry the request without fixing the problems with the request parameters.

500 Internal server error

Unexpected error occured. You can try retrying the request in a while.

cURL example

Note the limit param, these jsons can be huge. By default 50 latest events are returned.

curl "http://playlist.api-test.yle.fi/v1/playout_events.json?service=ylex&limit=2&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"
{
	"meta": {
		"offset": 0,
		"limit": 2,
		"service": "ylex"
	},
	"data": [{
		"partOf": {
			"radiomanId": "12-1025-4-119368",
			"type": "RadioProgram",
			"title": {
				"fi": "Poikelus ja Hätönen"
			}
		},
		"service": "ylex",
		"startTime": "2017-09-13T14:47:47+0300",
		"endTime": "2017-09-13T14:51:24+0300",
		"type": "NowPlaying",
		"content": {
			"playoutEventCount": 137,
			"duration": "PT217S",
			"performer": [{
				"name": "BIFFY CLYRO",
				"type": "agent"
			}],
			"radiomanId": "12-1025-2-17776",
			"type": "MusicRecording",
			"title": {
				"unknown": "Re-arrange"
			}
		}
	}, {
		"partOf": {
			"radiomanId": "12-1025-4-119368",
			"type": "RadioProgram",
			"title": {
				"fi": "Poikelus ja Hätönen"
			}
		},
		"service": "ylex",
		"startTime": "2017-09-13T14:42:50+0300",
		"endTime": "2017-09-13T14:46:27+0300",
		"type": "NowPlaying",
		"content": {
			"playoutEventCount": 19,
			"duration": "PT217S",
			"performer": [{
				"name": "ANNA PUU",
				"type": "agent"
			}],
			"radiomanId": "12-1025-2-18668",
			"type": "MusicRecording",
			"title": {
				"unknown": "Nälkäinen sydän"
			}
		}
	}]

GET /v1/songs.json Get songs

Returns information about songs played in service. Data includes, but is not limited to, lates playout event for song and total playout count.

Query parameters

Name Description Required
service Name of the service queried true
radioman_id Comma separated list of ids. Max 10 ids.  
performer_name Name of the performer, such as METALLICA  
start yyyy-MM-dd’T’HH:mm:ssZ for example 2014-08-21T10:53:05+0300  
end yyyy-MM-dd’T’HH:mm:ssZ for example 2014-08-21T10:53:05+0300  
sort Currently only playout_event_count:desc is supported  
limit Default value 50. Max 100.  
offset Default value 0  
title_prefix First letter(s) of the song titles searched for  
app_id Application id true
app_key Application key true

Response

200 OK on success

Everything went OK. Body contains all songs with playout count matching query.

400 Bad Request invalid parameters

Invalid request parameters. Do not retry the request without fixing the problems with the request parameters.

500 Internal server error

Unexpected error occured. You can try retrying the request in a while.

cURL example

curl "http://playlist.api-test.yle.fi/v1/songs.json?service=ylex&performer_name=METALLICA&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"
{
	"meta": {
		"offset": 0,
		"limit": 50,
		"service": "ylex",
		"performer_name": "METALLICA"
	},
	"data": [{
		"lastPlayoutEvent": {
			"partOf": {
				"radiomanId": "12-1025-4-103750",
				"type": "RadioProgram",
				"title": {
					"fi": "Parasta ennen!"
				}
			},
			"service": "ylex",
			"startTime": "2016-09-16T21:35:18+0300",
			"endTime": "2016-09-16T21:41:43+0300",
			"type": "NowPlaying"
		},
		"playoutEventCount": 2,
		"duration": "PT385S",
		"performer": [{
			"name": "METALLICA",
			"type": "agent"
		}],
		"radiomanId": "12-1025-2-1560",
		"type": "MusicRecording",
		"title": {
			"unknown": "NOTHING ELSE MATTERS"
		}
	}, {
		"lastPlayoutEvent": {
			"partOf": {
				"radiomanId": "12-1025-4-102181",
				"type": "RadioProgram",
				"title": {
					"fi": "YleX Kesätoiveet"
				}
			},
			"service": "ylex",
			"startTime": "2016-07-12T18:49:25+0300",
			"endTime": "2016-07-12T18:54:01+0300",
			"type": "NowPlaying"
		},
		"playoutEventCount": 3,
		"duration": "PT276S",
		"performer": [{
			"name": "METALLICA",
			"type": "agent"
		}],
		"radiomanId": "12-1025-2-37",
		"type": "MusicRecording",
		"title": {
			"unknown": "WHISKEY IN THE JAR"
		}
	}, {
		"lastPlayoutEvent": {
			"partOf": {
				"radiomanId": "12-1025-4-98660",
				"type": "RadioProgram",
				"title": {
					"fi": "Parasta ennen!"
				}
			},
			"service": "ylex",
			"startTime": "2016-03-18T21:20:16+0200",
			"endTime": "2016-03-18T21:29:32+0200",
			"type": "NowPlaying"
		},
		"playoutEventCount": 1,
		"duration": "PT556S",
		"performer": [{
			"name": "METALLICA",
			"type": "agent"
		}],
		"radiomanId": "12-1025-2-927",
		"type": "MusicRecording",
		"title": {
			"unknown": "THE UNFORGIVEN"
		}
	}, {
		"lastPlayoutEvent": {
			"partOf": {
				"radiomanId": "12-1025-4-82658",
				"title": {
					"fi": "YleX Jatkot"
				},
				"type": "RadioProgram"
			},
			"service": "ylex",
			"startTime": "2015-03-10T20:09:52+0200",
			"endTime": "2015-03-10T20:15:24+0200",
			"type": "NowPlaying"
		},
		"playoutEventCount": 2,
		"duration": "PT332S",
		"performer": [{
			"name": "METALLICA",
			"type": "agent"
		}],
		"radiomanId": "12-1025-2-353",
		"title": {
			"unknown": "ENTER SANDMAN"
		},
		"type": "MusicRecording"
	}]
}

Profiles API

General

Profiles API is a Yle Tunnus-authenticated RESTful API for user-specific data.

An Yle Tunnus-authenticated end user has a right to manipulate her own data, so Profiles API can also be used directly from JavaScript. No service-specific backend is required.
The two limitations are a cap of 1000 items per user per feature and the cap of 1000 bytes per item.
Contact Yle Tunnus Support if you want to increase either of these.

Getting started

  1. In order to use Profiles API, your application needs to register a feature to Profiles API. This is mandatory because otherwise a malicious authenticated user could flood the API with rubbish data. There is currently no way to programmatically register a feature. Features can only be registered by contacting Yle Tunnus Support.
  2. Profiles API requires the use of application-specific API gateway (Dragonscale) authentication keys. These keys are appended to the end of the request URL. You can get your Profiles API authentication keys from Yle Tunnus Support.

Schemas

Applications using Profiles API can optionally provide a JSON schema for their data. If a schema is provided, input data will be validated against it. More info on setting up and using schemas can be found here (in Finnish).

GET /v1/api/{userId}/{serviceId} Get all the features and their data of a service

Returns all features and their data for a given service.

URL parameters

Name Required Description
userId Yes Yle Tunnus surrogate key
serviceId Yes Service ID e.g. ‘tv’
limit No Limit the result to first N results
offset No Returns the result beginning from offset
<field name> No All other parameters work as a filter, for example name=john returns only the results which have a field named name with a value of john. The search is case-sensitive. Inverse filtering is also possible: name-=john returns all results where the field named name is not equal to john, or there is no field named name at all.

NOTE! Filtering byt field value does not support other than “string” types at the moment

Response

Example request

curl "https://profiles.api.yle.fi/v1/api/USER_ID/SERVICE_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"feature1": [{"id": "1234567",
               "dataItemName": "foo"} ...],
 "feature2": [],
 ...}

400 Bad Request if any serviceId does not match existing data

GET /v1/api/{userId}/{serviceId}/{featureId} Get all data items of a feature

Returns an array of all data items in a feature.

URL parameters

Name Required Description
userId Yes Yle Tunnus surrogate key
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’
order No Order of the feature data items can be modified with the order query parameter. For example order=name:asc sorts results by the field name in ascending order, whereas order=name:desc would sort them in descending order. Please note that sorting is always performed alphabetically regardless of the field type.
limit No Limit the result to first N results
offset No Returns the result beginning from offset
<field name> No All other parameters work as a filter, for example name=john returns only the results which have a field named name with a value of john. The search is case-sensitive. Inverse filtering is also possible: name-=john returns all results where the field named name is not equal to john, or there is no field named name at all.

NOTE! Filtering by field values that aren’t “string” types requires a json-schema to function correctly.

Response

Example request

curl "https://profiles.api.yle.fi/v1/api/USER_ID/SERVICE_ID/FEATURE_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

[
    {"id": "fFSFsdF9sdfj9098329rhfHNSDJKvSNFSjFK",
     "dataItemName": "foo",
     ...},
    {"id": "vndHFDSFIEho344nfkjVNKSJOFI2384scnjd",
     ...}
]

400 Bad Request if any serviceId or featureId does not match existing data

POST /v1/api/{userId}/{serviceId}/{featureId} Add new item to a feature

Add a new item and return it with the ID of the persisted item.

URL parameters

Name Required Description
userId Yes Yle Tunnus surrogate key
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’

Response

Example request

curl -XPOST -H "Content-Type: application/json" -d '{"dataItemName": "foo"}' \
  "https://profiles.api.yle.fi/v1/api/USER_ID/SERVICE_ID/FEATURE_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"id": "dsfnj2nf2jk3jkna", "dataItemName": "foo"}

400 Bad Request if any serviceId or featureId does not match existing data

DELETE /v1/api/{userId}/{serviceId}/{featureId} Delete all items of a feature

Delete all the items of a given feature.

URL parameters

Name Required Description
userId Yes Yle Tunnus surrogate key
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’

Response

Example request

curl -XDELETE "https://profiles.api.yle.fi/v1/api/USER_ID/SERVICE_ID/FEATURE_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"message":"OK"}

400 Bad Request if any serviceId or featureId does not match existing data

GET /v1/api/{userId}/{serviceId}/{featureId}/{dataId} Get a item of a feature

Returns a single item with the given ID.

URL parameters

Name Required Description
userId Yes Yle Tunnus surrogate key
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’
limit No Limit the result to first N results
offset No Returns the result beginning from offset

Response

Example request

curl "https://profiles.api.yle.fi/v1/api/USER_ID/SERVICE_ID/FEATURE_ID/DATA_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"id": "fFSFsdF9sdfj9098329rhfHNSDJKvSNFSjFK",
 "dataItemName": "foo",
 ...}

400 Bad Request if any serviceId or featureId does not match existing data

PUT /v1/api/{userId}/{serviceId}/{featureId}/{dataId} Update item content in a feature

Updates the content of an item in a feature.

URL parameters

Name Required Description
userId Yes Yle Tunnus surrogate key
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’
dataId Yes Data ID e.g. ‘fdsfh389h3’

Response

Example request

curl -XPUT -H "Content-Type: application/json" -d '{"dataItemName": "bar"}' "https://profiles.api.yle.fi/v1/api/USER_ID/SERVICE_ID/FEATURE_ID/DATA_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"id": "fFSFsdF9sdfj9098329rhfHNSDJKvSNFSjFK",
 "dataItemName": "bar"}

400 Bad Request if any serviceId or featureId does not match existing data

DELETE /v1/api/{userId}/{serviceId}/{featureId}/{dataId} Delete a single item

Delete a single item from a given feature.

URL parameters

Name Required Description
userId Yes Yle Tunnus surrogate key
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’
dataId Yes Data ID e.g. ‘fdsfh389h3’

Response

Example request

curl -XDELETE "https://profiles.api.yle.fi/v1/api/USER_ID/SERVICE_ID/FEATURE_ID/DATA_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"message":"OK"}

400 Bad Request if any serviceId or featureId does not match existing data

heading Version 2 endpoints

These endpoints do not have userId part in the path. Requests are targeted to correct user by the given Tunnus cookie.

GET /v2/api/{serviceId} Get all the features and their data of a service

Returns all features and their data for a given service.

URL parameters

Name Required Description
serviceId Yes Service ID e.g. ‘tv’
limit No Limit the result to first N results
offset No Returns the result beginning from offset
<field name> No All other parameters work as a filter, for example name=john returns only the results which have a field named name with a value of john. The search is case-sensitive. Inverse filtering is also possible: name-=john returns all results where the field named name is not equal to john, or there is no field named name at all.

Response

Example request

curl "https://profiles.api.yle.fi/v2/api/SERVICE_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"feature1": [{"id": "1234567",
               "dataItemName": "foo"} ...],
 "feature2": [],
 ...}

400 Bad Request if any serviceId does not match existing data

GET /v2/api/{serviceId}/{featureId} Get all data items of a feature

Returns an array of all data items in a feature.

URL parameters

Name Required Description
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’
order No Order of the feature data items can be modified with the order query parameter. For example order=name:asc sorts results by the field name in ascending order, whereas order=name:desc would sort them in descending order. Please note that sorting is always performed alphabetically regardless of the field type.
limit No Limit the result to first N results
offset No Returns the result beginning from offset
<field name> No All other parameters work as a filter, for example name=john returns only the results which have a field named name with a value of john. The search is case-sensitive. Inverse filtering is also possible: name-=john returns all results where the field named name is not equal to john, or there is no field named name at all.

Response

Example request

curl "https://profiles.api.yle.fi/v2/api/SERVICE_ID/FEATURE_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

[
    {"id": "fFSFsdF9sdfj9098329rhfHNSDJKvSNFSjFK",
     "dataItemName": "foo",
     ...},
    {"id": "vndHFDSFIEho344nfkjVNKSJOFI2384scnjd",
     ...}
]

400 Bad Request if any serviceId or featureId does not match existing data

POST /v2/api/{serviceId}/{featureId} Add new item to a feature

Add a new item and return it with the ID of the persisted item.\ Optionally returns all items in the feature.

URL parameters

Name Required Description
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’

Query parameters

Name Required Description
returnAll No If true returns all items in the feature in response. Default is false.

Response

Example request

curl -XPOST -H "Content-Type: application/json" -d '{"dataItemName": "foo"}' \
  "https://profiles.api.yle.fi/v2/api/SERVICE_ID/FEATURE_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"id": "dsfnj2nf2jk3jkna", "dataItemName": "foo"}

Example request with ‘returnAll’

curl -XPOST -H "Content-Type: application/json" -d '{"dataItemName": "quux"}' \
  "https://profiles.api.yle.fi/v2/api/SERVICE_ID/FEATURE_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY&returnAll=true" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{
 "data":
     {
        "newId": "fj09dn3ndjkwedks",
        "items":
            [
                {"id": "dsfnj2nf2jk3jkna", "dataItemName": "foo"},
                {"id": "fj09dn3ndjkwedks", "dataItemName": "quux"}
            ]
     }
}

400 Bad Request if any serviceId or featureId does not match existing data

DELETE /v2/api/{serviceId}/{featureId} Delete all items of a feature

Delete all the items of a given feature.

URL parameters

Name Required Description
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’

Response

Example request

curl -XDELETE "https://profiles.api.yle.fi/v2/api/SERVICE_ID/FEATURE_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"message":"OK"}

400 Bad Request if any serviceId or featureId does not match existing data

GET /v2/api/{serviceId}/{featureId}/{dataId} Get a item of a feature

Returns a single item with the given ID.

URL parameters

Name Required Description
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’
limit No Limit the result to first N results
offset No Returns the result beginning from offset
<field name> No All other parameters work as a filter, for example name=john returns only the results which have a field named name with a value of john. The search is case-sensitive. Inverse filtering is also possible: name-=john returns all results where the field named name is not equal to john, or there is no field named name at all.

Response

Example request

curl "https://profiles.api.yle.fi/v2/api/SERVICE_ID/FEATURE_ID/DATA_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"id": "fFSFsdF9sdfj9098329rhfHNSDJKvSNFSjFK",
 "dataItemName": "foo",
 ...}

400 Bad Request if any serviceId or featureId does not match existing data

PUT /v2/api/{serviceId}/{featureId}/{dataId} Update item content in a feature

Updates the content of an item in a feature.

URL parameters

Name Required Description
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’
dataId Yes Data ID e.g. ‘fdsfh389h3’

Response

Example request

curl -XPUT -H "Content-Type: application/json" -d '{"dataItemName": "bar"}' "https://profiles.api.yle.fi/v2/api/SERVICE_ID/FEATURE_ID/DATA_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"id": "fFSFsdF9sdfj9098329rhfHNSDJKvSNFSjFK",
 "dataItemName": "bar"}

400 Bad Request if any serviceId or featureId does not match existing data

DELETE /v2/api/{serviceId}/{featureId}/{dataId} Delete a single item

Delete a single item from a given feature.\ Optionally returns all items in the feature.

URL parameters

Name Required Description
serviceId Yes Service ID e.g. ‘tv’
featureId Yes Feature ID e.g. ‘history’
dataId Yes Data ID e.g. ‘fdsfh389h3’

Query parameters

Name Required Description
returnAll No If true returns all items in the feature in response. Default is false.

Response

Example request

curl -XDELETE "https://profiles.api.yle.fi/v2/api/SERVICE_ID/FEATURE_ID/DATA_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --cookie "ylelogin=COOKIE_VALUE"

200 OK on success

{"message":"OK"}

Example request with ‘returnAll’

Database having

[
    {"id": "dsfnj2nf2jk3jkna", "dataItemName": "foo"},
    {"id": "DATA_ID", "dataItemName": "quux"}
]

and then making the following request

curl -XDELETE "https://profiles.api.yle.fi/v2/api/SERVICE_ID/FEATURE_ID/DATA_ID?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY&returnAll=true" \
  --cookie "ylelogin=COOKIE_VALUE"

results in

200 OK on success

{
 "data":
     {
        "items":
            [
                {"id": "dsfnj2nf2jk3jkna", "dataItemName": "foo"}
            ]
     }
}

400 Bad Request if any serviceId or featureId does not match existing data

Programs API

GET /v1/id/{id}.json Get a single object (clip, program or series)

Returns a single item (clip, program or series) by the ID parameter. E.g. Getting program by id: v1/id/1-2.json

Parameters

Name Description
id The ID of the desired program, episode, clip or series

Response

200 OK on success

Response contains a JSON document with one program.

400 Bad Request if required parameters are missing

404 Not Found If the id given is not a valid program id

cURL example

Details about a program

curl -XGET "https://programs.api.yle.fi/v1/id/1-200102.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": {
	"@id": "https://programs.api.yle.fi/v1/id/1-200102",
	"alternativeId": [
	    "16-1-0650408"
	],
	"audio": [
	    {
		"format": [
		    {
			"inScheme": "mediaformat-classification",
			"key": "stereo",
			"type": "Concept"
		    }
		],
		"language": [
		    "fi"
		],
		"type": "AudioTrack"
	    }
	],
	"collection": "main",
	"contentRating": {
	    "reason": [],
	    "title": {}
	},
	"countryOfOrigin": [
	    "Suomi"
	],
	"creator": [
	    {
		"name": "YLE",
		"type": "Organization"
	    }
	],
	"description": {
	    "fi": "Kokki Anu valmistaa broiler-aterian uudella tavalla.",
	    "sv": "Kocken Anu tillreder en broilerr\u00e4tt p\u00e5 ett nytt s\u00e4tt."
	},
	"duration": "PT13M5S",
	"id": "1-200102",
	"image": {
	    "available": true,
	    "id": "13-1-200102",
	    "type": "ImageObject"
	},
	"indexDataModified": "2015-05-09T12:37:23.117+03:00",
	"itemTitle": {},
	"originalTitle": {},
	"partOfSeries": {
	    "@id": "https://programs.api.yle.fi/v1/id/1-200275",
	    "countryOfOrigin": [],
	    "creator": [],
	    "description": {},
	    "id": "1-200275",
	    "image": {},
	    "indexDataModified": "2015-05-09T00:36:24.419+03:00",
	    "subject": [],
	    "title": {
		"fi": "POPsis!",
		"sv": "POPsis!"
	    },
	    "type": "TVSeries"
	},
	"productionId": "51026301000",
	"publicationEvent": [
	    {
		"duration": "P1MT15H26M59S",
		"endTime": "2012-10-03T23:59:59+03:00",
		"id": "4-2331952",
		"media": {
		    "available": true,
		    "contentProtection": [
			{
			    "id": "22-1",
			    "type": "ContentProtectionPolicy"
			}
		    ],
		    "downloadable": false,
		    "duration": "PT13M5S",
		    "id": "6-b155e9ce6373450a8874cf3dadccfa78",
		    "type": "VideoObject"
		},
		"publisher": [
		    {
			"id": "yle-tv2"
		    }
		],
		"region": "Finland",
		"service": {
		    "id": "yle-areena"
		},
		"startTime": "2012-09-03T08:33:00+03:00",
		"temporalStatus": "in-past",
		"type": "OnDemandPublication"
	    },
	    {
		"duration": "PT16M2S",
		"endTime": "2012-06-04T08:50:02+03:00",
		"id": "4-2184750",
		"media": {},
		"region": "Finland",
		"service": {
		    "id": "yle-tv2"
		},
		"startTime": "2012-06-04T08:34:00+03:00",
		"temporalStatus": "in-past",
		"type": "ScheduledTransmission"
	    },
	    {
		"duration": "PT13M22S",
		"endTime": "2009-08-01T09:39:22+03:00",
		"id": "4-312581",
		"media": {},
		"region": "World",
		"service": {
		    "id": "yle-tv2"
		},
		"startTime": "2009-08-01T09:26:00+03:00",
		"temporalStatus": "in-past",
		"type": "ScheduledTransmission"
	    },
	    {
		"duration": "PT13M8S",
		"endTime": "2012-09-03T08:46:08+03:00",
		"id": "4-2331951",
		"media": {},
		"region": "Finland",
		"service": {
		    "id": "yle-tv2"
		},
		"startTime": "2012-09-03T08:33:00+03:00",
		"temporalStatus": "in-past",
		"type": "ScheduledTransmission"
	    },
	    {
		"duration": "PT14M27S",
		"endTime": "2009-08-05T08:34:27+03:00",
		"id": "4-320330",
		"media": {},
		"region": "World",
		"service": {
		    "id": "yle-tv2"
		},
		"startTime": "2009-08-05T08:20:00+03:00",
		"temporalStatus": "in-past",
		"type": "ScheduledTransmission"
	    },
	    {
		"duration": "P1MT15H25M59S",
		"endTime": "2012-07-04T23:59:59+03:00",
		"id": "4-2184751",
		"media": {
		    "available": true,
		    "contentProtection": [
			{
			    "id": "22-1",
			    "type": "ContentProtectionPolicy"
			}
		    ],
		    "downloadable": false,
		    "duration": "PT13M5S",
		    "id": "6-b155e9ce6373450a8874cf3dadccfa78",
		    "type": "VideoObject"
		},
		"region": "Finland",
		"service": {
		    "id": "yle-areena"
		},
		"startTime": "2012-06-04T08:34:00+03:00",
		"temporalStatus": "in-past",
		"type": "OnDemandPublication"
	    },
	    {
		"duration": "PT16M9S",
		"endTime": "2009-08-01T09:46:09+03:00",
		"id": "4-312773",
		"media": {},
		"region": "World",
		"service": {
		    "id": "tv-finland"
		},
		"startTime": "2009-08-01T09:30:00+03:00",
		"temporalStatus": "in-past",
		"type": "ScheduledTransmission"
	    }
	],
	"subject": [
	    {
		"broader": {
		    "id": "5-130"
		},
		"id": "5-195",
		"inScheme": "areena-content-classification",
		"key": "lapset",
		"title": {
		    "fi": "Lapset",
		    "sv": "Barn"
		},
		"type": "Concept"
	    },
	    {
		"id": "21-10",
		"inScheme": "finnpanel-genre-classification",
		"notation": [
		    {
			"value": "8",
			"valueType": "finnpanel-notation"
		    }
		],
		"title": {
		    "en": "Children programs",
		    "fi": "Lastenohjelmat"
		},
		"type": "Concept"
	    }
	],
	"subtitling": [],
	"title": {
	    "fi": "POPsis!",
	    "sv": "POPsis!"
	},
	"type": "TVProgram",
	"typeCreative": "Program",
	"typeMedia": "TVContent",
	"video": {
	    "format": [
		{
		    "inScheme": "mediaformat-classification",
		    "key": "16:9",
		    "type": "Concept"
		}
	    ],
	    "language": [],
	    "type": "VideoTrack"
	}
    },
    "meta": {
	"id": "1-200102"
    }
}

GET /v1/items.json Search programs, clips and episodes

Returns a collection of items (programs, episodes or clips) matching a specified query.

Parameters

NameDescription
idReturns items containing the specified ID. Multiple IDs can be passed as a comma separated list.
typeReturns items matching the given type. E.g. All clips(tv and radio): "/v1/items.json?type=clip", all radioprograms and radioclips: "/v1/items.json?type=radiocontent", all tvprograms: "/v1/items.json?type=tvprogram". Allowed values for type are: "program", "clip", "tvcontent", "tvprogram", "tvclip", "radiocontent", "radioprogram", "radioclip"
qReturns items matching the given keyword. E.g. Items matching search criteria \"muumi\": /v1/items.json?q=muumi
mediaobjectReturns items according to media type (video or audio). E.g. All audio objects: "/v1/items.json?mediaobject=audio". Allowed values are: "audio" and "video".
categoryReturns items linked to a specified category. Multiple category IDs can be passed as a comma separated list. To exclude items that belong to a specific category, add '-' before the id. E.g. category=1,2,-3,-4 returns items that belong to either category 1 or 2 AND do NOT belong to categories 3 AND 4.
seriesReturns items containing the given series ID. Multiple IDs can be passed as a comma separated list.
availabilityReturns items matching the given availability status. "ondemand": returns items whose ondemand publication is currently valid and media object is available. "future-ondemand" returns items will become available as ondemand in the future. "future-scheduled" return items that will be broadcasted in the future. "in-future" returns the items that will either be broadcasted or become available as ondemand in the future. "expiring-ondemand.month" return items whose ondemand is currently available and is expiring within the month.
  • "",
  • "ondemand",
  • "future-ondemand",
  • "current-or-future-ondemand",
  • "future-scheduled",
  • "in-future",
  • "expiring-ondemand.month"
downloadableReturns items that can be downloaded (and not just streamed). If this parameter is used, the value of this parameter must be 'true'.
languageReturns items with audio track or subtitle language matching the given language. Example values are "", "fi", "sv", "en".
regionReturns items that contain a publication event with the given region. Allowed values are "fi" and "world".
serviceReturns items containing the given service.
publisherReturns items originally published by the given service.
contentprotectionReturns items that contain a publication event with the content protection. Multiple content protection IDs can be passed as a comma separated list.
orderReturns items in specified order. E.g. Items sorted ascending according to publications' starttimes: /v1/items.json?order=publication.starttime:asc. Note that sorting by ondemand.publication.starttime is deprecated, use publication.starttime instead. Allowed order parameters are:
  • "ondemand.publication.starttime:asc",
  • "ondemand.publication.starttime:desc",
  • "playcount.6h:asc:asc",
  • "playcount.6h:asc:desc",
  • "playcount.24h:asc:asc",
  • "playcount.24h:asc:desc",
  • "playcount.week:asc:asc",
  • "playcount.week:asc:desc",
  • "playcount.month:asc:asc",
  • "playcount.month:asc:desc",
  • "publication.starttime:asc",
  • "publication.starttime:desc",
  • "publication.endtime:asc",
  • "publication.endtime:desc",
  • "updated:asc",
  • "updated:desc",
  • "scheduled.latest:asc",
  • "scheduled.latest:desc",
  • "scheduled.future:asc",
  • "scheduled.future:desc"
limitSets limit for the size of the returned collection
offsetSets offset for the collection. Note that limit + offset must not be greater than 15 000.

Response

200 OK on success

Response contains a JSON document with programs. Maximum number of programs returned is limited by limit parameter.

400 Bad Request if parameters have illegal values

cURL example

Free text search example

curl -XGET "https://programs.api.yle.fi/v1/items.json?q=muumit&limit=1&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": [
	{
	    "@id": "https://programs.api.yle.fi/v1/id/1-2700948",
	    "alternativeId": [
		"12-1022-4-253311"
	    ],
	    "audio": [
		{
		    "format": [
			{
			    "inScheme": "mediaformat-classification",
			    "key": "stereo",
			    "type": "Concept"
			}
		    ],
		    "language": [
			"fi"
		    ],
		    "type": "AudioTrack"
		}
	    ],
	    "collection": "main",
	    "contentRating": {
		"reason": [],
		"title": {}
	    },
	    "countryOfOrigin": [],
	    "creator": [],
	    "description": {
		"fi": "Mit\u00e4 on lohturuoka? Milloin sana ilmestyi ensimm\u00e4isen kerran lehtien palstoille? Toimittaja Kaisa Pulakka pohtii lohturuoan olemusta. Lohturuoka liittyy lapsuuteen ja siin\u00e4 maistuu nostalgia.\r\n\r\nLohturuoka voi my\u00f6s toimia siltana menneeseen. The Sopranos TV-sarjassa ruoka vahvistaa italialaista identiteetti\u00e4. Ohjelmasta selvi\u00e4\u00e4 my\u00f6s, millaisia lohturuoan popsijoita ovat Viisikoiden lapset, Nalle Puh ja Tove Janssonin Muumi-hahmot.\r\n\r\nToimittajana Kaisa Pulakka. Lukijana Pietari Kylm\u00e4l\u00e4."
	    },
	    "duration": "PT19M21S",
	    "id": "1-2700948",
	    "image": {
		"available": true,
		"id": "13-1-2700948",
		"type": "ImageObject"
	    },
	    "indexDataModified": "2015-06-01T09:14:07.142+03:00",
	    "itemTitle": {
		"fi": "Nalle Puh, Muumit ja Sopranosit sy\u00f6v\u00e4t lohturuokaa"
	    },
	    "originalTitle": {},
	    "partOfSeries": {
		"@id": "https://programs.api.yle.fi/v1/id/1-2704918",
		"availabilityDescription": {
		    "fi": "Maanantaisin klo 17.40."
		},
		"countryOfOrigin": [],
		"coverImage": {
		    "available": true,
		    "id": "13-1-2704918-cover",
		    "type": "ImageObject"
		},
		"creator": [],
		"description": {
		    "fi": "\"Minuun iski ruoka-ahdistus. Tuntui, ett\u00e4 l\u00e4hikaupasta ei voi en\u00e4\u00e4 ostaa mit\u00e4\u00e4n.\" Ruoka on jatkuvasti tapetilla niin perinteisess\u00e4 kuin sosiaalisessakin mediassa. Ruoka ja sy\u00f6minen n\u00e4ytt\u00e4ytyv\u00e4t portteina henkiseen hyvinvointiin, mutta jatkuva ruokahypetys voi my\u00f6s aiheuttaa pahoinvointia. Toimittaja Kaisa Pulakka peilaa sarjassa ajatuksiaan kulttuurihistoriaan. 12-osainen radioesseiden sarja."
		},
		"id": "1-2704918",
		"image": {
		    "available": true,
		    "id": "13-1-2704918",
		    "type": "ImageObject"
		},
		"interactions": [
		    {
			"title": {
			    "fi": "Yle Areena Ruoka-Suomi"
			},
			"type": "WebPage",
			"url": "http://areena.yle.fi/tv/2417961"
		    },
		    {
			"title": {
			    "fi": "Yle Kulttuuri"
			},
			"type": "WebPage",
			"url": "http://yle.fi/aihe/kulttuuri"
		    },
		    {
			"title": {
			    "fi": "Yle Ruoka"
			},
			"type": "WebPage",
			"url": "http://yle.fi/aihe/ruoka"
		    },
		    {
			"title": {
			    "fi": "Sy\u00f6d\u00e4\u00e4n ensin! Ohjelman oma sivu"
			},
			"type": "WebPage",
			"url": "http://yle.fi/aihe/ohjelma/syodaan-ensin"
		    }
		],
		"subject": [
		    {
			"broader": {
			    "id": "5-218"
			},
			"id": "5-217",
			"inScheme": "areena-content-classification",
			"key": "kulttuuri",
			"title": {
			    "fi": "Kulttuuri",
			    "sv": "Kulturprogram"
			},
			"type": "Concept"
		    },
		    {
			"id": "5-263",
			"inScheme": "areena-analytics-classification",
			"key": "kulttuuri",
			"title": {
			    "fi": "Kulttuuri"
			},
			"type": "Concept"
		    }
		],
		"title": {
		    "fi": "Sy\u00f6d\u00e4\u00e4n ensin!"
		},
		"type": "RadioSeries"
	    },
	    "publicationEvent": [
		{
		    "duration": "PT19M22S",
		    "endTime": "2015-05-09T23:04:26+03:00",
		    "id": "4-4229816",
		    "media": {},
		    "region": "World",
		    "service": {
			"id": "yle-radio-1"
		    },
		    "startTime": "2015-05-09T22:45:04+03:00",
		    "temporalStatus": "in-past",
		    "type": "ScheduledTransmission"
		},
		{
		    "duration": "PT19M21S",
		    "endTime": "2015-05-04T18:00:07+03:00",
		    "id": "4-4211782",
		    "media": {},
		    "region": "World",
		    "service": {
			"id": "yle-radio-1"
		    },
		    "startTime": "2015-05-04T17:40:46+03:00",
		    "temporalStatus": "in-past",
		    "type": "ScheduledTransmission"
		},
		{
		    "duration": "P1MT14H44M59S",
		    "endTime": "2015-06-04T23:59:59+03:00",
		    "id": "4-4360824",
		    "media": {
			"available": true,
			"contentProtection": [
			    {
				"id": "22-0",
				"type": "ContentProtectionPolicy"
			    }
			],
			"downloadable": false,
			"duration": "PT19M24S",
			"id": "6-ef0f1296ffaa4c94873e94bfb15a7214",
			"type": "AudioObject"
		    },
		    "publisher": [
			{
			    "id": "yle-radio-1"
			}
		    ],
		    "region": "Finland",
		    "service": {
			"id": "yle-areena"
		    },
		    "startTime": "2015-05-04T09:15:00+03:00",
		    "temporalStatus": "currently",
		    "type": "OnDemandPublication"
		}
	    ],
	    "subject": [
		{
		    "broader": {
			"id": "5-200"
		    },
		    "id": "5-218",
		    "inScheme": "areena-content-classification",
		    "key": "faktajakulttuuri",
		    "title": {
			"fi": "Fakta ja Kulttuuri",
			"sv": "Fakta och kultur"
		    },
		    "type": "Concept"
		},
		{
		    "broader": {
			"id": "5-218"
		    },
		    "id": "5-217",
		    "inScheme": "areena-content-classification",
		    "key": "kulttuuri",
		    "title": {
			"fi": "Kulttuuri",
			"sv": "Kulturprogram"
		    },
		    "type": "Concept"
		},
		{
		    "id": "5-263",
		    "inScheme": "areena-analytics-classification",
		    "key": "kulttuuri",
		    "title": {
			"fi": "Kulttuuri"
		    },
		    "type": "Concept"
		},
		{
		    "id": "21-4",
		    "inScheme": "finnpanel-genre-classification",
		    "notation": [
			{
			    "value": "3.2",
			    "valueType": "finnpanel-notation"
			}
		    ],
		    "title": {
			"en": "Cultural",
			"fi": "Kulttuuriohjelmat"
		    },
		    "type": "Concept"
		}
	    ],
	    "subtitling": [],
	    "title": {
		"fi": "Sy\u00f6d\u00e4\u00e4n ensin!: Nalle Puh, Muumit ja Sopranosit sy\u00f6v\u00e4t lohturuokaa"
	    },
	    "type": "RadioProgram",
	    "typeCreative": "Program",
	    "typeMedia": "RadioContent",
	    "video": {}
	}
    ],
    "meta": {
	"clip": 8,
	"count": 59,
	"limit": "1",
	"offset": "0",
	"program": 51,
	"q": "muumit"
    }
}

GET /v1/items/{id}.json Get a single program, clip or episode

Returns the program, episode or clip. E.g. /v1/items/1-2.json

Parameters

Name Description
id The ID of the desired program, episode or clip

Response

200 OK on success

Response contains a JSON document with one program.

400 Bad Request if required parameters are missing

404 Not Found If the id given is not a valid program id

cURL example

Details about a program

curl -XGET "https://programs.api.yle.fi/v1/items/1-200102.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": {
	"@id": "https://programs.api.yle.fi/v1/id/1-200102",
	"alternativeId": [
	    "16-1-0650408"
	],
	"audio": [
	    {
		"format": [
		    {
			"inScheme": "mediaformat-classification",
			"key": "stereo",
			"type": "Concept"
		    }
		],
		"language": [
		    "fi"
		],
		"type": "AudioTrack"
	    }
	],
	"collection": "main",
	"contentRating": {
	    "reason": [],
	    "title": {}
	},
	"countryOfOrigin": [
	    "Suomi"
	],
	"creator": [
	    {
		"name": "YLE",
		"type": "Organization"
	    }
	],
	"description": {
	    "fi": "Kokki Anu valmistaa broiler-aterian uudella tavalla.",
	    "sv": "Kocken Anu tillreder en broilerr\u00e4tt p\u00e5 ett nytt s\u00e4tt."
	},
	"duration": "PT13M5S",
	"id": "1-200102",
	"image": {
	    "available": true,
	    "id": "13-1-200102",
	    "type": "ImageObject"
	},
	"indexDataModified": "2015-05-09T12:37:23.117+03:00",
	"itemTitle": {},
	"originalTitle": {},
	"partOfSeries": {
	    "@id": "https://programs.api.yle.fi/v1/id/1-200275",
	    "countryOfOrigin": [],
	    "creator": [],
	    "description": {},
	    "id": "1-200275",
	    "image": {},
	    "indexDataModified": "2015-05-09T00:36:24.419+03:00",
	    "subject": [],
	    "title": {
		"fi": "POPsis!",
		"sv": "POPsis!"
	    },
	    "type": "TVSeries"
	},
	"productionId": "51026301000",
	"publicationEvent": [
	    {
		"duration": "P1MT15H26M59S",
		"endTime": "2012-10-03T23:59:59+03:00",
		"id": "4-2331952",
		"media": {
		    "available": true,
		    "contentProtection": [
			{
			    "id": "22-1",
			    "type": "ContentProtectionPolicy"
			}
		    ],
		    "downloadable": false,
		    "duration": "PT13M5S",
		    "id": "6-b155e9ce6373450a8874cf3dadccfa78",
		    "type": "VideoObject"
		},
		"publisher": [
		    {
			"id": "yle-tv2"
		    }
		],
		"region": "Finland",
		"service": {
		    "id": "yle-areena"
		},
		"startTime": "2012-09-03T08:33:00+03:00",
		"temporalStatus": "in-past",
		"type": "OnDemandPublication"
	    },
	    {
		"duration": "PT16M2S",
		"endTime": "2012-06-04T08:50:02+03:00",
		"id": "4-2184750",
		"media": {},
		"region": "Finland",
		"service": {
		    "id": "yle-tv2"
		},
		"startTime": "2012-06-04T08:34:00+03:00",
		"temporalStatus": "in-past",
		"type": "ScheduledTransmission"
	    },
	    {
		"duration": "PT13M22S",
		"endTime": "2009-08-01T09:39:22+03:00",
		"id": "4-312581",
		"media": {},
		"region": "World",
		"service": {
		    "id": "yle-tv2"
		},
		"startTime": "2009-08-01T09:26:00+03:00",
		"temporalStatus": "in-past",
		"type": "ScheduledTransmission"
	    },
	    {
		"duration": "PT13M8S",
		"endTime": "2012-09-03T08:46:08+03:00",
		"id": "4-2331951",
		"media": {},
		"region": "Finland",
		"service": {
		    "id": "yle-tv2"
		},
		"startTime": "2012-09-03T08:33:00+03:00",
		"temporalStatus": "in-past",
		"type": "ScheduledTransmission"
	    },
	    {
		"duration": "PT14M27S",
		"endTime": "2009-08-05T08:34:27+03:00",
		"id": "4-320330",
		"media": {},
		"region": "World",
		"service": {
		    "id": "yle-tv2"
		},
		"startTime": "2009-08-05T08:20:00+03:00",
		"temporalStatus": "in-past",
		"type": "ScheduledTransmission"
	    },
	    {
		"duration": "P1MT15H25M59S",
		"endTime": "2012-07-04T23:59:59+03:00",
		"id": "4-2184751",
		"media": {
		    "available": true,
		    "contentProtection": [
			{
			    "id": "22-1",
			    "type": "ContentProtectionPolicy"
			}
		    ],
		    "downloadable": false,
		    "duration": "PT13M5S",
		    "id": "6-b155e9ce6373450a8874cf3dadccfa78",
		    "type": "VideoObject"
		},
		"region": "Finland",
		"service": {
		    "id": "yle-areena"
		},
		"startTime": "2012-06-04T08:34:00+03:00",
		"temporalStatus": "in-past",
		"type": "OnDemandPublication"
	    },
	    {
		"duration": "PT16M9S",
		"endTime": "2009-08-01T09:46:09+03:00",
		"id": "4-312773",
		"media": {},
		"region": "World",
		"service": {
		    "id": "tv-finland"
		},
		"startTime": "2009-08-01T09:30:00+03:00",
		"temporalStatus": "in-past",
		"type": "ScheduledTransmission"
	    }
	],
	"subject": [
	    {
		"broader": {
		    "id": "5-130"
		},
		"id": "5-195",
		"inScheme": "areena-content-classification",
		"key": "lapset",
		"title": {
		    "fi": "Lapset",
		    "sv": "Barn"
		},
		"type": "Concept"
	    },
	    {
		"id": "21-10",
		"inScheme": "finnpanel-genre-classification",
		"notation": [
		    {
			"value": "8",
			"valueType": "finnpanel-notation"
		    }
		],
		"title": {
		    "en": "Children programs",
		    "fi": "Lastenohjelmat"
		},
		"type": "Concept"
	    }
	],
	"subtitling": [],
	"title": {
	    "fi": "POPsis!",
	    "sv": "POPsis!"
	},
	"type": "TVProgram",
	"typeCreative": "Program",
	"typeMedia": "TVContent",
	"video": {
	    "format": [
		{
		    "inScheme": "mediaformat-classification",
		    "key": "16:9",
		    "type": "Concept"
		}
	    ],
	    "language": [],
	    "type": "VideoTrack"
	}
    },
    "meta": {
	"id": "1-200102"
    }
}

GET /v1/series.json Search series

Returns a collection of series matching the specified query. E.g. Series in category 5-137: /v1/series.json?category=5-137

Parameters

NameDescription
categoryReturns items linked to a specified category. Multiple category IDs can be passed as a comma separated list. To exclude series that belong to a specific category, add '-' before the id. E.g. category=1,2,-3,-4 returns series that belong to either category 1 or 2 AND do NOT belong to categories 3 AND 4.
idReturns items containing the specified ID. Multiple IDs can be passed as a comma separated list. To exclude series by id, add '-' before the id. E.g. id=1,2,-3,-4 returns series that have either id 1 or 2 AND do NOT have id 3 AND 4.
limitSets limit for the size of the returned collection
offsetSets offset for the collection. Note that limit + offset must not be greater than 15 000.

Response

200 OK on success

Response contains a JSON document with series. Maximum number of serieses returned is limited by limit parameter.

400 Bad Request if parameters have illegal values

cURL example

Series example

curl -XGET "https://programs.api.yle.fi/v1/series.json?category=5-137&limit=1&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": [
	{
	    "@id": "https://programs.api.yle.fi/v1/id/1-2309229",
	    "countryOfOrigin": [
		"Belgia"
	    ],
	    "coverImage": {
		"available": true,
		"id": "13-1-2309229-cover",
		"type": "ImageObject"
	    },
	    "creator": [
		{
		    "name": "BetaFilm GmbH & Co.",
		    "type": "Organization"
		}
	    ],
	    "description": {
		"fi": "Brysselil\u00e4inen pankki ry\u00f6stet\u00e4\u00e4n tavallista kohtalokkaammin seurauksin. Belgian kermalle kuuluvat 66 tallelokeroa vied\u00e4\u00e4n, ja sis\u00e4lt\u00f6 on tietenkin tulenarkaa. Ry\u00f6st\u00f6\u00e4 tutkiva poliisi Paul Gerardi huomaa, ett\u00e4 uhrit kuuluvat kaikki salaper\u00e4iseen Salamander-organisaatioon. Belgialainen, suurelle yleis\u00f6lle tehty rikossarja on ollut ennenn\u00e4kem\u00e4t\u00f6n menestys kotimaassaan."
	    },
	    "id": "1-2309229",
	    "image": {
		"available": true,
		"id": "13-1-2309229",
		"type": "ImageObject"
	    },
	    "indexDataModified": "2015-05-09T00:31:14.084+03:00",
	    "interactions": [
		{
		    "title": {
			"fi": "Yle Areenan perjantaisarjat"
		    },
		    "type": "WebPage",
		    "url": "http://areena.yle.fi/tv/2403342"
		}
	    ],
	    "subject": [
		{
		    "broader": {
			"id": "5-131"
		    },
		    "id": "5-134",
		    "inScheme": "areena-content-classification",
		    "key": "ulkomaisetsarjat",
		    "title": {
			"fi": "Ulkomaiset sarjat",
			"sv": "Utl\u00e4ndska serier"
		    },
		    "type": "Concept"
		},
		{
		    "broader": {
			"id": "5-131"
		    },
		    "id": "5-137",
		    "inScheme": "areena-content-classification",
		    "key": "jannitys",
		    "title": {
			"fi": "J\u00e4nnitys",
			"sv": "Sp\u00e4nning"
		    },
		    "type": "Concept"
		},
		{
		    "id": "5-262",
		    "inScheme": "areena-analytics-classification",
		    "key": "draama",
		    "title": {
			"fi": "Draama"
		    },
		    "type": "Concept"
		}
	    ],
	    "title": {
		"fi": "Salamander",
		"sv": "Salamander"
	    },
	    "type": "TVSeries"
	}
    ],
    "meta": {
	"category": "5-137",
	"count": 260,
	"limit": "1",
	"offset": "0"
    }
}

GET /v1/series/{id}.json Get a series

Returns the series with the defined id. E.g. /v1/series/1-2.json

Parameters

Name Description
id The ID of the desired series.

Response

200 OK on success

Response contains a JSON document with the series.

404 Not Found if id does not match a series object.

cURL example

Series example

curl -XGET "https://programs.api.yle.fi/v1/series/1-2309229.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": {
	"@id": "https://programs.api.yle.fi/v1/id/1-2309229",
	"countryOfOrigin": [
	    "Belgia"
	],
	"coverImage": {
	    "available": true,
	    "id": "13-1-2309229-cover",
	    "type": "ImageObject"
	},
	"creator": [
	    {
		"name": "BetaFilm GmbH & Co.",
		"type": "Organization"
	    }
	],
	"description": {
	    "fi": "Brysselil\u00e4inen pankki ry\u00f6stet\u00e4\u00e4n tavallista kohtalokkaammin seurauksin. Belgian kermalle kuuluvat 66 tallelokeroa vied\u00e4\u00e4n, ja sis\u00e4lt\u00f6 on tietenkin tulenarkaa. Ry\u00f6st\u00f6\u00e4 tutkiva poliisi Paul Gerardi huomaa, ett\u00e4 uhrit kuuluvat kaikki salaper\u00e4iseen Salamander-organisaatioon. Belgialainen, suurelle yleis\u00f6lle tehty rikossarja on ollut ennenn\u00e4kem\u00e4t\u00f6n menestys kotimaassaan."
	},
	"id": "1-2309229",
	"image": {
	    "available": true,
	    "id": "13-1-2309229",
	    "type": "ImageObject"
	},
	"indexDataModified": "2015-05-09T00:31:14.084+03:00",
	"interactions": [
	    {
		"title": {
		    "fi": "Yle Areenan perjantaisarjat"
		},
		"type": "WebPage",
		"url": "http://areena.yle.fi/tv/2403342"
	    }
	],
	"subject": [
	    {
		"broader": {
		    "id": "5-131"
		},
		"id": "5-134",
		"inScheme": "areena-content-classification",
		"key": "ulkomaisetsarjat",
		"title": {
		    "fi": "Ulkomaiset sarjat",
		    "sv": "Utl\u00e4ndska serier"
		},
		"type": "Concept"
	    },
	    {
		"broader": {
		    "id": "5-131"
		},
		"id": "5-137",
		"inScheme": "areena-content-classification",
		"key": "jannitys",
		"title": {
		    "fi": "J\u00e4nnitys",
		    "sv": "Sp\u00e4nning"
		},
		"type": "Concept"
	    },
	    {
		"id": "5-262",
		"inScheme": "areena-analytics-classification",
		"key": "draama",
		"title": {
		    "fi": "Draama"
		},
		"type": "Concept"
	    }
	],
	"title": {
	    "fi": "Salamander",
	    "sv": "Salamander"
	},
	"type": "TVSeries"
    },
    "meta": {
	"id": "1-2309229"
    }
}

GET /v1/categories.json Get categories

Returns a collection of categories matching the query

Parameters

Name Description
scheme Returns categories attached to the specified category scheme.
  Allowed values: “areena-content-classification”, “areena-analytics-classification”
limit Sets limit for the size of the returned collection
offset Sets offset for the collection

Response

200 OK on success

Response contains a JSON document with the series.

404 Not Found if id does not match a series object.

cURL example

Category example

curl -XGET "https://programs.api.yle.fi/v1/categories.json?limit=1&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": [
	{
	    "id": "5-130",
	    "inScheme": "areena-content-classification",
	    "indexDataModified": "2015-03-26T10:25:23.307+02:00",
	    "key": "tv",
	    "title": {
		"fi": "Tv",
		"sv": "Tv"
	    },
	    "type": "Concept"
	}
    ],
    "meta": {
	"count": 148,
	"limit": "1",
	"offset": "0"
    }
}

GET /v1/categories/{id}.json Get a category

Returns the category with the defined id. E.g. /v1/categories/1-2.json

Parameters

Name Description
id The ID of the desired category.

Response

200 OK on success

Response contains a JSON document with the category.

404 Not Found if id does not match a category object.

cURL example

Category example

curl -XGET "https://programs.api.yle.fi/v1/categories/5-131.json?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": {
	"broader": {
	    "id": "5-130"
	},
	"id": "5-131",
	"inScheme": "areena-content-classification",
	"indexDataModified": "2015-03-26T10:25:23.307+02:00",
	"key": "sarjatjaelokuvat",
	"title": {
	    "fi": "Sarjat ja elokuvat",
	    "sv": "Serier och film"
	},
	"type": "Concept"
    },
    "meta": {
	"id": "5-131"
    }
}

GET /v1/services.json Get services

Returns a collection of services matching the query

Parameters

Name Description
type Returns services matching the given type
  Allowed values: “tvchannel”, “radiochannel”,
  “ondemandservice”, “webcastservice”
limit Sets limit for the size of the returned collection
offset Sets offset for the collection

Response

200 OK on success

Response contains a JSON document with the services.

400 Bad Request if parameters have illegal values

cURL example

Get radio services example

curl -XGET "https://programs.api.yle.fi/v1/services.json?type=radiochannel&limit=1&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": [
	{
	    "active": true,
	    "audio": [
		{
		    "format": [
			{
			    "inScheme": "mediaformat-classification",
			    "key": "stereo",
			    "type": "Concept"
			}
		    ],
		    "language": [
			"fi"
		    ],
		    "type": "AudioTrack"
		}
	    ],
	    "displayOrder": 1000,
	    "homepage": {
		"serviceProvider": "http://yle.fi",
		"title": {
		    "fi": "Kotisivu",
		    "sv": "Hemsida"
		},
		"type": "WebPage",
		"url": "http://yle.fi/radio1"
	    },
	    "id": "yle-radio-1",
	    "indexDataModified": "2015-03-26T10:25:23.569+02:00",
	    "interaction": [
		{
		    "hasVersion": [
			{
			    "device": "mobile",
			    "serviceProvider": "http://twitter.com",
			    "title": {
				"fi": "Twitter"
			    },
			    "type": "WebPage",
			    "url": "https://mobile.twitter.com/yleradio1"
			}
		    ],
		    "serviceProvider": "http://twitter.com",
		    "title": {
			"fi": "Twitter"
		    },
		    "type": "WebPage",
		    "url": "https://twitter.com/yleradio1"
		},
		{
		    "hasVersion": [
			{
			    "device": "mobile",
			    "serviceProvider": "http://facebook.com",
			    "title": {
				"fi": "Facebook"
			    },
			    "type": "WebPage",
			    "url": "https://m.facebook.com/yleradio1"
			}
		    ],
		    "serviceProvider": "http://facebook.com",
		    "title": {
			"fi": "Facebook"
		    },
		    "type": "WebPage",
		    "url": "https://facebook.com/yleradio1"
		}
	    ],
	    "language": [
		"fi"
	    ],
	    "outlet": [
		{
		    "media": {
			"id": "10-6",
			"type": "AudioObject"
		    },
		    "region": "Finland",
		    "type": "Webcast"
		},
		{
		    "media": {
			"id": "10-6",
			"type": "AudioObject"
		    },
		    "region": "World",
		    "type": "Webcast"
		}
	    ],
	    "programGuide": [
		{
		    "serviceProvider": "http://yle.fi",
		    "title": {
			"fi": "Ohjelmaopas",
			"sv": "Programguide"
		    },
		    "type": "WebPage",
		    "url": "http://ohjelmaopas.yle.fi/radio/opas"
		}
	    ],
	    "region": "Finland",
	    "title": {
		"fi": "Yle Radio 1"
	    },
	    "type": "RadioChannel",
	    "typeCreative": "Channel",
	    "typeMedia": "RadioContent"
	}
    ],
    "meta": {
	"count": 32,
	"limit": "1",
	"offset": "0",
	"type": "radiochannel"
    }
}

GET /v1/services/{id}.json Get a service

Returns a single service by the ID parameter

Parameters

Name Description
id The ID of the desired service.

Response

200 OK on success

Response contains a JSON document with the service.

404 Not Found if id does not match a service object.

cURL example

Service example

curl -XGET "https://programs.api.yle.fi/v1/services/yle-teema.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": {
	"active": true,
	"audio": [
	    {
		"format": [
		    {
			"inScheme": "mediaformat-classification",
			"key": "stereo",
			"type": "Concept"
		    }
		],
		"language": [
		    "fi"
		],
		"type": "AudioTrack"
	    },
	    {
		"language": [
		    "fi"
		],
		"type": "AudioSubtitling"
	    }
	],
	"displayOrder": 14000,
	"hasFormat": [
	    {
		"audio": [
		    {
			"format": [
			    {
				"inScheme": "mediaformat-classification",
				"key": "dolby-digital-2.0-stereo",
				"type": "Concept"
			    }
			],
			"language": [
			    "fi"
			],
			"type": "AudioTrack"
		    },
		    {
			"language": [
			    "fi"
			],
			"type": "AudioSubtitling"
		    }
		],
		"id": "yle-teema-hd",
		"subtitling": [
		    {
			"language": [
			    "fi"
			],
			"type": "Subtitling"
		    }
		],
		"title": {
		    "fi": "Yle Teema HD"
		},
		"type": "TVChannel",
		"typeCreative": "Channel",
		"typeMedia": "TVContent",
		"video": {
		    "format": [
			{
			    "inScheme": "mediaformat-classification",
			    "key": "HD",
			    "type": "Concept"
			},
			{
			    "inScheme": "mediaformat-classification",
			    "key": "16:9",
			    "type": "Concept"
			}
		    ],
		    "type": "VideoTrack"
		}
	    }
	],
	"homepage": {
	    "serviceProvider": "http://yle.fi",
	    "title": {
		"fi": "Kotisivu",
		"sv": "Hemsida"
	    },
	    "type": "WebPage",
	    "url": "http://teema.yle.fi"
	},
	"id": "yle-teema",
	"indexDataModified": "2015-03-26T10:25:23.569+02:00",
	"language": [
	    "fi"
	],
	"outlet": [
	    {
		"media": {
		    "id": "10-3",
		    "type": "VideoObject"
		},
		"region": "Finland",
		"type": "Webcast"
	    },
	    {
		"media": {
		    "id": "10-40",
		    "type": "VideoObject"
		},
		"region": "World",
		"type": "Webcast"
	    }
	],
	"programGuide": [
	    {
		"serviceProvider": "http://yle.fi",
		"title": {
		    "fi": "Ohjelmaopas",
		    "sv": "Programguide"
		},
		"type": "WebPage",
		"url": "http://ohjelmaopas.yle.fi/tv/opas"
	    }
	],
	"region": "Finland",
	"subtitling": [
	    {
		"language": [
		    "fi"
		],
		"type": "Subtitling"
	    }
	],
	"title": {
	    "fi": "Yle Teema"
	},
	"type": "TVChannel",
	"typeCreative": "Channel",
	"typeMedia": "TVContent",
	"video": {
	    "format": [
		{
		    "inScheme": "mediaformat-classification",
		    "key": "SD",
		    "type": "Concept"
		},
		{
		    "inScheme": "mediaformat-classification",
		    "key": "16:9",
		    "type": "Concept"
		}
	    ],
	    "type": "VideoTrack"
	}
    },
    "meta": {
	"id": "yle-teema"
    }
}

GET /v1/schedules.json Get schedules

Returns a collection of publication events. The publication events are a schedule for a specific service, time, category and other parameters used.

Parameters

NameDescription
idReturns items containing the specified ID. Multiple IDs can be passed as a comma separated list.
service
starttime
endtime
categoryReturns schedules linked to a specified category. Multiple category IDs can be passed as a comma separated list. To exclude schedules that belong to a specific category, add '-' before the id. E.g. category=1,2,-3,-4 returns schedules that belong to either category 1 or 2 AND do NOT belong to categories 3 AND 4.
regionReturns schedules that contain a publication event with the given region. Allowed values are "fi" and "world".
seriesReturns schedules containing the given series ID. Multiple IDs can be passed as a comma separated list.
mediaobjectReturns schedules according to media type (video or audio). E.g. All audio webcasts: "/v1/schedules.json?service=yle-areena&mediaobject=audio"
limitSets limit for the size of the returned collection
offsetSets offset for the collection. Note that limit + offset must not be greater than 15 000.

Response

200 OK on success

Response contains a JSON document with publication events. Maximum number of publication events returned is limited by limit parameter.

400 Bad Request if parameters have illegal values

cURL example

Free text search example

curl -XGET "https://programs.api.yle.fi/v1/schedules.json?service=yle-areena&mediaobject=audio&limit=1&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": [],
    "meta": {
	"count": 0,
	"endtime": "2015-06-05T03:59:59+0300",
	"limit": "1",
	"mediaobject": "audio",
	"offset": "0",
	"service": "yle-areena",
	"starttime": "2015-06-04T04:00:00+0300"
    }
}

GET /v1/schedules/now.json Get the current broadcast

Returns currently running programs, previous and upcoming programs. Can return multiple items that are running simultaneously. For example yle-areena may have multiple webcasts running at a time.

Parameters

NameDescription
serviceReturns programs currently running on specified service(s). Multiple service IDs can be passes as a comma separated list.
startHow many previous programs will be returned. Allows values from -10 to 0. -1 means that the previous program will be included in the response.
endHow many upcoming programs will be returned. Allows values from 0 to 10. 1 means that the next program will be included in the response.
mediaobjectReturns currently playing programs according to media type (video or audio). E.g. Audio webcasts: "/v1/schedules/now.json?service=yle-areena&mediaobject=audio". Allowed values: "audio" and "video".

Response

200 OK on success

Response contains a JSON document with the current broadcast publication.

404 Not Found if search parameters do not match any publications.

cURL example

Current broadcasts example

curl -XGET "https://programs.api.yle.fi/v1/schedules/now.json?service=yle-areena&mediaobject=audio&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": [],
    "meta": {
	"end": 0,
	"mediaobject": "audio",
	"service": "yle-areena",
	"start": 0
    }
}

GET /v1/lists.json Get list of curated lists

Returns a list of curated lists. For example /v1/lists.json retrieves all the curated lists.

Parameters

Name Description
language Returns lists contain items matching the given language. Allowed values: “”, “fi”, “sv”
type Returns index matching the given type. Allowed values: “”, “radiocontent”, “tvcontent”
limit Sets limit for the size of the returned collection. Default value is 25. Maximum number of results 100.
offset Sets offset for the collection.

Response

200 OK on success

Response contains a JSON document with the service.

400 Bad Request if parameters have illegal values

cURL example

Lists example

curl -XGET "https://programs.api.yle.fi/v1/lists.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": [
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-1802228",
	    "amountOfItems": 18,
	    "id": "8-1802228",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Suosittelemme"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-11795516",
	    "amountOfItems": 8,
	    "id": "8-11795516",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Vain Areenassa "
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-78030406",
	    "amountOfItems": 1,
	    "id": "8-78030406",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Eduskuntavaalit 2015"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-1392136",
	    "amountOfItems": 4,
	    "id": "8-1392136",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Kotimaiset sarjat ja elokuvat"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-1396335",
	    "amountOfItems": 10,
	    "id": "8-1396335",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Ulkomaiset sarjat ja elokuvat"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-3913395",
	    "amountOfItems": 12,
	    "id": "8-3913395",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Dokumentteja"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-7081193",
	    "amountOfItems": 12,
	    "id": "8-7081193",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Ajankohtaisohjelmat"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-13784020",
	    "amountOfItems": 6,
	    "id": "8-13784020",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Kotimainen viihde"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-2176694",
	    "amountOfItems": 6,
	    "id": "8-2176694",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Urheiluohjelmia"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-1392560",
	    "amountOfItems": 12,
	    "id": "8-1392560",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Kulttuuri"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-2239065",
	    "amountOfItems": 12,
	    "id": "8-2239065",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Dokumentteja maailmalta"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-7080594",
	    "amountOfItems": 8,
	    "id": "8-7080594",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Luonto ja el\u00e4imet"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-14527677",
	    "amountOfItems": 11,
	    "id": "8-14527677",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Matkailu"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-10813976",
	    "amountOfItems": 12,
	    "id": "8-10813976",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Terveys ja hyvinvointi"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-10260956",
	    "amountOfItems": 19,
	    "id": "8-10260956",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Toimitus suosittelee"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-5546629",
	    "amountOfItems": 24,
	    "id": "8-5546629",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Tuoreimmat radiouutiset"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-3395351",
	    "amountOfItems": 3,
	    "id": "8-3395351",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Vieraita"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-75814842",
	    "amountOfItems": 649,
	    "id": "8-75814842",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Urheilu"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-3379487",
	    "amountOfItems": 4,
	    "id": "8-3379487",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Ajankohtaisohjelmia"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-10456158",
	    "amountOfItems": 3,
	    "id": "8-10456158",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Tuoretta musiikkia"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-5307748",
	    "amountOfItems": 4,
	    "id": "8-5307748",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Iskelm\u00e4 & nostalgia"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-10455627",
	    "amountOfItems": 4,
	    "id": "8-10455627",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Hemmottelumusiikkia"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-2182582",
	    "amountOfItems": 4,
	    "id": "8-2182582",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Luonto"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-13337717",
	    "amountOfItems": 4,
	    "id": "8-13337717",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Kulttuuri"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-14898892",
	    "amountOfItems": 4,
	    "id": "8-14898892",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Sohkar\u0161ohkka (S\u00e1pmi)"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-3484736",
	    "amountOfItems": 12,
	    "id": "8-3484736",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Kuunnelmat"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-13338279",
	    "amountOfItems": 4,
	    "id": "8-13338279",
	    "language": [
		"fi"
	    ],
	    "list": [],
	    "title": {
		"fi": "Historia "
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-2148379",
	    "amountOfItems": 48,
	    "id": "8-2148379",
	    "language": [
		"sv"
	    ],
	    "list": [],
	    "title": {
		"sv": "F\u00f6rsta sidan"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-3996487",
	    "amountOfItems": 4,
	    "id": "8-3996487",
	    "language": [
		"sv"
	    ],
	    "list": [],
	    "title": {
		"sv": "Yle Nyheter: TV-nytt"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-57582635",
	    "amountOfItems": 315,
	    "id": "8-57582635",
	    "language": [
		"sv"
	    ],
	    "list": [],
	    "title": {
		"sv": "Sport"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-2184690",
	    "amountOfItems": 8,
	    "id": "8-2184690",
	    "language": [
		"sv"
	    ],
	    "list": [],
	    "title": {
		"sv": "Trailers - p\u00e5 kommande i Yle Fem"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-2184662",
	    "amountOfItems": 8,
	    "id": "8-2184662",
	    "language": [
		"sv"
	    ],
	    "list": [],
	    "title": {
		"sv": "Serier och film"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-2181769",
	    "amountOfItems": 8,
	    "id": "8-2181769",
	    "language": [
		"sv"
	    ],
	    "list": [],
	    "title": {
		"sv": "Dokument\u00e4rer"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-2188476",
	    "amountOfItems": 8,
	    "id": "8-2188476",
	    "language": [
		"sv"
	    ],
	    "list": [],
	    "title": {
		"sv": "Barn och unga "
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-2239043",
	    "amountOfItems": 13,
	    "id": "8-2239043",
	    "language": [
		"sv"
	    ],
	    "list": [],
	    "title": {
		"sv": "F\u00f6rsta sidan radio"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-2275950",
	    "amountOfItems": 8,
	    "id": "8-2275950",
	    "language": [
		"sv"
	    ],
	    "list": [],
	    "title": {
		"sv": "Nyheter"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-2239108",
	    "amountOfItems": 8,
	    "id": "8-2239108",
	    "language": [
		"sv"
	    ],
	    "list": [],
	    "title": {
		"sv": "Musik och underh\u00e5llning"
	    },
	    "type": "CuratedList"
	},
	{
	    "@id": "https://programs.api.yle.fi/v1/lists/8-3880929",
	    "amountOfItems": 8,
	    "id": "8-3880929",
	    "language": [
		"sv"
	    ],
	    "list": [],
	    "title": {
		"sv": "Nerladdningsbara program"
	    },
	    "type": "CuratedList"
	}
    ],
    "meta": {
	"count": 38,
	"limit": "38",
	"offset": "0"
    }
}

GET /v1/lists/{id}.json Get a curated list

Returns a curated list by list id. E.g. /v1/lists/8-1802228.json

Parameters

NameDescription
idThe ID of the list.
contentprotectionReturns items that contain a publication event with the content protection. Multiple content protection IDs can be passed as a comma separated list.
regionReturns items on the list that contain a publication event with the given region. Possible values: "", "fi", "world"
limitSets limit for the size of the returned collection. Default value is 25. Maximum number of results 100.
offsetSets offset for the collection.

Response

200 OK on success

Response contains a JSON document with the service.

400 Bad Request if parameters have illegal values

404 Not Found if id does not match a service object.

cURL example

Lists example

curl -XGET "https://programs.api.yle.fi/v1/lists/8-1802228.json?limit=1&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": {
	"@id": "https://programs.api.yle.fi/v1/lists/8-1802228",
	"amountOfItems": 18,
	"id": "8-1802228",
	"language": [
	    "fi"
	],
	"list": [
	    {
		"@id": "https://programs.api.yle.fi/v1/id/1-2669560",
		"alternativeId": [
		    "16-1-0838315"
		],
		"audio": [
		    {
			"format": [
			    {
				"inScheme": "mediaformat-classification",
				"key": "stereo",
				"type": "Concept"
			    }
			],
			"language": [
			    "es"
			],
			"type": "AudioTrack"
		    }
		],
		"collection": "main",
		"contentRating": {
		    "ageRestriction": 7,
		    "ratingSystem": "MEKU",
		    "reason": [
			{
			    "key": "anxiety",
			    "title": {
				"en": "Content may cause anxiety",
				"fi": "Voi aiheuttaa ahdistusta",
				"sv": "Kan skapa \u00e5ngest"
			    },
			    "type": "ContentRatingReason"
			}
		    ],
		    "title": {
			"en": "Not for persons under 7",
			"fi": "Sallittu yli 7-vuotiaille",
			"sv": "F\u00f6rbjudet under 7 \u00e5r"
		    },
		    "type": "ContentRating"
		},
		"countryOfOrigin": [
		    "Espanja"
		],
		"creator": [],
		"description": {
		    "fi": "5/16. Viimeinen ottelu. Clara sovittelee h\u00e4\u00e4pukuaan onnellisena mutta miksi sulhasella on muurahaisia housuissa? C\u00e9sar tekee juttua nyrkkeilij\u00e4yst\u00e4v\u00e4st\u00e4\u00e4n. Jalokivikuvauksessa sattuu ik\u00e4v\u00e4 v\u00e4likohtaus."
		},
		"duration": "PT1H15M",
		"episodeNumber": 5,
		"id": "1-2669560",
		"image": {
		    "available": true,
		    "id": "13-1-2669560",
		    "type": "ImageObject"
		},
		"indexDataModified": "2015-06-04T07:42:52.819+03:00",
		"itemTitle": {},
		"originalTitle": {
		    "unknown": "B & B Magazine"
		},
		"partOfSeason": {
		    "countryOfOrigin": [
			"Espanja"
		    ],
		    "creator": [],
		    "description": {
			"fi": "Uusi espanjalainen sarja, jossa n\u00e4hd\u00e4\u00e4n Serranon perheest\u00e4 tuttuja n\u00e4yttelij\u00f6ilt\u00e4! Muotilehden toimitukseen sijoittuva ihmissuhdesarja, kilpailua ja kieroiluja."
		    },
		    "id": "1-2669592",
		    "indexDataModified": "2015-06-04T07:42:52.499+03:00",
		    "partOfSeries": {
			"id": "1-2669556"
		    },
		    "seasonNumber": 1,
		    "subject": [
			{
			    "broader": {
				"id": "5-130"
			    },
			    "id": "5-131",
			    "inScheme": "areena-content-classification",
			    "key": "sarjatjaelokuvat",
			    "title": {
				"fi": "Sarjat ja elokuvat",
				"sv": "Serier och film"
			    },
			    "type": "Concept"
			},
			{
			    "broader": {
				"id": "5-131"
			    },
			    "id": "5-134",
			    "inScheme": "areena-content-classification",
			    "key": "ulkomaisetsarjat",
			    "title": {
				"fi": "Ulkomaiset sarjat",
				"sv": "Utl\u00e4ndska serier"
			    },
			    "type": "Concept"
			},
			{
			    "id": "5-262",
			    "inScheme": "areena-analytics-classification",
			    "key": "draama",
			    "title": {
				"fi": "Draama"
			    },
			    "type": "Concept"
			},
			{
			    "id": "5-271",
			    "inScheme": "areena-analytics-classification",
			    "key": "p\u00e4ivitt\u00e4isdraama",
			    "title": {
				"fi": "P\u00e4ivitt\u00e4isdraama"
			    },
			    "type": "Concept"
			}
		    ],
		    "title": {
			"fi": "B & B Magazine",
			"sv": "B & B Magazine"
		    },
		    "type": "TVSeason"
		},
		"partOfSeries": {
		    "@id": "https://programs.api.yle.fi/v1/id/1-2669556",
		    "countryOfOrigin": [
			"Espanja"
		    ],
		    "coverImage": {
			"available": true,
			"id": "13-1-2669556-cover",
			"type": "ImageObject"
		    },
		    "creator": [],
		    "description": {
			"fi": "Uusi espanjalainen sarja, jossa n\u00e4hd\u00e4\u00e4n Serranon perheest\u00e4 tuttuja n\u00e4yttelij\u00f6ilt\u00e4! Muotilehden toimitukseen sijoittuva ihmissuhdesarja, kilpailua ja kieroiluja."
		    },
		    "id": "1-2669556",
		    "image": {
			"available": true,
			"id": "13-1-2669556",
			"type": "ImageObject"
		    },
		    "season": [
			{
			    "countryOfOrigin": [
				"Espanja"
			    ],
			    "creator": [],
			    "description": {
				"fi": "Uusi espanjalainen sarja, jossa n\u00e4hd\u00e4\u00e4n Serranon perheest\u00e4 tuttuja n\u00e4yttelij\u00f6ilt\u00e4! Muotilehden toimitukseen sijoittuva ihmissuhdesarja, kilpailua ja kieroiluja."
			    },
			    "id": "1-2669592",
			    "indexDataModified": "2015-06-04T07:42:52.499+03:00",
			    "partOfSeries": {
				"id": "1-2669556"
			    },
			    "seasonNumber": 1,
			    "subject": [
				{
				    "broader": {
					"id": "5-130"
				    },
				    "id": "5-131",
				    "inScheme": "areena-content-classification",
				    "key": "sarjatjaelokuvat",
				    "title": {
					"fi": "Sarjat ja elokuvat",
					"sv": "Serier och film"
				    },
				    "type": "Concept"
				},
				{
				    "broader": {
					"id": "5-131"
				    },
				    "id": "5-134",
				    "inScheme": "areena-content-classification",
				    "key": "ulkomaisetsarjat",
				    "title": {
					"fi": "Ulkomaiset sarjat",
					"sv": "Utl\u00e4ndska serier"
				    },
				    "type": "Concept"
				},
				{
				    "id": "5-262",
				    "inScheme": "areena-analytics-classification",
				    "key": "draama",
				    "title": {
					"fi": "Draama"
				    },
				    "type": "Concept"
				},
				{
				    "id": "5-271",
				    "inScheme": "areena-analytics-classification",
				    "key": "p\u00e4ivitt\u00e4isdraama",
				    "title": {
					"fi": "P\u00e4ivitt\u00e4isdraama"
				    },
				    "type": "Concept"
				}
			    ],
			    "title": {
				"fi": "B & B Magazine",
				"sv": "B & B Magazine"
			    },
			    "type": "TVSeason"
			}
		    ],
		    "subject": [
			{
			    "broader": {
				"id": "5-130"
			    },
			    "id": "5-131",
			    "inScheme": "areena-content-classification",
			    "key": "sarjatjaelokuvat",
			    "title": {
				"fi": "Sarjat ja elokuvat",
				"sv": "Serier och film"
			    },
			    "type": "Concept"
			},
			{
			    "broader": {
				"id": "5-131"
			    },
			    "id": "5-134",
			    "inScheme": "areena-content-classification",
			    "key": "ulkomaisetsarjat",
			    "title": {
				"fi": "Ulkomaiset sarjat",
				"sv": "Utl\u00e4ndska serier"
			    },
			    "type": "Concept"
			},
			{
			    "id": "5-262",
			    "inScheme": "areena-analytics-classification",
			    "key": "draama",
			    "title": {
				"fi": "Draama"
			    },
			    "type": "Concept"
			},
			{
			    "id": "5-271",
			    "inScheme": "areena-analytics-classification",
			    "key": "p\u00e4ivitt\u00e4isdraama",
			    "title": {
				"fi": "P\u00e4ivitt\u00e4isdraama"
			    },
			    "type": "Concept"
			}
		    ],
		    "title": {
			"fi": "B & B Magazine",
			"sv": "B & B Magazine"
		    },
		    "type": "TVSeries"
		},
		"productionId": "91234605000",
		"promotionTitle": {
		    "fi": "Viimeinen ottelu"
		},
		"publicationEvent": [
		    {
			"duration": "P2M29DT11H55M59S",
			"endTime": "2015-08-30T23:59:59+03:00",
			"id": "4-4466671",
			"media": {
			    "available": true,
			    "contentProtection": [
				{
				    "id": "22-1",
				    "type": "ContentProtectionPolicy"
				}
			    ],
			    "downloadable": false,
			    "duration": "PT1H15M",
			    "id": "6-e727cecba5e04cf2bee56ce4a246cbbd",
			    "type": "VideoObject"
			},
			"publisher": [
			    {
				"id": "yle-areena"
			    }
			],
			"region": "Finland",
			"service": {
			    "id": "yle-areena"
			},
			"startTime": "2015-06-01T12:04:00+03:00",
			"temporalStatus": "currently",
			"type": "OnDemandPublication"
		    }
		],
		"subject": [
		    {
			"broader": {
			    "id": "5-130"
			},
			"id": "5-131",
			"inScheme": "areena-content-classification",
			"key": "sarjatjaelokuvat",
			"title": {
			    "fi": "Sarjat ja elokuvat",
			    "sv": "Serier och film"
			},
			"type": "Concept"
		    },
		    {
			"broader": {
			    "id": "5-131"
			},
			"id": "5-134",
			"inScheme": "areena-content-classification",
			"key": "ulkomaisetsarjat",
			"title": {
			    "fi": "Ulkomaiset sarjat",
			    "sv": "Utl\u00e4ndska serier"
			},
			"type": "Concept"
		    },
		    {
			"id": "5-262",
			"inScheme": "areena-analytics-classification",
			"key": "draama",
			"title": {
			    "fi": "Draama"
			},
			"type": "Concept"
		    },
		    {
			"id": "5-271",
			"inScheme": "areena-analytics-classification",
			"key": "p\u00e4ivitt\u00e4isdraama",
			"title": {
			    "fi": "P\u00e4ivitt\u00e4isdraama"
			},
			"type": "Concept"
		    },
		    {
			"id": "21-7",
			"inScheme": "finnpanel-genre-classification",
			"notation": [
			    {
				"value": "6",
				"valueType": "finnpanel-notation"
			    }
			],
			"title": {
			    "en": "Foreign Fiction",
			    "fi": "Ulkomainen fiktio"
			},
			"type": "Concept"
		    }
		],
		"subtitling": [
		    {
			"language": [
			    "fi"
			],
			"type": "Subtitling"
		    }
		],
		"title": {
		    "fi": "B & B Magazine",
		    "sv": "B & B Magazine"
		},
		"type": "TVProgram",
		"typeCreative": "Program",
		"typeMedia": "TVContent",
		"video": {
		    "format": [
			{
			    "inScheme": "mediaformat-classification",
			    "key": "16:9",
			    "type": "Concept"
			}
		    ],
		    "language": [],
		    "type": "VideoTrack"
		}
	    }
	],
	"title": {
	    "fi": "Suosittelemme"
	},
	"type": "CuratedList"
    },
    "meta": {
	"count": 18,
	"id": "8-1802228",
	"limit": "1",
	"offset": "0"
    }
}

GET /v1/nowplaying/{service}.json Get the currently playing song on a radio service

Returns information of currently ongoing song in chosen service. E.g. /v1/nowplaying/yle-radio-1.json. It is also possible to get previous and next songs with start and end parameters.

Parameters

Name Description
service The service from which to get the current current song. This parameter is required.
start Sets onset for the collection. Not required.
end Sets offset for the collection.

Response

200 OK on success

Response contains a JSON document with the currently ongoing song.

400 Bad Request if parameters have illegal values.

404 Not Found if service does not match a service object.

cURL example

Now playing example

curl -XGET "https://programs.api.yle.fi/v1/nowplaying/yle-radio-1.json?start=0&end=0&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": [
	{
	    "content": {
		"description": {
		    "unknown": "Porter: Get out of town (Mel Torme ja Artie Shawn orkesteri)."
		},
		"id": "12-1022-2-72745",
		"performer": [
		    {
			"name": "Mel Torme, laulu",
			"type": "agent"
		    },
		    {
			"name": "Artie Shaw and his Orchestra",
			"type": "agent"
		    }
		],
		"title": {
		    "unknown": "Get out of town"
		},
		"type": "MusicRecording"
	    },
	    "delta": "0",
	    "duration": "PT194S",
	    "endTime": "2015-06-04T09:55:19+0300",
	    "partOf": {
		"id": "12-1022-4-256469",
		"title": {
		    "fi": "Muistojen bulevardi"
		},
		"type": "RadioProgram"
	    },
	    "service": {
		"active": true,
		"audio": [
		    {
			"format": [
			    {
				"inScheme": "mediaformat-classification",
				"key": "stereo",
				"type": "Concept"
			    }
			],
			"language": [
			    "fi"
			],
			"type": "AudioTrack"
		    }
		],
		"displayOrder": 1000,
		"homepage": {
		    "serviceProvider": "http://yle.fi",
		    "title": {
			"fi": "Kotisivu",
			"sv": "Hemsida"
		    },
		    "type": "WebPage",
		    "url": "http://yle.fi/radio1"
		},
		"id": "yle-radio-1",
		"indexDataModified": "2015-03-26T10:25:23.569+02:00",
		"interaction": [
		    {
			"hasVersion": [
			    {
				"device": "mobile",
				"serviceProvider": "http://twitter.com",
				"title": {
				    "fi": "Twitter"
				},
				"type": "WebPage",
				"url": "https://mobile.twitter.com/yleradio1"
			    }
			],
			"serviceProvider": "http://twitter.com",
			"title": {
			    "fi": "Twitter"
			},
			"type": "WebPage",
			"url": "https://twitter.com/yleradio1"
		    },
		    {
			"hasVersion": [
			    {
				"device": "mobile",
				"serviceProvider": "http://facebook.com",
				"title": {
				    "fi": "Facebook"
				},
				"type": "WebPage",
				"url": "https://m.facebook.com/yleradio1"
			    }
			],
			"serviceProvider": "http://facebook.com",
			"title": {
			    "fi": "Facebook"
			},
			"type": "WebPage",
			"url": "https://facebook.com/yleradio1"
		    }
		],
		"language": [
		    "fi"
		],
		"outlet": [
		    {
			"media": {
			    "id": "10-6",
			    "type": "AudioObject"
			},
			"region": "Finland",
			"type": "Webcast"
		    },
		    {
			"media": {
			    "id": "10-6",
			    "type": "AudioObject"
			},
			"region": "World",
			"type": "Webcast"
		    }
		],
		"programGuide": [
		    {
			"serviceProvider": "http://yle.fi",
			"title": {
			    "fi": "Ohjelmaopas",
			    "sv": "Programguide"
			},
			"type": "WebPage",
			"url": "http://ohjelmaopas.yle.fi/radio/opas"
		    }
		],
		"region": "Finland",
		"title": {
		    "fi": "Yle Radio 1"
		},
		"type": "RadioChannel",
		"typeCreative": "Channel",
		"typeMedia": "RadioContent"
	    },
	    "startTime": "2015-06-04T09:52:05+0300",
	    "type": "NowPlaying"
	}
    ],
    "meta": {
	"count": 1,
	"end": 0,
	"service": "yle-radio-1",
	"start": 0
    }
}

GET /v1/index.json Get the index of the programs

The difference between this and the items search is that items always returns programs. Either individual programs or episodes of series. Index search returns individual programs or series objects. If any episode of a series matches a query, the series is returned.

Parameters

NameDescription
idReturns items containing the specified ID. Multiple IDs can be passed as a comma separated list.
typeReturns index matching the given type. Allowed values are:
  • "",
  • "tvseries",
  • "tvprogramsingle",
  • "radioseries",
  • "radioprogramsingle"
categoryReturns items linked to a specified category. Multiple category IDs can be passed as a comma separated list. To exclude items that belong to a specific category, add '-' before the id. E.g. category=1,2,-3,-4 returns items that belong to either category 1 or 2 AND do NOT belong to categories 3 AND 4.
availabilityReturns items matching the given availability status. "ondemand": returns items whose ondemand publication is currently valid and media object is available. "future-ondemand" returns items will become available as ondemand in the future. "future-scheduled" return items that will be broadcasted in the future. "in-future" returns the items that will either be broadcasted or become available as ondemand in the future. "expiring-ondemand.month" return items whose ondemand is currently available and is expiring within the month.
  • "",
  • "ondemand",
  • "future-ondemand",
  • "current-or-future-ondemand",
  • "future-scheduled",
  • "in-future",
  • "expiring-ondemand.month"
orderReturns items in specified order. E.g. Items sorted ascending according to Finnish title: /v1/index.json?order=title.fi:asc. Note that sorting by ondemand.publication.starttime is deprecated, use publication.starttime instead.
  • "",
  • "title.fi:asc",
  • "title.fi:desc",
  • "title.sv:asc",
  • "title.sv:desc",
  • "publication.starttime:asc",
  • "publication.starttime:desc",
  • "publication.endtime:asc",
  • "publication.endtime:desc",
  • "ondemand.publication.starttime:asc",
  • "ondemand.publication.starttime:desc",
  • "playcount.6h:asc:asc",
  • "playcount.6h:asc:desc",
  • "playcount.24h:asc:asc",
  • "playcount.24h:asc:desc",
  • "playcount.week:asc:asc",
  • "playcount.week:asc:desc",
  • "playcount.month:asc:asc",
  • "playcount.month:asc:desc"
serviceReturns items published on the given service.
publisherReturns items originally published by the given service.
productReturns items connected to a specific product. List of product IDs.
contentprotectionReturns items that contain a publication event with the content protection. Multiple content protection IDs can be passed as a comma separated list.
qReturns items matching the given keyword. E.g. Items matching search criteria "muumi": /v1/index.json?q=muumi
languageReturns items with audio track or subtitle language matching the given language. Example values are "", "fi", "sv", "en".
regionReturns items that contain a publication event with the given region
limitSets limit for the size of the returned collection. Default value is 25. Maximum number of results 100.
offsetSets offset for the collection. Note that limit + offset must not be greater than 15 000.

Response

200 OK on success

Response contains a JSON array with programs and series.

cURL example

Free text search example

curl -XGET "https://programs.api.yle.fi/v1/index.json?q=muumi&limit=1&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
    "@context": "https://programs.api.yle.fi/v1/context.jsonld",
    "apiVersion": "1.0.1299",
    "data": [
	{
	    "@id": "https://programs.api.yle.fi/v1/id/1-2748759",
	    "coverImage": null,
	    "description": {},
	    "id": "1-2748759",
	    "image": {},
	    "title": {
		"fi": "MUUMIT RIVIERALLA (SARJA)",
		"sv": "MUUMIT RIVIERALLA (SARJA)"
	    },
	    "type": "TVSeries"
	}
    ],
    "meta": {
	"count": 18,
	"limit": "1",
	"offset": "0",
	"q": "muumi"
    }
}

Data model

Programs API data documentation

Automatically generated on 04.06.2015, Kim Viljanen

Introduction

This document describes the schema of the Programs API data.

The abstract level

On the abstract level, the world of TV and Radio programs consists of many kinds of things, such as TV programs and Radio programs (for example, a specific episode of “Frasier” or the movie “Rentun ruusu”), TV series and Radio series (such as “Frasier”, “Yle Uutiset”), brands (e.g. “Pikku Kakkonen”, “Yle”), TV seasons and Radio seasons, channels and services (e.g. “Yle Areena”, “YleX”, “Yle Fem”), people and organizations, music records (e.g. played during a radio broadcast), and so on.

There is also lot of information describing these things, such as the title of the program and the format (e.g., video or audio) of the program, and the broadcast time and channel for the specific program. More importantly, there may also be lots of relations involved, such as <this program> –is a part of–> <that series>, and <this music record> –was played in–> <that radio show>.

The following example depicts a few relations a TV program may have in Yle’s case:

Example

In the image above, a specific TV program (episode) is part of a TV series. The TV Program has been created by a specific organization. The content subject of the program is described using vocabularies, by interlinking the program to descriptive concepts. The program has been both shown on a TV channel (scheduled transmission) and published via an ondemand service (ondemand publication).

There might also exist relations between things in the programs domain to other domains, such as newspaper articles mentioning a specific program, photographies shot during the production of the program, clips (e.g. trailer), and websites (such as the Wikipedia page of the “Frasier” series).

Linked data

To represent this multitude of different kinds of resources (the “things”) and the relations and other information involved, the Programs API uses a graph approach following the principles of Linked Data. Each resource is represented as a node in the graph and the resource can have relations to other nodes (e.g. “part of series” relation) and other attributes (e.g. title).

Each resource (node) is identified with a unique identifier (unique inside Yle’s data). In addition, each resource may have other attributes, such as the type of the resource (e.g. “TVProgram”) or the title, or have relations to other resources (nodes), such as <this program> –is part of–> <that series>.

The following example illustrates some of the information and relations of one episode of “Foyle’s War”:

Example

The practical level

Each API request provides one viewpoint to the graph. When the client application requests data from the Programs API, the response is represented as a JSON object tree, which contains a selection of resources from the underlying data graph. The following image gives an overview of how an API request is processed. The data provided via the API is updated constantly based on changes in the background systems.

API and the data architecture

The JSON format follows the JSON-LD recommendation for serializing the linked data. As a general rule, each JSON object corresponds and represents one resource in the underlying linked data graph. The object / resource is identified with an identifier (the “id” field) and described with a type (e.g. “TVProgram”). In addition to these core attributes, the JSON object may contain additional attributes (e.g. “title”) and relations (e.g. “partOfSeries”) to other objects.

For example if the user requests all information about the program identified with the id “1-217500”, the response would be following (lots of detail omitted below):

{
"id":"1-217500",
"@id":"https://programs.api.yle.fi/v1/id/1-217500",
"type":"TVProgram",
"title":{"fi":"Ponille kyytia"}
"partOfSeries":{
    "id":"1-105262",
    "type":"TVSeries",
    ...
    },
"publicationEvents":[ ... ]
...
}

To limit the size of the response, the amount of attributes may be reduced. Typically, on the root level of the JSON tree, the JSON objects contain more attributes and deeper in the tree the amount of attributes is reduced. If the client application needs to get the omitted information, the URL of the attribute “@id” can be used for requesting all information about the given resource.

The schema

The different attributes and the valid values for each attribute are defined in the Programs API data schema and are documented in this document (which you are now reading).

A few general remarks about the attributes:

  • All attributes are “global” among all results returned by the Programs API. They should be interpreted in the same way always when encountered in the data. For example, if a specific program and a specific series both have a attribute called “title”, the title represents the same information (=the title of that specific resource).

  • The value for each attribute is always represented in the same way, e.g. as JSON arrays or JSON objects. If the value of an attribute is sometimes an object, it will always be an object for that attribute.

  • Internationalized strings are represented as JSON objects where the key is the ISO language code for the language (e.g. “fi”) and the value is the string in that language. The language code is “unknown” if not known.

  • Attributes with no values are omitted from the result set. However, also attributes and their values which are considered less relevant for the specific API query at hand, may be omitted to minimize the size of the result.

The schema is built according to linked data practices and is following and is influenced by many existing metadata schemas, such as Schema.org, Dublin Core, and EBUCore. When possible, the relations between the Programs API data schema and external schemas have been or will be defined (e.g., Programs API’s title compared to Dublin core’s title). In addition, the JSON-LD Context definitions will later be published (work in progress), to make it possible for the user to automatically transform the Programs API data to an RDF representation.

Object types

All Program API data resources (serialized as JSON objects) are classified according to the following class hierarchy. The classes include, for example, “TVProgram” (subclass of “Program” and “TVContent”) and “ScheduledTransmission” (subclass of “PublicationEvent”).

The type of the resource (JSON object) is represented with the attribute type.

object types

Additional details about each class will be added later to this documentation.

Attributes

Please note: The documentation below is not completed and many details are missing. Work in progress!

Core attributes

All JSON objects representing resources have a type. Typically all objects have a (unique) identifier and/or a (mnemonic, descriptive) key.

Example of core attributes (of a TV Program resource):

{
   "id": "1-12345",
   "type": "TVProgram"
   ...
}

“id”

title: Primary identifier for this resource

value type: string

JSON-LD Context: @id

RDF: { ‘rdfs:subPropertyOf’ => ‘dc:identifier’ }

“@id”

title: API URL for fetching this resource

description: For fetching all data related to a specific resource (data object). To optimize the size of returned data, the JSON objects may contain only a selection of all available data. For example, objects deeper in the result tree (the JSON object tree) may be compressed to the most basic information, such as only the id of the resource.

value type: url

“key”

title: Human readable id

value type: string

“type”

title: Type of the resource

description: The nature (type) of the current JSON Object (resource), such as a TV Program, Radio Channel or an Organization. The possible type values are modelled as a class hierarchy where e.g. a TV Program and Radio Program has a common upper class, a Program.

value type: string

JSON-LD Context: @type

All other attributes

“addressCountry”

title: Country

value type: string

“addressLocality”

title: Post office

value type: string

“addressRegion”

title: Region/province/county

value type: string

“ageRating”

title: Age rating of the resource

value type: array

“ageRestriction”

title: Restricted under years (0 = no restriction)

value type: integer

“alternativeDescription”

title: Other description(s) of the resource

value type: array

value items: { ‘$ref’ => { ‘title’ => ‘Description of the resource’, ‘@context’ => { ‘@container’ => ‘@language’ }, ‘rdf’ => { ‘rdfs:subPropertyOf’ => ‘dcterms:description’ }, ‘$ref’ => ‘http://id.yle.fi/ns/yle-content-schema-v1.json#/definitions/_iString’ } }

“alternativeId”

title: Alternative identifiers for this resource

value type: array

value items: { ‘pattern’ => ‘^\d+\-\S+$’, ‘type’ => ‘string’ }

“alternativeTitle”

title: Alternative titles

value type: array

value items: { ‘$ref’ => { ‘patternProperties’ => { ‘^[a-z]{2,3}$’ => { ‘type’ => ‘string’ } }, ‘additionalProperties’ => bless( do{(my $o = 0)}, ‘JSON::XS::Boolean’ ), ‘type’ => ‘object’, ‘properties’ => { ‘unknown’ => { ‘type’ => ‘string’ } }, ‘title’ => ‘(Internal) Internationalized string’ } }

JSON-LD Context: { ‘@container’ => ‘@language’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dc:title’ }

“amountOfEpisodes”

title: Amount of episodes

value type: integer

“amountOfItems”

title: Amount of items

value type: integer

“amountOfSeasons”

title: Amount of seasons

value type: integer

“audio”

title: Audio tracks of the resource

value type: array

value items: { ‘type’ => ‘object’ }

“availability”

title: Availablity

value type: string

“available”

title: Is the resource represented by this object available currently?

value type: boolean

“band”

title: The frequency band

value type: string

“broader”

title: Parent concept

value type: object

“collection”

title: The collection this resource belongs to

value type: string

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:partOf’ }

“conductor”

title: Conductor

value type: object

“content”

title: The content related to the current resource, e.g. the publication event.

“contentRating”

title: The content rating of the current resource

value type: object

“contributor”

title: Contributor of the resource

value type: array

value items: { ‘type’ => ‘object’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:contributor’ }

“countryOfOrigin”

title: Country of origin of the resource

value type: array

“creator”

title: Creator of the resource

value type: array

value items: { ‘type’ => ‘object’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:creator’ }

“delta”

title: Relational position of this resource

description: Relational position of this resource compared to other resources in the result set. For example, the current song played by the radio station (delta=0), the previous song (delta=-1) and the next song is (delta=1).

value type: integer

“description”

title: Description of the resource

inherited definition: { ‘patternProperties’ => { ‘^[a-z]{2,3}$’ => { ‘type’ => ‘string’ } }, ‘additionalProperties’ => bless( do{(my $o = 0)}, ‘JSON::XS::Boolean’ ), ‘type’ => ‘object’, ‘properties’ => { ‘unknown’ => { ‘type’ => ‘string’ } }, ‘title’ => ‘(Internal) Internationalized string’ }

JSON-LD Context: { ‘@container’ => ‘@language’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:description’ }

“device”

title: Compatible device

value type: string

“displayOrder”

title: Recommended display order

description: This value can be used for displaying channels and other services in a logical order.

value type: integer

“duration”

title: Duration of the resource

description: Duration = endtime - starttime.

value type: string

“endTime”

value type: string

“episodeNumber”

title: Number of the episode this resource represents

value type: integer

“familyName”

title: Family name (last name) of the person.

value type: string

“format”

title: Technical format

description: For example, the video format of a VideoTrack can be HD.

value type: array

value items: { ‘type’ => ‘object’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:format’ }

“formatOf”

title: This resource is a format version of another resource (same intellectual content)

description: A related resource that is substantially the same - the same intellectual content - as the described resource, but in another format.

value type: array

value items: { ‘type’ => ‘object’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:isFormatOf’ }

“frequency”

title: The frequency (inside the given band)

value type: number

“frequencyUnit”

title: Frequency unit

value type: string

“givenName”

title: Given name (first name) of the person.

value type: string

“hasFormat”

title: Format version of this resource (same intellectual content)

description: A related resource that is substantially the same - the same intellectual content - as the described resource, but in another format.

value type: array

value items: { ‘type’ => ‘object’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:hasFormat’ }

“hasPart”

title: This resource has an other part / other parts

value type: string

“hasVersion”

title: Has a related resource that is a version, edition, or adaptation of the current resource.

description: For example, this movie has a remake.

value type: array

value items: { ‘type’ => ‘object’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:hasVersion’ }

“homepage”

title: Homepage for this resource.

description: For example, the homepage of a TV or Radio channel.

value type: object

“image”

title: Primary image of the resource

inherited definition: { ‘type’ => ‘object’, ‘properties’ => { ‘title’ => { ‘$ref’ => ‘http://id.yle.fi/ns/yle-content-schema-v1.json#/definitions/_iString’ }, ‘creator’ => { ‘type’ => ‘string’ } }, ‘title’ => ‘(Internal) Image object’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:description’ }

“inScheme”

title: Vocabulary identifier

description: The identifier key of the vocabulary this concept is part of. With the help of this key, the programmer can choose to use only those vocabularies that are relevant for ones application needs.

value type: string

RDF: { ‘rdfs:subPropertyOf’ => ‘skos:inScheme’ }

“interaction”

value type: array

value items: { ‘type’ => ‘object’ }

“itemTitle”

title: The episode / individual title

description: The title that identifies this specific resource, e.g. episode title of a program.

inherited definition: { ‘patternProperties’ => { ‘^[a-z]{2,3}$’ => { ‘type’ => ‘string’ } }, ‘additionalProperties’ => bless( do{(my $o = 0)}, ‘JSON::XS::Boolean’ ), ‘type’ => ‘object’, ‘properties’ => { ‘unknown’ => { ‘type’ => ‘string’ } }, ‘title’ => ‘(Internal) Internationalized string’ }

JSON-LD Context: { ‘@container’ => ‘@language’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dc:title’ }

“items”

value type: array

value items: { ‘type’ => ‘object’ }

“language”

title: The language version(s) of the resource

value type: array

value items: { ‘type’ => ‘string’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:language’ }

“license”

title: License for using the resource

value type: string

title: Logo of the resource

value type: object

“longDescription”

title: Long description of the resource

inherited definition: { ‘title’ => ‘Description of the resource’, ‘@context’ => { ‘@container’ => ‘@language’ }, ‘rdf’ => { ‘rdfs:subPropertyOf’ => ‘dcterms:description’ }, ‘$ref’ => { ‘patternProperties’ => { ‘^[a-z]{2,3}$’ => { ‘type’ => ‘string’ } }, ‘additionalProperties’ => bless( do{(my $o = 0)}, ‘JSON::XS::Boolean’ ), ‘type’ => ‘object’, ‘properties’ => { ‘unknown’ => { ‘type’ => ‘string’ } }, ‘title’ => ‘(Internal) Internationalized string’ } }

“media”

value type: object

“name”

title: Name of the agent/person/organization

value type: string

“narrower”

title: Child concept

value type: object

“operatingSystem”

title: Operating system

value type: string

“originalTitle”

title: Title of the resource

inherited definition: { ‘patternProperties’ => { ‘^[a-z]{2,3}$’ => { ‘type’ => ‘string’ } }, ‘additionalProperties’ => bless( do{(my $o = 0)}, ‘JSON::XS::Boolean’ ), ‘type’ => ‘object’, ‘properties’ => { ‘unknown’ => { ‘type’ => ‘string’ } }, ‘title’ => ‘(Internal) Internationalized string’ }

JSON-LD Context: { ‘@container’ => ‘@language’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dc:title’ }

“outlet”

title: The available receiving/distribution methods of the service

description: For example, the outlets of a radio service may contain multiple different broadcast frequencies at different geographical locations, internet streaming services, mobile applications, among others.

value type: array

value items: { ‘type’ => ‘object’ }

“partOf”

title: Part of something

value type: object

“partOfSeason”

title: Part of season

value type: object

“partOfSeries”

title: Part of series

value type: object

“performer”

title: Performer

value type: array

value items: { ‘type’ => ‘object’ }

“postOfficeBoxNumber”

title: Post office box number

value type: string

“postalCode”

title: Postal code

value type: string

“productionId”

title: Yle production identifier

description: This program (and potentially other programs) have been created as a result of a production identified with this production identifier.

value type: string

RDF: { ‘rdfs:subPropertyOf’ => ‘dc:identifier’ }

“programGuide”

title: Program guide(s) for this resource.

description: For example, the program guide(s) of a TV or Radio channel.

value type: array

value items: { ‘type’ => ‘object’ }

“publicationEvent”

title: Publication events of this resource

value type: array

value items: { ‘type’ => ‘object’ }

“ratingSystem”

title: Rating System

value type: string

“reason”

title: Content rating reason

value type: array

“region”

title: Region

value type: string

title: related to

value type: object

“releaseDate”

title: Release date of the resource

value type: string

“restrictions”

title: Haittamerkinnät

value type: string

“season”

title: The seasons of this series

value type: array

value items: { ‘type’ => ‘object’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dc:hasPart’ }

“seasonNumber”

title: The number of this season

description: Based on the original season numbering given by the producer of the series, if possible.

value type: integer

“seeAlso”

title: See also

description: Related, additional content

value type: array

value items: { ‘type’ => ‘object’ }

“service”

title: The publication service for this content

value type: object

“serviceProvider”

title: Service provider

value type: string

“shortDescription”

title: Short description of the resource

inherited definition: { ‘title’ => ‘Description of the resource’, ‘@context’ => { ‘@container’ => ‘@language’ }, ‘rdf’ => { ‘rdfs:subPropertyOf’ => ‘dcterms:description’ }, ‘$ref’ => { ‘patternProperties’ => { ‘^[a-z]{2,3}$’ => { ‘type’ => ‘string’ } }, ‘additionalProperties’ => bless( do{(my $o = 0)}, ‘JSON::XS::Boolean’ ), ‘type’ => ‘object’, ‘properties’ => { ‘unknown’ => { ‘type’ => ‘string’ } }, ‘title’ => ‘(Internal) Internationalized string’ } }

“startTime”

value type: string

“streetAddress”

title: Street address

value type: string

“subject”

title: The topic(s) of the resource

description: The content subject of the resource will be represented with controlled vocabularies / categorizations.

value type: array

value items: { ‘type’ => ‘object’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:subject’ }

“subtitling”

title: Subtitling tracks of the resource

value type: array

value items: { ‘type’ => ‘object’ }

“symbol”

title: Id object

value type: object

“targetAudience”

title: Target audience of the resource

value type: string

“teletextPage”

title: Teletext page number for subtitling

value type: integer

“temporalStatus”

title: Is this event in past, current or in future

value type: string

“title”

title: Title of the resource

description: The default, recommended title for this resource. Hint: This title should be useful in most cases, but e.g. in the case of programs consider also itemTitle and other titles.

inherited definition: { ‘patternProperties’ => { ‘^[a-z]{2,3}$’ => { ‘type’ => ‘string’ } }, ‘additionalProperties’ => bless( do{(my $o = 0)}, ‘JSON::XS::Boolean’ ), ‘type’ => ‘object’, ‘properties’ => { ‘unknown’ => { ‘type’ => ‘string’ } }, ‘title’ => ‘(Internal) Internationalized string’ }

JSON-LD Context: { ‘@container’ => ‘@language’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dc:title’ }

“topConcept”

title: Top concepts of the classification

value type: array

value items: { ‘type’ => ‘object’ }

“tracking”

title: Tracking for statistical purposes

value type: object

“typeCreative”

title: Type helper: the inherited creative type of the current type value. See: type

value type: string

“typeMedia”

title: Type helper: the inherited media type of the current type value. See: type

value type: string

“url”

title: URL of the object

value type: string

“value”

title: Value of the object

value type: string

“versionOf”

title: A related resource that is a version, edition, or adaptation of the described resource.

description: For example, this movie is a remake of the given movie.

value type: array

value items: { ‘type’ => ‘object’ }

RDF: { ‘rdfs:subPropertyOf’ => ‘dcterms:isVersionOf’ }

“video”

title: Video track of the resource

value type: object

“vocalist”

title: Vocalist

value type: array

value items: { ‘type’ => ‘object’ }

“webpage”

value type: string

RDF Schema mappings (experimental)

Schema mappings, serialized in RDF / Turtle format. (Please note, only existing mapping definitions are listed, may contain errors - there will be more soon. Work in progress!)

@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix : <https://programs.api.yle.fi/v1/data-schema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .

:itemTitle rdfs:subPropertyOf dc:title .

:contributor rdfs:subPropertyOf dcterms:contributor .

:language rdfs:subPropertyOf dcterms:language .

:format rdfs:subPropertyOf dcterms:format .

:title rdfs:subPropertyOf dc:title .

:alternativeTitle rdfs:subPropertyOf dc:title .

:image rdfs:subPropertyOf dcterms:description .

:hasVersion rdfs:subPropertyOf dcterms:hasVersion .

:versionOf rdfs:subPropertyOf dcterms:isVersionOf .

:productionId rdfs:subPropertyOf dc:identifier .

:hasFormat rdfs:subPropertyOf dcterms:hasFormat .

:description rdfs:subPropertyOf dcterms:description .

:subject rdfs:subPropertyOf dcterms:subject .

:collection rdfs:subPropertyOf dcterms:partOf .

:season rdfs:subPropertyOf dc:hasPart .

:inScheme rdfs:subPropertyOf skos:inScheme .

:creator rdfs:subPropertyOf dcterms:creator .

:id rdfs:subPropertyOf dc:identifier .

:formatOf rdfs:subPropertyOf dcterms:isFormatOf .

:originalTitle rdfs:subPropertyOf dc:title .

JSON-LD Context (experimental)

JSON-LD Context, serialized in JSON format. (Please note, only existing context definitions are listed, may contain errors - there will be more soon. Work in progress!)

{
   "@base" : "https://programs.api.yle.fi/v1/id/",
   "@vocab" : "https://programs.api.yle.fi/v1/data-schema#",
   "alternativeTitle" : {
      "@container" : "@language"
   },
   "description" : {
      "@container" : "@language"
   },
   "id" : "@id",
   "itemTitle" : {
      "@container" : "@language"
   },
   "originalTitle" : {
      "@container" : "@language"
   },
   "title" : {
      "@container" : "@language"
   },
   "type" : "@type"
}

GET /v1/episodesbymonth/{seriesId}.json Get episode counts by month

Returns series episode counts for each month. All months with episodes are returned. The episodes are grouped to months by their original publication dates.

Parameters

Name Description
seriesId Returns episodes for the series identified by this id.
   

Response

200 OK on success

Response contains a JSON document with the episode counts. If the series has no episodes or if the series does not exist the data is an empty JSON array.

cURL example

Get episodes for Game of Thrones

curl -XGET "https://programs.api.yle.fi/v1/episodesbymonth/1-2278755.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
  "@context": "https://programs.api.yle.fi/v1/context.jsonld",
  "apiVersion": "0.1.0.12-AK-1971-aggregate-episodes-monthly",
  "meta": {
    "series": "1-2278755"
  },
  "data": [
    {
      "year": 2012,
      "month": 1,
      "episodeCount": 2
    },
    {
      "year": 2012,
      "month": 2,
      "episodeCount": 4
    },
    {
      "year": 2012,
      "month": 3,
      "episodeCount": 3
    },
    {
      "year": 2013,
      "month": 1,
      "episodeCount": 12
    },
    {
      "year": 2013,
      "month": 2,
      "episodeCount": 6
    }
  ]
}

GET /v1/episodes(before|after)/{programId}.json Get episodes before or after a certain episode

Returns episodes that were published before or after the program given as parameter. The episode given as parameter is not returned. This can be used to find next episodes for a given episode of a series.

Parameters

Name Description
before There are two endpoints: one find previous episodes and the
after other finds coming episodes.
programId The episodes are returned relative to this program.
availability Filters relative episodes by availability. Valid values are:
  “ondemand”, “future-ondemand”, “current-or-future-ondemand”,
  “future-scheduled” and “in-future”
limit Sets limit for the size of the returned collection
offset Sets offset for the collection

Response

200 OK on success

Response contains a JSON document with the episodes (Programs). If the series has no episodes that are before|after the given program ID the result array is empty.

cURL example

Get newer episodes of the news series

curl -XGET "https://programs.api.yle.fi/v1/episodesafter/1-2396968.json?limit=5&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

{
  "@context": "https://programs.api-test.yle.fi/v1/context.jsonld",
  "apiVersion": "0.1.0.12-AK-1971-aggregate-episodes-monthly",
  "meta": {
    "offset": "0",
    "limit": "5",
    "episode": "1-2396968",
    "count": 42,
    "program": 42,
    "clip": 0
  },
  "data": [
    {
      "productionId": "49221520000",
      "audio": [
        {
          "language": [
            "fi"
          ],
          "format": [
            {
              "inScheme": "mediaformat-classification",
              "type": "Concept",
              "key": "stereo"
            }
          ],
          "type": "AudioTrack"
        }
      ],
      "alternativeId": [
        "16-2-E0524647"
      ],
      "typeMedia": "TVContent",
      "subject": [
        {
          "id": "5-163",
          "title": {
            "fi": "Uutisohjelmat",
            "sv": "Nyhetsprogram"
          },
          "broader": {
            "id": "5-162"
          },
          "inScheme": "areena-content-classification",
          "type": "Concept",
          "key": "uutisohjelmat"
        },
        {
          "id": "5-268",
          "title": {
            "fi": "Uutiset"
          },
          "inScheme": "areena-analytics-classification",
          "type": "Concept",
          "key": "uutiset"
        },
        {
          "id": "21-1",
          "title": {
            "fi": "Uutiset",
            "en": "News"
          },
          "inScheme": "finnpanel-genre-classification",
          "type": "Concept",
          "notation": [
            {
              "value": "1",
              "valueType": "finnpanel-notation"
            }
          ]
        }
      ],
      "image": {
        "id": "13-1-2397178",
        "available": true,
        "type": "ImageObject"
      },
      "collection": "main",
      "type": "TVProgram",
      "subtitling": [
        {
          "language": [
            "fi"
          ],
          "type": "HardOfHearingSubtitling"
        }
      ],
      "typeCreative": "Program",
      "creator": [
        {
          "name": "YLE",
          "type": "Organization"
        }
      ],
      "id": "1-2397178",
      "title": {
        "fi": "Yle Uutiset",
        "sv": "Yle Nyheter"
      },
      "duration": "PT24M30S",
      "description": {},
      "contentRating": {
        "title": {},
        "reason": []
      },
      "originalTitle": {},
      "itemTitle": {},
      "countryOfOrigin": [
        "Suomi"
      ],
      "video": {
        "language": [],
        "format": [
          {
            "inScheme": "mediaformat-classification",
            "type": "Concept",
            "key": "16:9"
          }
        ],
        "type": "VideoTrack"
      },
      "indexDataModified": "2015-07-28T21:07:34.243+03:00",
      "@id": "https://programs.api-test.yle.fi/v1/id/1-2397178",
      "partOfSeries": {
        "id": "1-2540138",
        "title": {
          "fi": "Yle Uutiset 20.30",
          "sv": "Yle Uutiset 20.30"
        },
        "alternativeId": [
          "1-2096927",
          "1-1753468",
          "1-918441",
          "1-1473834",
          "1-2095849",
          "1-1790187",
          "1-1369235",
          "1-2121675",
          "1-2127409",
          "1-2401079",
          "1-1790647",
          "1-1754492",
          "1-2396923",
          "1-1369536",
          "1-917493"
        ],
        "subject": [
          {
            "id": "5-162",
            "title": {
              "fi": "Uutiset",
              "sv": "Nyheter"
            },
            "broader": {
              "id": "5-130"
            },
            "inScheme": "areena-content-classification",
            "type": "Concept",
            "key": "uutiset"
          },
          {
            "id": "5-268",
            "title": {
              "fi": "Uutiset"
            },
            "inScheme": "areena-analytics-classification",
            "type": "Concept",
            "key": "uutiset"
          }
        ],
        "description": {
          "fi": "Teksti-TV 335.",
          "sv": "Text-TV 335."
        },
        "image": {
          "id": "13-1-2540138",
          "available": true,
          "type": "ImageObject"
        },
        "type": "TVSeries",
        "coverImage": {
          "id": "13-1-2540138-cover",
          "available": true,
          "type": "ImageObject"
        },
        "interactions": [
          {
            "title": {
              "fi": "Facebook: Yle Uutiset"
            },
            "type": "WebPage",
            "url": "https://fi-fi.facebook.com/yleuutiset"
          },
          {
            "title": {
              "fi": "Yle Uutiset - yle.fi/uutiset"
            },
            "type": "WebPage",
            "url": "http://yle.fi/uutiset/"
          },
          {
            "title": {
              "fi": "Ota käyttöösi Ylen Uutisvahti-mobiilisovellus ja pysyt haluamissasi aiheissa koko ajan tasalla"
            },
            "type": "WebPage",
            "url": "http://yle.fi/uutiset/yle_uutiset_uutisvahdin_saa_nyt_myos_iphoneen/7099634?ref=uutisvahti-ylefi"
          },
          {
            "title": {
              "fi": "Twitter: Yle Uutiset"
            },
            "type": "WebPage",
            "url": "https://twitter.com/yleuutiset"
          }
        ],
        "countryOfOrigin": [],
        "creator": [],
        "@id": "https://programs.api-test.yle.fi/v1/id/1-2540138"
      },
      "publicationEvent": [
        {
          "id": "4-4110324",
          "startTime": "2015-07-28T20:30:00+03:00",
          "region": "World",
          "duration": "PT25M",
          "service": {
            "id": "yle-tv1"
          },
          "endTime": "2015-07-28T20:55:00+03:00",
          "type": "ScheduledTransmission",
          "media": {},
          "temporalStatus": "in-past"
        },
        {
          "id": "4-4574582",
          "startTime": "2015-07-28T20:30:00+03:00",
          "region": "World",
          "duration": "P30DT3H29M59S",
          "service": {
            "id": "yle-areena"
          },
          "endTime": "2015-08-27T23:59:59+03:00",
          "type": "OnDemandPublication",
          "media": {
            "id": "6-a3504b8ba58e445391e5a1ce3ce2d114",
            "duration": "PT24M30S",
            "contentProtection": [
              {
                "id": "22-1",
                "type": "ContentProtectionPolicy"
              }
            ],
            "available": true,
            "type": "VideoObject",
            "downloadable": false
          },
          "publisher": [
            {
              "id": "yle-tv1"
            }
          ],
          "temporalStatus": "currently"
        },
        {
          "id": "4-4318474",
          "startTime": "2015-07-28T20:30:00+03:00",
          "region": "World",
          "duration": "PT25M",
          "service": {
            "id": "tv-finland"
          },
          "endTime": "2015-07-28T20:55:00+03:00",
          "type": "ScheduledTransmission",
          "media": {},
          "temporalStatus": "in-past"
        }
      ]
    },

    ...
  ]
}

GET /v1/episodes/{seriesId}.json Get episodes published in a given time period

Returns episodes that were published before or after the program given as parameter. The episode given as parameter is not returned. This can be used to find next episodes for a given episode of a series.

Parameters

Name Description
seriesId The id of a series. The episodes come from this series.
season The id of a season. Lists the episodes from this season.
firstpublicationbefore A date in the format “yyyy-MM-dd’T’HH:mm:ss.SSSZZ”.
  Return episodes published before this date.
firstpublicationafter A date in the format “yyyy-MM-dd’T’HH:mm:ss.SSSZZ”.
  Return episodes published after this date.
availability Filters relative episodes by availability. Valid values are:
  “ondemand”, “future-ondemand”, “current-or-future-ondemand”,
  “future-scheduled” and “in-future”
limit Sets limit for the size of the returned collection
offset Sets offset for the collection

Response

200 OK on success

Response contains a JSON document with the episodes (Programs). If the series has no episodes that are published in the given time frame the result data array is empty.

cURL example

Find episodes published in a single month

curl -XGET "https://programs.api.yle.fi/v1/episodes/1-2396968.json?firstpublicationbefore=2015-04-01T00:00:00.000EET&firstpublicationafter=2015-03-01T00:00:00.000EET&limit=100&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

Programs API v2

GET /v1/items/{id}.json Get a single object

Returns a single item (clip, program, series or season) by the ID parameter. For example, to get a program by id 1-2, request /v1/items/1-2.json

Parameters

Name Description
id The ID of the desired program, episode, clip, series or season

Response

200 OK on success

Response contains a JSON document with one item as data.

400 Bad Request if required parameters are missing

404 Not Found If the requested entity is not found in the database

Example

Get a TVSeason by ID

curl "https://programs-v2.api.yle.fi/v1/items/1-4468885.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID" | jq

{
  "meta": {
    "id": "1-4468885"
  },
  "data": {
    "indexDataModified": "2019-03-26T02:15:18.651Z",
    "id": "1-4468885",
    "type": "TVSeason",
    "title": {
      "fi": "Alina idässä",
      "sv": "Alina i öst"
    },
    "description": {
      "fi": "Trump-wannabe, huumehuuruiset teknofestarit ja ydintuhoasebunkkeri. Näyttelijä Alina Tomnikov kiertää slaavimaita, eläen, kokien ja tutkien miten paikalliset nuoret elävät ja ajattelevat. Kuukauden mittaisella reissulla vieraillaan Puolassa, Sloveniassa, Tsekeissä ja Pietarissa. Matkalla on tällä kertaa mukana myös Alinan puoliso Lauri.",
      "sv": "En Trump-wannabe, en drogfylld teknofestival och en kärnvapenbunker. Skådespelaren Alina Tomnikov reser runt i slaviska länder och upplever och undersöker hur de lokala unga lever och tänker. På den månadslånga resan besöker hon Polen, Slovenien, Tjeckien och S:t Petersburg. Med på resan den här gången är Alinas man Lauri."
    },
    "subject": [
      {
        "id": "21-3",
        "title": {
          "fi": "Asiaohjelmat/lifestyle",
          "en": "Factual/lifestyle"
        },
        "inScheme": "finnpanel-genre-classification",
        "type": "Concept",
        "notation": [
          {
            "value": "3.1",
            "valueType": "finnpanel-notation"
          }
        ]
      },
      {
        "id": "31-1-4",
        "title": {
          "fi": "Asia"
        },
        "inScheme": "yle-content-main-classification",
        "type": "Concept"
      },
      {
        "id": "31-2-9.8",
        "title": {
          "fi": "Reality"
        },
        "inScheme": "yle-content-format-classification",
        "type": "Concept"
      },
      {
        "id": "31-3-4.72",
        "title": {
          "fi": "Matkailu"
        },
        "inScheme": "yle-content-topic-classification",
        "type": "Concept"
      },
      {
        "id": "5-260",
        "title": {
          "fi": "Asiaohjelmat"
        },
        "inScheme": "areena-analytics-classification",
        "type": "Concept",
        "key": "asiaohjelmat"
      }
    ],
    "countryOfOrigin": [],
    "creator": [
      {
        "name": "AITO MEDIA OY",
        "type": "Organization"
      }
    ],
    "partOfSeries": {
      "description": {
        "fi": "Trump-wannabe, huumehuuruiset teknofestarit ja ydintuhoasebunkkeri - sarjan toisella kaudella näyttelijä Alina Tomnikov kiertää slaavimaita, eläen, kokien ja tutkien miten paikalliset nuoret elävät ja ajattelevat. Kuukauden mittaisella reissulla vieraillaan Puolassa, Sloveniassa, Tsekeissä ja Pietarissa. Matkalla on tällä kertaa mukana myös Alinan puoliso Lauri.",
        "sv": "En Trump-wannabe, en drogfylld teknofestival och en kärnvapenbunker. Skådespelaren Alina Tomnikov reser runt i slaviska länder och upplever och undersöker hur de lokala unga lever och tänker. På den månadslånga resan besöker hon Polen, Slovenien, Tjeckien och S:t Petersburg. Med på resan den här gången är Alinas man Lauri."
      },
      "posterImage": {
        "id": "13-1-4252556-1552562315070",
        "type": "ImageObject",
        "version": 1553566518,
        "available": true
      },
      "squareImage": {
        "id": "13-1-4252556-1552562315071",
        "type": "ImageObject",
        "version": 1553566518,
        "available": true
      },
      "creator": [
        {
          "name": "AITO MEDIA OY",
          "type": "Organization"
        }
      ],
      "promotionTitle": {
        "fi": "Trump-wannabe, huumehuuruiset teknofestarit ja ydintuhoasebunkkeri -  Alina Tomnikov tutustuu slaavimaiden nuorten elämään"
      },
      "type": "TVSeries",
      "title": {
        "fi": "Alina idässä",
        "sv": "Alina i öst"
      },
      "shortDescription": {
        "fi": "Miten slaavimaiden nuoret elävät?"
      },
      "coverImage": {
        "id": "13-1-4252556-1552562315068",
        "type": "ImageObject",
        "version": 1553566518,
        "available": true
      },
      "countryOfOrigin": [],
      "id": "1-4252556",
      "image": {
        "id": "13-1-4252556-1552562315069",
        "type": "ImageObject",
        "version": 1553566518,
        "available": true
      },
      "highlightTag": {
        "fi": "Uusi kausi"
      },
      "subject": [
        {
          "id": "21-3",
          "title": {
            "fi": "Asiaohjelmat/lifestyle",
            "en": "Factual/lifestyle"
          },
          "inScheme": "finnpanel-genre-classification",
          "type": "Concept",
          "notation": [
            {
              "value": "3.1",
              "valueType": "finnpanel-notation"
            }
          ]
        },
        {
          "id": "31-1-4",
          "title": {
            "fi": "Asia"
          },
          "inScheme": "yle-content-main-classification",
          "type": "Concept"
        },
        {
          "id": "31-2-9.8",
          "title": {
            "fi": "Reality"
          },
          "inScheme": "yle-content-format-classification",
          "type": "Concept"
        },
        {
          "id": "31-3-4.72",
          "title": {
            "fi": "Matkailu"
          },
          "inScheme": "yle-content-topic-classification",
          "type": "Concept"
        },
        {
          "id": "5-150",
          "title": {
            "fi": "Fakta",
            "sv": "Fakta"
          },
          "broader": {
            "id": "5-148"
          },
          "inScheme": "areena-content-classification",
          "type": "Concept",
          "key": "fakta"
        },
        {
          "id": "5-260",
          "title": {
            "fi": "Asiaohjelmat"
          },
          "inScheme": "areena-analytics-classification",
          "type": "Concept",
          "key": "asiaohjelmat"
        }
      ],
      "availabilityDescription": {
        "fi": "Toinen kausi nyt Areenassa, Yle TV2 maanantaisin klo 21.30"
      }
    },
    "productionId": "88800102636",
    "seasonNumber": 2
  }
}

GET /v1/publications/{id}.json Get a single publication

Returns a single publication by the ID parameter. For example, to get a publication by id 4-123, request /v1/publications/4-123.json

Parameters

Name Description
id The ID of the desired publication

Response

200 OK on success

Response contains a JSON document with one item as data.

400 Bad Request if required parameters are missing

404 Not Found If the requested entity is not found in the database

Example

Get a Publication by ID

curl "https://programs-v2.api.yle.fi/v1/publications/4-50447051.json?app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID" | jq

{
  "meta": {
    "id": "4-50447051"
  },
  "data": {
    "content": {
      "description": {
        "fi": "Hippaleikki. Titta ja ystävät leikkivät hippaa, ja sen jälkeen Ruupen ja Emilian päivä on totisesti kommelluksia täynnä.",
        "sv": "Leka kull. Tilda och hennes vänner leker kull och efter det är Ruperts och Emilias dag verkligen full av missöden."
      },
      "video": {
        "format": [
          {
            "key": "HD",
            "type": "Concept",
            "inScheme": "mediaformat-classification"
          },
          {
            "key": "16:9",
            "type": "Concept",
            "inScheme": "mediaformat-classification"
          }
        ],
        "type": "VideoTrack",
        "language": []
      },
      "typeMedia": "TVContent",
      "creator": [
        {
          "name": "Beta Film GmbH",
          "type": "Organization"
        }
      ],
      "partOfSeason": {
        "description": {
          "fi": "Pieni valkoinen hiiri, Titta Pikkanen, asuu pienessä talossa, Sydänsalossa, Villiruusukujalla. Aina, kun joku tarvitsee apua, Titta auttaa. Luotettava ja sydämellinen hiirineiti kuuntelee ja neuvoo sekä keittää teetä ja tarjoaa herkkuja. Päivät Titta touhuaa ystäviensä Eeva-oravan, postihiiri Maijan, Ruupen-siilin, Sointu-punarinnan, Etanaisen sekä oravakaksosten Villen ja Penan ja heidän äitinsä kanssa.",
          "sv": "En liten mus, som heter Tilda Äppelkärna, bor i ett litet hus vid Stenrosvägen. Om någon behöver hjälp, ställer Tilda gärna upp. Den pålitliga och älskvärda fröken mus lyssnar till en, ger sina råd samt kokar te och bjuder på läckerheter. Om dagarna umgås Tilda med sina vänner Molly Postmus, Rupert Igelkott, Robin Rödhake, Svea Snigel och med ekorrtvillingarna Billy och Benny och deras mamma Edna Ekorre."
        },
        "seasonNumber": 1,
        "creator": [
          {
            "name": "Beta Film GmbH",
            "type": "Organization"
          }
        ],
        "partOfSeries": {
          "id": "1-3841681"
        },
        "type": "TVSeason",
        "productionId": "55174601000",
        "title": {
          "fi": "Titta Pikkanen (S)",
          "sv": "Tilda Äppelkärna (T)"
        },
        "countryOfOrigin": [],
        "id": "1-3841622",
        "subject": [
          {
            "id": "21-10"
          },
          {
            "id": "31-1-8"
          },
          {
            "id": "31-2-8.12"
          },
          {
            "id": "31-3-8.73"
          },
          {
            "id": "31-4-8"
          },
          {
            "id": "31-5-9"
          },
          {
            "id": "31-6-2"
          },
          {
            "id": "31-7-5"
          },
          {
            "id": "5-264"
          }
        ]
      },
      "partOfSeries": {
        "description": {
          "fi": "Pieni valkoinen hiiri, Titta Pikkanen, asuu pienessä talossa, Sydänsalossa, Villiruusukujalla. Aina, kun joku tarvitsee apua, Titta auttaa. Luotettava ja sydämellinen hiirineiti kuuntelee ja neuvoo sekä keittää teetä ja tarjoaa herkkuja. Päivät Titta touhuaa ystäviensä Eeva-oravan, postihiiri Maijan, Ruupen-siilin, Sointu-punarinnan, Etanaisen sekä oravakaksosten Villen ja Penan ja heidän äitinsä kanssa.",
          "sv": "En liten mus, som heter Tilda Äppelkärna, bor i ett litet hus vid Stenrosvägen. Om någon behöver hjälp, ställer Tilda gärna upp. Den pålitliga och älskvärda fröken mus lyssnar till en, ger sina råd samt kokar te och bjuder på läckerheter. Om dagarna umgås Tilda med sina vänner Molly Postmus, Rupert Igelkott, Robin Rödhake, Svea Snigel och med ekorrtvillingarna Billy och Benny och deras mamma Edna Ekorre."
        },
        "creator": [
          {
            "name": "Beta Film GmbH",
            "type": "Organization"
          }
        ],
        "type": "TVSeries",
        "title": {
          "fi": "Titta Pikkanen",
          "sv": "Tilda Äppelkärna"
        },
        "coverImage": {
          "type": "ImageObject",
          "id": "13-1-3841681-cover-1522155280459",
          "available": true,
          "version": 1570586826
        },
        "countryOfOrigin": [],
        "id": "1-3841681",
        "image": {
          "type": "ImageObject",
          "id": "13-1-3841681-1508765654015",
          "available": true,
          "version": 1570586826
        },
        "partOfProduct": {
          "id": "1-2450991"
        },
        "subject": [
          {
            "id": "21-10"
          },
          {
            "id": "31-1-8"
          },
          {
            "id": "31-2-8.12"
          },
          {
            "id": "31-3-8.73"
          },
          {
            "id": "31-4-8"
          },
          {
            "id": "31-5-9"
          },
          {
            "id": "31-6-2"
          },
          {
            "id": "31-7-5"
          },
          {
            "id": "5-195"
          },
          {
            "id": "5-197"
          },
          {
            "id": "5-198"
          },
          {
            "id": "5-199"
          },
          {
            "id": "5-262"
          },
          {
            "id": "5-264"
          }
        ]
      },
      "alternativeId": [
        "16-1-0865385"
      ],
      "type": "TVProgram",
      "duration": "PT7M3S",
      "productionId": "55174617000",
      "contentRating": {
        "type": "ContentRating",
        "title": {
          "fi": "Sallittu kaikenikäisille",
          "en": "For all ages",
          "sv": "Tillåtet för alla åldrar"
        },
        "ageRestriction": 0,
        "reason": [],
        "ratingSystem": "MEKU"
      },
      "title": {
        "fi": "Hippaleikki",
        "sv": "Leka kull"
      },
      "countryOfOrigin": [],
      "id": "1-3841638",
      "typeCreative": "Program",
      "image": {
        "type": "ImageObject",
        "id": "13-1-3841638-1517579880319",
        "available": true,
        "version": 1570788461
      },
      "audio": [
        {
          "format": [
            {
              "key": "stereo",
              "type": "Concept",
              "inScheme": "mediaformat-classification"
            }
          ],
          "type": "AudioTrack",
          "language": [
            "fi"
          ]
        }
      ],
      "partOfProduct": {
        "id": "1-2450991"
      },
      "originalTitle": {
        "en": "Tilda Appleseed"
      },
      "collection": "main",
      "subject": [
        {
          "id": "21-10"
        },
        {
          "id": "31-1-8"
        },
        {
          "id": "31-2-8.12"
        },
        {
          "id": "31-3-8.73"
        },
        {
          "id": "31-4-8"
        },
        {
          "id": "31-5-9"
        },
        {
          "id": "31-6-2"
        },
        {
          "id": "31-7-5"
        },
        {
          "id": "5-264"
        }
      ],
      "subtitling": [
        {
          "type": "HardOfHearingSubtitling",
          "language": [
            "fi"
          ]
        }
      ]
    },
    "duration": "PT7M3S",
    "endTime": "2019-10-15T07:32:28+03:00",
    "id": "4-50447051",
    "publisher": [
      {
        "id": "yle-tv2"
      }
    ],
    "region": "Finland",
    "related_publication": {
      "id": "4-8710314"
    },
    "service": {
      "id": "yle-tv2"
    },
    "startTime": "2019-10-15T07:25:25+03:00",
    "tags": {
      "snap_rerun": false,
      "live": false,
      "catalog": true
    },
    "type": "ScheduledTransmission",
    "version": 1570788461
  }
}

Programs API Queues

Program messages

Payload for “update”

Name Required Valid values
data.id true  
data.title true In any language, preferably in Finnish.
data.type true ‘Program’, ‘Clip’, ‘TVProgram’,’TVContent’, ‘TVClip’, ‘RadioContent’,’RadioProgram’, ‘RadioClip’
data.languages true An array of supported languages. Empty array if no languages available. Audio languages are listed first if available.
data.alternativeIds true An array of values. Empty array if no alternative ids.
data.publicationEvents true  
data.publicationEvents[].id true  
data.publicationEvents[].startTime true  
data.publicationEvents[].endTime false  
data.publicationEvents[].type false  
data.publicationEvents[].serviceId false  
data.publicationEvents[].publisherId false  
data.publicationEvents[].mediaType false ‘AudioObject’, ‘VideoObject’
data.publicationEvents[].mediaId false  
data.publicationEvents[].mediaDuration false  
data.partOfSeries false Null if program is not an episode in a series.
data.partOfSeries.id false Series id.
data.partOfProduct false Null if program is not a part of product.
data.partOfProduct.id false Product id.
data.subjects true An array of subject elements. Empty array if none present. See subject element spec below.
data.productionId false  
data.typeMedia false ‘TVContent’, ‘RadioContent’
data.typeCreative false  
data.episodeNumber false  
concepts false  

Example

{
  "data" : {
    "id" : "1-2749009",
    "title" : "Hittimittari: Jäähyväiset Hittimittarille",
    "type" : "TVProgram",
    "languages" : [ "fi" ],
    "alternativeIds" : [ "16-4-0900112027" ],
    "publicationEvents" : [ {
      "id" : "4-4515955",
      "startTime" : "2015-06-09T16:05:00+03:00",
      "endTime" : "2100-01-01T23:59:59+02:00",
      "type" : "OnDemandPublication",
      "serviceId" : "yle-areena",
      "publisherId" : "yle-elava-arkisto",
      "mediaType" : "VideoObject",
      "mediaId" : "6-bb5e57aa6dfe44b4affc89fd748c6533",
      "mediaDuration" : "PT45M25S"
    }, {
      "id" : "4-4419428",
      "startTime" : "2015-06-14T22:35:00+03:00",
      "endTime" : "2015-06-14T23:20:31+03:00",
      "type" : "ScheduledTransmission",
      "serviceId" : "tv-finland",
      "publisherId" : null,
      "mediaType" : null,
      "mediaId" : null,
      "mediaDuration" : null
    }, {
      "id" : "4-4299476",
      "startTime" : "2015-06-14T14:12:06+03:00",
      "endTime" : "2015-06-14T15:00:00+03:00",
      "type" : "ScheduledTransmission",
      "serviceId" : "yle-teema",
      "publisherId" : null,
      "mediaType" : null,
      "mediaId" : null,
      "mediaDuration" : null
    } ],
    "partOfSeries" : {
      "id" : "1-2838887"
    },
    "partOfProduct" : {
      "id" : "1-2450994"
    },
    "subjects" : [ {
      "key" : "musiikki",
      "title" : "Musiikki",
      "notations" : [ ],
      "inScheme" : "areena-content-classification"
    }, {
      "key" : "poprockjazz",
      "title" : "Pop, rock & jazz",
      "notations" : [ ],
      "inScheme" : "areena-content-classification"
    }, {
      "key" : "konsertitjatapahtumat",
      "title" : "Konsertit ja tapahtumat",
      "notations" : [ ],
      "inScheme" : "areena-content-classification"
    }, {
      "key" : "viihde",
      "title" : "Viihde",
      "notations" : [ ],
      "inScheme" : "areena-analytics-classification"
    }, {
      "key" : null,
      "title" : "Muut ohjelmat",
      "notations" : [ {
        "value" : "12",
        "valueType" : "finnpanel-notation"
      } ],
      "inScheme" : "finnpanel-genre-classification"
    } ],
    "productionId" : "53631717000",
    "typeMedia" : "TVContent",
    "typeCreative" : "Program",
    "episodeNumber" : 61
 }

Payload for “delete”

Name Required Valid values
data.id true  

Series messages

Payload for “update”

Name Required Valid values
data.id true  
data.title true In any language, preferably in Finnish.
data.type false  
data.alternativeIds true Array of ids. Empty if none present.
data.type true ‘RadioSeries’, ‘TVSeries’
data.languages true An array of supported languages. Empty array if no languages available.
data.subjects true An array of subject elements. Empty array if none present. See subject element spec below.
concepts false  

Example

{
    "data": {
        "id": "1-2345030",
        "title": "Uutisikkuna"
        "type": "TVSeries",
        "languages": ["fi", "sv"],
        "alternativeIds": ["16-0-341048424813", "16-0-341048424811"]
    }
}

Payload for “delete”

Name Required Valid values
data.id true  

Subject element

Subject element properties

Name Required Valid values
key false  
title false Title in Finnish.
notations true An array of notation objects. May be empty.
notations[].value false  
notations[].valueType false  
inScheme false  

Example

{
  "key" : null,
  "title" : "Ulkomainen fiktio",
  "notations" : [ {
    "value" : "6",
    "valueType" : "finnpanel-notation"
  } ],
  "inScheme" : "finnpanel-genre-classification"
}

Product messages

Payload for “update”

Name Required Valid values
data.id true  
data.title true In any language, preferably in Finnish.

Example

{
    "data": {
        "id": "1-2450994",
        "title": "Hajbo"
        
    }
}

Payload for “delete”

Name Required Valid values
data.id true  

Relations API

General information

API for linking Yle objects.

API defined relationships with three parameters: sourceId, targetId and relationType.

As an example relationship between a meta-api concept ( an external ontology subject ) and an article is defined with following relationship:

Relations api takes inspiration from RDF triplets.

RDF subject is sourceId, RDF object is the targetId and RDF predicate is the relationType.

If in doubt on how and what relations to use, please contact Pia Virtanen

Relation examples

Source relationType Target Example of usage
Politician (concept) isSubjectOf Content Article is written about a politician
Journalist (concept) isAuthorOf Content Article is written by some person.
True-crime (concept) isGenreOf Content Program belongs to a truecrime genre
Gloomy (concept) isAtmosphereOf Content Program has gloomy atmosphere
Sweden (concept) isCountryOfOriginOf Content Program is created in Sweden
Nenäpäivä 2019 (concept) isRelatedEventOf Content Program is related to Nenäpäivä festival in 2019
Sign language people (concept) isTargetAudienceOf Content Program is targeted to people who communicate in sign language
Tommi Korpela (concept) isPersonOfInterestOf Content Tommi Korpela is in this program
‘I love muovi’ (concept) isEditorialSectionOf Content ‘I love muovi’ theme includes this program
Areena Program isRelatedContentOf Content Areena clip about Kekkonen’s sauna is related content to an Article of Kekkonen

For documentation about concepts, see Meta API general information.

For more detailed and up-to-date information about relation types, see this Google document.

Relations and Ancestors

In YLE context, many targets that have some relations associated with them belong to a larger structure with possible ancestors and descendants. For example, a simple program might belong into a series, which in turn might belong to some bigger group, such as project (or possibly even to multiple projects).

Relations might be attached to any of these levels.

GET /v2/relation/ Get relations

Retrieves relations that match given request parameters or their combinations.

Using the example given in General section:

This relationship can be queried with either:

  • just sourceId
  • sourceId and relationType
  • just targetId

You can also send sourceId or targetId as a list of ids separated by comma.

By default this endpoint returns only direct relations (see General information about the Relations and Ancestors) when querying with targetId.

Using the withAncestorRelations=true parameter the response will also contain all the relations that have been defined in the levels above the given target.

Request parameters

Name Required Description
sourceId No Yle ID of the source of the relation. Usually a concept id starting with 18- , but with relationType relatedContent can be a content id ( for example program id starting with 1- ). If the relationship is of type subjectOf, then source is the concept that defines the subject of the target yle id. Can be a comma-separated list.
relationType No Type of the relation. Defines how a concept is related to content. See allowed values from General information.
targetId No Yle ID of the object of the relation. Can be a comma-separated list.
withAncestorRelations No If given, must be true or false. Defaults to false when omitted.

Response

200 OK on success

Response is a JSON object with a data array that contains one JSON object per relation, sorted by relation ID in ascending order. If no relations exist for given concept, the array will be empty.

Example request

curl "https://relations.api.yle.fi/v2/relation?sourceId=18-1&relationType=isSubjectOf&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{ "data":
  [
    {
      "id": "52-1",
      "sourceId": "18-1",
      "relationType": "isSubjectOf",
      "targetId": "1-123456",          
      "originId": "51-2"
    },
    {
      "id": "52-2",
      "sourceId": "18-1",
      "relationType": "isSubjectOf",
      "targetId": "1-431112",
      "originId": "51-3"
    },
    ...
  ]
}

POST /v2/relation Add a new relation

Adds a new relation between two Yle ids. Relation data must be sent in request body as JSON object.

Clients must add the Content-Type: application/json header.

JSON body parameters

Request body must be a JSON object with the following attributes.

Name Required Description
sourceId Yes Yle ID starting with 1 or 2 digits and a hyphen. For example 18-189148
relationType Yes Type of the relation. Allowed relationTypes are listed in General information.
targetId Yes Yle ID starting with 1 or 2 digits and a hyphen. For example 1-3339547
originId Yes Yle ID of the system or application that is the creator of the relation. Must start with 51- (see YleID documentation in confluence, schema 51).

Response

200 OK if the relation was added successfully

Response body contains a relation JSON.

400 Bad Request if given relation object was not valid

409 Conflict if a relation with matching sourceId, relationType, targetId and originId already exists

Example request

curl --request POST \
     --header 'Content-Type: application/json' \
     --data '{"sourceId": "18-1", "relationType": "isSubjectOf", "targetId": "1-123456",  "originId": "50-2"}' \
     "https://relations.api.yle.fi/v2/relation?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
  "id": "52-1",
  "sourceId": "18-1",
  "relationType": "isSubjectOf",
  "targetId": "1-123456",
  "originId": "51-2"
}

POST /v2/relation/_multi Add multiple new relations

Adds a new relation between two Yle ids. Relation data must be sent in request body as JSON object. Relation data must be sent in request body as a JSON array of JSON objects.

Clients must add the Content-Type: application/json header.

JSON body parameters

Request body must be a JSON array of JSON objects with the following attributes.

Name Required Description
sourceId Yes Yle ID starting with 1 or 2 digits and a hyphen. For example 18-189148
relationType Yes  
targetId Yes Yle ID starting with 1 or 2 digits and a hyphen. For example 1-3339547
originId Yes Yle ID of the system or application that is the creator of the relation. Must start with 51- (see YleID documentation in confluence, schema 51).

Response

200 OK if relations were added or already existed

Response body contains a JSON array of the relations that were added.

400 Bad Request if any of the given relation objects is not valid

Example request

curl --request POST \
     --header 'Content-Type: application/json' \
     --data '[{"targetId": "1-123456", sourceId": "18-1", "relationType": "isSubjectOf", "originId": "50-2"},{"targetId": "1-123456", sourceId": "18-2", "relationType": "isSubjectOf", "originId": "50-2"}]' \
     "https://relations.api.yle.fi/v2/relation/_multi?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

[
  {
    "id": "52-1",
    "sourceId": "18-1",
    "relationType": "isSubjectOf",
    "targetId": "1-123456",
    "originId": "51-2"
  },
  {
    "id": "52-2",
    "sourceId": "18-2",
    "relationType": "isSubjectOf",
    "targetId": "1-123456",
    "originId": "51-2"
  }
]

DELETE /v2/relation/{relationId} Delete a relation

Deletes a relation defined by the given relation ID.

URL parameters

Name Required Description
relationId Yes ID of the relation to be deleted. Must start with "52-".

Response

200 OK when the relation was successfully deleted

Response body is a JSON object that contains the deleted relation’s ID.

400 Bad Request when given relation ID was not valid

404 Not Found when a relation with the given ID was not found

Example request

curl -X DELETE "https://relations.api.yle.fi/v2/relation/52-123456?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
  "id": "52-123456"
}

POST /v2/relation/update Add or remove relations

Add new relations between two Yle ids and remove existing relations.

Relation data must be sent in request body as JSON object.

Clients must add the Content-Type: application/json header.

JSON body parameters

Request body must be a JSON object with keys added and removed, both JSON arrays.

Added relations must be JSON objects with the following properties:

Name Required Description
sourceId Yes Yle ID starting with 1 or 2 digits and a hyphen. For example 18-189148
relationType Yes  
targetId Yes Yle ID starting with 1 or 2 digits and a hyphen. For example 1-3339547
originId Yes Yle ID of the system or application that is the creator of the relation. Must start with 51- (see YleID documentation in confluence, schema 51).

Removed relations is simply a list of relation IDs.

Response

200 OK if relations were added or already existed

Response body contains a JSON object with the added and removed relations.

400 Bad Request if any of the given relation objects is not valid

Example request

curl --request POST \
     --header 'Content-Type: application/json' \
     --data '{"added": [{"targetId": "1-123456", sourceId": "18-1", "relationType": "isSubjectOf", "originId": "50-2"},{"targetId": "1-123456", sourceId": "18-2", "relationType": "isSubjectOf", "originId": "50-2"}], "removed": ["50-99", "50-98"]}' \
     "https://relations.api.yle.fi/v2/relation/update?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
  "added": [
    {
      "id": "52-1",
      "sourceId": "18-1",
      "relationType": "isSubjectOf",
      "targetId": "1-123456",
      "originId": "51-2"
    },
    {
      "id": "52-2",
      "sourceId": "18-2",
      "relationType": "isSubjectOf",
      "targetId": "1-123456",
      "originId": "51-2"
    }
  ],
  "removed": [
    "52-99",
    "52-98"
  ]
}

GET /v2/relation_types List relation types

Retrieves all relation types.

Response

200 OK on success

Response is a JSON object with a data array that contains relation type names as strings.

Example request

curl "https://relations.api.yle.fi/v2/relation_types?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{ "data": 
  [
    "isAtmosphereOf",
    "isAuthorOf",
    ...
  ]
}

Rabbitmq change messages

Relations api publishes changes to relations via Rabbitmq.

Routing key used is relations-api.changes and used exchange is exchange.ylefibackend.internal

Payload lists all the relations on an targetId to which a change was made.

{"targetId" : "1-1111",
 "relations" : [  { "id" : "52-112",
                    "sourceId" :    "18-1",
                    "relationType" : "isAuthorOf",
                    "targetId" : "1-1111",
                    "origin-id" : "51-3"} ] }

If the last relation pointing to that targetId was removed, then the relations array is empty.

{"targetId" : "1-1111",
 "relations" : [] }

Publication API

GET /v1/publications/scheduled-transmissions/now.json Get current scheduled transmissions

Returns scheduled transmissions of programs that are being broadcasted at the moment. Optionally returns also up to 2 previous and 10 upcoming (per service) scheduled transmissions.

On-demand publications are not returned by this API.

Parameters

All parameters are optional.

Name Description
service_id Return only scheduled transmissions broadcasted on given service(s). Multiple values can be given as comma separated list.
next Defines how many upcoming transmissions (per service) should be returned. Allowed values from 0 to 10 (default 0).
previous Defines how many previous transmissions (per service) should be returned. Allowed values from 0 to 2 (default 0).

Response

200 OK on success

Response is a JSON object with data array that contains one JSON object for each scheduled transmission (that is currently being broadcasted, or is within the given previous and next limits). Transmissions are sorted by their start time in ascending order.

For each transmission, the following attributes are included:

  • publication id (Ohjus2 publish id)
  • program id (Ohjus2 program id)
  • service id (for example yle-tv1)
  • start time
  • end time

When processing the results, keep in mind that multiple transmissions may be broadcasted simultaneously on one service (for example, yle-areena broadcasting multiple webcasts).

400 Bad Request if parameters are invalid

cURL example

curl -XGET "https://publication.api.yle.fi/v1/publications/scheduled-transmissions/now.json?app_id=YOUR_APP_KEY&app_key=YOUR_APP_ID"

{
  "data": [
    {
      "publicationId": "4-123456",
      "programId": "1-3995138",
      "serviceId": "yle-teema",
      "startTime": "2017-02-17T04:00:00+02:00",
      "endTime": "2017-02-17T17:00:00+02:00"
    },
    {
      "publicationId": "4-623456",
      "programId": "1-3888843",
      "serviceId": "yle-klassinen",
      "startTime": "2017-02-17T06:00:00+02:00",
      "endTime": "2017-02-17T13:00:00+02:00"
    }]
  "meta": {}
}

Consuming current scheduled transmissions

Publication API publishes events to REST MQ API when any scheduled transmission starts or stops. These events can be consumed by applications that need to constantly be in sync with the currently broadcasted programs. The events are published to queue publication-api.scheduled-transmission-events, and contain (only) the information of the particular transmission that started or stopped.

Publication API also publishes the complete “currently scheduled transmissions” data set to REST MQ API queue publication-api.scheduled-transmissions-now. This is the same data that could be retrieved by sending a request to GET /v1/publications/scheduled-transmissions/now.json endpoint with parameters previous=2 and next=10. However, consuming changes from a message queue is more efficient than constantly polling the API and checking whether the data has changed. These messages are published when (and only when) a change occurs in the data set, either because some scheduled transmission starts or stops as time goes by, or because the data of some scheduled transmission that is currently part of the data set is updated.

You can consume events from these REST MQ API queues by creating an HTTP endpoint in your application for receiving the events, and then registering a consumer in REST MQ API.

Event data

Queue publication-api.scheduled-transmission-events

These events are published whenever any scheduled transmission starts or stops being broadcasted on any service. The consumer endpoint will receive a request containing JSON body with the following attributes:

Attribute Description
eventType "transmission-start" or "transmission-stop"
data.publicationId Id of the scheduled transmission (Ohjus2 publish id)
data.programId Id of the program (Ohjus2 program id)
data.serviceId Id of the service the transmission is broadcasted on (such as "yle-areena")
data.startTime Start time of the scheduled transmission
data.endtime End time of the scheduled transmission

Queue publication-api.scheduled-transmissions-now

These events are published every time the “currently scheduled transmissions” data set changes in any way. The consumer endpoint will receive a request containing JSON body with data array holding the complete data set. The data set is an array with one JSON object for each transmission (see table below for details). Transmissions are sorted by their start time in ascending order. This data is exactly the same data that one would receive by sending a GET /v1/publications/scheduled-transmissions/now.json?previous=2&next=10 request to Publication API.

Attribute Description
eventType "update"
data[].publicationId Id of the scheduled transmission (Ohjus2 publish id)
data[].programId Id of the program (Ohjus2 program id)
data[].serviceId Id of the service the transmission is broadcasted on (such as "yle-areena")
data[].startTime Start time of the scheduled transmission
data[].endtime End time of the scheduled transmission

Registering a consumer in REST MQ API

To register a consumer, choose an id for your consumer. This id should be human readable and describe the consuming application (for example, metrics-api). Then, issue an HTTP PUT request to the following URI:

https://rest-mq.api.yle.fi/v1/queue/{queue-id}/consumer/{consumer-id}

Replace {queue-id} with either publication-api.scheduled-transmission-events or publication-api.scheduled-transmissions-now, depending on what type of information your application needs. Also, replace {consumer-id} with your consumer id.

Request body

Request body must contain a JSON object with callback attribute at its root. Callback object defines your application’s endpoint that will receive the events from Publication API.

Callback attribute Description
url URL of the endpoint that will consume the events. For example, https://metrics.api.yle.fi/v2/nowPlaying.json?app_id=APP_ID&app_key=APP_KEY.
method HTTP method of your consuming endpoint. Must be either "POST" or "PUT".

It is important to include API key parameters app_id and app_key in the callback url, if your application is authorized by 4scale. This API key must have access to the consuming endpoint - otherwise the events will not reach your application.

Response

200 OK when consumer was registered successfully

After the consumer has been registered successfully, you start receiving the events from Publication API in the consumer endpoint.

400 Bad Request if required parameters were missing or invalid

Example request

$ curl -XPUT -H "Content-Type: application/json" \
  "https://rest-mq.api.yle.fi/v1/queue/publication-api.scheduled-transmission-events/consumer/metrics-api?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --data '{"callback": { \
             "url": "https://metrics.api.yle.fi/v2/nowPlaying.json?app_id=APP_ID&app_key=APP_KEY", \
             "method": "POST" \
           }}'

Consuming available on-demand publications

Publication API publishes an event to REST MQ API for every on-demand publication when its availability starts, and another event when the availability ends. The events are published to queue publication-api.ondemand-events, to be consumed by applications that need to keep up with what on-demand publications are available. Events are published within 60 seconds of publication becoming available or unavailable.

Note: Consumers must be prepared for situations where these events are not published (for example, during maintenance breaks). It is also possible (and even likely) that duplicate events will be published within the 60 seconds timeframe. Events may also be published in non-linear order.

The events can be consumed by creating an HTTP endpoint in your application for receiving the events, and then registering a consumer in REST MQ API. This is described in more detail in the documentation about consuming current scheduled transmissions. Just remember to use publication-api.ondemand-events as the queue id!

Event data

Queue publication-api.ondemand-events

The events are published within 60 seconds of any on-demand publication becoming available or ceasing to be available. The consumer endpoint will receive a request containing JSON body with the following attributes:

Attribute Description
eventType "ondemand-start" or "ondemand-end"
data.publicationId Id of the publication (Ohjus2 publish id)
data.programId Id of the program (Ohjus2 program id)
data.serviceId Id of the service the publication is available on (such as "yle-areena")
data.startTime Start time of the publication
data.endtime End time of the publication

REST MQ API

General information

REST MQ API provides message queues as a RESTful HTTP service. It can be used to decouple applications for simplified scalability and performance considerations and availability, just like any other message queue provider. Applications integrate with REST MQ API with exactly the same tools as they do with any other RESTful API.

DEPRECATED Instead of developing new features using Rest MQ, we suggest the use of AWS SQS, AWS SNS, RabbitMQ or some other queue/pub-sub service available.

REMOVED FEATURES many-to-one queue type has been removed in July 2020.

POST /v1/queue/{queueId} Create new one-to-many queue (basic use case)

Create a queue for publishing messages. Other applications can then subscribe as consumers to this queue using register consumer endpoint.

Example use case: your API holds some master data, and other services are dependent on this data. Your API can publish changes to this data via a queue, and other services can receive the data without polling your API.

URL parameters

Name Description
queueId Queue identifier that must be unique and is highly recommended to be descriptive. Recommended format: "your-application.the-data" eg. "publication-api.events".

Request body

Request body must contain a JSON object with queueType attribute at its root.

Attribute Description
queueType Use "one-to-many"

Response

200 OK when queue was created successfully

400 Bad Request if required parameters were missing or invalid

409 Conflict when queue with the provided queue id already exists

Example request

$ curl -XPOST -H "Content-Type: application/json" \
  "https://rest-mq.api.yle.fi/v1/queue/publication-api.events?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --data '{"queueType": "one-to-many"}'

PUT /v1/queue/{queueId}/consumer/{consumerId} Register a consumer for a queue

Register a consumer for a queue.

URL parameters

Parameter Description
queueId Id of the queue to be consumed
consumerId Descriptive and human readable id of the consumer (for example, "metrics-api")

Request body

Request body must contain a JSON object with callback attribute at its root. Callback object defines the consumer endpoint that will receive messages from the queue.

Attribute Description
callback.url URL of the endpoint that will consume the messages. For example, https://metrics.api.yle.fi/v2/nowPlaying.json?app_id=APP_ID&app_key=APP_KEY.
callback.method HTTP method of the consuming endpoint. Must be either "POST" or "PUT".
callback.timeout Timeout for the request to the consumer in milliseconds (optional, needs to be in the range of 2000-60000, default 2000).

It is important to include API key parameters app_id and app_key in the callback URL, if the consuming application is authorized by dragonscale. This API key must have access to the callback endpoint - otherwise the messages will not reach the consumer.

Response

200 OK when consumer was registered successfully

After the consumer has been registered successfully, the defined callback endpoint will start receiving messages from the queue immediately. The consuming endpoint must respond with “200 OK” or “400 Bad Request” status within the timeout of receiving the message. Otherwise REST MQ API considers the delivery to have failed, and will send the same message again after a short while (approximately 1 minute).

When consumer already exists its data is updated and 200 OK is returned.

400 Bad Request if required parameters were missing or invalid

Queue must exist before consumer can be registered. Consumers cannot be registered for many-to-one queues.

Example request

$ curl -XPUT -H "Content-Type: application/json" \
  "https://rest-mq.api.yle.fi/v1/queue/publication-api.events/consumer/metrics-api?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --data '{"callback": { \
             "url": "https://metrics.api.yle.fi/v2/nowPlaying.json?app_id=APP_ID&app_key=APP_KEY", \
             "method": "POST" \
           }}'

DELETE /v1/queue/{queueId}/consumer/{consumerId} Remove consumer from a queue

Removes consumer from one-to-many queue. If the consumer has undelivered messages, they are removed as well.

URL parameters

Parameter Description
queueId Id of the queue that the consumer is registered for.
consumerId Id of the consumer to be removed from the queue.

Response

200 OK when consumer was removed successfully

When consumer is removed, all undelivered messages are removed as well, and no more messages are sent to the callback endpoint of the consumer.

400 Bad Request If the queue does not exist, or its type is not one-to-many

This endpoint cannot be used to remove consumer from many-to-one queue.

404 Not Found if no consumer was found with given consumer id

Example request

$ curl -X DELETE \
  "https://rest-mq.api.yle.fi/v1/queue/data-api.messages/consumer/your-api?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

POST /v1/queue/{queueId}/message Publish message to a queue

Publish a new message to a queue. The message will be delivered to all registered consumers of the queue. If no consumers are registered, the request is accepted but the message is dropped.

URL parameters

Parameter Description
queueId Id of the queue to which the message will be published

Request body

Request body must contain a JSON object with message attribute at its root. This is the message that will be delivered to consumers.

Attribute Description
message Message payload
queryParams Optional query parameters to be included in the message delivery HTTP request to consumer(s).

Response

200 OK when message was received successfully by REST MQ API

Note that this does not necessarily indicate that the message was successfully delivered to the consumers (yet), or that any consumers are even registered.

400 Bad Request if queue does not exist, or message is missing from request body

Example request

$ curl -XPOST -H "Content-Type: application/json" \
  "https://rest-mq.api.yle.fi/v1/queue/queuename?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY" \
  --data '{"message": {"foo": "bar"}}'

GET /v1/queue Get status of queues

This is a monitoring endpoint for retrieving information about queues. It outputs all existing queues, and their unconsumed messages count.

Response

Response contains a JSON array of queue objects. Each queue has an id attribute and a consumers attribute. The latter is an array of consumers. See example request and response below.

Example request

$ curl -XGET -H "Content-Type: application/json" \
    "https://rest-mq.api.yle.fi/v1/queue?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

[{
    "id": "publication-api.events",
    "consumers": [{
        "id": "metrics-api",
        "unconsumedMessagesCount": 0
    }]
 }]

Scheduler API

General information

Scheduler API can be used to trigger HTTP requests using a cron-like schedule.

GET /v2/tasks/{taskId} Get task by id

Retrieves information of a task defined by the given task ID.

URL parameters

Name Description
taskId ID of the task to retrieve.

Response

200 OK when the requested task is found

Response body is a JSON object that contains the requested task. See example below.

404 Not Found when a task with the given ID is not found

Example request

curl -X GET "https://scheduler.api.yle.fi/v2/tasks/foobar?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
  "id": "foobar",
  "url": "https://example.api.yle.fi/do_stuff?app_id=SOME_APP_ID&app_key=SOME_APP_KEY",
  "cron": "0 0/30 * * * ?",
  "method": "post",
  "headers": {
    "Content-Type": "application/json"
  }
}

POST /v2/tasks/http.json Create or update an HTTP task

Schedules a new HTTP task, or updates an existing one.

The task has a cron-like schedule and a target HTTP endpoint. A request will be sent to that endpoint by Scheduler API according to the defined schedule.

Task information must be sent in request body as JSON object. Clients should add the Content-Type: application/json header.

JSON body parameters

Request body must be a JSON object with the following attributes.

Name Required Description
id Yes Unique identifier for the task. Should be some human-readable value that identifies the application that owns the task.
url Yes Target URL that will receive the requests. Must include authentication parameters, if necessary.
method Yes HTTP method that should be used in requests. Allowed values are "get", "post", "put", "patch", and "delete".
cron Yes Cron-like schedule for the task. Underlying implementation is powered by Quartz - see Quartz documentation for more information on cron trigger syntax.
headers No JSON object that contains the HTTP headers and their values that should be sent with the request.
payload No JSON object that contains the body that should be included in the request.

Response

200 OK if the task was created or updated successfully

Response body is JSON and contains a meta object with inserted and updated attributes. This can be used to determine whether the operation created a new task, or updated an existing one.

400 Bad Request if given task definition was not valid

This status code indicates that the task definition included in request body was not valid.

Example request

Here is an example request that schedules a new HTTP task:

curl -X POST \
     --header 'Content-Type: application/json' \
     --data '{"id": "foobar", "url": "https://example.api.yle.fi/do_stuff?app_id=SOME_APP_ID&app_key=SOME_APP_KEY", \
              "cron": "0 0/30 * * * ?", "method": "post", "headers": { "Content-Type": "application/json"}}' \
     "https://scheduler.api.yle.fi/v2/tasks/http.json?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

{
  "meta": {
    "inserted": 1,
    "updated": 0
  }
}

From then on, endpoint https://example.api.yle.fi/do_stuff?app_id=SOME_APP_ID&app_key=SOME_APP_KEY will receive a POST request every 30 minutes.

DELETE /v2/tasks/{taskId} Delete task by id

Deletes a task defined by the given task ID.

URL parameters

Name Description
taskId ID of the task to delete.

Response

200 OK when the task was deleted successfully

404 Not Found when a task with the given ID was not found

Example request

curl -X DELETE "https://scheduler.api.yle.fi/v2/tasks/foobar?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

Scores API

Somedata API v2

GET /v2/facebook/latest.json Facebook share counts

Returns latest Facebook stats for item.

Parameters

Parameter Description
yle_id Required item ID in Yle ID format

Response

200 OK on success

{
  "meta" : {
    "yle_id": "3-7593193",
    "count": 1
  },
  "data": [
    {
      "yleId": "3-7593193",
      "total": 32
    }
  ]
}

404 Not Found if no Facebook stats are recorded for the item

It might take a while after article is published for it to be shared on Facebook. If you get 404, try again in a few minutes.

If you keep getting 404, check that the ID is valid and that it exists.

400 Bad Request with invalid parameters

cURL examples

Get Facebook stats for article 3-7593193

curl -XGET "https://somedata.api.yle.fi/v2/facebook/latest.json?yle_id=3-7593193&app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

Consuming most popular articles and programs

Somedata API publishes statistics about most popular articles and programs to RabbitMQ every five minutes. The messages are published to exchange.api.internal exchange with routing keys somedata.most_read.update (for most popular articles) and somedata.most_watched.update (for most popular programs).

The messages that are sent are rather large, as they contain Yle ids and view counts for every article or program viewed within the following time periods:

  • last 30 minutes (for articles only)
  • last hour (for articles only)
  • last 6 hours
  • last 12 hours (for articles only)
  • last 24 hours
  • last 2 days (for articles only)
  • last week
  • last month

Message format is JSON, where at the root level there are attributes for each of the aforementioned time periods: "30min", "1h", "6h", "12h", "24h", "2d", "week", and "month". Each of these attributes contains an array with objects that have an "yleId" attribute and a "score" attribute. Score is the number of page views or stream starts that the content with the given Yle id has received within the time period. Objects are sorted by their score in descending order (in other words, the most popular contents are on top).

Example message

Below is an example of the message structure. In reality the messages are much larger, as there is more data.

{
  "6h": [
    {
      "yleId": "1-123456789",
      "score": 10
    }
  ],
  "24h": [
    {
      "yleId": "1-123456789",
      "score": 20
    },
    {
      "yleId": "1-234567890",
      "score": 5
    }
  ],
  "week": [
    {
      "yleId": "1-123456789",
      "score": 100
    },
    {
      "yleId": "1-234567890",
      "score": 50
    }
  ],
  "month": [
    {
      "yleId": "1-123456789",
      "score": 1000
    },
    {
      "yleId": "1-234567890",
      "score": 500
    },
    {
      "yleId": "1-345678901",
      "score": 200
    }
  ]
}

Text Analysis API

POST /v1/text_analysis.json Analyse concepts from given text

This endpoint analyses given text (for example, an article), and returns a list of concepts (including their Meta API ids) that describe what the text is about.

Please do not overuse the service. Text analysis pricing is based on amount of requests, so you shouldn’t repeatedly send the same text to be analysed, send thousands of articles to be analysed, etc. If you need to do a migration or some other mass analysis, contact API team first and agree on acceptable use.

Request parameters

Name Required Description
lang Yes Language of text to be analysed. Supported values: fi, sv, en.
headline No Headline of the article, if request body is a body text of an article.

Including the headline parameter may improve analysis accuracy.

Body

Post the text to be analysed in request body with Content-Type text/plain. The text should contain at least a few sentences. Otherwise it cannot be properly analysed, and Text Analysis API will return an empty list of concepts.

Response

200 OK on success

Response will contain the related concepts in JSON array data.

{
  "meta": {
    "lang": "fi",
    "count": 15
  },
  "notifications": [ ],
  "data": [
    {
      "id": "18-34312",
      "title": {
        "fi": "Menojen leikkaaminen",
        "sv": "nedskärning av kostnader"
      },
      "exactMatch": [
        "leiki:focus100k_na_198221"
      ],
      "valid": true,
      "relevance": 16
    },
    ...
  ]
}

400 Bad Request language parameter is missing, or provided headline is invalid

Supported languages are fi, sv, and en.

Headline must be a string of 1 to 1000 characters.

429 Too Many Requests request quota has been exceeded

This endpoint is rate limited, and you have exceeded your daily quota.

502 Bad Gateway Meta API or text analysis service is not available

If you receive this error, just wait few seconds and try again later. This may happen if the connections to Meta API / text analysis service are temporarily down or those services have a maintenance break going on.

cURL example

curl --request POST \
     --header 'Content-Type:text/plain' \
     --data 'Hallitusneuvottelut jatkuvat Smolnassa perjantaina talousasioilla. \
             Tavoitteena on rakentaa noin kymmenen miljardin euron sopeutus- ja säästöpaketti.' \
     "https://text-analysis.api.yle.fi/v1/text_analysis.json?lang=fi&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

POST /v1/concepts/leiki/{leikiConceptId}.json Add new concept from Leiki

Adds new concept from Leiki. Concept is considered to be new if it does not exist in Meta API. If the concept exists in Meta API, it is not updated (and no requests are sent to Leiki at all).

Note: this endpoint is rate limited, and must not be overused with a large amount of new concept requests. This is because Leiki pricing model is based on the amount of requests. If you need to add a large amount of new concepts, contact API team first and agree on acceptable use.

Example request

curl --request POST \
     "https://text-analysis.api.yle.fi/v1/concepts/leiki/focus100k_na_4152.json?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

URL Parameter

Name Type Required Description
leikiConceptId string yes Id of the concept in Leiki, for example focus100k_na_4152.

Response

200 OK when successful

Response is a JSON object where the data attribute contains the corresponding Meta API concept (regardless of whether the concept was new or not).

Attribute meta is reserved for machine-readable metadata about the request. Attribute notifications can contain human-readable notifications concerning the request.

{ "meta": {},
  "notifications": ["Concept already exists."],
  "data": {
    "id":"18-218195",
    "alternativeIds": [
      "18-212993",
      "18-4886",
      "18-218969",
      "18-35241",
      "18-142719",
      "18-434",
      "18-81608"
    ],
    "types": [
      "Concept"
    ],
    "exactMatch": [
      "wikidata:Q40231",
      "finto:http://www.yso.fi/onto/koko/p32366",
      "escenic:vaalit",
      "freebase:/m/02l3h",
      "leiki:focus100k_na_4152"
    ],
    "title": {
      "fi":"vaalit",
      "sv":"val (samhälleliga händelser)"
    },
    "description": {
      "fi":"yhteiskunnalliset tapahtumat",
      "sv":"samhälleliga händelser"
    }
  }
}

400 Bad Request when given Leiki concept id is not valid

404 Not Found when concept is not found from Meta API nor Leiki

Concept does not exist. Check your Leiki concept id.

429 Too Many Requests when request quota has been exceeded

Leiki service usage via Text Analysis API is rate limited. If you receive this result, you have exceeded your quota and will need to postpone further requests.

Text Analysis API v2

Overview

Please see the GitHub repo for more detailed documentation.

Like Text Analysis API v1, Text Analysis API v2 serves concept word predicitons for a piece of text (usually an article). However, in addition to Leiki, the v2 API also serves predictions from Annif trained on Yle data.

The main job of the API at the moment is to enable validating the quality of predictions from Annif. The API only serves predictions to app ids it recognises. If you wish to use the API, please contact the content meta data team (sisältömetadatatiimi) by email or at the flowdock channel Sisältömetadata-support and indicate if you wish to obtain predictions from Leiki or Annif.

POST /v2/text_analysis.json Analyse concepts for given text

This endpoint analyses given text (an article for example), and returns a list of concepts (including their yle ids fetched from meta API) describing the text. For now, the endpoint saves predictions from both Annif and Leiki, but only one prediction set is returned as a response based on the request app id. All predictions are stored in S3 to the yle-metadata-lake bucket and reused in case a prediction has been asked for the same text.

Since Leiki predictions are stored for each request, the same warning applies as for the v1 endpoint: Please do not overuse the service. Leiki text analysis pricing is based on amount of requests, so you shouldn’t send thousands of articles to be analysed without consulting the concept meta data team (sisältömetadatatiimi) first.

Request parameters

Name Required Description
lang Yes Language of text to be analysed. Supported values: fi, sv, en.
app_id Yes The app id used to identify the organisation making the request.
app_key Yes The key used to authorise the request.
headline No Headline of the article, if request body is a body text of an article.
yle_id No The Yle id of the resource to be analysed. Is used in storing it to S3 in case included.

Including the headline parameter may improve the analysis accuracy of Leiki predictions. For Annif, the headline is simply concatenated to the beginning of the body text.

Body

Post the text to be analysed in request body with Content-Type text/plain and it should contain at least a few sentences.

Response

The responses from Text Analysis API v2 are made to be very similar to ones from v1. The effect is achieved by fetching information about the concept words by Annif from Meta API. This allows easy migration from v1 to v2. Note that we do not return the field meta or the field valid inside the predictions.

200 OK on success

Response will contain the related concepts in JSON array data.

    {
        "data": [
            {
                "id": "18-218737",
                "title": {
                    "fi": "työelämä",
                    "sv": "arbetsliv",
                    "en": null
                },
                "exactMatch": [
                    "finto:http://www.yso.fi/onto/koko/p2010",
                    "leiki:focus100k_na_19"
                ],
                "relevance": 0.9416835308074951
            },
            {
                "id": "18-34837",
                "title": {
                    "fi": "Kotimaan uutiset",
                    "sv": "Inrikesnyheter",
                    "en": "Home News"
                },
                "exactMatch": [
                    "freebase:/m/0zphp7z",
                    "leiki:focus100k_na_520252",
                    "escenic:kotimaa",
                    "escenic:uutiset-kotimaa",
                    "escenic:mediasali-jalkapallo-kotimaa"
                ],
                "relevance": 0.7190120220184326
            }
            ...
        }

422 Unprocessable Entity A required parameter is missing

The API returns 422 in many different scenarios when the request is invalid:

  • The lang query parameter is required, and it should be fi or sv.

  • A request body is required

  • The app id in the request should be configured in the API. If you see this error, make sure you have registered to the meta concept data team as a user of the API.

500 Internal Error Unexpected error or a service is unavailable

If you receive this error, please contact the content meta data team at sisaltometadatatiimi@yle.fi.

cURL example

curl --request POST \
     --header 'Content-Type:text/plain' \
     --data 'Hallitusneuvottelut jatkuvat Smolnassa perjantaina talousasioilla. \
             Tavoitteena on rakentaa noin kymmenen miljardin euron sopeutus- ja säästöpaketti.' \
     "https://text-analysis-v2.api.yle.fi/v1/text_analysis.json?lang=fi&app_key=YOUR_APP_KEY&app_id=YOUR_APP_ID"

User Data Download API

General information

User Data Download API is used to fetch and aggregate data about Yle Tunnus users from several systems. User data download jobs can be created on a per-user basis, which run in the background once created. Once a job is finished, resulting in either success or failure, the user is then notified via email about the completion (or failure) of the job, in which case, if successful, the user can navigate to their personal information page and download a JSON dump containing information stored about them.

The API provides endpoints for creating download jobs, retrieving their statuses and downloading the gathered data of successful jobs.

The API requires user authentication with Yle login cookie and Auth API access token.

The status of a job can be pending, success or failure. There can be only one pending job per user at any time, but new jobs can be created freely, if there are no previous jobs, or the previous jobs have been completed.

A job succeeds if data can be gathered from all systems within the time window during which the Auth API access token is valid. If data from all the sources cannot be acquired during this time window, then the job is considered a failure.

Authenticating user for job and data routes

Creating user data download jobs, and downloading job data requires a valid Yle login cookie and Auth API access token in Authorization HTTP header. The access token must contain user-data-download scope.

Reading the status of download jobs only requires a valid Yle login cookie.

When access token is included, the header must have Bearer as schema, for example Bearer accessToken1234.

An access token can be obtained from Auth API.

If either Yle login cookie or access token is invalid, then calls to job and data routes return 401 Unauthorized.

Example HTTP headers

Cookie: ylelogin=...
Authorization: Bearer ...

POST /v1/job?notification_language={notification_language} Creating data download job for user

Creates a new data download job for a user, unless they already have a pending job. If the job is successfully created, then the API will start gathering data on the user, sending a notification to the user when the job has been completed.

Requires valid Yle login cookie and access token, see user authentication instructions for details.

Parameters

 Parameter Required? Description
 notification_language  no Determines the language that will be used in the notification email sent to user after data is available for download. Possible values: fi or sv, default is fi

Response

201 Created when job created successfully, returning job ID, status and creation time

{
  "id": "4b4138d0-ea20-42d0-b2f8-7e20b5d1969e",
  "status": "pending",
  "createdAt": "2018-06-01T12:00:00+0300"
}

409 Conflict when pending job already exists for user, returning job ID and status

Example request

curl --request POST \
     --header 'Cookie: ylelogin=USER_YLE_LOGIN_COOKIE' \
     --header 'Authorization: Bearer USER_AUTH_API_TOKEN' \
     "https://user-data-download.api.yle.fi/v1/job?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

GET /v1/job Get data download jobs of user

Returns a list of data download jobs for user, sorted by creation time in descending order.

Requires valid Yle login cookie, see user authentication instructions for details.

Response

200 OK with a list of jobs, each containing job ID, status, creation time and possible finish time

[
  {
    "id": "4b4138d0-ea20-42d0-b2f8-7e20b5d1969e",
    "status": "pending",
    "createdAt": "2018-06-03T12:00:00Z"
  },
  {
    "id": "16b2038a-0063-4715-9462-bc61896d9bb9",
    "status": "success",
    "createdAt": "2018-06-02T12:00:00+0300",
    "finishedAt": "2018-06-02T12:05:00+0300",
  },
  {
    "id": "7180c9d2-2a08-493c-8b7c-9797b405c56e",
    "status": "failure",
    "createdAt": "2018-06-01T12:00:00+0300",
    "finishedAt": "2018-06-01T12:05:00+0300",
  }
]

Example request

curl --request GET \
     --header 'Cookie: ylelogin=USER_YLE_LOGIN_COOKIE' \
     "https://user-data-download.api.yle.fi/v1/job?app_id=YOUR_APP_ID&app_key=YOUR_APP_KEY"

Yle Tunnus web SDK

Getting started

What is Yle Tunnus?

Yle Tunnus is a project that aims to provide Yle wide single sign-on. It currently consists of three core components:

  • Login API, which handles user registrations

  • Profiles API, which can be used as a database for user profile data

  • Tunnus JavaScript SDK, which makes it easy to integrate Yle Tunnus sign in to your applications

Checklist for new users

  • Are you making a website? If so, check out the JavaScript SDK documentation

  • If you want, you can create your own landing page. This is the page the user will be redirected to after successfully completing the registration.

  • Think about how you’re going to use Profiles API. List any databases you’re going to need and give the list to API team.

Using the JavaScript SDK

Implement the relevant parts from below to your own page:

<html>
<head>
  <link rel="dns-prefetch" href="//login.api.yle.fi" />
  <!-- YOUR TAGS HERE -->
</head>
<body>
    <!-- YOUR CONTENT HERE -->

    <div id="tunnus">
      <style type="text/css">a#login, a#logout { display:none; }</style>
      <a id="login" href="#">Kirjaudu sisään</a>
      <a id="logout" href="#">Kirjaudu ulos</a>
    </div>

    <script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.min.js"></script>
    <script type="text/javascript">
      requirejs.config({
        baseUrl: '/js',
        paths: {
          'yleTunnus': '//cdn.tunnus.yle.fi/sdk/4.1.13/yle-tunnus-sdk',
          'jquery': '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min'
        }
      })
      require(['main'])
    </script>
</body>
</html>

Now you can use Yle Tunnus in your /js/main.js:

define('main', ['yleTunnus'], function(yleTunnus) {
  var tunnus = yleTunnus({
      trackingAppName: 'YOUR_APP_NAME',
      language: 'fi',
      profilesApiAppId: 'YOUR_PROFILES_API_APP_ID',
      profilesApiAppKey: 'YOUR_PROFILES_API_APP_KEY',
      loginApiAppId: 'YOUR_LOGIN_API_APP_ID',
      loginApiAppKey: 'YOUR_LOGIN_API_APP_KEY'
    },
    userLoggedIn,
    userNotLoggedIn
  )

  // if Yle global header is in use, tunnus can adjust to it.
  var header = yleHeader(headerConfig)

  tunnus.initHeader($('.yle__global-header')) // or
  tunnus.initHeader(header)

  $('a#login').click(function() {
    tunnus.login(function(userId, nick) {
      // User is now logged in
    }, function() {
      // User exited the dialog without logging in
    })
  })

  $('a#login-from-example1').click(function() {
    tunnus.login(
      function(userId, nick, latestTermsOfServiceAccepted) {
        // User is now logged in from "example1" context
      },
      function() {
        // User exited the dialog without logging in
      },
      tunnus.contexts.example1,
      [
        {id: 'nick', successCallback: function(nick) { console.log('nickname set ' + nick) }},
        {id: 'verify', successCallback: function() { console.log('user verified') }}
      ]
    )
  })

  $('a#logout').click(function() {
   tunnus.logout(function() {
     // Logout succeeded
     $('a#logout').hide()
     $('a#login').show()
   }, function() {
     // Logout failed
   })
  })

  function userLoggedIn(userId, nick) {
    // User is now logged in
    $('a#logout').show()
  }

  function userNotLoggedIn() {
    // User is NOT logged in
    $('a#login').show()
  }
})

JavaScript SDK reference

Note! Starting from version 4.0, Yle Tunnus SDK integrates with Yle Analytics SDK for collecting analysis information. Contact the API team if you are unsure on how this affects your application.

Dependencies

  • jQuery 1.11 or later
  • The YleTunnus SDK, https://cdn.tunnus.yle.fi/sdk/4.1.13/yle-tunnus-sdk.js
  • Cross domain requests are done with CORS, check supported browsers http://caniuse.com/#feat=cors and read more from http://enable-cors.org/client.html

yleTunnus(options, alreadyLoggedIn, notLoggedIn)

Initializes the SDK with given options and alreadyLoggedIn, notLoggedIn callbacks. Returns initialized SDK object (tunnus from now)

Options

Name Required? Description
trackingAppName yes Name of your application. Used in analytics.
loginApiAppId yes Your Login API application ID
loginApiAppKey yes Your Login API application key
profilesApiAppId yes Your Profiles API application ID
profilesApiAppKey yes Your Profiles API application key
language no fi or sv. Defaults to fi
loginBanner no Object with keys corresponding to selected language and values that are used as the HTML content for the banner, eg. loginBanner: { "fi": "<h1>Terve</h1>", "sv": "<h1>Hejsan</h1>" }
returnToUrl no URL where the user will be redirected to after successfully registering a new Yle Tunnus account. URL must be located in yle.fi domain. If not provided, default value https://tunnus.yle.fi/tervetuloa or https://tunnus.yle.fi/valkommen (depending on language) will be used.

Callbacks

Callback Arguments Description
alreadyLoggedIn userId, nick, latestTermsOfServiceAccepted called if the SDK determines the user is already logged in.
notLoggedIn   called if the SDK determines the user is not logged in.

Public methods

.login(successCallback, cancelCallback, context, postLoginConfig)

Presents the user with the login dialog and calls successCallback(userId, nick, latestTermsOfServiceAccepted) after successful login. If the user closes the dialog without logging in, cancelCallback will be called.

Does not present the login dialog again if the user is already logged in. Thus you can use tunnus.login whenever you need to know the user’s ID or nick.

Optional context parameter indicates where the login screen is launched from. It is used in statistics collection to gain insight on user behaviour (where the users logged in from), and has no other functionality. Only preset contexts can be used, and they can be found from yleTunnus.contexts. The parameter exists until the launched dialog is closed.

Post-login actions

The optional postLoginConfig (array of objects) defines which actions need completion after the login process. The configured actions are launched in the order specified in the array.

  • The general success callback is called when the login is completed.
  • If any one fails, cancelCallback is called. User still stays logged in.
  • Each action has their own success callback. The last configured callback to be called finishes the whole operation.

Currently available actions are:

  1. ‘nick’, asks the user to set a nickname, if none is currently set or the current one is autogenerated (i.e. Anonyymi123456)
    • action successCallback receives the newly set value for the nickname as it’s only parameter
  2. ‘verify’, launches captcha (this functionality was previously used via the method “loginVerified”)

.logout(successCallback, failureCallback)

Logs the currently logged in user out of Yle Tunnus. On successful logout, successCallback is called. If there’s a network failure, failureCallback is called.

.loginVerified(verificationSuccessCallback, loginSuccessCallback, cancelCallback, context)

deprecated: use the post-login configuration object instead.

Presents the user with a login dialog (unless user is already logged in), and then a separate verification dialog, for ensuring that the user is a real user and not a bot. (User who has already completed verification earlier will not be requested to do it again.)

Callback function loginSuccessCallback(userId, nick) is called immediately after successful login. Then, the callback function verificationSuccessCallback is called either when the logged in user successfully completes verification, or immediately after login if the user has already completed verification earlier.

If the user closes either the login dialog or the verification dialog without completing its action, cancelCallback is called.

You can use tunnus.loginVerified whenever you need to know the user’s ID or nick, and you need to be sure that the user has successfully verified himself or herself at some point.

The optional context parameter works similarly as in login function.

.showSignUp(successCallback, cancelCallback, context)

Displays the registration dialog for creating a new user account. It is also possible for the user to navigate back to login dialog, hence the option to provide callback functions for successful or cancelled login as in method login above. The optional context parameter also functions in the same way here.

.completeRegistration(successCallback, cancelCallback)

Displays the dialog for completing the registration of a new user account. This is the dialog that the user is presented with after confirming the registration (by clicking the link in the email that was sent to user after submitting initial signup information).

After user has completed registration, successCallback is called. If user closes the dialog without completing the registration, cancelCallback is called.

.initHeader(header)

If Yle global header is in use, tunnus overlay can adjust it’s positioning based on header’s height. Pass the header’s root/container dom node, or the initialized header object to tunnus’s initHeader function. Tunnus will also react to click events from the header. See header documentation at http://static.cdn.yle.fi/10m/hf/v2/header/manual.html

SMS verification

If your application requires strong authentication you can require users to authenticate via SMS.

In case that the user has already completed strong authentication before they will not be asked to do it again.

To use this service include the following to your page:

  • https://cdn.tunnus.yle.fi/sms-verification/vX.Y/yle-tunnus-sms-verification-ui.min.js
  • https://cdn.tunnus.yle.fi/sms-verification/vX.Y/yle-tunnus-verifications.css

where vX.Y is the version number eg. v1.7 and then call yleTunnusSmsVerifications.open as shown below. This function takes your Login API access id and key and a success callback function as parameters.

User must be logged in with Yle Tunnus before calling yleTunnusSmsVerifications.open.

Interface is translated into desired language. Currently two languages are supported, fi and sv. Use either one as a YOUR_LANGUAGE_ID parameter value for the yleTunnusSmsVerifications.open function. If the parameter is omitted, Finnish will be selected as a default language. Translated UI is available from version 1.5 and above.

Example usage

<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta charset='utf-8'>
    <link rel="stylesheet" href="https://cdn.tunnus.yle.fi/sms-verification/vX.Y/yle-tunnus-verifications.css">
  </head>
  <body>
    <script src="https://cdn.tunnus.yle.fi/sms-verification/vX.Y/yle-tunnus-sms-verification-ui.min.js"></script>
    <script>
      function onSmsVerifiedUser() {
        console.log("User is sms verified!");
        // YOUR CODE HERE
      }
    </script>
    <button onclick="yleTunnusSmsVerifications.open('YOUR_LOGIN_API_APP_ID', 'YOUR_LOGIN_API_APP_KEY', onSmsVerifiedUser, 'YOUR_LANGUAGE_ID')">SMS Verify</button>
  </body>
</html>

Contacts app

The Contacts application allows sending emails to Tunnus users.

The application is hosted at https://tunnus-contacts.apps.yle.fi/contacts-app/v1.0/index.html and requires that the surrogate_id parameter is supplied as a URL parameter; for example, https://tunnus-contacts.apps.yle.fi/contacts-app/v1.0/index.html?surrogate_id=123456789. The surrogate ID is the recipient’s Tunnus ID.

In order to send emails, the user of the Contacts app needs to first sign in using a Yle Google account that has a validated email address ending with @yle.fi.

Tunnus SDK with iframe

Tunnus SDK (version 5.0)

Tunnus SDK is implemented using Tunnus Shared UI in iframe. Tunnus Shared UI was first implemented to be used in native mobile applications but can be used in web applications too. With this implementation the version of Tunnus SDK doesn’t need to be updated every time there are changes in the registration/login flow since Tunnus Shared UI can be updated separately.

The new Tunnus SDK API uses promises and observables, and is designed to be easy to use with async-await. It also has support for legacy callbacks like the previous version of Tunnus SDK had.

It is recommended to use Tunnus SDK from the same environment where your application runs, e.g. test or production. If this is difficult to implement for your application, it is also possible to only use production version with { environment: 'test' } argument but this is generally discouraged.

Dependencies

yleTunnus(options)

Initializes the SDK with given options. Returns initialized tunnus Promise.

Example usage with async-await:

async function initializeTunnus() {
    const tunnus = await window.yleTunnus(options)

    tunnus.state.subscribe(state => {
        if (state.loggedIn) {
            alert('logged in!')
        }
    })

    await tunnus.logIn()
}

Or with ES5 and Promises:

function initializeTunnus() {
    return window.yleTunnus(options).then(function(tunnus) {
        tunnus.state.subscribe(function(state) {
            if (state.loggedIn) {
                alert('logged in!')
            }
        })

        return tunnus.logIn()
    })
}

Or with legacy callbacks:

var createTunnus = window.yleTunnus
function initializeTunnus() {
    var tunnusOptions = options
    tunnusOptions.legacyCallbacks = {
        alreadyLoggedIn: userLoggedIn,
        notLoggedIn: userNotLoggedIn,
        loginSuccess: userLoggedIn,
        logoutSuccess: userNotLoggedIn
    }
    createTunnus(tunnusOptions)
    .then(function(tunnus) {
        tunnus.logIn()
    })
}

Options

Name Required? Description
trackingAppName yes Name of your application. Used in analytics.
initiatingApp yes Your authorization app_id. This is collected for statistical purposes. It is renamed as yle_client in analytics events.
environment yes Options: test or production
elementId no Id of the element you want to embed the iframe
language no fi or sv. Defaults to fi
theme no light or dark. Color theme of the site. Defaults to light.
returnToUrl no URL where the user will be redirected to after successfully registering a new Yle Tunnus account. URL must be located in yle.fi domain. If not provided, default value https://tunnus.yle.fi/tervetuloa or https://tunnus.yle.fi/valkommen (depending on language) will be used.
legacyCallbacks no In case you want to use Tunnus with legacyCallbacks these are needed. These callback will be called when the state changes.

Public API

.state

An RxJS observable for the current Tunnus SDK state. You can subscribe to the state changes, and the callback will be called with the current state, and in the future when it updates:

tunnus.state.subscribe(state => {
    if (state.loggedIn) {
        // ...
    }
})

The state type is:

interface TunnusState {
  loggedIn: boolean
  user: UserInfo | null
}

interface UserInfo {
  userId: string
  username: string
  initials: string
  nick: string
  latestTermsOfServiceAccepted: boolean
}

.actions

An RxJS observable for user actions events You can subscribe to the events, and the provided callback will be called with an object that tells the status of every action (performed or not, failed or not).

tunnus.actions.subscribe(actions => {
    if (actions.logOut) {
        alert('User logged out!')
    }
})

The type of actions is:

interface UserActions {
  logIn: UserAction
  logOut: UserAction
  registration: UserAction
}

interface UserAction {
  ran: boolean
  ranAndSucceeded: boolean
  ranAndCancelled: boolean
  ranAndFailed: boolean
  error?: Error
}

.beginIdentification(returnToUrl)

Opens a dialog where user can begin identification (strong authentication) process. After identification, Login API can tell whether the user’s home residence is located in Finland or not. Applications can then use this information to limit some of the functionality to only certain users, for example.

If user chooses to begin identification, he/she is redirected to identity provider’s service to perform the actual identification. After the identification process has been completed (either successfully, or failing for some reason), user is redirected to the given returnToUrl. That URL must have either https:// or areena:// protocol, and it must be under yle.fi domain.

If returnToUrl is not defined, the returnToUrl value from Tunnus.options is used instead.

Return value of this function is a Promise that is resolved when user closes the dialog. (Remember, this does not yet indicate that the identification process has completed - only that it has begun.) The returned promise contains an actions object with a report of the actions that the user performed while the dialog was open (see .actions for more details).

.loggedInUser()

Returns a promise containing the logged in users information, or null if the user is not logged in.

Type of user information:

interface UserInfo {
  userId: string
  username: string
  initials: string
  nick: string
  latestTermsOfServiceAccepted: boolean
}

.logIn()

Opens a log in dialog, and returns a promise that is resolved when the user closes the dialog. The promise contains an actions object, containing a report of the actions that the user performed while the dialog was open, since the user can navigate to other screens from the login screen (see .actions for the type).

If you need to know the users nick or other information, subscribe to .state, or call .loggedInUser().

.logOut()

Logs the user out, returns a promise that is resolved when it’s done.

.register()

Opens a registration dialog, and returns a promise that is resolved when the user closes the dialog. The promise contains an actions object, containing a report of the actions that the user performed while the dialog was open (see .actions for the type).

.resetPassword()

Opens a reset password dialog, and returns a promise that is resolved when the user closes the dialog. The promise contains an actions object, containing a report of the actions that the user performed while the dialog was open (see .actions for the type).

.getUserEmail()

Returns users email address when user is logged in.

Yle Tunnus SDK Migration Guide (from 4.0 -> 5.0)

Yle Tunnus SDK Migration Guide

  1. Replace Yle Tunnus SDK scripts with new ones
    • Production: <script type="text/javascript" src="https://tunnus-sdk.yle.fi/v1/index.js"></script>
    • Test: <script type="text/javascript" src="https://tunnus-sdk.test.yle.fi/v1/index.js"></script>
  2. Remove jQuery if it was required only for the old tunnus SDK
  3. If IE11 support is needed add promise polyfill for example by adding this script before the tunnus SDK script <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.auto.min.js"></script>
  4. Replace old Yle Tunnus initialization:
    $(document).ready(function() {
      tunnus = yleTunnus({
       trackingAppName: 'example',
       language: 'fi',
       profilesApiAppId: 'example',
       profilesApiAppKey: 'example',
       loginApiAppId: 'example',
       loginApiAppKey: 'example',
       returnToUrl: window.location.href
     },
     userLoggedIn,
     userNotLoggedIn
      )
    })
    

    with new Yle Tunnus initialization:

    const tunnus = await window.yleTunnus({
      trackingAppName: 'example',
      initiatingApp: 'example',
      environment: 'test',
    })
    

    The full details of the initialization are available here

  5. Replace tunnus.login, tunnus.logout and tunnus.showSignUp calls with tunnus.logIn, tunnus.logOut and tunnus.register calls respectively. Remove all arguments from the function calls. Handle returned promises if needed. For example:
    function addClickHandlers(tunnus) {
      loginButton.addEventListener('click', tunnus.logIn)
      logoutButton.addEventListener('click', tunnus.logOut)
      registerButton.addEventListener('click', tunnus.register)
    }
    
  6. Subscribe to SDK state and handle the login and logout state changes as well as any other state changes you might need to handle. For example:
    function subscribeToTunnusState(tunnus) {
      tunnus.state.subscribe((state) => {
     if(state.loggedIn) {
       renderLoggedIn(state.user)
     } else {
       renderLoggedOut()
     }
      })
    }
    

    7.If Yle header is used replace old header with new header and pass tunnus to the header by adding header.initializeTunnus(tunnus)) where tunnus is an initialized instance of yleTunnus. See example.

See full example for reference.

Yle Tunnus in Native apps

Accepting Terms of Service in native apps

Accepting Terms of Service in native apps

Accepting Terms of Service (later TOS) in native apps will be implemented with webview and common content served from tunnus-shared-ui.

How to integrate to tunnus TOS view in native apps

  1. Login API will provide boolean field latestTermsOfServiceAccepted. If the field is false you should prompt the user to launch the acceptance process. This field will be available in endpoint GET and POST /v1/user/login (See documentation of endpoints here).

  2. Open a fullscreen WebView to the url https://tunnus-shared-ui.yle.fi/terms-of-service (https://tunnus-shared-ui.test.yle.fi/terms-of-service in test). Open the webview with the ylelogin cookie or with window.yleNative.yleTunnusSession set. Please note that tracking_app_name is required query parameter.

  3. Provide the webview with a global javascript object function called yleNative with a method sendCommand. You should add close-button to the webview in case user decides not to accept TOS.

  4. After the user has pressed the accept-button in the view, the webview javascript will call window.yleNative.sendCommand("close") signalling that you can close the webview.

  5. Terms of service and Privacy Statement have some links to external yle pages. Because of this it’s good to implement the webview so that it will open links not hosted by tunnus-shread-ui.yle.fi to browser instead of the webview.

Information you need to provide to webview

Name Required Description
ylelogin yes* User session token. *Not required if you set window.yleNative.yleTunnusSession.

Query parameters

Name Required Options Description
tracking_app_name yes (service name) App key that is used in analytics, min length 5 characters
language no fi, sv Language of the user, default fi
theme no dark, light Choose if you want the theme to be dark or light, default light
application no (app name, TBD) App name to determine what app specific text to show (*)

(*) The Application specific texts will have their own repository so that they can be easily updated and they will be served from S3. Tunnus-shared-ui will fetch the text based on the application parameter given.

Callback

Authentication

Name Required Description
window.yleNative.yleTunnusSession no User session token. If you set this, you do not need to provide ylelogin cookie.

Callbacks

Name Required Call args Description
window.yleNative.sendCommand yes “close” Function to be called when accepted

Login and Registration in native apps

Login and Registration in native apps

Login and Registration are available for native apps through tunnus-shared-ui. If you implement the Login-feature users can also register through it. In case you you want to link directly to Registration that is also possible.

How to integrate to tunnus Login in native apps

  1. Open a fullscreen WebView to the url https://tunnus-shared-ui.yle.fi/login (https://tunnus-shared-ui.test.yle.fi/login in test). Please note that tracking_app_name is required query parameter.

  2. Provide the webview with a global javascript object function called yleNative with a method sendCommand. You should also add close-button to the webview in case user decides not to log in.

  3. After successfull login tunnus-shared-ui will call window.yleNative.sendCommand-function with params close-login signalling that the webview can be closed.

The ylelogin cookie is available in the webview if you want to store it.

How to integrate to tunnus Registration in native apps

  1. Open a fullscreen WebView to the url https://tunnus-shared-ui.yle.fi/register (https://tunnus-shared-ui.test.yle.fi/register in test). Please note that tracking_app_name is required query parameter.

  2. Provide the webview with a global javascript object function called yleNative with a method sendCommand. You should also add close-button to the webview in case user decides not to log in.

  3. After succesfull registration and login tunnus-shared-ui will call window.yleNative.sendCommand-function with param close-login signalling that the webview can be closed.

After succesfull login, the ylelogin cookie is available in the webview if you want to store it.

Please note, that after registration user has to confirm their new account via email. After confirming created account user can login in to app.

Getting the session token without using cookies

If you include with_token=true in the query parameters for tunnus-shared-ui, the close-login callback parameters include a temporary token. This can be exchanged to a session token with by calling https://login-api.yle.fi/v3/user/session/{token}.

You can then use the session token as the value of ylelogin cookie or Yle-Tunnus-Session header.

Logout

Logout should be implemented natively if needed. See Login API docs to see how to use logout.

Information you need to provide to webview

Query parameters

Name Required Options Description
tracking_app_name yes app name App name that is used in analytics, min length is 5 characters
initiating_app yes app id Authorization app_id of application which initiated the registration. This is collected for statistical purposes. It is renamed as yle_client in analytics events.
language no fi, sv Language of the user, default fi
theme no dark, light Choose if you want the theme to be dark or light, default light
application no app name App name to determine app specific text and to use branch.io return_to_url in registration (*)
with_token no true Choose if you want to include a temporary token in the close-login command.

(*) The Application specific texts will have their own repository so that they can be easily updated and they will be served from S3. Tunnus-shared-ui will fetch the text based on the application parameter given.

Callback

Name Required Call args Description
window.yleNative.sendCommand yes "close-login", { token: "TEMPORARY TOKEN"} Function to be called when accepted. token is only included if with_token query parameter was used.

Identification in native apps

Identification in native apps

User identification is available for native apps through tunnus-shared-ui. After user has completed the identification process, Login API can tell whether the user’s home residence is located in Finland or not. Applications can then use this information to limit some of the functionality to only certain users, for example.

Identification process starts from webview, moves to browser for actual identification process and returns to webview for identification status. The steps are described better below.

1. Begin identification process

Identification process starts by opening a fullscreen WebView to the URL https://tunnus-shared-ui.yle.fi/begin-identification. From there, user can choose to begin identification (or cancel). User does not need to be logged in prior to opening the dialog - the dialog will direct user to login (or to register) if needed.

See table below for required query parameters.

Query parameters

URL https://tunnus-shared-ui.yle.fi/begin-identification supports the following query parameters.

Name Required Options Description
tracking_app_name yes app name App name that is used in analytics, min length is 5 characters
initiating_app yes app id Authorization app_id of application which initiated the registration. This is collected for statistical purposes. It is renamed as yle_client in analytics events.
return_to_url yes URL URL where the user should be redirected after completing the identification process. The URL must have either https:// or areena:// protocol, and it must be under yle.fi domain.
language no fi, sv Language of the user, default fi
theme no dark, light Choose if you want the theme to be dark or light, default light

Contract between WebView and tunnus-shared-ui

The native application must provide the webview with a global JavaScript object yleNative with a sendCommand function. When the dialog is closed, this function will be called with either "close" or "close-login" argument (depending on whether user was logged in or not). When user has started identification process sendCommand is called with "close-and-open-url", url. The url given as second argument should be opened in browser for user to start identification process.

2. After identification has begun

If user chooses to begin identification, a new browser window is opened to the identity provider’s service. The user will then perform the actual identification (strong authentication). After the identification process has been completed (either successfully, or failing for some reason), user is redirected to the return_to_url provided in query parameters. That URL is appended with an identification_id, which the native application should pass to tunnus-shared-ui when opening the “show identification end result” dialog https://tunnus-shared-ui.yle.fi/identification-status.

Query parameters

URL https://tunnus-shared-ui.yle.fi/identification-status supports the following query parameters.

Name Required Options Description
tracking_app_name yes app name App name that is used in analytics, min length is 5 characters
initiating_app yes app id Authorization app_id of application which initiated the registration. This is collected for statistical purposes.
return_to_url yes URL URL where the user should be redirected after completing the identification process. The URL must have either https:// or areena:// protocol, and it must be under yle.fi domain.
identification_id yes identification id This id is needed to fetch the status of the identification event.
language no fi, sv Language of the user, default fi
theme no dark, light Choose if you want the theme to be dark or light, default light

Showing MyData page

Showing MyData page

MyData page offers users possibility to edit information they have given during registeration, download their saved data and confirm their identification (see also Identification in native apps).

How to integrate to tunnus MyData view in native apps

  1. After user has logged in create a link or menuitem that opens a fullscreen WebView to the url:
    https://tunnus-shared-ui.yle.fi/my-data?initiating_app=<YOUR_APP_ID>&tracking_app_name=<YOUR_APP_NAME>&return_to_url=<YOUR_RETURN_TO_URL>
    

    Open the webview with ylelogin cookie or with window.yleNative.yleTunnusSession set. Please note that tracking_app_name, initiating_app, return_to_url are required query parameters.

  2. Provide the webview with a global javascript object function called yleNative with a method sendCommand. You should add close-button to the webview for user to close the view.

Information you need to provide to webview

Name Required Description
ylelogin yes* User session token. *Not required if you set window.yleNative.yleTunnusSession.

Query parameters

Name Required Options Description
tracking_app_name yes app name App name that is used in analytics, min length is 5 characters
initiating_app yes app id Authorization app_id of application which initiated the registration. This is collected for statistical purposes. It is renamed as yle_client in analytics events.
return_to_url yes URL URL where the user should be redirected after completing the identification process. The URL must have either https:// or areena://** protocol, and it must be under yle.fi** domain.
identification no true Feature switch for showing residence identification status and flow, default false
language no fi, sv Language of the user, default fi
theme no dark, light Choose if you want the theme to be dark or light, default light

JavaScript data

Authentication

Name Required Description
window.yleNative.yleTunnusSession no User session token. If you set this, you do not need to provide ylelogin cookie.

Callbacks

Name Required Call args Description
window.yleNative.sendCommand yes “close” OR “close-and-open-url” Function to be called on close

Yle-fi-search API

General information

Yle-fi-search API allows users to search artciles or areena content with full text search parameters.

API uses areena search api in the background.

Documentation is work in progress.

GET /v1/search/ Search content

Retrieves content from the search index and optionally from areena search index.

Supported search paramet

Request parameters

Name Required Description
query yes Free text search terms to be used in the query. Example: Nokia
language No Language used in the article. Allowed values: fi, sv, se, ru, krl, all. Those values map to: Finnish, Swedish, Saame, Russian, Karelian, All languages.
type No Content to search: article, areena
service No Limit search to a specific Yle-subservice. Allowed values: uutiset, urheilu, yle-oppiminen, elava-arkisto, ylex
time No Where to limit search scope in time: today, week, month, custom
timeFrom No Used with time=custom parameter. Articles from given date. Example: 2020-09-01
timeto No Used with time=custom parameter. Articles to given date. Example: 2020-09-31
limit No How many results to return. Defaults to 10.
offset No At what point in the result set start returning results. Defaults to 0.

Response

200 OK on success

Response is a JSON object with a data array that contains one JSON object per search result. And ‘meta’ lists how many results were found from the index and what were the used results set limiting parameters used.

Example request

curl "https://yle-fi-search.api.yle.fi/v1/search?app_id=APPID&app_key=APPKEY&language=fi&limit=10&offset=0&query=nokia&type=article"

{"meta": {"count":11085,"offset":0,"limit":10},
 "data":
  [
  {"headline":"Moni asia on vaakalaudalla jos Suomeen ei pääse ulkomaalaisia: Matkailu, rakentaminen, ydinvoima – Ministeri vaatii rajoitusten höllentämistä","datePublished":"2020-09-01T12:59:47Z","type":"article","author":["Juha-Matti Mäntylä"],"id":"3-11521534","url":{"short":"https://yle.fi/uutiset/3-11521534","full":"https://yle.fi/uutiset/3-11521534"},"lead":"Elinkeinoministeri Mika Lintilän mielestä harva yritys saa uusia asiakkaita digitaalisten kanavien kautta.","image":{"id":"13-3-11497346"},"services":["yle-uutiset"]},
  {"headline":"Rekisterikilvetön auto jahtasi lapsia koulun pihalla Nokialla – rehtori: \"Miten joku voi tehdä tällaista?\"","datePublished":"2020-08-20T14:02:54Z","type":"article","author":["Heli Mansikka"],"id":"3-11504368","url":{"short":"https://yle.fi/uutiset/3-11504368","full":"https://yle.fi/uutiset/3-11504368"},"lead":"Poliisi tiedotti asiasta illalla. Auto oli varastettu ja varkaat olivat muun muassa murtautuneet apteekkiin.","image":{"id":"39-7104465f3f6fc9537c0"},"services":["yle-uutiset"]}
    ...
  ]
}

Feeds Application

General information

The purpose of Feeds application is to provide RSS feeds to end users. Currently only Areena streams are available, but we hope to add more feeds in the future. Feeds application works with IDs available from Programs API endpoints.

GET /areena/v1/series/{id}.rss Get RSS from a single series

Returns a RSS feed for a series with provided id. For example: areena/v1/series/1-1591985.rss?page=2&downloadable=true&lang=sv

Parameters

Name Description
id Series ID
page Page number. Feeds are paginated 25 items per page
downloadable Show only downloadable programs
lang Feed language, fi(default) or sv

###Response

200 OK on success

Response contains a XML/RSS document with 25 items of the searched series.

404 Not Found If the id given is not a valid series id

‘204 No Content’ If Feeds application can’t connect to APIs

GET /areena/v1/live.rss Get RSS from current live multicasts

Returns a RSS feed for a series with provided id. For example: areena/v1/live.rss&lang=sv

Parameters

Name Description
lang Feed language, fi(default) or sv

###Response

200 OK on success

Response contains a XML/RSS document with current live programs

‘204 No Content’ If Feeds application can’t connect to APIs

GET /areena/v1/category/{id}.rss Get RSS from a single category

Returns a RSS feed for a series with provided id. For example: areena/v1/series/5-240.rss.rss?page=2&downloadable=true&lang=sv

Parameters

Name Description
id Category ID
page Page number. Feeds are paginated 25 items per page
downloadable Show only downloadable programs
lang Feed language, fi or sv

###Response

200 OK on success

Response contains a XML/RSS document with 25 items of the searched series.

404 Not Found If the id given is not a valid category id

‘204 No Content’ If Feeds application can’t connect to APIs

GET /areena/v1/list/{id}.rss Get RSS from a list

Returns a RSS feed for a list with provided id. For example: areena/v1/list/8-1802228?page=2&lang=sv

Parameters

Name Description
id List ID
page Page number. Feeds are paginated 25 items per page
lang Feed language, fi(default) or sv

###Response

200 OK on success

Response contains a XML/RSS document with 25 items of the searched list.

404 Not Found If the id given is not a valid list id

‘204 No Content’ If Feeds application can’t connect to APIs

GET /areena/v1/{tv|radio}/all.rss Get RSS of all items on a given media type

Returns all programs of given media type (tv, radio). Eg. /areena/v1/tv/all.rss?order=top&page=2&lang=sv&downloadable=true

Parameters

Name Description    
order Sorting order. Newest(default) top(24h.) closing(in 24h.)
page Page number. Feeds are paginated 25 items per page    
lang Feed language, fi(default) or sv    
downloadable Show only downloadable programs (default false)    

###Response

200 OK on success

Response contains a XML/RSS document with 25 items.

‘204 No Content’ If Feeds application can’t connect to APIs

Meta API Queues

Meta API Message Headers

Message headers

Name Valid values
content-type program, series, article
event-type create, update, delete

Program messages

Payload for “program” “create” or “program” “update”

Name Required Valid values
data.id true  
data.title true In any language, preferably in finnish.
 data.type true ‘Program’, ‘Clip’, ‘TVProgram’,’TVContent’,
    ‘TVClip’, ‘RadioContent’,’RadioProgram’, ‘RadioClip’
data.languages true at least one language
data.alternativeIds true array of values. Empty array if no alternative ids
 data.publicationEvents true  
data.publicationEvents[].startTime true    
 data.publicationEvents[].endTime false  
data.publicationEvents[].type true Only “onDemandPublication” type is currently processed
data.partOfSeries false  example: {“id”:”1-1234567”}
concepts false example: [{“yleId”: “18-123456”}]

Example

{"concepts": [{"yleId": "18-123456"} {"yleId": "18-65432"}],
 "data":
  {"id": "1-2345030",
    "title": "Uutisikkuna"
    "type": "TVProgram",
    "languages": ["fi", "sv"],
    "alternativeIds": ["16-0-341048424813", "16-0-341048424811"],
    "publicationEvents": [
     {"startTime": "2014-09-06T01:03:00+03:00",
      "endTime": "2014-09-06T04:00:00+03:00",
      "type": "OnDemandPublication"}],
    "partOfSeries":
      {"id": "1-2347576",
       ... see series message spec below}}}

Payload for “program” “delete”

Name Required Valid values
data.id true  

Series messages

Payload for “series” “create” or “series” “update”

Name Required Valid values
data.id true  
data.alternativeIds true Array of ids. Empty if needed.
data.title true  
 data.type true ‘RadioSeries’, ‘TVSeries’
data.languages true at least on language
{"data":
  {"id": "1-2345030",
   "title": "Uutisikkuna"
   "type": "TVSeries",
   "languages": ["fi", "sv"],
   "alternativeIds": ["16-0-341048424813", "16-0-341048424811"]}}

Payload for “series” “delete”

Name Required Valid values
data.id true  

Article messages

Payload for “article” “create” or “article” “update”

Name Required Valid values
data.id true example: “3-2”
data.title true In any language, preferably in finnish.
 data.datePublished true example: “2014-08-28T12:00:00+0300”
data.language true example: “fi”
data.concepts false example: [{“id”: “18-123456”}]
data.meta.relations.relation true Array of related contents. Empty if none.
    example: [{“id”: “1-2345030”, “type”: “TVProgram”}]
    Acceptable types: ‘Program’, ‘Clip’, ‘TVProgram’,’TVContent’,
    ‘TVClip’, ‘RadioContent’,’RadioProgram’, ‘RadioClip’

Payload for “article” “delete”

Name Required Valid values
data.id true example: “3-2”

Concept messages

Concept create

Sent when concept is created for the first time. Payload contains all the same information you’d get by making Concepts API GET concepts.json?yle_id=18-1 request.

routing keys:

  • concepts.create

headers:

  • event_timestamp (yyyy-MM-dd’T’HH:mm:ssZ)
  • event_type - CREATED

example payload:

{
 "id": "18-1",
 "alternativeIds": [],
 "types":["Concept"],
  "exactMatch":["leiki:focus100k_na_49593"],
  "title": {
    "fi": "Urho Kekkonen",
    "sv": "Urho Kekkonen"
  },
  "description": {
    "fi": "Urho Kaleva Kekkonen oli suomalainen poliitikko",
    "sv": "Urho Kaleva Kekkonen, född 3 september 1900"
  }
}

Concept update

Sent when concept is updated in any way: title changes, disambiguation changes, type changes. Payload contains the same information as it would in CREATED message. NOTE: Payload might contain alternativeIds field. See concept combine below.

routing keys

  • concepts.update

headers

  • event_timestamp (yyyy-MM-dd’T’HH:mm:ssZ)
  • event_type - UPDATED

example payload

{
  "id": "18-1",
  "alternativeIds": [],
  "types":["Concept"],
  "exactMatch":["leiki:focus100k_na_49593"],
  "title": {
    "fi": "Urho Kekkonen",
    "sv": "Urho Kekkonen"
  },
  "description": {
    "fi": "Urho Kaleva Kekkonen oli suomalainen poliitikko",
    "sv": "Urho Kaleva Kekkonen, född 3 september 1900"
  }
}

Concept combine

Sent when two or more concepts are combined. Message contains the same payload as CREATED or UPDATED message would, but with alternativeIds field.

routing keys

  • concepts.combine

headers

  • event_timestamp (yyyy-MM-dd’T’HH:mm:ssZ)
  • event_type - COMBINED

example payload

{
  "id": "18-2",
  "alternativeIds":["18-1"],
  "types":["Concept", "Person", "Agent"],
  "exactMatch":["leiki:focus100k_na_49593", "freebase:/m/07w5w"],
  "title": {
    "fi": "Urho Kekkonen",
    "sv": "Urho Kekkonen"
  },
  "description": {
    "fi": "Urho Kaleva Kekkonen oli suomalainen poliitikko",
    "sv": "Urho Kaleva Kekkonen, född 3 september 1900"
  }
}

In this example, concept 18-1 (Leiki) is combined with 18-2 (Freebase), making Freebase’s 18-2 the new primary id for Urho Kekkonen. The old id, 18-1 is now alternative id of 18-2.

In your end, you should now make sure that if your content was attached to 18-1, you should after receiving this message show 18-2 and it’s information instead.

Also, any queries for content with Leiki’s 18-1 concept attached should also return content that is attached to Freebase’s 18-2. This applies to another direction too: requests with 18-2 should also return results that’d match 18-1

After this message, there won’t be further UPDATED or CREATED messages directly to 18-1, but there might be UPDATED and CREATED messages to the 18-2 (the new primary). Also, there might be further COMBINED messages if 18-2 is further combined with yet another concept.