NAV Navbar
Shell HTTP JavaScript Ruby Python PHP Java Go

PlanetTerp API v1

Introduction

Select a language above to show examples of using the API in that language.

Welcome to PlanetTerp's API. This API provides access to data relating to courses, professors, and grade data at the University of Maryland — College Park (UMD).

The primary purpose of this API is to provide access to grade data. There is already a student-run API that provides access to professor and course data: umd.io.

This API is open source; you can check it out on GitHub. If you find any issues, please email us or create a ticket on GitHub. If you have an improvement, please submit a pull request.

The course and professor data on this website was obtained using a combination of umd.io and UMD's Schedule of Classes. The grade data is from the UMD Office of Institutional Research, Planning & Assessment (IRPA) and obtained through a request under the state of Maryland's Public Information Act (PIA).

The base URL of the API is https://api.planetterp.com/v1.

For support, please email admin@planetterp.com.

Usage

This API does not require any authentication. There are no hard rate limits, but please take a pause between each request.

The API has a Python wrapper on GitHub.

Example

Let's walk through an example of outputting the number of students who received an A in a course. This example will be written in Python.

In our program, a user will enter the course they want to receive data for. We will then determine the number of students who received an A and tell the user that number.

First, we read input from the user:

course_name = raw_input("Enter a course: ")

Next, we get data from the API. We will use the Grades endpoint. Specifically, we will get the grades for a course. To do this, we will use pass the course on the course parameter. The URL to do this is https://api.planetterp.com/v1/grades?course=COURSE_NAME.

We will get the data using the Requests Python library:

import requests
import json

grade_data = requests.get('https://api.planetterp.com/v1/grades?course=' + course_name).json()

Now we report the data to the user:

