Skip to content

Example: Recent News

As our first example, we'll tackle a common question: how do I simply get a news feed?

Background Information

In Apollo, news feeds are represented as Channels, which are JSON expressions that allow you to define simple or complex filters on news content. Channels can define streams of content that produce thousands of documents per day, or a single document out of our billions stored. They can contain a single filter, or even hundreds. Channels are versatile objects that form the core of how to build FTS Apollo™ news and content into your workflows.

In this example, our goal is to simply fetch recent news for a pre-defined channel. We'll accomplish this by chaining together two API requests: the first to read the detailed definition of a stored channel, and a second which uses that channel definition to pull recent news.

Building the Requests

Authenticating

First, we need to authenticate with the API. Please see the page on Authentication. You will need an access token in order to authenticate the following requests.

Fetching the Channel

Now that we're authenticated, the next step is to fetch the channel definition. Channels are identified using their distinct IDs. For this example, we'll be using channel 233, which is configured to return high-quality, financial services news content. This will work for any channel that is set to public or owned by you.

The endpoint we need to use is GET /channel/id/{channelID}. Looking at the associated information in the OpenAPI/Swagger reference page, we see that all we need is to supply the channel ID parameter. So, we come up with the following request:

Request

curl --location --request GET 'https://global-api.fintechstudios.com/v1/channel/id/233' \
--header 'x-api-key: <key>' \
--header 'Authorization: Bearer <token>' \
--data-raw ''
GET /v1/channel/id/233 HTTP/1.1
Host: global-api.fintechstudios.com
x-api-key: <key>
: 
Authorization: Bearer <token>
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
Request request = new Request.Builder()
  .url("https://global-api.fintechstudios.com/v1/channel/id/233")
  .method("GET", null)
  .addHeader("x-api-key", "<key>")
  .addHeader("Authorization", "Bearer <token>")
  .build();
Response response = client.newCall(request).execute();
var request = require('request');
var options = {
  'method': 'GET',
  'url': 'https://global-api.fintechstudios.com/v1/channel/id/233',
  'headers': {
    'x-api-key': '<key>',
    '': '',
    'Authorization': 'Bearer <token>'
  }
};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://global-api.fintechstudios.com/v1/channel/id/233',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'x-api-key: <key>', 
    'Authorization: Bearer <token>'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;
import http.client

conn = http.client.HTTPSConnection("global-api.fintechstudios.com")
payload = ''
headers = {
  'x-api-key': '<key>',
  'Authorization': 'Bearer <token>'
}
conn.request("GET", "/v1/channel/id/233", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))

The response will be an array of channel objects containing the channel definition we requested:

Response

{
    "channels": [
        {
            "owner": "",
            "subscriber_count": 1,
            "subscribers": [],
            "created": "2017-12-26T20:50:31.478Z",
            "updated": "2017-12-26T20:50:31.478Z",
            "public": true,
            "name": "FTS Curated News",
            "description": "The default FTS news feed, with some basic filters applied.",
            "id": 233,
            "stages": [
                {
                    "not": false,
                    "entities": [
                        {
                            "type": "entity",
                            "value": "13512"
                        }
                    ]
                },
                {
                    "not": false,
                    "entities": [
                        {
                            "type": "entity",
                            "value": "13579"
                        }
                    ]
                },
                {
                    "not": false,
                    "entities": [
                        {
                            "type": "entity",
                            "value": "14613"
                        },
                        {
                            "type": "entity",
                            "value": "750861"
                        }
                    ]
                }
            ]
        }
    ]
}

The top fields, just as created, updated, name and id are all metadata fields for the channel, while the contents of stages contains the filter definition.

This channel has three stage items in the stages field:

Warning

