API manual

DreamApply provides programmatic access to many application-related resources and actions via a RESTful API. This document should get you acquainted with issuing queries to the API.

Testing

Even though the API is based on HTTP requests, it is not possible to debug and test the service via the browse location bar. All requests require the authentication header to be set - see the “Authentication” section for details. This is not accomplished via the location bar. cURL should work fine of course, as do many REST tools, like Postman (for Chrome).

Please note that we have seen that all (most?) browser-based REST tools have difficulties displaying responses of the image type. For example, the REST query that returns the applicant's photo (image/jpeg) might show a “broken image” icon, even though the request succeeded.

Authentication and security

HTTPS

The first pre-requisite to securing the API, is HTTPS, which is always enabled automatically for all DreamApply instances.

HTTPS is of course HTTP-within-TLS, so TLS provides both confidentiality as well as integrity (via HMAC, to be precise - see 6.3.2). Given that any API calls are always placed over a secure channel enables us to simplify the API design a lot - most notably to avoid a complicated “custom” HMAC scheme (think: AWS). Also, we would not need to worry about re-play attacks and thus do not need to use a “nonce” to be transmitted with each request (another simplification).

Designing your own crypto protocols is not a good practice. Utilising existing and proven protocols, however, definitely is.

In short, HTTPS is a design requirement.

API key

In order to sign and authenticate your requests, you first need the API key. API keys are obtained via the administration interface (look under Settings → API). If you cannot find such a menu item, it means that the API feature has not been activated.

Remember, your API key is secret material. This is one reason why we require HTTPS to be a pre-requisite to using the API. An API key transmitted via an unsecured channel would be immediately compromised.

Authentication header

The name of the standard header is unfortunate because it carries authentication information, not authorization. Under the DreamApply API authentication scheme, the standard Authorization header that must be present in each and every request (except /api/version), takes the following form:

Authorization: DREAM apikey="Your secret API Key"

That's it! We derive most of the security mechanism from the use of HTTPS, most notably confidentiality (of the API key as well as the data sent and received), integrity (data cannot be altered while “in transit”) and mitigation against man-in-the-middle and re-play attacks.

Here is a quick way to make your first API request:

curl -v -X GET -H "Authorization: DREAM apikey=\"YOUR-API-KEY\"" https://apply.uni.edu/api/institutions

On the request above, apply.uni.edu is the domain for your DreamApply installation. It may also be in the form of “your-uni.dreamapply.com” if you have not yet configured the domain in DreamApply settings. Tip - you can add | python -m json.tool to the end of the command if you expect to receive JSON data (not all API queries return JSON) to prettify the output.

Versioning

The API version number will only incremented if backwards-incompatible changes have been introduced or in case if the semantics or data structure has been sufficiently changed to warrant a new version number. If, for example, some new data have been made available (a new field in the application, perhaps) the version number is not necessarily incremented as long as a client not aware of the changes is not disrupted. Backwards compatibility remains a high priority, but if it has to be broken, the previous API version will remain available (but not indefinitely).

By default, the latest version of the API is used for all requests. If you would like to use a specific API version for your queries, use the following syntax:

GET /api/v2/applicants/123/photo

If the version number is omitted, the latest version of the API is used:

GET /api/applicants/123/photo

Implications of using the latest version. Simply put, it means that if a certain query is no longer available in the latest version of the API, you will receive an error. The version number literally means the version of the API, not version of a particular API query. For example, if GET /api/something is removed (in favour of something else, perhaps) then all subsequent requests will return an error. To use such a legacy query, you would need to specify the last version of the API where the query still existed, like so: GET /api/v9/something. Similarly, any queries that were not yet available in a certain specified version, will return an error.

So summarise, we would recommend always prefixing all of your queries with the current API version. This guarantees a stable interface. You may always increment the version number to “unlock” new features or go back to a previous version if you prefer. But do not expect the API to do anything “magical”. The version number you specify defines the interface. If you fail to do so, you are on the “bleeding edge”. This might be good for testing, but before you go live, please stabilise the interface on your part.

To query the current API version, issue:

GET /api/version

If you happen to be using a version of the API that is about to be discontinued, we will make sure to notify you. We promise to never discontinue an API version before giving you a reasonable time to make any necessary changes.

Conventions

Identificators (ID-s)

All resources have numeric ID-s: applicant ID, application ID, tracker ID, institution ID etc.

  1. The ID-s carry no meaning or information
  2. The ID-s will never change
  3. There might be gaps between ID-s
  4. ID-s will never be reused in case they are deleted

