The Patrons Account Information API (PAIA) is a HTTP based programming interface to access library patron information, such as loans, reservations, and fees. Its primary goal is to provide patron access for discovery interfaces and other third-party applications to integrated library system, as easy and open as possible.
PAIA consists of two independent parts:
PAIA core defines six basic API methods to look up loaned and reserved items, to request and cancel loans and reservations, and to look up fees and general patron information.
PAIA auth defines three authentication API methods (login, logout, and password change) to get or invalidate an access token, and to modify credentials.
Authentication in PAIA is based on OAuth 2.0 (RFC 6749) with bearer tokens (RFC 6750) over HTTPS (RFC 2818).
This specification has been created collaboratively based on use cases and taking into account existing related standards and products of integrated library systems (ILS), such as NISO Circulation Interchange Protocol (NCIP), SIP2, [X]SLNP,1 DLF-ILS recommendations, and VuFind ILS.
All sources and updates can be found in a public git repository at http://github.com/gbv/paia. See the list of releases at https://github.com/gbv/paia/releases for functional changes. The master file paia.md is written in Pandoc’s Markdown. HTML version of the specification is generated from the master file with makespec. The specification can be distributed freely under the terms of CC-BY-SA.
Additional information and references about PAIA can be found in the public PAIA Wiki at https://github.com/gbv/paia/wiki.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
A PAIA server MUST implement PAIA core and it MAY implement PAIA auth. If PAIA auth is not implemented, another way SHOULD BE documented to distribute patron identifiers and access tokens. A PAIA server MAY support only a subset of methods but it MUST return a valid response or an error response on every method request, as defined in this document.
Each API method is accessed at a unique URL with a HTTP verb GET, POST, or PATCH:
PAIA core | PAIA auth |
---|---|
GET/PATCH patron: general patron information | POST login: get access token |
GET items: current loans, reservations, … | POST logout: invalidate access token |
POST request: new reservation, delivery, … | POST change: modify credentials |
POST renew: existing loans, reservations, … | |
POST cancel: requests, reservations, … | |
GET fees: paid and open charges |
All supported API method URLs MUST also be accessible with HTTP verb OPTIONS. All API methods with HTTP verb GET MAY also be accessible with HTTP verb HEAD.
API method URLs share a common base URL for PAIA core methods and common base URL for PAIA auth methods. A server SHOULD NOT provide additional methods at these base URLs and it MUST NOT propagate additional methods at these base URLs as belonging to PAIA.
Base URLs of PAIA auth and PAIA core are not required to share a common host, nor to include the URL path core/
or auth/
. In the following, the base URL https://example.org/core/ is used for PAIA core and https://example.org/auth/ for PAIA auth.
For security reasons, PAIA methods MUST be requested via HTTPS only. A PAIA client MUST NOT ignore SSL certificate errors; otherwise access token (PAIA core) or even password (PAIA auth) are compromised by the client.
All PAIA API methods, except PAI auth login and HTTP OPTIONS requests require an access token as a special request parameter. The access token is a so called bearer token as described in RFC 6750. The access token can be sent either as a URL query parameter or in an HTTP header. For instance the following requests both get information about patron 123
with access token vF9dft4qmT
:
curl -H "Authorization: Bearer vF9dft4qmT" https://example.org/core/123
curl -H https://example.org/core/123?access_token=vF9dft4qmT
An access token is valid for a limited set of actions, referred to as scope. The following scopes are possible for PAIA core:
For instance a particular token with scopes read_patron
and read_items
may be used for read-only access to information about a patron, including its loans and requested items but not its fees.
For PAIA auth there is an additional scope:
A PAIA auth server MAY support additional scopes to share an access token with other services.
Each API method call expects a set of request parameters, given as URL query fields, HTTP headers, or HTTP message body and return a JSON object. Most parts of PAIA core request parameters and JSON response can be mapped to RDF as defined by the PAIA Ontology.
Request parameters and fields of response objects are defined in this document with:
0..1
(optional, non repeatable)1..1
(mandatory, non repeatable)1..n
(mandatory, repeatable)0..n
(optional, repeatable)Simple parameter names and response fields consist of lowercase letters a-z
only.
Repeatable response fields are encoded as JSON arrays with irrelevant order, for instance:
{ "fee" : [ { ... }, { ... } ] }
Hierarchical JSON structures in this document are referenced with a dot (.
) as separator. For instance the subfield/parameter item
of the doc
element is referenced as doc.item
and refers to the following JSON structure:
{ "doc" : [ { "item" : "..." } ] }
The following special request parameters can be added to any request as URL query fields:
The following HTTP request headers SHOULD or MAY be sent by PAIA clients in particular:
application/json
application/json
or for PAIA core and application/x-www-form-urlencoded
for PAIA auth.
A OPTIONS preflight request for Cross-Origin Resource Sharing (CORS) MUST include the cross-origin request headers:
Authorization
if access tokens are sent as HTTP headers
Note that PAIA specification does not require clients to respect CORS rules. CORS preflight requests in browsers can be avoided by using request format application/x-www-form-urlencoded
and omitting the request headers Accept
and Authorization
.
Both PAIA core and PAIA auth servers SHOULD include the following HTTP response headers:
application/json
or application/json; charset=utf-8
for JSON response; the value application/javascript
or application/javascript; charset=utf-8
for JSONP response
change_password
scope MAY be omitted in PAIA core responses.
X-OAuth-Scopes X-Accepted-OAuth-Scopes
*
or another origin domain in response to a Origin
request header.
Bearer
for request errors with status 401
GET, HEAD, OPTIONS
) for request errors with status 405
All POST and PATCH requests MUST include a HTTP message body.
For PAIA core the message body MUST be sent in JSON format with content type application/json
. A PAIA core server MAY also support message body as URL encoded query string.
For PAIA auth the message body MUST be sent as URL encoded query string with content type application/x-www-form-urlencoded
. A PAIA auth server MAY also support message body in JSON.
A PAIA Server MUST also accept the explicit charset UTF8 (content type application/json; charset=utf-8
or application/x-www-form-urlencoded; charset=utf-8
). A PAIA Server MAY support additional request charsets such as ISO-8859-1.
Malformed requests, failed authentication, unsupported methods, and unexpected server errors such as backend downtime etc. MUST result in an error response. An error response is returned with an HTTP status code 4xx (client error) or 5xx (server error) as defined in RFC 2616, unless the request parameter suppress_response_codes
is given.
Document errors MUST NOT result in a request error but they are part of a normal response.
The response body of a request error is a JSON object with the following fields (compatible with OAuth error response):
name | occ | data type | description |
---|---|---|---|
error | 1..1 | string | alphanumerical error code |
code | 0..1 | nonnegative integer | HTTP status error code |
error_description | 0..1 | string | Human-readable error description |
error_uri | 0..1 | string | Human-readable web page about the error |
The code
field is REQUIRED with request parameter suppress_response_codes
in PAIA core. It SHOULD be omitted with PAIA auth requests to not confuse OAuth clients.
The response header of a request error MUST include a WWW-Authenticate
header field to indicate the need of providing a proper access token. The field MAY include a short name of the PAIA service with a “realm” parameter:
WWW-Authenticate: Bearer
WWW-Authenticate: Bearer realm="PAIA Core"
The following error responses are expected:2
error | code | description |
---|---|---|
not_found | 404 | Unknown request URL or unknown patron. Implementations SHOULD first check authentication and prefer error invalid_grant or access_denied to prevent leaking patron identifiers. |
not_implemented | 501 | Known but unsupported request URL (for instance a PAIA auth server server may not implement http://example.org/core/change ) |
invalid_request | 405 | Unexpected HTTP verb |
invalid_request | 400 | Malformed request (for instance error parsing JSON, unsupported request content type, etc.) |
invalid_request | 422 | The request parameters could be parsed but they don’t match the request method (for instance missing fields, invalid values, etc.) |
invalid_grant | 401 | The access token was missing, invalid, or expired |
insufficient_scope | 403 | The access token was accepted but it lacks permission for the request |
access_denied | 403 | Wrong or missing credentials to get an access token |
internal_error | 500 | An unexpected error occurred. This error corresponds to a bug in the implementation of a PAIA auth/core server |
service_unavailable | 503 | The request couldn’t be serviced because of a temporary failure |
bad_gateway | 502 | The request couldn’t be serviced because of a backend failure (for instance the library system’s database) |
gateway_timeout | 504 | The request couldn’t be serviced because of a backend failure |
For instance the following response could result from a request with malformed URIs:
{
"error": "invalid_request",
"code": "422",
"error_description": "malformed item identifier provided: must be an URI",
"error_uri": "http://example.org/help/api"
}
The following data types are used to define request and response format:
YYYY-MM-DD
format. A datetime value with time and timezone SHOULD be used instead, if possible.
A date value in YYY-MM-DD
format, optionally followed by a time value. A time value consists of the letter T
followed by hh:mm:ss
format, and a timezone indicator (Z
for UTC or +hh:mm
or -hh:mm
) where:
YYYY
indicates a year (0001
through 9999
)MM
indicates a month (01
through 12
)DD
indicates a day (01
through 31
)hh
indicates an hour (00
through 23
)mm
indicates a minute (00
through 59
)ss
indicates a second (00
through 59
)Examples of valid datetime values include 2015-03-20
(a date), 2016-03-09T11:58:19+10:00
, and 2017-08-21T12:24:28-06:00
.
[0-9]+\.[0-9][0-9] [A-Z][A-Z][A-Z]
), for instance 0.80 USD
.
A nonnegative integer representing the current state of a patron account. Possible values are:
A PAIA server MAY define additional states which can be mapped to 1
by PAIA clients. In JSON account states MUST be encoded as numbers instead of strings.
A nonnegative integer representing the current status in fulfillment of a service. In most cases the service is related to a document, so the service status is a relation between a particular document and a particular patron. Possible values are:
A PAIA server MUST NOT define any other service status. In JSON service status MUST be encoded as numbers instead of strings.
A document is a key-value structure with the following fields:
name | occ | data type | description |
---|---|---|---|
status | 1..1 | service status | status (0, 1, 2, 3, 4, or 5) |
item | 0..1 | URI | URI of a particular copy |
edition | 0..1 | URI | URI of a the document (no particular copy) |
requested | 0..1 | URI | URI that was originally requested |
about | 0..1 | string | textual description of the document |
label | 0..1 | string | call number, shelf mark or similar item label |
queue | 0..1 | nonnegative integer | number of waiting requests for the document or item |
renewals | 0..1 | nonnegative integer | number of times the document has been renewed |
reminder | 0..1 | nonnegative integer | number of times the patron has been reminded |
starttime | 0..1 | datetime | date and time when the status began |
endtime | 0..1 | datetime | date and time when the status will expire |
duedate | 0..1 | date | date when the current status will expire (deprecated) |
cancancel | 0..1 | boolean | whether an ordered or provided document can be canceled |
canrenew | 0..1 | boolean | whether a document can be renewed |
error | 0..1 | string | textual document error, for instance if a request was rejected |
condition | 0..1 | condition | condition (only in responses to request, renew, or cancel) |
storage | 0..1 | string | textual description of location of the document |
storageid | 0..1 | URI | URI of location of the document |
For each document at least an item URI or an edition URI MUST be given. Together, item and edition URI MUST uniquely identify a document within the set of documents related to a patron.
The fields starttime
and endtime
MUST be interpreted as following:
status | starttime | endtime |
---|---|---|
0 | - | - |
1 | when the document was reserved | when the reserved document is expected to be available |
2 | when the document was ordered | when the ordered document is expected to be available |
3 | when the document was lend | when the loan period ends or ended (due) |
4 | when the document is provided | when the provision will expire |
5 | when the request was rejected | - |
Note that timezone information is mandatory in these fields. The field duedate
is deprecated. Clients SHOULD only use it as endtime
if no endtime
was given.
If both storage
and storageid
are given, a PAIA server MUST return identical values of storage
for identical id
and identical content language. PAIA clients MAY override the value of storage
based on storageid
and a preferred language.
Unknown document URIs and failed attempts to request, renew, or cancel a document MUST NOT result in a request error. Instead they are indicated by a document error with field error
. Form and type of document errors are not specified, so clients SHOULD use these messages for display only.
If condition
is given, a PAIA server MUST also include a document error for the same document, for instance the error message “confirmation required”. This allows PAIA clients without support of conditions and conformations to treat conditions as simple, unrecoverable document errors.
An example of a document serialized in JSON is given below. In this case a general document (http://example.org/documents/9876543
) was requested an mapped to a particular copy (http://example.org/items/barcode1234567
) by the PAIA server. The copy turned out to be lost, so the request was rejected (status 5) at 2014-07-12, 14:07 UTC.
{
"status": 5,
"item": "http://example.org/items/barcode1234567",
"edition": "http://example.org/documents/9876543",
"requested": "http://example.org/documents/9876543",
"starttime": "2014-07-12T14:07Z",
"error": "sorry, we found out that our copy is lost!"
}
The following document could result from a request for an item given by an unknown URI:
{
"item": "http://example.org/some/uri",
"error": "item URI not found"
}
Conditions and confirmations can OPTIONALLY be used to require or to select from additional options in PAIA core methods request, renew, and cancel. For instance a PAIA server MAY allow to choose among multiple delivery methods or it MAY require to explicitly agree to some terms of services when a special document is requested. A PAIA client without support of conditions and confirmations will always be assigned to the default option or it will experience a condition as document error if no default option is available.
A condition is a key-value structure that maps condition types to condition settings.
Conditions can be included in response field condition
of a document if the same document also includes a document error in field error
. The error SHOULD provide a short description of the condition, for instance “delivery type must be selected” or “confirmation required”.
A condition type is an URI that identifies the purpose of a condition. A PAIA client MUST be able to handle arbitrary condition type URIs. A PAIA server SHOULD support at least the following two condition types:
A condition setting is a key-value structure with the following keys:
name | occ | data type | description |
---|---|---|---|
option | 1..n | condition option | list of condition options |
multiple | 0..1 | boolean | whether multiple options can be selected |
default | 0..n | URI | set of default option identifiers |
A missing field multiple
MUST be treated equal to a multiple
field with value false
. The field default
MAY be an empty array — this case MUST NOT be confused with a missing field default
. All URIs listed in field default
MUST also be included as field id
of one condition option.
If multiple condition options are given, they SHOULD be ordered, for instance by popularity.
A condition option is a key-value structure with the following keys:
name | occ | data type | description |
---|---|---|---|
id | 1..1 | URI | unique identifier of this option |
about | 1..1 | string | textual description or label of this option |
amount | 0..1 | money | fee implied by chosing this option |
A condition setting MUST NOT contain multiple condition options with same id
. A PAIA server MUST return identical values of about
for identical values of id
and identical content language. PAIA clients MAY override the value of about
based on id
and a preferred language.
Values of amout
matching the regular expression /^0+\.00/
MUST be treated equal to no amount and vice versa.
A PAIA server SHOULD use the condition option id http://purl.org/ontology/dso#DocumentService or other URIs from the Document Service Ontology for condition options of type http://purl.org/ontology/paia#FeeCondition. Id and amount of the selected condition option SHOULD later occurr in response to request method fees.
Most simple condition only contain a single condition type. In the following example condition type http://purl.org/ontology/paia#FeeCondition is mapped to a condition setting with one condition option. No default option is given, so an explicit confirmation is required.
{
"http://purl.org/ontology/paia#FeeCondition": {
"option": [
{
"id": "http://purl.org/ontology/dso#Loan",
"about": "loan",
"amount": "0.50 EUR"
}
]
}
}
The following condition contains two condition types. The first condition type (http://purl.org/ontology/paia#StorageCondition) refers to a list of delivery places. The first place is marked as default and the third place implies a fee. The second condition type (http://example.org/purpose) lists two options which can also be selected together. An empty set is given as default option.
{
"http://purl.org/ontology/paia#StorageCondition": {
"option": [
{
"id": "http://example.org/locations/pickup-desk",
"about": "pickup desk"
},
{
"id": "http://example.org/locations/branch",
"about": "branch office"
},
{
"id": "http://example.org/services/home-delivery",
"amount": "2.50 EUR",
"about": "home delivery"
}
],
"default": [ "http://example.org/locations/pickup-desk" ]
},
"http://example.org/purpose": {
"multiple": true,
"option": [
{
"id": "http://example.org/purpose/research",
"about": "document usage for research"
},
{
"id": "http://example.org/purpose/leisure",
"about": "document usage for leisure"
}
],
"default": [ ]
}
}
Confirmations can be sent as part of a PAIA core request of methods request, renew, and cancel in field confirm
of a document to choose among condition options for selected condition types.
A confirmation is a key-value structure that maps condition types to (possibly empty) sets of identifiers of selected condition options.
This confirmation confirms condition type http://purl.org/ontology/paia#FeeCondition with condition option identified by http://purl.org/ontology/dso#DocumentService and confirms another condition type with two options from the example condition given above:
{
"http://purl.org/ontology/paia#FeeCondition": [
"http://purl.org/ontology/dso#DocumentService"
],
"http://example.org/purpose": [
"http://example.org/purpose/research",
"http://example.org/purpose/leisure"
]
}
Valid confirmations can be empty, which is distinct from a missing confirmation. Confirmations can also contain empty lists of option identifiers:
{ }
{ "http://purl.org/ontology/paia#FeeCondition": [ ] }
A PAIA server MUST use the following algorithm or an equivalent mechanism to check whether a given condition is met by a given confirmation or by a missing confirm
field. If a condition is not met, the server MUST return a document error for the given document.
If no confirmation is given, a default confirmation is created by mapping all condition types to the default values of their condition settings.
All condition types in the conformation are removed, unless they have a correspondence in the condition.
All condition option identifiers in the conformation are removed, unless they also occur in the condition settings of the corresponding condition.
If the confirmation contains multiple condition option identifiers for a condition type that does not have a condition setting with field multiple
set to true
, all but the first identifier are removed.
The condition is not met, if there is a condition type in the condition without correspondence in the confirmation.
The condition is met if for each condition setting either field default
is set to the empty array ([ ]
) or the corresponding list of remaining option identifiers in the confirmation is not empty.
To not select any default confirmation options, a PAIA client can send an empty object ({ }
).
Non applying condition types or options in a confirmation are ignored, so a PAIA client can choose to always sent some custom default confirmation.
The following condition contains the empty set as default value, so it is met by any confirmation except a confirmation that does not include condition type http://example.org/purpose (for instance { }
):
{
"http://example.org/purpose": {
"multiple": true,
"option": [
{ "id": "http://example.org/research", "about": "for research" },
{ "id": "http://example.org/leisure", "about": "for leisure" }
],
"default": [ ]
}
All other possible confirmations are reduced to one of this cases (the first also used if no confirmation is given):
{ "http://example.org/purpose": [ ] }
{ "http://example.org/purpose": [ "http://example.org/research" ] }
{ "http://example.org/purpose": [ "http://example.org/leisure" ] }
{ "http://example.org/purpose": [ "http://example.org/research", "http://example.org/leisure" ] }
Each API method of PAIA core is accessed at a URL that includes the URI escaped patron identifier.
name | occ | data type | description |
---|---|---|---|
name | 1..1 | string | full name of the patron |
0..1 | email address of the patron | ||
address | 0..1 | string | freeform address of the patron |
expires | 0..1 | datetime | patron account expiry |
status | 0..1 | account state | current state (0, 1, 2, or 3) |
type | 0..n | URI | list of custom URIs to identify patron types |
PAIA server documentation SHOULD refer to a specialized API, such as LDAP, to get more detailed patron information.
GET /core/123 HTTP/1.1
Host: example.org
User-Agent: MyPAIAClient/1.0
Accept: application/json
Authorization: Bearer a0dedc54bbfae4b
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-Accepted-OAuth-Scopes: read_patron
X-OAuth-Scopes: read_fees read_items read_patron write_items
{
"name": "Jane Q. Public",
"email": "jane@example.org",
"address": "Park Street 2, Springfield",
"expires": "2015-05-18",
"status": 0,
"type": ["http://example.org/usertypes/default"]
}
name | occ | data type | description |
---|---|---|---|
name | 0..1 | string | new full name of the patron |
0..1 | new email address of the patron | ||
address | 0..1 | string | new freeform address of the patron |
This PAIA core method can be used to modify parts of the general patron information: Fields “name”, “email”, and “address” can be changed with scope update_patron
for all of these fields, or with the scopes update_patron_name
, update_patron_email
, and/or update_patron_address
for each corresponding field.
This PAIA core method will be introduced with PAIA 1.4.0. A PAIA server MAY chose not not implement this method and return an error response with error code access_denied
(403), invalid_request
(405), or not_implemented
(501) instead.
Update of patron fields expires, status, and type via this method is not supported. To change a patron password see method change of PAIA auth.
PATCH /core/123 HTTP/1.1
Host: example.org
User-Agent: MyPAIAClient/1.0
Accept: application/json
Content-Type: application/json
Authorization: Bearer 08568be488a2539
{
"email": "janes-new-mail@example.com"
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-Accepted-OAuth-Scopes: update_patron update_patron_email
X-OAuth-Scopes: read_patron update_patron
{
"name": "Jane Q. Public",
"email": "janes-new-mail@example.com",
"address": "Park Street 2, Springfield",
"expires": "2015-05-18",
"status": 0,
"type": ["http://example.org/usertypes/default"]
}
name | occ | data type | description |
---|---|---|---|
doc | 0..n | document | list of documents (order is irrelevant) |
In most cases, each document will refer to a particular copy (doc.item
), but users may also have requested (doc.requested
) and/or reserved (doc.edition
) an edition.
GET /core/123/items HTTP/1.1
Host: example.org
User-Agent: MyPAIAClient/1.0
Accept: application/json
Authorization: Bearer a0dedc54bbfae4b
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-Accepted-OAuth-Scopes: read_patron
X-OAuth-Scopes: read_items read_patron
{
"doc": [{
"status": 3,
"item": "http://bib.example.org/105359165",
"edition": "http://bib.example.org/9782356",
"about": "Maurice Sendak (1963): Where the wild things are",
"label": "Y B SEN 101",
"queue": 0,
"renewals": 0,
"reminder": 0,
"starttime": "2014-05-08T12:37Z",
"endtime": "2014-06-09",
"cancancel": false,
},{
"status": 1,
"item": "http://bib.example.org/8861930",
"about": "Janet B. Pascal (2013): Who was Maurice Sendak?",
"label": "BIO SED 03",
"queue": 1,
"starttime": "2014-05-12T18:07Z",
"endtime": "2014-05-24",
"cancancel": true,
"storage": "pickup service desk",
"storageid": "http://bib.example.org/library/desk/7",
}]
}
name | occ | data type | description |
---|---|---|---|
doc | 1..n | array | list of documents requested |
doc.item | 0..1 | URI | URI of a particular item |
doc.edition | 0..1 | URI | URI of a particular edition |
doc.confirm | 0..1 | confirmation | Confirmation |
doc.storageid | 0..1 | URI | Requested document location (deprecated) |
name | occ | data type | description |
---|---|---|---|
doc | 1..n | document | list of documents (order is irrelevant) |
The response SHOULD include the same documents as requested. A client MAY also use the items method to get the service status after request.
The field doc.storageid
is deprecated and MUST be ignored if field doc.confirm
is given. Otherwise a PAIA core server SHOULD map the value of field doc.storageid
(e.g http://example.org/a/location
) to a corresponding confirmation in field doc.confirm
:
{
"http://purl.org/ontology/paia#StorageCondition": [
"http://example.org/a/location"
]
}
doc | 1..n | array | list of documents to renew |
doc.item | 0..1 | URI | URI of a particular item |
doc.edition | 0..1 | URI | URI of a particular edition |
doc.confirm | 0..1 | confirmation | Confirmation |
name | occ | data type | description |
---|---|---|---|
doc | 1..n | document | list of documents (order is irrelevant) |
The response SHOULD include the same documents as requested. A client MAY also use the items method to get the service status after renewal.
name | occ | data type | |
---|---|---|---|
doc | 1..n | array | list of documents to cancel |
doc.item | 0..1 | URI | URI of a particular item |
doc.edition | 0..1 | URI | URI of a particular edition |
doc.confirm | 0..1 | confirmation | Confirmation |
name | occ | data type | description |
---|---|---|---|
doc | 1..n | document | list of documents (order is irrelevant) |
name | occ | data type | description |
---|---|---|---|
amount | 0..1 | money | sum of all fees. May also be negative. |
fee | 0..n | array | list of fees |
fee.amount | 1..1 | money | amount of a single fee |
fee.date | 0..1 | date | date when the fee was claimed |
fee.about | 0..1 | string | textual information about the fee |
fee.item | 0..1 | URI | item that caused the fee |
fee.edition | 0..1 | URI | edition that caused the fee |
fee.feetype | 0..1 | string | textual description of the type of service that caused the fee |
fee.feeid | 0..1 | URI | URI of the type of service that caused the fee |
A PAIA server MUST return identical values of fee.feetype
for identical fee.feeid
and identical content language. PAIA clients MAY override the value of fee.feetype
based on fee.feeid
and a preferred language.
If a fee was caused by a document (fee.item
or fee.edition
is set) then fee.feeid
SHOULD be taken as http://purl.org/ontology/dso#DocumentService if not given and SHOULD be a class URI from the Document Service Ontology otherwise. If the fee was confirmed with a confirmation, the value of fee.feeid
SHOULD be the value of the confirmed condition option.
GET /core/123/fees HTTP/1.1
Host: example.org
User-Agent: MyPAIAClient/1.0
Accept: application/json
Authorization: Bearer 90245facece931f
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-Accepted-OAuth-Scopes: read_fees
X-OAuth-Scopes: read_patron read_items read_fees
{
"amount": "18.00 EUR",
"fee": [
{
"amount": "15.00 EUR",
"date": "2016-05-13T00:00:00Z",
"about": "annual fee"
},
{
"amount": "2.50 EUR",
"date": "2016-08-01T13:17:02Z",
"item": "http://bib.example.org/105359165",
"feeid": "http://example.org/services/home-delivery",
"feetype": "home delivery"
},
{
"amount": "0.50 EUR",
"date": "2016-09-02T12:30:00Z",
"item": "http://bib.example.org/105359165",
"about": "late return",
"feeid": "http://purl.org/ontology/dso#Loan",
"feetype": "loan"
}
]
}
PAIA core server are not required to track lists of fees. A plain sum can be returned as single value like this:
{
"amount": "3.00 EUR",
"fee": [ { "amount": "3.00 EUR" } ]
}
PAIA auth defines three methods for authentication based on username and password. These methods can be used to get access tokens and patron identifiers, which are required to access PAIA core methods. There MAY be additional or alternative ways to distribute and manage access tokens and patron identifiers.
There is no strict one-to-one relationship between username/password and patron identifier/access token, but a username SHOULD uniquely identify a patron identifier. A username MAY even be equal to a patron identifier, but this is NOT RECOMMENDED. An access token MUST NOT be equal to the password of the same user.
A PAIA auth server acts as OAuth authorization server (RFC 6749) with password credentials grant, as defined in section 4.3 of the OAuth 2.0 specification. The access tokens provided by the server are so called OAuth 2.0 bearer tokens (RFC 6750).
A PAIA auth server MUST protect against brute force attacks (e.g. using rate-limitation or generating alerts). It is RECOMMENDED to further restrict access to PAIA auth to specific clients, for instance by additional authorization.
The PAIA auth login
method is the only PAIA method that does not require an access token as part of the query.
name | occ | data type | |
---|---|---|---|
username | 1..1 | string | User name of a patron |
password | 1..1 | string | Password of a patron |
grant_type | 1..1 | string | Fixed value set to “password” |
scope | 0..1 | string | Space separated list of scopes |
If no scope
parameter is given, it is set to the default value read_patron read_fees read_items write_items
for full access to all PAIA core methods (see access tokens and scopes).
The response format is a JSON structure as defined in section 5.1 (successful response) and section 5.2 (error response) of OAuth 2.0. The PAIA auth server MAY grant different scopes than requested for, for instance if the account of a patron has expired, so the patron should not be allowed to request and renew new documents.
name | occ | data type | description |
---|---|---|---|
patron | 1..1 | string | Patron identifier |
access_token | 1..1 | string | The access token issued by the PAIA auth server |
token_type | 1..1 | string | Fixed value set to “Bearer” or “bearer” |
scope | 1..1 | string | Space separated list of granted scopes |
expires_in | 0..1 | nonnegative integer | The lifetime in seconds of the access token |
A successful login request:
POST /auth/login
Host: example.org
User-Agent: MyPAIAClient/1.0
Accept: application/json
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=alice02&password=jo-!97kdl%2B0tt
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-OAuth-Scopes: read_patron read_fees read_items write_items
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "2YotnFZFEjr1zCsicMWpAA",
"token_type": "Bearer",
"expires_in": 3600,
"patron": "8362432",
"scope": "read_patron read_fees read_items write_items"
}
Response to a rejected login request:
HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
Cache-Control: no-store
Pragma: no-cache
WWW-Authenticate: Bearer realm="PAIA auth example"
{
"error": "access_denied",
"error_description": "invalid patron or password"
}
name | occ | data type | description |
---|---|---|---|
patron | 1..1 | string | patron identifier |
name | occ | data type | description |
---|---|---|---|
patron | 1..1 | string | patron identifier |
The logout method invalidates an access token, independent from the previous lifetime of the token. On success, the server MUST invalidate at least the access token that was used to access this method. The server MAY further invalidate additional access tokens that were created for the same patron.
name | occ | data type | description |
---|---|---|---|
patron | 1..1 | string | Patron identifier |
username | 1..1 | string | User name of the patron |
old_password | 1..1 | string | Password of the patron |
new_password | 1..1 | string | New password of the patron |
name | occ | data type | description |
---|---|---|---|
patron | 1..1 | string | patron identifier |
The server MUST check
change_password
A PAIA server MAY reject this method and return an error response with error code access_denied
(403) or error code not_implemented
(501). On success, the patron identifier is returned.
Security of OAuth 2.0 with bearer tokens relies on correct application of HTTPS. It is known that SSL certificate errors are often ignored just because of laziness. It MUST be clear to all implementors that this breaks the chain of trust and is as secure as sending access tokens in plain text.
To limit the risk of spoiled access tokens, PAIA servers SHOULD put limits on the lifetime of access tokens and on the number of allowed requests per minute among other security limitations.
It is also known that several library systems allow weak passwords. For this reason PAIA auth servers MUST follow appropriate security measures, such as protecting against brute force attacks and blocking accounts with weak passwords or with passwords that have been sent unencrypted.
This non-normative section contains additional examples and explanations to illustrate the semantics of PAIA concepts and methods and usage.
Six service status data type values are possible. One document can have different status for different patrons and for different times. The following table illustrates reasonable transitions of service status with time for a fixed patron. For instance some document held by another patron is first requested (0 → 1) with PAIA method request, made available after return (1 → 4), picked up (4 → 3), renewed after some time with PAIA method renew (3 → 3) and later returned (3 → 0).
transition → | 0 | 1: reserved | 2: ordered | 3: held | 4: provided | 5: rejected |
---|---|---|---|---|---|---|
0 | = | request |
request |
loan | request |
request |
1: reserved | cancel |
= | available | loan | available | patron inactive, document lost … |
2: ordered | cancel |
/ | = | loan | available | patron inactive, document lost … |
3: held | return | / | / | renew |
/ | / |
4: provided | not picked up | / | / | loan | = | patron inactive, … |
5: rejected | time passed | patron active | patron active | / | patron active | = |
Transitions marked with “/” may also be possible in special circumstances: for instance a book ordered from the stacks (status 2) may turn out to be damaged, so it is first repaired and reserved for the patron meanwhile (status 1). Transitions for digital publications may also be different. Note that a PAIA server does not need to implement all service status. A reasonable subset is to only support 0, 1, 3, and 5.
The handling of digital documents is subject to frequently asked questions. The following rules of thumb may help:
document.edition
field should be used instead of document.item
.provided
and status held
. The status provided
should be preferred when the same document can be used by multiple patrons at the same time, and held
should be used when the document can exclusively be used by the patron.A future version of PAIA may be extended to support services not related to documents. For instance a patron may reserve a cabin or some other facility. The following methods may be added to PAIA core for this purpose:
Bradner, S. 1997. “RFC 2119: Key words for use in RFCs to Indicate Requirement Levels”. http://tools.ietf.org/html/rfc2119.
Crockford, D. 2006. “RFC 6427: The application/json Media Type for JavaScript Object Notation (JSON)”. http://tools.ietf.org/html/rfc4627.
Fielding, R. 1999. “RFC 2616: Hypertext Transfer Protocol”. http://tools.ietf.org/html/rfc2616.
D. Hardt. 2012. “RFC 6749: The OAuth 2.0 Authorization Framework”. http://tools.ietf.org/html/rfc6749.
Jones, M. and Hardt, D. 2012. “RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage”. http://tools.ietf.org/html/rfc6750.
van Kesteren, Anne. 2014. “Cross-Origin Resource Sharing” http://www.w3.org/TR/cors/
Rescorla, E. 2000. “RFC 2818: HTTP over TLS.” http://tools.ietf.org/html/rfc2818.
3M. 2006. “3M Standard Interchange Protocol Version 2.00“. http://mws9.3m.com/mws/mediawebserver.dyn?6666660Zjcf6lVs6EVs66S0LeCOrrrrQ-.
ILS-DI. 2008. “DLF ILS Discovery Interface Task Group (ILS-DI) Technical Recommendation - revision 1.1“ http://old.diglib.org/architectures/ilsdi/.
Katz, D. 2013. “ILS Driver (VuFind 2.x)“. http://vufind.org/wiki/vufind2:building_an_ils_driver.
NISO. 2010. “NISO Circulation Interchange Protocol (NCIP) - Z39.83-1-2008 Version 2.01“. http://www.ncip.info/.
Voß, J. 2015. “PAIA Ontology“. http://gbv.github.io/paia-rdf/.
Voß, J. 2014. “Document Service Ontology“ http://purl.org/ontology/dso.
“PAIA Wiki“. https://github.com/gbv/paia/wiki
This is version 1.3.0+3 of PAIA specification, last modified at 2016-12-05 with revision 599ba07.
Version numbers follow Semantic Versioning: each number consists of three numbers, optionally followed by +
and a suffix:
Releases with functional changes are tagged with a version number and included at https://github.com/gbv/paia/releases with release notes.
application/x-www-form-urlencoded
to align with OAuth 2.0 (issue #50)Access-Control-...
)WWW-Authenticate
headerdoc.storage
and deprecate field doc.storageid
type
address
starttime
and endtime
User-Agent
header2016-12-05 11:23:20 +0100
: Add fees example2016-12-05 10:39:56 +0100
: Add PAIA core method to update patron (#58)2015-11-16 09:52:47 +0100
: Adjust links and example2015-11-06 09:30:37 +0100
: Introduce conditions and confirmations2015-04-28 09:57:09 +0200
: PAIA auth requires application/x-www-form-urlencoded (#50)2015-04-21 15:19:10 +0200
: document semantic versioning2015-04-21 14:45:40 +0200
: remove request field doc.storage, deprecate doc.storageid2015-04-21 14:41:52 +0200
: mandatory HTTP OPTIONS for CORS (#46)2015-04-21 11:09:38 +0200
: rearranged section 32015-04-21 10:00:49 +0200
: updated readme2015-04-21 09:52:47 +0200
: include list of releases2015-04-21 08:50:27 +0200
: moved ‘How to contribute’ to wiki2015-04-16 14:53:42 +0200
: support content-negotiation for languages (issue #32)2015-04-16 14:33:26 +0200
: rearranged section 22015-04-16 13:44:22 +0200
: make clear that URLs can be chosen freely (issue #40)2015-04-16 13:34:34 +0200
: allow additional scopes2015-04-16 09:32:28 +0200
: PAIA ontology as independent specification (issue #21)2015-04-14 14:57:44 +0200
: add patron types2014-11-10 09:45:08 +0100
: include optional patron address field (#29)2014-09-10 10:58:53 +0200
: fix JSON example2014-07-16 13:24:24 +0200
: fixed timezone2014-07-16 12:07:03 +0200
: CORS (issue #37)2014-07-16 10:40:02 +0200
: typo2014-07-14 09:29:24 +0200
: fixed datetime2014-07-11 13:27:03 +0200
: include full example (issue #27)2014-07-11 11:02:00 +0200
: introduce starttime and endtime2014-07-02 11:54:22 +0200
: ontology2014-06-30 16:32:41 +0200
: Clients should send User-Agent header (issue #35)2014-05-16 09:26:25 +0200
: make clear that document errors are not specified2013-11-20 12:57:11 +0100
: example of a document error response2013-11-18 14:33:19 +0100
: extended PAIA ontology2013-10-31 12:32:07 +0100
: updated makespec2013-10-31 10:56:44 +0100
: Corrected logical, grammar, and spelling mistakes2013-07-17 09:34:52 +0200
: remove ‘code’ in PAIA auth error response, close #142013-07-17 09:25:57 +0200
: update makespec, closes issue #8 on charset2013-04-16 12:15:42 +0200
: synopsis, ontology, and informative parts2013-04-15 09:05:50 +0200
: note on non-document services (issue #16)2013-04-10 10:47:29 +0200
: fixes wrong examples, closes #182013-04-10 10:42:00 +0200
: introduced fee.feetype/feeid, closes #192013-04-10 10:16:48 +0200
: updated makespec2013-03-13 10:43:00 +0100
: started to tackle issue #15 and issue #162013-02-25 15:15:00 +0100
: more on the ontology2013-02-22 15:03:17 +0100
: correction on callback, closes #122013-02-22 15:00:31 +0100
: added WWW-Authentificate header, closes #112013-02-15 10:40:57 +0100
: clarified document return of renew and request2012-12-06 12:38:55 +0100
: charset and HTTP verbs2012-12-02 20:14:53 +0100
: whitespace and namespaces2012-12-02 10:05:51 +0100
: started with PAIA ontology2012-11-30 10:41:22 +0100
: change_password scope (issue #10)2012-11-19 11:27:31 +0100
: make URL-encoded HTTP POST optionalThe Simple Library Network Protocol (SLNP) and its variant XSLNP is an internal protocol of the the SISIS-Sunrise™ library system, providing access to patron information, among other functionality. OCLC does not allow publication of the specification or public use of SLNP.↩
The error list was compiled from the HTTP and OAuth 2.0 specifications, the Twitter API, the StackExchange API, and the GitHub API.↩