for course_grade_data in grade_data:
    print "Number of students who received an A in {course} section {section} for semester {semester}: {num_a}".format(course = course_grade_data['course'], section = course_grade_data['section'], semester = course_grade_data['semester'], num_a = course_grade_data['A']

At this point, when the user enters a course, they will be shown the number of students who received an A.

Let's handle the case where a user enters a course that hasn't been taught at UMD. If the user enters, for example, "ABCD123", we will receive this error: TypeError: string indices must be integers, because the endpoint did not return grade data and our program tried to access grade data that was not returned.

We can handle this error. If a course is requested on the API, and the course is not found, the following response is returned: {"error": "course not found"}. Let's handle this case:

if 'error' in grade_data and grade_data['error'] == "course not found":
    print "Error: Course not found."
else:
    ... print out relevant data

That's it! Here is our program:

import requests
import json
course_name = raw_input("Enter a course: ")

grade_data = requests.get('https://api.planetterp.com/v1/grades?course=' + course_name).json()

if 'error' in grade_data and grade_data['error'] == "course not found":
    print "Error: Course not found."
else:
    for course_grade_data in grade_data:
        print "Number of students who received an A in {course} section {section} for semester {semester}: {num_a}".format(course = course_grade_data['course'], section = course_grade_data['section'], semester = course_grade_data['semester'], num_a = course_grade_data['A'])

Courses

Get a course

# You can also use wget
curl -X GET https://api.planetterp.com/v1/course?name=MATH140

GET https://api.planetterp.com/v1/course?name=MATH140 HTTP/1.1
Host: api.planetterp.com


fetch('https://api.planetterp.com/v1/course?name=MATH140',
{
  method: 'GET'

})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

require 'rest-client'
require 'json'

result = RestClient.get 'https://api.planetterp.com/v1/course',
  params: {
  'name' => 'string'
}

p JSON.parse(result)

import requests

r = requests.get('https://api.planetterp.com/v1/course', params={
  'name': 'MATH140'
})

print(r.json())

<?php

require 'vendor/autoload.php';

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('GET','https://api.planetterp.com/v1/course', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

URL obj = new URL("https://api.planetterp.com/v1/course?name=MATH140");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
    new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
    response.append(inputLine);
}
in.close();
System.out.println(response.toString());

package main

import (
       "bytes"
       "net/http"
)

func main() {

    data := bytes.NewBuffer([]byte{jsonReq})
    req, err := http.NewRequest("GET", "https://api.planetterp.com/v1/course", data)
    req.Header = headers

    client := &http.Client{}
    resp, err := client.Do(req)
    // ...
}

Running the above returns something similar to the following:

{
    "department": "MATH",
    "course_number": "140",
    "title": "Calculus I",
    "description": "Introduction to calculus, including functions, limits, continuity, derivatives and applications of the derivative, sketching of graphs of functions, definite and indefinite integrals, and calculation of area. The course is especially recommended for science, engineering and mathematics majors.",
    "credits": 4,
    "professors": ["Jon Snow", "Tyrion Lannister"]
}

Get a course.

GET https://api.planetterp.com/v1/course

Query Parameters

Name Type Description
name string Required. Show the given course.
reviews boolean Optional. Show reviews for the course (reviews for professors that taught the course and have this course listed as the one being reviewed). Default: false

Get courses

# You can also use wget
curl -X GET https://api.planetterp.com/v1/courses?department=MATH&limit=1

GET https://api.planetterp.com/v1/courses?department=MATH&limit=1 HTTP/1.1
Host: api.planetterp.com


fetch('https://api.planetterp.com/v1/courses?department=MATH&limit=1',
{
  method: 'GET'

})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

require 'rest-client'
require 'json'

result = RestClient.get 'https://api.planetterp.com/v1/courses',
  params: {
  'department' => 'string',
'limit' => 'integer'
}

p JSON.parse(result)

import requests

r = requests.get('https://api.planetterp.com/v1/courses', params={
  'department': 'MATH',  'limit': '1'
})

print(r.json())

<?php

require 'vendor/autoload.php';

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('GET','https://api.planetterp.com/v1/courses', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

URL obj = new URL("https://api.planetterp.com/v1/courses?department=MATH&limit=1");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
    new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
    response.append(inputLine);
}
in.close();
System.out.println(response.toString());

package main

import (
       "bytes"
       "net/http"
)

func main() {

    data := bytes.NewBuffer([]byte{jsonReq})
    req, err := http.NewRequest("GET", "https://api.planetterp.com/v1/courses", data)
    req.Header = headers

    client := &http.Client{}
    resp, err := client.Do(req)
    // ...
}

Running the above returns something similar to the following:

[
    {
        "department": "MATH",
        "course_number": "140",
        "title": "Calculus I",
        "description": "Introduction to calculus, including functions, limits, continuity, derivatives and applications of the derivative, sketching of graphs of functions, definite and indefinite integrals, and calculation of area. The course is especially recommended for science, engineering and mathematics majors.",
        "credits": 4,
        "professors": ["Jon Snow", "Tyrion Lannister"]
  }
]

Get all courses, in alphabetical order.

GET https://api.planetterp.com/v1/courses

Query Parameters

Name Type Description
department string Optional. Only get courses in a department. Must be four characters. Default: all departments
reviews boolean Optional. Show reviews for the course (reviews for professors that taught the course and have this course listed as the one being reviewed). Default: false
limit integer Optional. Maximum number of records to return. Must be between 1 and 1000. Default: 100
offset integer Optional. Number of records to skip for pagination. Default: 0

Professors

Get a professor

# You can also use wget
curl -X GET https://api.planetterp.com/v1/professor?name=Jon%20Snow&reviews=true \
  -H 'Accept: application/json'

GET https://api.planetterp.com/v1/professor?name=Jon%20Snow&reviews=true HTTP/1.1
Host: api.planetterp.com
Accept: application/json


const headers = {
  'Accept':'application/json'
};

fetch('https://api.planetterp.com/v1/professor?name=Jon%20Snow&reviews=true',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get 'https://api.planetterp.com/v1/professor',
  params: {
  'name' => 'string',
'reviews' => 'boolean'
}, headers: headers

p JSON.parse(result)

import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('https://api.planetterp.com/v1/professor', params={
  'name': 'Jon Snow',  'reviews': 'true'
}, headers = headers)

print(r.json())

<?php

require 'vendor/autoload.php';

$headers = array(
    'Accept' => 'application/json',
);

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('GET','https://api.planetterp.com/v1/professor', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

URL obj = new URL("https://api.planetterp.com/v1/professor?name=Jon%20Snow&reviews=true");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
    new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
    response.append(inputLine);
}
in.close();
System.out.println(response.toString());

package main

import (
       "bytes"
       "net/http"
)

func main() {

    headers := map[string][]string{
        "Accept": []string{"application/json"},
    }

    data := bytes.NewBuffer([]byte{jsonReq})
    req, err := http.NewRequest("GET", "https://api.planetterp.com/v1/professor", data)
    req.Header = headers

    client := &http.Client{}
    resp, err := client.Do(req)
    // ...
}

Running the above returns something similar to the following:

{
    "name": "Jon Snow",
    "type": "professor",
    "slug": "snow",
    "courses": ["MATH140", "MATH141"],
    "reviews": [
                    {
                        "professor": "Jon Snow",
                        "course": "MATH140",
                        "review": "Jon Snow is a great professor!",
                        "rating": 5,
                        "expected_grade": "A",
                        "created": "2020-01-01T00:00:00"
                    }
                ]
}

Get a professor.

GET https://api.planetterp.com/v1/professor

Query Parameters

Name Type Description
name string Required. Show the given professor.
reviews boolean Optional. Show reviews for the professor. Default: false

Get all professors

# You can also use wget
curl -X GET https://api.planetterp.com/v1/professors?reviews=true&limit=1 \
  -H 'Accept: application/json'

GET https://api.planetterp.com/v1/professors?reviews=true&limit=1 HTTP/1.1
Host: api.planetterp.com
Accept: application/json


const headers = {
  'Accept':'application/json'
};

fetch('https://api.planetterp.com/v1/professors?reviews=true&limit=1',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get 'https://api.planetterp.com/v1/professors',
  params: {
  'reviews' => 'boolean',
'limit' => 'integer'
}, headers: headers

p JSON.parse(result)

import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('https://api.planetterp.com/v1/professors', params={
  'reviews': 'true',  'limit': '1'
}, headers = headers)

print(r.json())

<?php

require 'vendor/autoload.php';

$headers = array(
    'Accept' => 'application/json',
);

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('GET','https://api.planetterp.com/v1/professors', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

URL obj = new URL("https://api.planetterp.com/v1/professors?reviews=true&limit=1");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
    new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
    response.append(inputLine);
}
in.close();
System.out.println(response.toString());

package main

import (
       "bytes"
       "net/http"
)

func main() {

    headers := map[string][]string{
        "Accept": []string{"application/json"},
    }

    data := bytes.NewBuffer([]byte{jsonReq})
    req, err := http.NewRequest("GET", "https://api.planetterp.com/v1/professors", data)
    req.Header = headers

    client := &http.Client{}
    resp, err := client.Do(req)
    // ...
}

Running the above returns something similar to the following:

[
    {
        "name": "Jon Snow",
        "type": "professor",
        "slug": "snow",
        "courses": ["MATH140", "MATH141"],
        "reviews": [
                        {
                            "professor": "Jon Snow",
                            "course": "MATH140",
                            "review": "Jon Snow is a great professor!",
                            "rating": 5,
                            "expected_grade": "A",
                            "created": "2020-01-01T00:00:00"
                        }
                    ]
    }
]

Get all professors, in alphabetical order.

GET https://api.planetterp.com/v1/professors

Query Parameters

Name Type Description
type string Optional. Show only reviews for professors or teaching assistants. Default: show both. Options: professor, ta
reviews boolean Optional. Show reviews for the professors. Default: false
limit integer Optional. Maximum number of records to return. Must be between 1 and 1000. Default: 100
offset integer Optional. Number of records to skip for pagination. Default: 0

Grades

Get grades

# You can also use wget
curl -X GET https://api.planetterp.com/v1/grades?professor=Jon%20Snow&semester=202001&section=0101 \
  -H 'Accept: application/json'

GET https://api.planetterp.com/v1/grades?professor=Jon%20Snow&semester=202001&section=0101 HTTP/1.1
Host: api.planetterp.com
Accept: application/json


const headers = {
  'Accept':'application/json'
};

fetch('https://api.planetterp.com/v1/grades?professor=Jon%20Snow&semester=202001&section=0101',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get 'https://api.planetterp.com/v1/grades',
  params: {
  'professor' => 'string',
'semester' => 'string',
'section' => 'string'
}, headers: headers

p JSON.parse(result)

import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('https://api.planetterp.com/v1/grades', params={
  'professor': 'Jon Snow',  'semester': '202001',  'section': '0101'
}, headers = headers)

print(r.json())

<?php

require 'vendor/autoload.php';

$headers = array(
    'Accept' => 'application/json',
);

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('GET','https://api.planetterp.com/v1/grades', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

URL obj = new URL("https://api.planetterp.com/v1/grades?professor=Jon%20Snow&semester=202001&section=0101");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
    new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
    response.append(inputLine);
}
in.close();
System.out.println(response.toString());

package main

import (
       "bytes"
       "net/http"
)

func main() {

    headers := map[string][]string{
        "Accept": []string{"application/json"},
    }

    data := bytes.NewBuffer([]byte{jsonReq})
    req, err := http.NewRequest("GET", "https://api.planetterp.com/v1/grades", data)
    req.Header = headers

    client := &http.Client{}
    resp, err := client.Do(req)
    // ...
}

Running the above returns something similar to the following:

[
    {
        "course": "MATH140",
        "professor": "Jon Snow",
        "semester": "202001",
        "section": "0101",
        "A+": 1,
        "A": 1,
        "A-": 1,
        "B+": 1,
        "B": 1,
        "B-": 1,
        "C+": 1,
        "C": 1,
        "C-": 1,
        "D+": 1,
        "D": 1,
        "D-": 1,
        "F": 1,
        "W": 1,
        "Other": 1
    }
]

Get grades for a course, professor, or both. This endpoint returns all of the grades available by section.

GET https://api.planetterp.com/v1/grades

Query Parameters

Name Type Description
course string Optional. Show only grades for the given course.
professor string Optional. Show only grades for the given professor.
semester string Optional. Show only grades for the given semester. Semester should be provided as the year followed by the semester code. 01 means Spring and 08 means Fall. For example, 202001 means Spring 2020. Default: all semesters
section string Optional. Show only grades for the given section. Default: all sections