This also applies in cases where it might seem redundant, such as trackers or flags, which have a uniquely defining properties already (flag's name or tracker's code). However, keep in mind that there might be a need to change a tracker's code or a flag's name. Since ID-s must never change, we cannot use such properties as ID-s.

API calls

The following section lists all API calls supported in the latest API version. Please take note:

  • In the examples only the relevant headers are depicted, for brevity;
  • HEAD and GET request syntax and responses are identical, except for the fact that for HEAD requests, the response body is omitted. In most cases, HEAD requests are to be used for checking if such a resource exist, what is the size of the resource or to return other metadata about the resource without actually transferring it. Use of the HEAD request is appreciated, whenever possible.
  • The Content-Length header is not always representative of the data being transferred. The API will, whenever possible, try to take advantage of compression. Thus, if the HEAD request reports the size of the resource, it is meant to be understood as the size of the resource, uncompressed. The actual data transmitted will, hopefully, be somewhat less due to compression.
  • Parameters that start with by.. indicate filtering parameters. For example byStatuses should be read as: “filter by statuses”.
  • Any lists appearing in filtering parameters may be either comma or space separated. All list items are combined with logical OR operators - in other words an application is considered matching if it matches to any of the values in the list.
  • Filtering parameters themselves, however, will be combined with a logical AND, hence the API calls will only return matching objects that satisfy all of the filters specified.
  • Typically, any resource ID's (such as the applicant ID 123 in api/applicants/123) are used in object keys in any representations enumerating the resources. For example /api/applicants will return the collection of applicants as a JSON object with the resource IDs as keys. You would expect to see something like that from /api/applicants:
{
  "123": { .. applicant properties .. },
  "124": { .. applicant properties .. },
  "125": { .. applicant properties .. }
}

Thus it follows that you can obtain more information about, say applicant 124 by issuing /api/applicants/124

List of API calls

This list is intended only to give a broad overview of the available API calls. Click on the links below to read detailed information regarding each API call.