You should make sure you're familiar with creating and managing channels.

  1. The first selects any documents that are tagged with entity ID 13512, which is the topic Major Corporate News. This means that all stories in this channel will need to contain this tag.
  2. The next stage selects any documents that are tagged with entity ID 13579, which is the topic Financial. This means that all stories in this channel will also need to contain this tag, in addition to Major Corporate News.
  3. The final stage contains two entities 14613 and 750861, which are the feed categories Major News Publications and Highly Ranked Sources, respectively. Since these two items are in the same channel stage, it means that any document that contains one of more of these two entities will pass.

The stages object is the important piece, so let's save that for our next step.

Requesting News

Tip

You can easily retrieve a user ID from your access token. Simply inspect the JWT token using a tool like JWT.io, and look at the sub (Subject) field.

The next step is to use the stages in order to request relevant news. The endpoint we need to use is POST /news/user/{userId}/query. The only required parameter is {userId}, but we'll also want to include the stages body parameter. For detailed request options, you'll want to visit the OpenAPI/Swagger reference page.

Using the stages data from before, we can create the following API request:

Request

curl --location --request POST 'https://global-api.fintechstudios.com/v1/news/user/<userId>/query' \
--header 'x-api-key: <key>' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "stages": [
        {
            "not": false,
            "entities": [
                {
                    "type": "entity",
                    "value": "13512"
                }
            ]
        },
        {
            "not": false,
            "entities": [
                {
                    "type": "entity",
                    "value": "13579"
                }
            ]
        },
        {
            "not": false,
            "entities": [
                {
                    "type": "entity",
                    "value": "14613"
                },
                {
                    "type": "entity",
                    "value": "750861"
                }
            ]
        }
    ]
}'
POST /v1/news/user/<userId>/query HTTP/1.1
Host: global-api.fintechstudios.com
x-api-key: <key>
Authorization: Bearer <token>
Content-Type: application/json

{
    "stages": [
        {
            "not": false,
            "entities": [
                {
                    "type": "entity",
                    "value": "13512"
                }
            ]
        },
        {
            "not": false,
            "entities": [
                {
                    "type": "entity",
                    "value": "13579"
                }
            ]
        },
        {
            "not": false,
            "entities": [
                {
                    "type": "entity",
                    "value": "14613"
                },
                {
                    "type": "entity",
                    "value": "750861"
                }
            ]
        }
    ]
}
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\"stages\":[{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"13512\"}]},{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"13579\"}]},{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"14613\"},{\"type\":\"entity\",\"value\":\"750861\"}]}]}");
Request request = new Request.Builder()
  .url("https://global-api.fintechstudios.com/v1/news/user/<userId>/query")
  .method("POST", body)
  .addHeader("x-api-key", "<key>")
  .addHeader("", "")
  .addHeader("Authorization", "Bearer <token>")
  .addHeader("Content-Type", "application/json")
  .build();
Response response = client.newCall(request).execute();
var request = require('request');
var options = {
  'method': 'POST',
  'url': 'https://global-api.fintechstudios.com/v1/news/user/<userId>/query',
  'headers': {
    'x-api-key': '<key>',
    'Authorization': 'Bearer <token>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({"stages":[{"not":false,"entities":[{"type":"entity","value":"13512"}]},{"not":false,"entities":[{"type":"entity","value":"13579"}]},{"not":false,"entities":[{"type":"entity","value":"14613"},{"type":"entity","value":"750861"}]}]})

};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://global-api.fintechstudios.com/v1/news/user/<userId>/query',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_POSTFIELDS =>'{
    "stages": [
        {
            "not": false,
            "entities": [
                {
                    "type": "entity",
                    "value": "13512"
                }
            ]
        },
        {
            "not": false,
            "entities": [
                {
                    "type": "entity",
                    "value": "13579"
                }
            ]
        },
        {
            "not": false,
            "entities": [
                {
                    "type": "entity",
                    "value": "14613"
                },
                {
                    "type": "entity",
                    "value": "750861"
                }
            ]
        }
    ]
}',
  CURLOPT_HTTPHEADER => array(
    'x-api-key: <key>',
    'Authorization: Bearer <token>',
    'Content-Type: application/json'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;
import http.client

conn = http.client.HTTPSConnection("global-api.fintechstudios.com")
payload = "{\"stages\":[{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"13512\"}]},{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"13579\"}]},{\"not\":false,\"entities\":[{\"type\":\"entity\",\"value\":\"14613\"},{\"type\":\"entity\",\"value\":\"750861\"}]}]}"
headers = {
  'x-api-key': '<key>',
  'Authorization': 'Bearer <token>',
  'Content-Type': 'application/json'
}
conn.request("POST", "/v1/news/user/<userId>/query", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))

