Publisher API

  • SECTIONS
  • Overview
  • API Definition
  • API Documentation
  • Code Snippet
  • Changelog
Overview

The Publisher API allows users to programmatically execute their reporting documents. Our Publisher solution provides custom client branded reporting documents for multi-channel distribution that seamlessly combine market data and analytics with your proprietary content and commentary. Publisher is a managed reporting offering where the creation and maintenance of documents is achieved through collaboration with FactSet’s implementation team of experts. Once documents have been configured, users can then execute them through our Publisher API. The API opens the ability to run, view and download documents in third-party portals and tools.

Use Case

  1. Identify the required inputs to execute a Publisher document.

• GET a list of documents within a FactSet directory and sub-directories – GET /analytics/engines/pub/v3/documents/{path}

• GET a list of accounts within a FactSet directory and sub-directories – GET /analytics/lookups/v3/accounts/{path}

  1. Submit a run of the Publisher document(s) for the required inputs. View the sample request body in the API definition under PubCalculations to see how to achieve this.

• POST /analytics/engines/pub/v3/calculations endpoint. This can support executing multiple document, account and date combinations in a single request. A calculationid will be returned when the request is submitted successfully.

  1. Manage the execution of the document(s) run and retrieve outputs.

• GET the status of a run execution using the calculationid returned previously – GET /analytics/engines/pub/v3/calculations/{id}/status. (A 200 indicates success. A 202 indicates the calculation is still executing.)

• Once an execution has completed the response body will contain a units object. The result field will contain a URI to pickup the output.

• GET the output(s) generated from the run execution – GET /analytics/engines/pub/v3/calculations/{id}/units/{unitId}/result

API Definition
Code Snippet
Single calculation
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;

using FactSet.AnalyticsAPI.Engines.Api;
using FactSet.AnalyticsAPI.Engines.Client;
using FactSet.AnalyticsAPI.Engines.Model;

namespace FactSet.AnalyticsAPI.Engines.Example.Examples
{
    public class PubEngineSingleUnitExample
    {
        private static Configuration _engineApiConfiguration;
        private static readonly string BasePath = Environment.GetEnvironmentVariable("FACTSET_HOST");
        private static readonly string UserName = Environment.GetEnvironmentVariable("FACTSET_USERNAME");
        private static readonly string Password = Environment.GetEnvironmentVariable("FACTSET_PASSWORD");
        private const string PubDocument = "Client:/AAPI/Puma Test Doc.Pub_bridge_pdf";
        private const string PubAccountId = "BENCH:SP50";
        private const string StartDate = "-1M";
        private const string EndDate = "0M";
    