API call (click to read) Type ♦ Verb ♠ Summary
/api/journal C GET HEAD List journal events. Start point for many integrations :!:
/api/applicants C GET HEAD List applicants using filters set as parameters
/api/applicants C POST Create a new applicant / lead and send welcome letter
/api/applicants/ID R GET HEAD Return information about an applicant
/api/applicants/ID/photo R GET HEAD Get the applicant's photo
/api/applicants/ID/consents C GET HEAD Get a list of consents that are associated with an applicant
/api/applicants/ID/consents/ID A GET HEAD Get information about a specific consent associated with an applicant
/api/applicants/ID/emails C GET HEAD Get a list of emails that are sent to an applicant
/api/applicants/ID/emails/ID A GET HEAD Get information about a specific emails sent to an applicant
/api/applicants/ID/trackers C GET HEAD Get a list of tracker associations
/api/applicants/ID/trackers/ID A GET HEAD Get information about a specific tracker set on an applicant
/api/applicants/ID/trackers/ID A PUT Set a tracker code to the applicant in question
/api/applicants/ID/trackers/ID A DELETE Remove the tracker code from the applicant in question
/api/applicants/ID/invoices C GET HEAD List invoices for this applicant
/api/applicants/ID/invoices/ID R GET HEAD Get information about an applicant invoice
/api/applicants/ID/wishes C GET HEAD Applicants wishlist
/api/applicants/ID/wishes/ID R GET HEAD Get information about an applicant wishlist item
/api/applicants/ID/applications C GET HEAD List applications for this applicant
/api/applicants/ID/applications/ID R GET HEAD Get information about an applicant application
/api/applicants/ID/reference R GET HEAD Get the reference code for this applicant
/api/applicants/ID/reference R PUT Store a new reference code for this applicant
/api/applicants/consents C GET HEAD Get a list of all consents
/api/applicants/consents/ID R GET HEAD Get information about a specific consent
/api/applicants/trackers C GET HEAD Get a list of all trackers
/api/applicants/trackers C POST Create a new tracker
/api/applicants/trackers/ID R GET HEAD Get information about a specific tracker
/api/applicants/trackers/ID R DELETE Delete a tracker, removing it from all applicants
/api/applicants/ID/notes R GET HEAD Get the notes on the applicant
/api/applicants/ID/notes R PUT Set the notes box on an applicant card, overwriting existing
/api/applicants/ID/notes R PATCH Append to existing applicant notes
/api/applications C GET HEAD Get a list of applications that match the set filtering criterion
/api/applications/ID R GET HEAD Get the application contents (data input by the application).
/api/applications/ID/courses C GET HEAD List courses that have been added to this application
/api/applications/ID/courses/ID A GET HEAD Get information about a course and application association
/api/applications/ID/flags C GET HEAD List all flags assigned to the application in question.
/api/applications/ID/flags/ID A GET HEAD Get information about a specific flag set to an application
/api/applications/ID/flags/ID A PUT Set the flag to the application in question.
/api/applications/ID/flags/ID A DELETE Remove the flag from the application in question.
/api/applications/ID/offers C GET HEAD List offers created for this application
/api/applications/ID/offers/ID R GET HEAD Get information about a specific application offer
/api/applications/ID/offers/ID/type R GET HEAD Get the offer type of a specific application offer
/api/applications/ID/offers/ID/type R PUT Set the offer type of the application offer in question
/api/applications/ID/offers/ID/subject R GET HEAD Get the subject line of a specific application offer
/api/applications/ID/offers/ID/subject R PUT Set the subject line of the application offer in question
/api/applications/ID/offers/ID/comments R GET HEAD Get the offer letter text/comments of a specific application offer
/api/applications/ID/offers/ID/comments R PUT Set the offer letter text/comments of the application offer in question
/api/applications/ID/offers/ID/confirm R POST Confirm an offer
/api/applications/ID/offers/ID/decision R GET HEAD Get the decision of a specific application offer
/api/applications/ID/offers/ID/decision R PUT Set the decision of the application offer in question
/api/applications/ID/offers/ID/notes R GET HEAD Get the notes on the offer
/api/applications/ID/offers/ID/notes R PUT Set the notes box on an offer, overwriting existing
/api/applications/ID/offers/ID/notes R PATCH Append to existing offer notes
/api/applications/ID/offers/ID/score/extra R GET HEAD Get the extra score of a specific application offer
/api/applications/ID/offers/ID/score/extra R PUT Set the extra score of the application offer in question
/api/applications/ID/offers/ID/score/extra R DELETE Clear the extra score of the application offer in question
/api/applications/ID/tasks C GET HEAD List tasks created for this application
/api/applications/ID/tasks/ID R GET HEAD Get information about a specific application task
/api/applications/ID/tasks/ID/status R GET HEAD Get the status of a specific application task
/api/applications/ID/tasks/ID/status R PUT Set the status to the application task in question
/api/applications/ID/exports C GET HEAD List all exports that have been generated from the application in question
/api/applications/ID/exports/ID R GET HEAD Fetch a specific application export identified by the export ID
/api/applications/ID/exports/ID/blobs C GET HEAD Get a list of the downloadable files (blobs) regarding this export
/api/applications/ID/exports/ID/blobs/blob R GET HEAD Retrieve a downloadable file (blob) regarding this export
/api/applications/ID/documents C GET HEAD Get a list of documents attached to this application
/api/applications/ID/documents/ID R GET HEAD Get a specific applicant document (binary data)
/api/applications/ID/scores C GET HEAD Get a list of scores for this application
/api/applications/ID/pdf C GET HEAD Get The PDF printout of this application
/api/applications/ID/invoices C GET HEAD List invoices for this application
/api/applications/ID/invoices C POST Create an invoice for this application
/api/applications/ID/invoices/ID R GET HEAD Get information about an application invoice
/api/applications/flags C GET HEAD Get a list of all flags
/api/applications/flags C POST Create a new flag
/api/applications/flags/ID R GET HEAD Get information about a specific flag
/api/applications/flags/ID R DELETE Delete a flag, removing it from all applications
/api/applications/statuses R GET HEAD Get a list of all application statuses
/api/applications/offers/types R GET HEAD Get a list of all offer types
/api/institutions C GET HEAD List institutions using filters set as parameters
/api/institutions/ID R GET HEAD More detailed information about a specific institution
/api/institutions/ID/departments C GET HEAD List departments under the given institution
/api/institutions/ID/departments/ID R GET HEAD Show information about a given institution department
/api/courses C GET HEAD List courses using filters set as parameters
/api/courses C POST Create a new blank course
/api/courses/ID R GET HEAD More detailed information about a specific course
/api/intakes R GET HEAD List configured intakes
/api/intakes/ID R GET HEAD Get details of a specific intake
/api/invoices C GET HEAD List all issued invoices
/api/invoices/ID R GET HEAD Get more information about an invoice
/api/invoices/ID R DELETE Delete an invoice
/api/invoices/ID/transactions C GET HEAD List transactions of a specific invoice
/api/invoices/ID/transactions C POST Create transaction for invoice (“collect invoice”)
/api/invoices/ID/transactions/ID R GET HEAD Get more information about a transaction
/api/invoices/series R GET HEAD List invoice series
/api/invoices/transactions C GET HEAD List transactions
/api/invoices/transactions/ID R GET HEAD Get more information about a transaction
/api/academic-terms R GET HEAD Get a list of all academic terms configured
/api/academic-terms/ID R GET HEAD Get information about an academic term
/api/academic-terms/types R GET HEAD Get a list of all academic term types configured
/api/academic-terms/types/ID R GET HEAD Get information about an academic term type
/api/academic-years R GET HEAD Get a list of all academic years configured
/api/academic-years/year R GET HEAD Get information about an academic year
/api/classificators R GET HEAD Get a list of system classificators
/api/reports C GET HEAD List all reports available
/api/reports/ReportName R GET HEAD Request data from a specific report
/api/scoresheets C GET HEAD List all scoresheets
/api/scoresheets/ID R GET HEAD Get info about scoresheet
/api/scoresheets/ID/scores C GET HEAD Get scores
/api/scoresheets/ID/scores C POST Append an application for scoring
/api/scoresheets/ID/scores/ID R GET HEAD Get information about a score
/api/scoresheets/ID/scores/ID/points R GET HEAD Get the points of a scoresheet score
/api/scoresheets/ID/scores/ID/points R PUT Set the points of a scoresheet score
/api/scoresheets/ID/scores/ID/points R DELETE Clear the points of a scoresheet score
/api/scoresheets/ID/scores/ID/comments R GET HEAD Get the comments of a scoresheet score
/api/scoresheets/ID/scores/ID/comments R PUT Set the comments of a scoresheet score
/api/scoresheets/ID/scores/ID/comments R DELETE Clear the comments of a scoresheet score
/api/tableviews C GET HEAD List all tableviews created with the GUI
/api/tableviews/ID R GET HEAD Get more information about a tableview
/api/tableviews/ID/tabledata R GET HEAD Get the csv data from a tableview
/api/administrators R GET HEAD List all administrators in the system
/api/administrators/ID R GET HEAD Get information about an administrator
/api/ping R GET HEAD A dummy call for testing authentication

