openapi: 3.0.0
info:
title: UCL Analytics Room Bookings API
description: "An API generated by a team of student developers to interact with student and university data at UCL.\n\nThe API is made up of several services, each of which will be separately explained. Every service will be documented here with important information, tips and examples.\n\n## Get Your API Key\n\nBefore you can use the API you should head to the API Dashboard and sign up using your UCL user account. Once logged into the dashboard simply name your app and you’ll be given a key that you can use to access all the services. Simple!\n\n## API Rate Limits\n\nRate limiting of the API is primarily on a per-user basis. The limit is calculated against the user, across all their access tokens.\n\nThe limit is 10,000 requests per day and resets every day at midnight, London time.\n\nWhen a request is throttled, the response returned by the server has HTTP Status Code “429 Too Many Requests”. It includes a Retry-After header with the number of seconds the client is throttled for.\n\nIf you would like your rate limit to be increased, contact us at isd.apiteam@ucl.ac.uk\n\n## API Data Freshness\n\nMuch of the data available from the API is served from cache. Bookings and Timetable data are updated every twenty minutes from UCL, and we update the [Library Study Spaces (Workspaces) API](https://uclapi.com/docs/#workspaces) every two minutes. The `Last-Modified` header will provide the time that the most recent caching operation completed in [RFC 2616](https://stackoverflow.com/a/21121453) format. Endpoints that do not rely on cached data will return the current timestamp in this field instead.\n\nThis allows your application to judge whether the data is stale, or might need refreshing. For example, if a booking is added to the database and the data you are using is more than twenty minutes old, it may be that the booking is not visible to you yet. Consider creating a fresh request in this case.\n\nIf you notice that the `Last-Modified` timestamp you see is unreasonably old, please [get in contact with us](mailto:isd.apiteam@ucl.ac.uk) ASAP to report this as it may indicate very stale data and an issue at our end.\n\n## OAuth\n\nOAuth is a protocol that lets external apps request secure access to private UCL account data without getting your password. This can be done with a \"Sign In With UCL\" button on your website or app which saves UCL users the trouble of registering a new account with you. It also allows your app or website to retrieve a user's personal timetable.\n\nCheck out a JS web app demo [here](https://uclapi-oauth-demo.glitch.me/). The source code for the demo is available [here](https://glitch.com/edit/#!/uclapi-oauth-demo).\n\nFor an example of a mobile app implementation, check out [UCL Assistant](https://github.com/uclapi/ucl-assistant-app) (written in React Native) and the accompanying [UCL Assistant API backend](https://github.com/uclapi/ucl-assistant-api/tree/master/src/oauth) (written in Node.JS).\n\n### Sign In With UCL Button\nIf you want to add a \"Sign In With UCL\" button to your site, which looks like this:\n\n<a href=\"https://uclapi.com/oauth/authorise?client_id=CLIENT_ID&state=STATE\">\n <img width=\"20%\" src=\"https://s3.eu-west-2.amazonaws.com/uclapi-static/SignInWithUCLSmall.png\">\n</a>\n\nyou can copy the following the code below and replace CLIENT_ID and STATE by the `client_id` of your app and a random `state`:\n\n```\n<a href=\"https://uclapi.com/oauth/authorise?client_id=CLIENT_ID&state=STATE\">\n <img src=\"https://s3.eu-west-2.amazonaws.com/uclapi-static/SignInWithUCLSmall.png\">\n</a>\n```\n\n### Scopes\n\nOAuth scopes specify what access your app needs to a UCL user’s account. As an app developer, you set the desired scopes in the API Dashboard. When a user is responding to your authorisation request, the requested scopes will be displayed to the user.\n\n### OAuth Workflow\n\nIf your application uses OAuth, you must set a callback URL in the dashboard. Then the app should follow this procedure:\n\n1. Redirect the user to `https://uclapi.com/oauth/authorise` with `state` and the application’s `client_id` as query parameters.\n\n2. The user logs in with their UCL credentials on the UCL Single Sign-on website (if not logged in already).\n\n3. The user reviews the OAuth scopes requested and either authorises or denies the application's request. If the application is authorised, the callback URL receives `client_id`, `state` (specified in 1.), `result`, and `code`.\n\nIf the application is denied, the callback URL receives `result` and `state`, and no private data will be provided to the application.\n\n4. To obtain a OAuth user token (necessary for retrieving personal data and certain API endpoints), we require `code` (from 3.), `client_id`, and `client_secret`. These should then be sent to `https://uclapi.com/oauth/token`, which will return a response containing `state`, `ok`, `client_id`, `token` (OAuth user token), and `scope` (OAuth scopes the app can access on the user’s behalf).\n\n**Note**: OAuth tokens and general API tokes are different. Whilst general API tokens can be used for all non-personal, generic data (such as room bookings), OAuth tokens must be used with an app's client_secret in order to retrieve personal data for a user. To make things easier, you can use personal OAuth tokens in place of general tokens once a user has logged into your app to retrieve generic data too.\n\n### Tokens\n\nTokens uniquely identify an app that is requesting data from the API.\n\nTokens are a long string variable of numbers and letters. e.g. `uclapi-5d58c3c4e6bf9c-c2910ad3b6e054-7ef60f44f1c14f-a05147bfd17fdb`.\n\nThere are two different kinds of tokens you can work with:\n\n1. Generic Tokens: These are tokens that are used to request non-personal data. These tokens are used between applications and the API to request any sort of data that the app may need that is not tied to a specific student. For example, UCL API’s Room booking service uses tokens to return information about rooms - when they are booked and which UCL rooms are free.\n\n2. OAuth Tokens: This type of token is used when an app requires personal data from users. One of the most common uses of this type of token is when you sign in via UCL on an app. The app will then use a token to request a user’s personal data such as:\n\n- Department\n- Email\n- Full name\n- Given name\n- UPI\n- If they are a student or not\n- Student number (*note:* to get this, you need to tick the relevant scope in the dashboard before a user logs in; more on scopes above).\n\nNote that you can also use OAuth Tokens to access all the same data that generic app tokens can access.\n\nEach token is uniquely generated for each user logging into each app.\n\nPlease note, access to any of this data needs to be approved by the user first.\n\nTo use this type of token for your app, you need to redirect the user to the \"Authorise\" endpoint at: `https://uclapi.com/oauth/authorise` which can be done directly or by including a “Sign in With UCL Button” in your app, such as the one provided below, which links users to the authorisation endpoint with your app’s Client ID (accessible via the dashboard) and a random state number included in the GET parameters.\n\nThe users then sign in with their UCL credentials and, if they authorise your app to use their personal data, a token will be generated which your app can use to get user’s personal data in JSON format from the oauth/user/data. Your application will receive the token at the callback URL you provided in the [Dashboard](https://uclapi.com/dashboard).\n\n## Code Samples\n\nAfter authorisation, calling most of the API endpoints will be fairly similar to each other. Authorisation code samples are provided in their respective descriptions.\n\nIn addition, please find short code examples of how you might call the `/roombookings/equipment` endpoint in your own code (you will find that only the request parameters will change between most different endpoints):\n\nPython:\n```python\nimport requests\n\nparams = {\n \"token\": \"uclapi-5d58c3c4e6bf9c-c2910ad3b6e054-7ef60f44f1c14f-a05147bfd17fdb\",\n \"roomid\": \"433\"\n \"siteid\": \"086\"\n}\n\nr = requests.get(\"https://uclapi.com/roombookings/equipment\", params=params)\nprint(r.json())\n```\n\nShell:\n```shell\ncurl -G https://uclapi.com/roombookings/equipment -d token=uclapi-5d58c3c4e6bf9c-c2910ad3b6e054-7ef60f44f1c14f-a05147bfd17fdb -d roomid=433 -d siteid=086\n```\n\nJavaScript:\n```js\nfetch(\"https://uclapi.com/roombookings/equipment?token=uclapi-5d58c3c4e6bf9c-c2910ad3b6e054-7ef60f44f1c14f-a05147bfd17fdb&roomid=433&siteid=086\")\n .then(response => response.json())\n .then(json => console.log(json));\n```"
contact:
name: API Support
email: isd.apiteam@ucl.ac.uk
url: https://uclapi.com
version: 1.0.0-oas3
termsOfService: https://github.com/uclapi/uclapi/blob/master/backend/uclapi/uclapi/UCLAPIAcceptableUsePolicy.txt
license:
url: https://github.com/uclapi/uclapi/blob/master/LICENSE
name: MIT License
servers:
- url: https://uclapi.com
description: Deployment server
- url: https://staging.ninja
description: Staging server
tags:
- name: Room Bookings
description: Fetch details of room bookings within UCL
paths:
/roombookings/rooms:
get:
summary: Returns rooms and information about them. If you don’t specify any query parameters besides the token, all rooms will be returned.
tags:
- Room Bookings
security:
- OAuthSecurity: []
OAuthToken: []
parameters:
- $ref: '#/components/parameters/roomname'
- $ref: '#/components/parameters/roomid'
- $ref: '#/components/parameters/siteid'
- $ref: '#/components/parameters/sitename'
- $ref: '#/components/parameters/classification'
- $ref: '#/components/parameters/capacity'
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
rooms:
type: array
items:
$ref: '#/components/schemas/room'
'400':
description: Request error
content:
application/json:
schema:
$ref: '#/components/schemas/error'
examples:
'1':
$ref: '#/components/examples/ErrorNoToken'
'2':
$ref: '#/components/examples/ErrorTokenNotExist'
'3':
$ref: '#/components/examples/ErrorInvalidToken'
'4':
$ref: '#/components/examples/ErrorThrottling'
'5':
$ref: '#/components/examples/ErrorNoClientSecret'
'6':
$ref: '#/components/examples/ErrorInvalidClientSecret'
'7':
$ref: '#/components/examples/ErrorInactiveToken'
Invalid capacity:
value:
ok: false
error: capacity should always be an int
/roombookings/bookings:
get:
summary: Returns the results to a bookings or space availability query. It returns a paginated list of bookings. Note that this endpoint only returns publicly displayed bookings. Departmental bookings are not included.
tags:
- Room Bookings
security:
- OAuthSecurity: []
OAuthToken: []
parameters:
- $ref: '#/components/parameters/roomname'
- $ref: '#/components/parameters/roomid'
- $ref: '#/components/parameters/start_datetime'
- $ref: '#/components/parameters/end_datetime'
- $ref: '#/components/parameters/date'
- $ref: '#/components/parameters/siteid'
- $ref: '#/components/parameters/description'
- $ref: '#/components/parameters/contact'
- $ref: '#/components/parameters/results_per_page'
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
next_page_exists:
type: boolean
page_token:
type: string
count:
type: number
bookings:
type: array
items:
$ref: '#/components/schemas/booking'
'400':
description: Request error
content:
application/json:
schema:
$ref: '#/components/schemas/error'
examples:
'1':
$ref: '#/components/examples/ErrorNoToken'
'2':
$ref: '#/components/examples/ErrorTokenNotExist'
'3':
$ref: '#/components/examples/ErrorInvalidToken'
'4':
$ref: '#/components/examples/ErrorThrottling'
'5':
$ref: '#/components/examples/ErrorNoClientSecret'
'6':
$ref: '#/components/examples/ErrorInvalidClientSecret'
'7':
$ref: '#/components/examples/ErrorInactiveToken'
Invalid date/time:
value:
ok: false
error: date/time isn't formatted as suggested in the docs
Invalid results_per_page:
value:
ok: false
error: results_per_page should be an integer
Non-existent page token:
value:
ok: false
error: Page token does not exist
/roombookings/equipment:
get:
summary: Returns any equipment/feature information about a specific room. So, for example whether there is a Whiteboard or a DVD Player in the room. A full example can be seen here.
tags:
- Room Bookings
security:
- OAuthSecurity: []
OAuthToken: []
parameters:
- $ref: '#/components/parameters/roomid'
- $ref: '#/components/parameters/siteid'
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
equipment:
type: array
items:
$ref: '#/components/schemas/equipment'
'400':
description: Request error
content:
application/json:
schema:
$ref: '#/components/schemas/error'
examples:
'1':
$ref: '#/components/examples/ErrorNoToken'
'2':
$ref: '#/components/examples/ErrorTokenNotExist'
'3':
$ref: '#/components/examples/ErrorInvalidToken'
'4':
$ref: '#/components/examples/ErrorThrottling'
'5':
$ref: '#/components/examples/ErrorNoClientSecret'
'6':
$ref: '#/components/examples/ErrorInvalidClientSecret'
'7':
$ref: '#/components/examples/ErrorInactiveToken'
Invalid roomid:
value:
ok: false
error: No roomid supplied
Invalid siteid:
value:
ok: false
error: No siteid supplied
/roombookings/freerooms:
get:
summary: Given a start time and an end time, this endpoint returns all rooms which are free in that time range.
tags:
- Room Bookings
security:
- OAuthSecurity: []
OAuthToken: []
parameters:
- $ref: '#/components/parameters/start_datetime'
- $ref: '#/components/parameters/end_datetime'
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
count:
type: integer
free_rooms:
type: array
items:
$ref: '#/components/schemas/room'
'400':
description: Request error
content:
application/json:
schema:
$ref: '#/components/schemas/error'
examples:
'1':
$ref: '#/components/examples/ErrorNoToken'
'2':
$ref: '#/components/examples/ErrorTokenNotExist'
'3':
$ref: '#/components/examples/ErrorInvalidToken'
'4':
$ref: '#/components/examples/ErrorThrottling'
'5':
$ref: '#/components/examples/ErrorNoClientSecret'
'6':
$ref: '#/components/examples/ErrorInvalidClientSecret'
'7':
$ref: '#/components/examples/ErrorInactiveToken'
Invalid parameters:
value:
ok: false
error: start_datetime or end_datetime not provided
Invalid date/time:
value:
ok: false
error: date/time isn't formatted as suggested in the docs
components:
parameters:
contact:
name: contact
in: query
description: The name of the person who made the booking. Substrings of the contact name can be used, Queries for Mark will include Mark Herbster. Sometimes, a society or student group may be the contact for a booking.
required: false
schema:
type: string
classification:
name: classification
in: query
description: The room type ID
required: false
schema:
type: string
end_datetime:
name: end_datetime
in: query
description: End datetime of the booking. Returns bookings with an end_datetime before the one supplied. Follows the ISO 8601 formatting standard.
required: false
schema:
type: string
siteid:
name: siteid
in: query
description: Every room is inside a site (building). All sites have IDs.
required: false
schema:
type: string
roomid:
name: roomid
in: query
description: The room ID (not to be confused with the roomname).
required: false
schema:
type: string
capacity:
name: capacity
in: query
description: Every room has a set capacity of how many people can fit inside it. When supplied, all rooms with the given capacity or greater will be returned.
required: false
schema:
type: string
date:
name: date
in: query
description: Date of the bookings you need, in the format YYYYMMDD. Returns bookings occurring on this day. This query parameter is only considered when end_datetime and start_datetime are not supplied.
required: false
schema:
type: string
roomname:
name: roomname
in: query
description: Every site (building) has a name. In some cases this is contained in the roomname as well.
required: false
schema:
type: string
description:
name: description
in: query
description: Describes what the booking is. Could contain a module code (for example WIBRG005) or just the type of activity (for example Lecture).
required: false
schema:
type: string
sitename:
name: sitename
in: query
description: Every site (building) has a name. In some cases this is contained in the roomname as well.
required: false
schema:
type: string
start_datetime:
name: start_datetime
in: query
description: Start datetime of the booking. Returns bookings with a start_datetime after the one supplied. Follows the ISO 8601 formatting standard.
required: false
schema:
type: string
results_per_page:
name: results_per_page
in: query
description: Number of bookings returned per page. Maximum allowed value is 1000. Defaults to 1000.
required: false
schema:
type: number
schemas:
room:
properties:
roomname:
type: string
example: Wilkins Building (Main Building) Portico
roomid:
type: string
example: Z4
siteid:
type: string
example: '005'
sitename:
type: string
example: Main Building
capacity:
type: string
example: 50
classification:
type: string
example: SS
classification_name:
type: string
example: Social Space
automated:
type: string
example: N
location:
type: object
properties:
address:
type: array
minItems: 4
maxItems: 4
items:
type: string
example:
- Gower Street
- London
- WC1E 6BT
coordinates:
type: object
properties:
lat:
type: number
example: '51.524699'
lng:
type: number
example: '-0.13366'
booking:
properties:
slotid:
type: number
example: 998503
end_time:
type: string
example: '2016-09-02T18:00:00+00:00'
description:
type: string
example: split weeks to assist rooming 29.06
roomname:
type: string
example: Torrington (1-19) 433
siteid:
type: number
example: 86.0
contact:
type: string
example: Ms Leah Markwick
weeknumber:
type: number
example: 1
roomid:
type: number
example: '433'
start_time:
type: string
example: '2016-09-02T09:00:00+00:00'
phone:
type: string
example: '45699'
equipment:
properties:
type:
type: string
example: FFF
description:
type: string
example: Managed PC
units:
type: number
example: 1
error:
type: object
properties:
ok:
type: boolean
default: false
error:
type: string
examples:
ErrorInactiveToken:
value:
ok: false
error: The token is inactive as the user has revoked your app's access to their data.
summary: Inactive token
ErrorNoClientSecret:
value:
ok: false
error: No Client Secret provided.
summary: No Client Secret provided
ErrorThrottling:
value:
ok: false
error: You have been throttled. Please try again in 10 seconds.
summary: Throttling
ErrorInvalidToken:
value:
ok: false
error: Token is invalid.
summary: Invalid token
ErrorTokenNotExist:
value:
ok: false
error: Token does not exist.
summary: Non-existent token
ErrorInvalidClientSecret:
value:
ok: false
error: Client secret incorrect.
summary: Client secret incorrect
ErrorNoToken:
value:
ok: false
error: No token provided.
summary: No token provided
securitySchemes:
OAuthToken:
type: apiKey
description: This API requires you to pass your OAuth2 token as a query parameter called 'token'. Use the /authorize and /oauth/token endpoints to authorize a user and get this token.
name: token
in: query
OAuthSecurity:
type: oauth2
description: This API uses OAuth2 with the implicit grant flow. [More info](https://uclapi.com/docs#OAuthSecurity)
flows:
authorizationCode:
authorizationUrl: /authorise
tokenUrl: /token
scopes:
personal_timetable: read user's timetable
student_number: read user's student number