        public static void Main(string[] args)
        {
            try
            {
                var calculationParameters = GetPubCalculationParameters();

                var calculationApi = new PubCalculationsApi(GetApiConfiguration());

                var calculationResponse = calculationApi.PostAndCalculateWithHttpInfo(null, null, calculationParameters);               
                // Comment the above line and uncomment the below lines to add cache control configuration. Results are by default cached for 12 hours; Setting max-stale=300 will fetch a cached result which is at max 5 minutes older.
                //var cacheControl = "max-stale=300";
                //var calculationResponse = calculationApi.PostAndCalculateWithHttpInfo(null, cacheControl, calculationParameters);
                
                if (calculationResponse.StatusCode == HttpStatusCode.Created)
                {
                    Stream result = (Stream)calculationResponse.Data;
                    OutputResult(result);
                    return;
                }

                CalculationStatusRoot status = (CalculationStatusRoot)calculationResponse.Data;
                var calculationId = status.Data.Calculationid;
                Console.WriteLine("Calculation Id: " + calculationId);

                ApiResponse<CalculationStatusRoot> getStatusResponse = null;

                while (status.Data.Status == CalculationStatus.StatusEnum.Queued || status.Data.Status == CalculationStatus.StatusEnum.Executing)
                {
                    if (getStatusResponse != null)
                    {
                        if (getStatusResponse.Headers.ContainsKey("Cache-Control"))
                        {
                            var maxAge = getStatusResponse.Headers["Cache-Control"][0];
                            if (string.IsNullOrWhiteSpace(maxAge))
                            {
                                Console.WriteLine("Sleeping for 2 seconds");
                                // Sleep for at least 2 seconds.
                                Thread.Sleep(2000);
                            }
                            else
                            {
                                var age = int.Parse(maxAge.Replace("max-age=", ""));
                                Console.WriteLine($"Sleeping for {age} seconds");
                                Thread.Sleep(age * 1000);
                            }
                        }
                    }

                    getStatusResponse = calculationApi.GetCalculationStatusByIdWithHttpInfo(calculationId);
                    status = getStatusResponse.Data;
                }
                Console.WriteLine("Calculation Completed");

                
                foreach (var calculation in status.Data.Units)
                {
                    if (calculation.Value.Status == CalculationUnitStatus.StatusEnum.Success)
                    {
                        var resultResponse = calculationApi.GetCalculationUnitResultByIdWithHttpInfo(calculationId, calculation.Key);
                        OutputResult(resultResponse.Data);
                    }
                    else
                    {
                        Console.WriteLine($"Calculation Unit Id : {calculation.Key} Failed!!!");
                        Console.WriteLine($"Error message : {calculation.Value.Errors?.FirstOrDefault()?.Detail}");
                    }
                }

                Console.ReadKey();
            }
            catch (ApiException e)
            {
                Console.WriteLine($"Status Code: {e.ErrorCode}");
                Console.WriteLine($"Reason : {e.Message}");
                Console.WriteLine(e.StackTrace);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        private static Configuration GetApiConfiguration()
        {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            if (_engineApiConfiguration != null)
            {
                return _engineApiConfiguration;
            }

            _engineApiConfiguration = new Configuration
            {
                BasePath = BasePath,
                Username = UserName,
                Password = Password
            };
            
            // Uncomment below lines for adding the proxy configuration
            //System.Net.WebProxy webProxy = new System.Net.WebProxy("http://myProxyUrl:80/");
            //webProxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
            //_engineApiConfiguration.Proxy = webProxy;

            return _engineApiConfiguration;
        }


        private static PubCalculationParametersRoot GetPubCalculationParameters()
        {
            var pubAccountIdentifier = new PubIdentifier(PubAccountId);
            var pubDates = new PubDateParameters(StartDate, EndDate);

            var pubCalculation = new PubCalculationParameters(PubDocument, pubAccountIdentifier, pubDates);

            var calculationParameters = new PubCalculationParametersRoot
            {
                Data = new Dictionary<string, PubCalculationParameters> { { "1", pubCalculation } }
            };

            return calculationParameters;
        }

        private static void OutputResult(Stream result)
        {
            Console.WriteLine("Calculation Result");

            File.WriteAllBytes("output.pdf", ((MemoryStream)result).ToArray());

            Console.WriteLine("Calculation output saved to output.pdf");
        }
    }
}
Multiple calculation
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;

using FactSet.AnalyticsAPI.Engines.Api;
using FactSet.AnalyticsAPI.Engines.Client;
using FactSet.AnalyticsAPI.Engines.Model;

namespace FactSet.AnalyticsAPI.Engines.Example.Examples
{
    public class PubEngineMultipleUnitExample
    {
        private static Configuration _engineApiConfiguration;
        private static readonly string BasePath = Environment.GetEnvironmentVariable("FACTSET_HOST");
        private static readonly string UserName = Environment.GetEnvironmentVariable("FACTSET_USERNAME");
        private static readonly string Password = Environment.GetEnvironmentVariable("FACTSET_PASSWORD");
        private const string PubDocument = "Client:/AAPI/Puma Test Doc.Pub_bridge_pdf";
        private const string PubAccountId = "BENCH:SP50";
        private const string StartDate = "-1M";
        private const string EndDate = "0M";
 
