Basic Information
- a live version of the API (using Swagger) is here
- version 5 of the API was released April 24, 2014 (ALM 2.14).
- version 6 of the API was released April, 2015 (Lagotto 4.0).
Base URL
- API calls start with
/api/
. API versioning is done via the request header, e.g.Accept: application/json; version=6
, and currently defaults toversion=6
.
Supported Media Types
- application/json
The default media type is JSON. The media type is set in the header, e.g. "Accept: application/json", but defaults to this format anyway. Media type negotiation via file extension (e.g. ".json") is not supported. JSONP
and CORS
are supported.
API Key
Almost all information regarding works (with the exception of sources that don't allow redistribution of data) is available without API keys since the Lagotto 3.12.7 release (January 9, 2015). An API key is required to add/update works, and to access some of the internal data of the application. A key can be obtained by registering as API user with the ALM application and this shouldn't take more than a few minutes. By default the ALM application uses Mozilla Persona, but it can also be configured to use other services usch as OAuth and CAS. For the PLOS ALM application you need to sign in with your PLOS account.
For the v5 API the API key shoould be part of the URL in the format ?api_key=API_KEY
. The v6 API requires the API key in the header in the format Authorization: Token token=API_KEY
.
Meta
Every API response starts with a meta
object that starts with basic information such as message-type
and number of results (total
).
"meta": {
"status": "ok",
"message-type": "work-list",
"message-version": "6.0.0",
"total": 1077,
"total_pages": 2,
"page": 1
}
Query for one or several works
Specify one or more works by a comma-separated list of pids in the ids
parameter. These DOIs have to be URL-escaped, e.g. %2F
for /
:
/api/v5/articles?ids=doi:10.1371%2Fjournal.pone.0036240
/api/v5/articles?ids=doi:10.1371%2Fjournal.pone.0036240,doi:10.1371%2Fjournal.pbio.0020413
Queries for up to 50 works at a time are supported. With many ids, in particular DOIs or URLs, the size limit of the query URL might be reached. It is therefore advisable to put the ids into the body of a POST, and include an X-HTTP-Method-Override: GET
header:
curl -X POST -d "ids=10.1371%2Fjournal.pone.0036240,10.1371%2Fjournal.pbio.0020413" -H "Authorization: Token token=API_KEY" -H "X-HTTP-Method-Override: GET" "http://alm.plos.org/api/works"
Events
The events for every source are returned as total number, and separated in categories, e.g. html
and pdf
views for usage data, readers
for bookmarking services, and likes
and comments
for social media:
CiteULike: readers
Mendeley: readers
Twitter: comments
Facebook: likes, comments
Reddit: likes, comments
Counter, PubMed Central: html, pdf
Some events can only be obtained by substracting from total
, e.g. Counter
xml downloads: total
- (html
+ pdf
).
Search
Search is not supported by the API, users have to provide specific identifiers or retrieve batches of 50 documents, sorted by descending date or source event count.
Date and Time Format
All dates and times with the exception of publication dates are in ISO 8601 format, e.g. 2003-10-13T07:00:00Z
. date-parts
uses the Citeproc convention to allow incomplete dates (e.g. year only):
"date-parts": [
[
2008,
10,
31
]
date-parts
is a nested array of year, month, day, with only the year being required.
Additional Parameters
type=doi|pmid|pmcid|arxiv|scp|wos|ark|url
The API supports queries for DOI, PubMed ID, PubMed Central ID, ArXiV ID, Scopus ID, Web of Science ID, ark, and publisher URL. The pid is used if no type is given in the query. The following queries are all for the same work:
/api/works?ids=doi:10.1371%2Fjournal.pmed.1001361
/api/works?ids=10.1371%2Fjournal.pmed.1001361&type=doi
/api/works?ids=23300388&type=pmid
/api/works?ids=PMC3531501&type=pmcid
/api/works?ids=84871667565&type=scp
/api/works?ids=000312934200011&type=wos
/api/works?ids=http://www.plosmedicine.org/article/info:doi/10.1371/journal.pmed.1001361&type=url
publisher_id=x
Only show works from a given publisher, using the publisher CrossRef ID. The response format is the same as the default response.
/api/works?publisher_id=340
sort=x
Results are sorted by descending event count when given the source name, e.g. &sort=wikipedia
. Otherwise (the default) results are sorted by descending publication date. When using &source=x
, we can only sort by publication date or that source, not a different source.
page|per_page
Results of the v6 API are paged with 1000 results per page. Use per_page
to pick a smaller number (0-1000) of results per page, and use page
to page through the results.
Example Responses
/api/works/
{
"meta": {
"status": "ok",
"message-type": "work-list",
"message-version": "6.0.0",
"total": 1077,
"total_pages": 2,
"page": 1
},
"works": [
{
"id": "http://doi.org/10.1371/journal.pgen.1003182",
"publisher_id": 340,
"title": "Alternative Oxidase Expression in the Mouse Enables Bypassing Cytochrome <i>c</i> Oxidase Blockade and Limits Mitochondrial ROS Overproduction",
"issued": {
"date-parts": [
[
2013,
1,
3
]
]
},
"container-title": "PLOS Genetics",
"volume": 9,
"page": "e1003182",
"issue": 1,
"DOI": "10.1371/journal.pgen.1003182",
"events": {
"crossref": 16,
"counter": 6702
},
"timestamp": "2015-04-16T06:14:07Z"
},
{
"id": "http://doi.org/10.1371/journal.pgen.1003145",
"publisher_id": 340,
"title": "The Telomere Capping Complex CST Has an Unusual Stoichiometry, Makes Multipartite Interaction with G-Tails, and Unfolds Higher-Order G-Tail Structures",
"issued": {
"date-parts": [
[
2013,
1,
3
]
]
},
"container-title": "PLOS Genetics",
"volume": 9,
"page": "e1003145",
"issue": 1,
"DOI": "10.1371/journal.pgen.1003145",
"events": {
"crossref": 5,
"counter": 5282
},
"timestamp": "2015-04-12T08:19:11Z"
},
{
"id": "http://doi.org/10.1371/journal.pgen.1003147",
"publisher_id": 340,
"title": "A Genome-Wide Integrative Genomic Study Localizes Genetic Factors Influencing Antibodies against Epstein-Barr Virus Nuclear Antigen 1 (EBNA-1)",
"issued": {
"date-parts": [
[
2013,
1,
10
]
]
},
"container-title": "PLOS Genetics",
"volume": 9,
"page": "e1003147",
"issue": 1,
"DOI": "10.1371/journal.pgen.1003147",
"PMID": "23326239",
"PMCID": "3542101",
"events": {
"europe_pmc": 8,
"crossref": 9,
"counter": 6355
},
"timestamp": "2015-04-12T08:01:33Z"
},
{
"id": "http://doi.org/10.1371/journal.pgen.1003144",
"publisher_id": 340,
"title": "Starvation, Together with the SOS Response, Mediates High Biofilm-Specific Tolerance to the Fluoroquinolone Ofloxacin",
"issued": {
"date-parts": [
[
2013,
1,
3
]
]
},
"container-title": "PLOS Genetics",
"volume": 9,
"page": "e1003144",
"issue": 1,
"DOI": "10.1371/journal.pgen.1003144",
"events": {
"crossref": 21,
"counter": 6722
},
"timestamp": "2015-04-12T08:19:12Z"
}
]
}
/api/works/doi:10.1371/journal.pgen.1003182
{
"meta": {
"status": "ok",
"message-type": "work",
"message-version": "6.0.0"
},
"work": {
"id": "http://doi.org/10.1371/journal.pgen.1003182",
"publisher_id": 340,
"title": "Alternative Oxidase Expression in the Mouse Enables Bypassing Cytochrome <i>c</i> Oxidase Blockade and Limits Mitochondrial ROS Overproduction",
"issued": {
"date-parts": [
[
2013,
1,
3
]
]
},
"container-title": "PLOS Genetics",
"volume": 9,
"page": "e1003182",
"issue": 1,
"DOI": "10.1371/journal.pgen.1003182",
"events": {
"crossref": 16,
"counter": 6702
},
"timestamp": "2015-04-16T06:14:07Z"
}
}
Create/Update/Delete
These actions are limited to users with admin privileges, authenticated with the API key via HTTP header. The API supports the following REST actions:
HTTP Verb | Path | Action |
---|---|---|
GET | /api/works | index |
POST | /api/works | create |
GET | /api/works/info:doi/DOI | show |
PUT | /api/works/info:doi/DOI | update |
DELETE | /api/works/info:doi/DOI | delete |
Create work
A sample curl API call to create a new work would look like this:
curl -X POST -H "Content-Type: application/json" -H "Authentication: Token token=API_KEY" -d '{"work":{"doi":"10.1371/journal.pone.0036790","year":2012,"month":5,"day":15,"title":"Test title"}}' http://HOST/api/works
When a work has been created successfully, the server reponds with Status 201 Created
and the following JSON (the data
object will include all work attributes):
$ curl -i -X POST -H "Content-Type: application/json" -H "Authentication: Token token=API_KEY" -d '{"work":{"doi":"10.7554/eLife.09002","year":2013,"month":5,"day":21,"title":"Structure of a pore-blocking toxin in complex with a eukaryotic voltage-dependent K+ channel"}}' http://HOST/api/works
HTTP/1.1 201 Created
Status: 201 Created
Content-Type: application/json; charset=utf-8
{"success":"Work created.","error":null,"work":{"doi":"10.7554/eLife.09002","title":"Structure of a pore-blocking toxin in complex with a eukaryotic voltage-dependent K+ channel","canonical_url":null,"mendeley_uuid":null,"pmid":null,"pmcid":null,"views":0,"shares":0,"bookmarks":0,"citations":0,"sources":[{"name":"pmc","display_name":"PubMed Central Usage Stats","events_url":null,"metrics":[]},{"name":"copernicus",
... more ...
When a work with the specified DOI already exists, the server returns HTTP 400 error with a JSON body indicating the work exists:
$ curl -i -X POST -H "Content-Type: aapplication/json" -H "Authentication: Token token=API_KEY" -d '{"work":{"doi":"10.7554/eLife.09002","year":2013,"month":5,"day":21,"title":"Structure of a pore-blocking toxin in complex with a eukaryotic voltage-dependent K+ channel"}}' http://HOST/api/works
HTTP/1.1 400 Bad Request
Status: 400 Bad Request
Content-Type: application/json; charset=utf-8
{"total":0,"total_pages":0,"page":0,"success":null,"error":{"doi":["has already been taken"]},
"data":{"doi":"10.7554/eLife.99002","title":"Structure of a pore-blocking toxin in complex with a eukaryotic
voltage-dependent K+ channel","canonical_url":null,"mendeley_uuid":null,"pmid":null,"pmcid":null,"views":0,
"shares":0,"bookmarks":0,"citations":0,"sources":[]}}
In order to be accepted the following conditions must hold:
The JSON must be valid, this means that string variables such as the DOI must be quoted in the request. The day, month and year are integers and can be left unquoted.
The publication date can't be in the future (as understood by the server's date).
The API key must be valid, and for a user with role admin.
Update work
A sample curl API call to update a work would look like this:
curl -X POST -H "Content-Type: application/json" -H "Authentication: Token token=API_KEY" -d '{"work":{"pmid":"22615813"}}' http://HOST/api/works/doi:10.1371/journal.pone.0036790
When a work has been updated successfully, the server reponds with Status 200 Ok
and the following JSON (the data
object will include all work attributes):
{"success":"Work updated.","error":null,"data":{ ... }
Delete work
A sample curl API call to delete a work would look like this:
curl -X POST -H "Content-Type: application/json" -H "Authentication: Token token=API_KEY" -d '{"work":{"pmid":"22615813"}}' http://HOST/api/works/doi:10.1371/journal.pone.0036790
When a work has been deleted successfully, the server reponds with Status 200 Ok
and the following JSON (the data
object will include all work attributes):
{"success":"Work deleted.","error":null,"data":{ ... }
Get alerts
The alerts API endpoint is only available to authenticated admin users. The same query parameters as in the admin web interface are supported:
- source
- class_name
- level
- query (but using
q
)
By default the API returns all alerts, add &unresolved=1
to only retrieve unresolved alerts, as in the admin web interface. An example API response would be:
{
"meta": {
"status": "ok",
"message-type": "alert-list",
"message-version": "6.0.0",
"total": 152,
"total_pages": 4,
"page": 1
},
"alerts": [
{
"id": "39586c14-8d3e-4f83-9636-d36ca2d6b958",
"level": "FATAL",
"class_name": "StandardError",
"message": "No Sidekiq process running, Sidekiq process started at 2015-04-16T06:24:14Z.",
"hostname": "lagotto-4-0-unstable.local",
"unresolved": true,
"timestamp": "2015-04-16T06:24:15Z"
},
{
"id": "018a1fb6-60e3-4b63-b84f-f33204163917",
"level": "ERROR",
"class_name": "NameError",
"message": "uninitialized constant DeleteEventJob::Relation",
"hostname": "lagotto-4-0-unstable.local",
"unresolved": true,
"timestamp": "2015-04-16T06:21:51Z"
},
{
"id": "ecccba25-4c11-4396-b1d1-5534ca60c27d",
"level": "FATAL",
"class_name": "StandardError",
"message": "No Sidekiq process running, Sidekiq process started at 2015-04-16T06:14:24Z.",
"hostname": "lagotto-4-0-unstable.local",
"unresolved": true,
"timestamp": "2015-04-16T06:14:24Z"
},
{
"id": "12b40b31-e347-4ec7-ac26-545844be872a",
"level": "ERROR",
"class_name": "NoMethodError",
"message": "undefined method `DOI' for #<Work:0x00000007f00008>",
"status": 422,
"hostname": "lagotto-4-0-unstable.local",
"unresolved": false,
"timestamp": "2015-04-16T05:01:30Z"
}
]
}