Tech Blog

Working with Analytics REST APIs

As of the September Alma release, the Analytics API is RESTful. Like other REST APIs, documentation is available in the Alma section of this website. The following post provides some more detail for advanced users.

Reports resource

The reports resource (/almaws/v1/analytics/reports) requires one mandatory request parameter: path. The path is a URL-encoded full path to the report in the OBI catalog, so the simplest way to get this (and other arguments, as we will see) would be to open report in the Analytics UI. The path will appear in the URL:

So all you need to get started is to copy and paste it into your REST client (don’t forget a valid API key) with GET:


By default, the response will include up to 25 results. If there are more than 25 results, the response will include a ResumptionToken and IsFinished will be false:


To get the next page, replace your path parameter with a token parameter:


Repeat the request until IsFinished=true. Note that only the initial response will return a token, and the same token should be used throughout the session for a given report – you simply send the same request over and over until IsFinished=true.
You can increase the number of results per request by setting a ‘limit’ parameter (any value between 25 and 1000), e.g.:


Note: OBI returns bulks of 25 results, i.e. if you set the limit to 30 and have more than 30 results, you will get up to 50 results in your response. To avoid confusion, it is therefore recommended to set your limit to multiples of 25.


There are two typical ways to work with filters:

1. Apply the filter directly to the report. Use this option when your filter parameters are static. For example, in the “Expenditure Per Transaction Item Type for the current year” report, the filter “Year(Current_Date)” is applied to the “Transaction Date Fiscal Year” field, and there is no need to routinely change this value:

In this case, calling the API will always return the filtered results without any further necessary action.

2. Add the filter to the API request. Use this option when your app needs to run the same report with changing (or multiple) filters. The filter should be appended to the request as a filter querystring parameter. The value is an XML representation of a saw:filter object. The syntax is not very straightforward. Fortunately, the OBI UI can help with this. Going back to the report in the previous example, click on the ‘Advanced’ tab and in the Analysis XML text area search for ‘saw:filter’:

You can clearly see how the filter is expressed in XML format. This would be the recommended method for building your filters: create them in the UI, copy the XML, and delete using the UI.

Returning to our original example using the ‘Expenditure Per year – Month’ report, let’s add a filter to remove all data before 2010:

In the “Advanced” tab, locate the relevant expression within the filter:

Now you need to go back and remove the filter (since you\re going to be applying it through the URL).

Note: In some cases we have found that setting the filter to ‘prompted’ is required by OBI for the API call to work. It is therefore recommended to add an ‘is prompted’ condition for every field you plan to filter (you do not need to add this in the API request itself). In the example below, I plan to add a filter by Year Key, so, using the ‘add filter’ icon on the far right I selected the ‘Year Key’ column and added an “is prompted” condition.

Let’s get back to the xml-formatted filter. Before we can add this as a filter parameter, we need to add 4 namespaces:

<sawx:expr xsi:type="sawx:comparison" op="greaterOrEqual" 
<sawx:expr xsi:type="sawx:sqlExpression">"Transaction Dates"."Transaction Date Fiscal Year"</sawx:expr>
<sawx:expr xsi:type="xsd:decimal">2010</sawx:expr>

This needs to be URL encoded, so our request should look like this:


Which returns the following set.

As you can see, the results are properly filtered.


  1. If your filter contains apostrophes, these must be xml-escaped (i.e. replace ‘ with &apos;) before URL-encoding. An apostrophe after xml-escaping and URL-encoding will be %26apos%3B.
  2. Requests submitted via the the API console should not be URL-encoded.
  3. If your report has more than one filter you can sew them together like so:
<sawx:expr xsi:type="sawx:logical" op="and"
	<sawx:expr xsi:type="sawx:comparison" op="equal">
		<sawx:expr xsi:type="sawx:sqlExpression">"Patron Details"."Patron Id"</sawx:expr>
		<sawx:expr xsi:type="xsd:string">12345</sawx:expr>
	<sawx:expr xsi:type="sawx:comparison" op="equal">
		<sawx:expr xsi:type="sawx:sqlExpression">"Loan Circulation Desk"."Circ Desk Code"</sawx:expr>
		<sawx:expr xsi:type="xsd:string">MAINCIRC</sawx:expr>