        public static void Main(string[] args)
        {
            try
            {
                var calculationParameters = GetPubCalculationParameters();

                var calculationApi = new PubCalculationsApi(GetApiConfiguration());

                var calculationResponse = calculationApi.PostAndCalculateWithHttpInfo(null, null, calculationParameters);
                // Comment the above line and uncomment the below lines to add cache control configuration. Results are by default cached for 12 hours; Setting max-stale=300 will fetch a cached result which is at max 5 minutes older.
                //var cacheControl = "max-stale=300";
                //var calculationResponse = calculationApi.PostAndCalculateWithHttpInfo(null, cacheControl, calculationParameters);

                CalculationStatusRoot status = (CalculationStatusRoot)calculationResponse.Data;
                var calculationId = status.Data.Calculationid;
                Console.WriteLine("Calculation Id: " + calculationId);

                ApiResponse<CalculationStatusRoot> getStatusResponse = null;

                while (status.Data.Status == CalculationStatus.StatusEnum.Queued || status.Data.Status == CalculationStatus.StatusEnum.Executing)
                {
                    if (getStatusResponse != null)
                    {
                        if (getStatusResponse.Headers.ContainsKey("Cache-Control"))
                        {
                            var maxAge = getStatusResponse.Headers["Cache-Control"][0];
                            if (string.IsNullOrWhiteSpace(maxAge))
                            {
                                Console.WriteLine("Sleeping for 2 seconds");
                                // Sleep for at least 2 seconds.
                                Thread.Sleep(2000);
                            }
                            else
                            {
                                var age = int.Parse(maxAge.Replace("max-age=", ""));
                                Console.WriteLine($"Sleeping for {age} seconds");
                                Thread.Sleep(age * 1000);
                            }
                        }
                    }

                    getStatusResponse = calculationApi.GetCalculationStatusByIdWithHttpInfo(calculationId);
                    status = getStatusResponse.Data;
                }
                Console.WriteLine("Calculation Completed");

                
                foreach (var calculation in status.Data.Units)
                {
                    if (calculation.Value.Status == CalculationUnitStatus.StatusEnum.Success)
                    {
                        var resultResponse = calculationApi.GetCalculationUnitResultByIdWithHttpInfo(calculationId, calculation.Key);
                        OutputResult(resultResponse.Data, $"output-{calculation.Key}");
                    }
                    else
                    {
                        Console.WriteLine($"Calculation Unit Id : {calculation.Key} Failed!!!");
                        Console.WriteLine($"Error message : {calculation.Value.Errors?.FirstOrDefault()?.Detail}");
                    }
                }

                Console.ReadKey();
            }
            catch (ApiException e)
            {
                Console.WriteLine($"Status Code: {e.ErrorCode}");
                Console.WriteLine($"Reason : {e.Message}");
                Console.WriteLine(e.StackTrace);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        private static Configuration GetApiConfiguration()
        {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            if (_engineApiConfiguration != null)
            {
                return _engineApiConfiguration;
            }

            _engineApiConfiguration = new Configuration
            {
                BasePath = BasePath,
                Username = UserName,
                Password = Password
            };
            
            // Uncomment below lines for adding the proxy configuration
            //System.Net.WebProxy webProxy = new System.Net.WebProxy("http://myProxyUrl:80/");
            //webProxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
            //_engineApiConfiguration.Proxy = webProxy;

            return _engineApiConfiguration;
        }


        private static PubCalculationParametersRoot GetPubCalculationParameters()
        {
            var pubAccountIdentifier = new PubIdentifier(PubAccountId);
            var pubDates = new PubDateParameters(StartDate, EndDate);

            var pubCalculation = new PubCalculationParameters(PubDocument, pubAccountIdentifier, pubDates);

            var calculationParameters = new PubCalculationParametersRoot
            {
                Data = new Dictionary<string, PubCalculationParameters> { { "1", pubCalculation }, { "2", pubCalculation } }
            };

            return calculationParameters;
        }

        private static void OutputResult(Stream result, string fileName)
        {
            Console.WriteLine("Calculation Result");

            File.WriteAllBytes($"{fileName}.pdf", ((MemoryStream)result).ToArray());

            Console.WriteLine($"Calculation output saved to {fileName}.pdf");
        }
    }
}
Changelog

v3

Summary