♦ The types are as follows: Collection, Resource, Association. The latter is an object that represents the relationship between two resources. It is used on one-to-many and many-to-many relationships. However, an association between an applicant and a tracker may carry some information itself, such as the time the association was established. Thus is a special kind of resource.

Where a GET verb is specified, a HEAD verb is also always available. A HEAD call will return everything that a GET call, except for the return body. See each individual API call for examples where this might be useful: retrieving only a count of items, getting just metadata (saving bandwidth) etc.

Response codes

More specific meanings of status codes are listed under individual API calls where applicable. Here you can find the general logic for HTTP status codes that apply generally.

Success

200 OK Generic success code
201 Created Used for indicating that a resource was created as a response to a POST request.
204 No Content Typical response for PUT and DELETE requests. Indicates that the work was carried out, but content is applicable.

Error

400 Bad Request Mostly used if the ID is not in the correct format on some of the filtering parameters are invalid
404 Not Found Usually indicates that the resource (generally identified by it's ID) does not exist. *

* Note that if you issue multiple DELETE requests for the same resource, you will receive this error on any subsequent requests.

Throttling

All API calls placed to the same API key are, by default, limited to 180 queries per minute and 600 queries per hour. Please note that 60 queries/minute is not the same as 1 query per second, see below.

If you exceed your API key queries-per-minute quota, you may start to receive 429 Too Many Requests responses. This means that the request was not processed and will have to be issued again.

In order to not throttle your queries in an overly intrusive manner, we count queries per minute and per hour. This means that if you happen to issue a few queries in a quick succession, you are fine. Only when the numbers start exceeding your per-minute or hourly quotas, will you start receiving the 429 Too Many Requests responses.

We also use other methods to monitor the amount of resources consumed with a specific API key and will notify you in case we find anything in your usage patterns that seems unreasonable or seems to constitute a bug on your part.