Paths resource

The paths resource (/almaws/v1/analytics/paths) allows you to retrieve the path to an analytics report: It takes the analytics catalog path as a URL parameter and returns a list of sub directories and reports that appear under that path.
The API can be called without specifying the path – i.e. /almaws/v1/analytics/paths. Alma will return the root directory(s) in the analytics file hierarchy. e.g.:

     <path link="/almaws/v1/analytics/paths/shared" type="dir">shared</path>

It is also possible to call the API with the path specified – e.g. /almaws/v1/analytics/paths/shared.

See also our Access Your Report List with the New Analytics Paths API blog.

12 Replies to “Working with Analytics REST APIs”

  1. Do i need to set particular permissions for the report? out of the box reports work ok, but my own report comes back 500 access denied for user to path /users/200640760002461_2461_d/CK copies history.


    By University of Sussex 44SUS_INST on June 29, 2015 at 4:48 PM

  2. How do I get the column names outputted with the XML, the order does not seem to represent the view or criteria so I need to analyse each column to find out what its supposed to be.

    Am I missing a parameter or something in the original report?

    I would expect the names of the columns to appear in where they are being defined.


    By Victoria University Wellington 64VUW_INST on September 16, 2015 at 11:39 PM

  3. Updated response (March 2017):
    The column names are now included in the output.
    The columns in the API are ordered alphabetically first by folder name and then by column name.
    This is evident in the |sequence” section at the top of the API results and also in the “sql issued” section of the “Advanced” tab of the report.

    For example:
    “Titles”.”Bibliographic Details”.”Author” s_1,
    “Titles”.”Bibliographic Details”.”ISBN” s_2,
    “Titles”.”Bibliographic Details”.”MMS Id” s_3,
    “Titles”.”Bibliographic Details”.”Title (Normalized)” s_4,
    “Titles”.”Bibliographic Details”.”Uniform Title” s_5,
    “Titles”.”Institution”.”Institution Name” s_6,
    “Titles”.”Title Measures”.”Num of Active Physical Items” s_7,
    “Titles”.”Title Measures”.”Num of Active Portfolios” s_8,
    “Titles”.”Usage Measures”.”Num of Loans (In House + Not In House)” s_9

    By Ori Miller on August 25, 2016 at 06:38 AM

  4. Regarding the “access denied for user to path …” error:

    This mignt happen when the report is saved under a personal folder.
    Please save the reports under shared folders to access them via API

    By Admin on November 20, 2016 at 2:27 PM

  5. With regards to the Column names appearing in the XML response, we are not seeing this.
    The sequence section of the XML has “Column0” “Column1” etc even though the sql issued section of the advanced tab does have the columns name, e.g.
    “Primo Device Usage”.”Dates”.”Month (date)” s_1,
    “Primo Device Usage”.”Device Usage”.”Browser Type” s_2,

    Is there something we are missing?

    By UCL Library on January 5, 2018 at 2:24 PM

  6. Yeah Currently I am working on Laravel development and the API integration with Laravel will boost the efficiency of Laravel thank you for sharing this information Keep posting…

  7. So at least with my initial experimentation it seems like the first set of results will always include a token and have “IsFinished” set to true…..even if the results are less than 25 rows. (And hence, there is no next page, so I’d expect at least the IsFinished to be true.)

    It’s not a huge deal, I’m modifying some code to also check stop / skip when the following error is encounterd

    No more rows to fetch

    Tried seeing if there was a bug report, but not finding anything but wanted to note this somewhere.

  8. So just submitted a comment, but now I’m pretty sure I was wrong and need to do some more digging. Going to try to get time to set up some analytics reports that returns a set # of rows (or maybe even have that be based off a prompt) to do more tests.

  9. I am not able to get the dynamic filtering to work. I’ve already worked with issues such as may be absent if there is for instance no “Author” found in bibliographic details, and that only the token should appear on subsequent pages.

    Should the SAW filter expression be wrapped with saw:filter perhaps?

Leave a Reply