  • Version 3.10.0 - Released on 02/14/2022
  • Version 3.9.0 - Released on 11/22/2021
  • Version 3.8.0 - Released on 10/21/2021
  • Version 3.7.0 - Released on 09/20/2021
  • Version 3.6.0 - Released on 09/07/2021
  • Version 3.6.0 - Released on 08/23/2021
  • Version 3.5.0 - Released on 08/06/2021
  • Version 3.4.2 - Released on 07/28/2021
  • Version 3.4.1 - Released on 07/19/2021
  • Version 3.3.2 - Released on 07/12/2021
  • Version 3.3.1 - Released on 06/28/2021
  • Version 3.3.0 - Released on 06/07/2021
  • Version 3.2.0 - Released on 05/21/2021
  • Version 3.1.2 - Released on 04/21/2021
  • Version 3.1.1 - Released on 03/20/2021
  • Version 3.1.0 - Released on 03/18/2021
  • Version 3.0.0 - Released on 02/10/2021

Functionality Additions

  • Calculation points will be returned in the GET status endpoints once the calculation completes successfully. [v3.9.0]
  • Improved performance through concurrency [v3.8.0]
  • New field “path” in "GET by Component ID" endpoint response [v3.7.0]
  • New cache-control headers “Age” and “Last-Modified” [v3.6.0]
  • Support cache-control headers max-age, max-stale, max-stale & max-age [v3.1.0]
  • Initial Release [v3.0.0]

Changes

  • New "data" top-level object in request and response body
  • Cache control functionality
  • GET analytics/engines/{engine}/v3/calculations/{id} - now returns calculation parameters instead of calculation status
  • Updated lookup endpoint URLs

Bug Fixes

  • Fixes bug in the content-type header [v3.10.0]
  • Fixed an issue where progress percentage on calculation units was not included in POST or GET requests on Engines API [v3.8.0]
  • Improved error messaging for Invalid component id [v3.6.0]
  • Minor bug fixes for a multi-unit calculation [v3.5.0]
  • Minor bug fixes [v3.4.1]
  • Fix for the decoding of v3 Document’s endpoint. [v3.3.2]

v1

Summary

  • v1.1.1 - Released on 11/16/20
  • v1.1.0 - Released on 10/06/20
  • v1.0.6 - Released on 08/27/20
  • v1.0.5 - Released on 07/23/20
  • v1.0.4 - Released on 06/25/20
  • v1.0.3 - Released on 04/19/20
  • v1.0.2 - Released on 03/26/20
  • v1.0.1 - Released on 02/27/20
  • v1.0.0 - Released on 01/16/20

Functionality Additions

  • Support for “EXT” External Returns holdings mode PUB calculations  [v1.0.5]
  • Better logging [v1.0.3]
  • Performance improvements [v1.0.1]
  • Initial release [v1.0.0]

Changes

  • No changes

Bug Fixes

  • Minor bug fixes [v1.1.1]
  • Fixing minor bug causing a crash [v1.1.0]
  • Fixed bug in rate limiting, preventing cancelling a calculation [v1.0.6]
  • Return 400 on null values in Accounts [v1.0.6]
  • Cache control header fix [v1.0.4]
  • Rate limiting header fix [v1.0.4]
  • Minor bug fixes [v1.0.3]
  • Fixed a bug while passing invalid format [v1.0.2]