The response will be an array of article objects and result metadata, looking something like this:

Response

{
    "articles": [
        {
            "id": 1274021709,
            "title": "Renewed tax break for Arizona angel investors heads to Ducey’s desk",
            "summary": "The angel investment tax credit bill passed both chambers of the Arizona legislature just as the session came to a close, and the governor is expected to sign it into law this week. See what Arizona startups have benefited from the program in the past.",
            "url": "https://www.bizjournals.com/phoenix/news/2021/07/06/angel-tax-credit-10-year-20-million-extension.html?ana=RSS&s=article_search&utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+bizj_phoenix+%28Phoenix+Business+Journal%29",
            "published": "2021-07-06T16:35:44.000Z",
            "updated": "2021-07-06T16:35:44.000Z",
            "created_at": "2021-07-06T16:35:50.166Z",
            "updated_at": "2021-07-06T16:36:01.062Z",
            "source": 103593,
            "contributor": 103594,
            "author": 0,
            "headline_cluster": "lzh3fPDLafPV3IRhptshOwonGSY8C5t+Hj0o0G/gBLs=",
            "url_cluster": "Na4DEEID8DoGTPdLB2c2bmfmLYgl+HecZrwlNi6ZU/8=",
            "entities": [
                2307607,
                2307504,
                8857455,
                84590,
                ...
            ],
            "primary_entities": [
                84564,
                13513,
                13512,
                2,
                14629,
                750862,
                ...
            ],
            "secondary_entities": [
                2307607,
                2307504,
                8857455,
                ...
            ],
            "tertiary_entities": [
                84590,
                1949690,
                13502,
                ...
            ],
            "image_url": "https://media.bizj.us/view/img/4834571/page10arizonacapitol*100xx1198-1200-301-0.jpg",
            "metadata": {
                "docSummary": {
                    "type": "text",
                    "values": [
                        "The angel investment tax credit bill passed both chambers of the Arizona legislature just as the session came to a close, and the governor is expected to sign it into law this week."
                    ]
                }
            },
            "verifications": {},
            "score": 1.4969288
        },
        ...
    ],
    "hits": {
        "to": 1625597514019,
        "clusterCountMap": {
            "lzh3fPDLafPV3IRhptshOwonGSY8C5t+Hj0o0G/gBLs=": 1,
            "tz1gyFR3vElhTNI36RDuWeDplYLoFwWFCdpEyW4vOGk=": 3,
            "uDyTiylW9+Dc3fRL2nN/RnbUF0YVf0P7/wF11Go4Bts=": 1,
            "21wCyN9b2iRNjmtnptQh/OTlrIwn7DZSEa90zcXUCVE=": 1,
            "ttbSS3gtayywefKfXWKlDEf80yznxEU8IM18yU6XSUQ=": 9,
            "MKIy3SfFkbGQ1a2OH0vvTv0bIRhpGQbHTqfOUo+vE6I=": 1,
            ...
        },
        "count": 9950,
        "hiddenCount": 0,
        "clusterCount": 0,
        "from": 1625097600000
    },
    "hiddenClusterMap": {},
    "articleWorkflowStates": []
}

The results about were truncated, but are representative of what you should expect from the output.

Next Steps

For next steps, try modifying your news request to account for the following:

  • A different public channel
  • A private channel owned by the requesting user
  • A channel with more or fewer filters.

Last update: November 22, 2021
Back to top