packages <- c("httr2", "jsonlite", "dplyr", "purrr", "tibble", "tidyr", "ggplot2", "knitr", "stringr", "scales")
missing_packages <- setdiff(packages, rownames(installed.packages()))
if (length(missing_packages) > 0) {
install.packages(missing_packages, repos = "https://cloud.r-project.org")
}
invisible(lapply(packages, library, character.only = TRUE))Assignment 10B: Nobel Prize JSON Code Base
Introduction
The Nobel Prize Developer Zone provides public data about Nobel laureates and awards through a JSON API. Continuing my Approach deliverable, I investigate how recognition varies across categories and decades, women’s representation, age at award, and differences between laureates’ birth countries and their award-time affiliation countries. The analysis follows the Nobel Prize API documentation and builds three related tidy tables so that shared awards and multiple affiliations are handled explicitly.
API Source, Request, and Workflow
I use the official Nobel Prize API v2.1 laureates endpoint: https://api.nobelprize.org/2.1/laureates. The request uses limit=250 and successive offset values (0, 250, 500, and so on) to retrieve all available pages, without an API key or local files. The public API can change as records are updated; the report displays the retrieval date.
My workflow is to fetch JSON, extract laureate-level fields, unnest each laureate’s prize records into an award-level table, and extract affiliations into a third table. I then validate identifiers, handle missing values, and answer each question with a table and (where appropriate) a visualization. One row in the award table means one laureate–prize record, not necessarily one distinct prize event.
R packages and API retrieval
The following setup installs missing CRAN packages only when necessary. An internet connection is required both for package installation (if needed) and the live API request.
I retrieve pages until the API returns fewer records than the requested page size. A non-successful request raises an informative error rather than silently producing an incomplete dataset.
api_url <- "https://api.nobelprize.org/2.1/laureates"
page_size <- 250L
fetch_page <- function(offset) {
response <- httr2::request(api_url) |>
httr2::req_url_query(limit = page_size, offset = offset) |>
httr2::req_user_agent("DATA607-NobelJSON-Analysis/1.0 (academic project)") |>
httr2::req_timeout(60) |>
httr2::req_retry(max_tries = 3) |>
httr2::req_perform()
# simplifyVector=FALSE preserves nested JSON arrays as lists.
jsonlite::fromJSON(httr2::resp_body_string(response), simplifyVector = FALSE)
}
all_laureates <- list()
offsets_fetched <- integer()
for (page_number in seq_len(50L)) {
offset <- (page_number - 1L) * page_size
parsed <- fetch_page(offset)
batch <- parsed$laureates
if (is.null(batch) || length(batch) == 0L) break
all_laureates <- c(all_laureates, batch)
offsets_fetched <- c(offsets_fetched, offset)
if (length(batch) < page_size) break
}
stopifnot(length(all_laureates) > 0L)
retrieved_on <- Sys.Date()
cat("Retrieved", length(all_laureates), "laureate objects on", as.character(retrieved_on),
"from offsets:", paste(offsets_fetched, collapse = ", "), "\n")Retrieved 1028 laureate objects on 2026-11-08 from offsets: 0, 250, 500, 750, 1000
Transform nested JSON into tidy tables
Some fields in the API are optional, and localized names are objects containing an en field. I define helpers that safely return NA for absent values, rather than letting one missing JSON field interrupt the analysis.
# Safely traverse a nested JSON object, returning NA for missing or empty values.
get_nested <- function(x, ...) {
keys <- list(...)
for (key in keys) {
if (is.null(x) || !is.list(x) || is.null(x[[key]])) return(NA_character_)
x <- x[[key]]
}
if (is.null(x) || length(x) == 0L || is.list(x)) return(NA_character_)
as.character(x[[1]])
}
clean_text <- function(x) {
x <- stringr::str_squish(as.character(x))
x[is.na(x) | x == ""] <- NA_character_
x
}
# The laureate ID is the stable join key. Birth-country-now is preferred for
# cross-country comparisons because historic political boundaries can differ.
laureates <- purrr::map_dfr(all_laureates, function(x) {
tibble::tibble(
laureate_id = get_nested(x, "id"),
laureate_name = dplyr::coalesce(
get_nested(x, "knownName", "en"),
get_nested(x, "orgName", "en"),
get_nested(x, "fullName", "en"),
get_nested(x, "fileName", "en")
),
gender = clean_text(get_nested(x, "gender")),
birth_date = get_nested(x, "birth", "date"),
birth_country = clean_text(dplyr::coalesce(
get_nested(x, "birth", "place", "countryNow", "en"),
get_nested(x, "birth", "place", "country", "en")
))
)
}) |>
dplyr::distinct(laureate_id, .keep_all = TRUE) |>
dplyr::mutate(birth_year = suppressWarnings(as.integer(substr(birth_date, 1, 4))))
# One award row per laureate and Nobel prize. Keep prize year and category.
awards <- purrr::map_dfr(all_laureates, function(x) {
laureate_id <- get_nested(x, "id")
prizes <- x$nobelPrizes
if (is.null(prizes) || length(prizes) == 0L) return(tibble::tibble())
purrr::map_dfr(prizes, function(p) {
tibble::tibble(
laureate_id = laureate_id,
award_year = suppressWarnings(as.integer(get_nested(p, "awardYear"))),
category = dplyr::coalesce(get_nested(p, "category", "en"),
get_nested(p, "categoryFullName", "en"),
get_nested(p, "category")),
prize_share = get_nested(p, "portion")
)
})
}) |>
dplyr::filter(!is.na(laureate_id), !is.na(award_year), !is.na(category)) |>
dplyr::distinct(laureate_id, award_year, category, .keep_all = TRUE) |>
dplyr::mutate(decade = (award_year %/% 10L) * 10L)
# One affiliation row per laureate, award, and listed affiliation.
# Some awards have no affiliation; those awards remain in the awards table.
affiliations <- purrr::map_dfr(all_laureates, function(x) {
laureate_id <- get_nested(x, "id")
prizes <- x$nobelPrizes
if (is.null(prizes) || length(prizes) == 0L) return(tibble::tibble())
purrr::map_dfr(prizes, function(p) {
affs <- p$affiliations
if (is.null(affs) || length(affs) == 0L) return(tibble::tibble())
purrr::map_dfr(seq_along(affs), function(i) {
a <- affs[[i]]
tibble::tibble(
laureate_id = laureate_id,
award_year = suppressWarnings(as.integer(get_nested(p, "awardYear"))),
category = dplyr::coalesce(get_nested(p, "category", "en"),
get_nested(p, "categoryFullName", "en"),
get_nested(p, "category")),
affiliation_number = i,
affiliation_country = clean_text(dplyr::coalesce(
get_nested(a, "countryNow", "en"),
get_nested(a, "country", "en")
))
)
})
})
}) |>
dplyr::distinct(laureate_id, award_year, category, affiliation_number,
.keep_all = TRUE)
# Validate table integrity before analysis.
stopifnot(!anyDuplicated(laureates$laureate_id))
stopifnot(!anyDuplicated(awards[c("laureate_id", "award_year", "category")]))
stopifnot(all(awards$laureate_id %in% laureates$laureate_id))
stopifnot(all(affiliations$laureate_id %in% laureates$laureate_id))
# Summary of the units of observation and missingness.
data_quality <- tibble::tibble(
Check = c("Unique laureates", "Laureate–award records", "Affiliation records",
"Laureates missing birth year", "Laureates missing birth country",
"Laureates with unspecified gender", "Affiliations missing country"),
Value = c(nrow(laureates), nrow(awards), nrow(affiliations),
sum(is.na(laureates$birth_year)),
sum(is.na(laureates$birth_country)),
sum(is.na(laureates$gender)),
sum(is.na(affiliations$affiliation_country)))
)
knitr::kable(data_quality, caption = "Validation and completeness overview")| Check | Value |
|---|---|
| Unique laureates | 1028 |
| Laureate–award records | 1036 |
| Affiliation records | 856 |
| Laureates missing birth year | 28 |
| Laureates missing birth country | 31 |
| Laureates with unspecified gender | 28 |
| Affiliations missing country | 3 |
knitr::kable(dplyr::slice_head(awards, n = 6), caption = "Sample tidy laureate–award records")| laureate_id | award_year | category | prize_share | decade |
|---|---|---|---|---|
| 745 | 2001 | Economic Sciences | 1/3 | 2000 |
| 102 | 1975 | Physics | 1/3 | 1970 |
| 779 | 2004 | Chemistry | 1/3 | 2000 |
| 259 | 1982 | Chemistry | 1 | 1980 |
| 1004 | 2021 | Literature | 1 | 2020 |
| 114 | 1979 | Physics | 1/3 | 1970 |
Cleaning decisions and limitations
The JSON’s nested nobelPrizes and affiliations arrays are separated into different tables to avoid multiplying awards when laureates have multiple affiliations. Names and country labels are extracted from their English-language fields where possible. Missing dates or countries are retained as NA; organizations are excluded from person-specific analyses. To compare geography, I prefer the API’s present-day country label when available, but some affiliation labels may not have an equivalent historical-to-modern mapping.
Four Research Questions and Results
Question 1: How has the distribution of Nobel awards by category changed across decades?
I count distinct prize events, defined by award year and category, rather than laureate recipients. A shared prize therefore counts once for this question. The table below compares awards by decade and category, while the chart highlights the distribution across time.
prize_events <- awards |>
dplyr::distinct(award_year, category, decade)
awards_by_decade <- prize_events |>
dplyr::count(decade, category, name = "prize_events") |>
dplyr::arrange(decade, category)
knitr::kable(awards_by_decade, caption = "Distinct Nobel prize events by decade and category")| decade | category | prize_events |
|---|---|---|
| 1900 | Chemistry | 9 |
| 1900 | Literature | 9 |
| 1900 | Peace | 9 |
| 1900 | Physics | 9 |
| 1900 | Physiology or Medicine | 9 |
| 1910 | Chemistry | 7 |
| 1910 | Literature | 8 |
| 1910 | Peace | 6 |
| 1910 | Physics | 9 |
| 1910 | Physiology or Medicine | 6 |
| 1920 | Chemistry | 9 |
| 1920 | Literature | 10 |
| 1920 | Peace | 7 |
| 1920 | Physics | 10 |
| 1920 | Physiology or Medicine | 8 |
| 1930 | Chemistry | 9 |
| 1930 | Literature | 9 |
| 1930 | Peace | 8 |
| 1930 | Physics | 8 |
| 1930 | Physiology or Medicine | 10 |
| 1940 | Chemistry | 7 |
| 1940 | Literature | 6 |
| 1940 | Peace | 5 |
| 1940 | Physics | 7 |
| 1940 | Physiology or Medicine | 7 |
| 1950 | Chemistry | 10 |
| 1950 | Literature | 10 |
| 1950 | Peace | 8 |
| 1950 | Physics | 10 |
| 1950 | Physiology or Medicine | 10 |
| 1960 | Chemistry | 10 |
| 1960 | Economic Sciences | 1 |
| 1960 | Literature | 10 |
| 1960 | Peace | 8 |
| 1960 | Physics | 10 |
| 1960 | Physiology or Medicine | 10 |
| 1970 | Chemistry | 10 |
| 1970 | Economic Sciences | 10 |
| 1970 | Literature | 10 |
| 1970 | Peace | 9 |
| 1970 | Physics | 10 |
| 1970 | Physiology or Medicine | 10 |
| 1980 | Chemistry | 10 |
| 1980 | Economic Sciences | 10 |
| 1980 | Literature | 10 |
| 1980 | Peace | 10 |
| 1980 | Physics | 10 |
| 1980 | Physiology or Medicine | 10 |
| 1990 | Chemistry | 10 |
| 1990 | Economic Sciences | 10 |
| 1990 | Literature | 10 |
| 1990 | Peace | 10 |
| 1990 | Physics | 10 |
| 1990 | Physiology or Medicine | 10 |
| 2000 | Chemistry | 10 |
| 2000 | Economic Sciences | 10 |
| 2000 | Literature | 10 |
| 2000 | Peace | 10 |
| 2000 | Physics | 10 |
| 2000 | Physiology or Medicine | 10 |
| 2010 | Chemistry | 10 |
| 2010 | Economic Sciences | 10 |
| 2010 | Literature | 10 |
| 2010 | Peace | 10 |
| 2010 | Physics | 10 |
| 2010 | Physiology or Medicine | 10 |
| 2020 | Chemistry | 7 |
| 2020 | Economic Sciences | 7 |
| 2020 | Literature | 7 |
| 2020 | Peace | 7 |
| 2020 | Physics | 7 |
| 2020 | Physiology or Medicine | 7 |
ggplot2::ggplot(awards_by_decade,
ggplot2::aes(x = decade, y = prize_events, fill = category)) +
ggplot2::geom_col(width = 8) +
ggplot2::scale_x_continuous(breaks = sort(unique(awards_by_decade$decade))) +
ggplot2::labs(title = "Nobel prize events across decades",
subtitle = "One prize event per year and category; shared awards counted once",
x = "Decade", y = "Prize events", fill = "Category") +
ggplot2::theme_minimal(base_size = 11) +
ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, hjust = 1))The categories do not all have the same starting year (notably Economic Sciences), so raw totals across the full historical period should not be treated as direct measures of relative importance. The chart is descriptive and does not explain why particular categories began later or had years with no award.
Question 2: How has the representation of women among individual laureate-award recipients changed over time and categories?
For this question I join the award table to the laureate table, restrict the denominator to records explicitly marked female or male, and count one observation per individual laureate–award. Organizations and unspecified genders are excluded, so the percentages refer to recipients with recorded gender, not all Nobel awards or all people who might have been considered.
recipient_gender <- awards |>
dplyr::left_join(laureates |>
dplyr::select(laureate_id, gender), by = "laureate_id") |>
dplyr::mutate(gender = tolower(gender),
period = paste0((award_year %/% 20) * 20, "s–",
(award_year %/% 20) * 20 + 19)) |>
dplyr::filter(gender %in% c("female", "male"))
women_by_period <- recipient_gender |>
dplyr::group_by(period, category) |>
dplyr::summarise(recipients = dplyr::n(),
women = sum(gender == "female"),
percent_women = 100 * women / recipients, .groups = "drop") |>
dplyr::arrange(period, category)
knitr::kable(women_by_period, digits = 1,
caption = "Women among laureate–award recipients, by 20-year period and category")| period | category | recipients | women | percent_women |
|---|---|---|---|---|
| 1900s–1919 | Chemistry | 17 | 1 | 5.9 |
| 1900s–1919 | Literature | 19 | 1 | 5.3 |
| 1900s–1919 | Peace | 18 | 1 | 5.6 |
| 1900s–1919 | Physics | 23 | 1 | 4.3 |
| 1900s–1919 | Physiology or Medicine | 17 | 0 | 0.0 |
| 1920s–1939 | Chemistry | 23 | 1 | 4.3 |
| 1920s–1939 | Literature | 19 | 3 | 15.8 |
| 1920s–1939 | Peace | 19 | 1 | 5.3 |
| 1920s–1939 | Physics | 23 | 0 | 0.0 |
| 1920s–1939 | Physiology or Medicine | 25 | 0 | 0.0 |
| 1940s–1959 | Chemistry | 23 | 0 | 0.0 |
| 1940s–1959 | Literature | 16 | 1 | 6.2 |
| 1940s–1959 | Peace | 11 | 1 | 9.1 |
| 1940s–1959 | Physics | 27 | 0 | 0.0 |
| 1940s–1959 | Physiology or Medicine | 34 | 1 | 2.9 |
| 1960s–1979 | Chemistry | 30 | 1 | 3.3 |
| 1960s–1979 | Economic Sciences | 17 | 0 | 0.0 |
| 1960s–1979 | Literature | 22 | 1 | 4.5 |
| 1960s–1979 | Peace | 17 | 3 | 17.6 |
| 1960s–1979 | Physics | 42 | 1 | 2.4 |
| 1960s–1979 | Physiology or Medicine | 50 | 1 | 2.0 |
| 1980s–1999 | Chemistry | 39 | 0 | 0.0 |
| 1980s–1999 | Economic Sciences | 27 | 0 | 0.0 |
| 1980s–1999 | Literature | 20 | 3 | 15.0 |
| 1980s–1999 | Peace | 22 | 4 | 18.2 |
| 1980s–1999 | Physics | 44 | 0 | 0.0 |
| 1980s–1999 | Physiology or Medicine | 43 | 4 | 9.3 |
| 2000s–2019 | Chemistry | 52 | 2 | 3.8 |
| 2000s–2019 | Economic Sciences | 40 | 2 | 5.0 |
| 2000s–2019 | Literature | 20 | 6 | 30.0 |
| 2000s–2019 | Peace | 20 | 7 | 35.0 |
| 2000s–2019 | Physics | 54 | 1 | 1.9 |
| 2000s–2019 | Physiology or Medicine | 50 | 6 | 12.0 |
| 2020s–2039 | Chemistry | 18 | 3 | 16.7 |
| 2020s–2039 | Economic Sciences | 17 | 1 | 5.9 |
| 2020s–2039 | Literature | 7 | 4 | 57.1 |
| 2020s–2039 | Peace | 6 | 4 | 66.7 |
| 2020s–2039 | Physics | 18 | 2 | 11.1 |
| 2020s–2039 | Physiology or Medicine | 16 | 2 | 12.5 |
ggplot2::ggplot(women_by_period,
ggplot2::aes(x = period, y = percent_women, group = category,
color = category)) +
ggplot2::geom_line(linewidth = 0.8) +
ggplot2::geom_point(size = 1.6) +
ggplot2::scale_y_continuous(labels = function(x) paste0(x, "%")) +
ggplot2::labs(title = "Share of laureate–award recipients recorded as women",
subtitle = "Organizations and missing gender records excluded",
x = "Twenty-year period", y = "Women among recipients", color = "Category") +
ggplot2::theme_minimal(base_size = 10) +
ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, hjust = 1))These comparisons describe patterns in the available recipient records. They do not establish why representation changed, and small category–period groups can produce volatile percentages.
Question 3: How does age at award differ across Nobel categories?
I combine birth year from the laureate-level table with award year from the award-level table. Because some birth dates omit a known month or day and the award date is not used, the calculation is an approximate year-based age, not the exact age on the award ceremony day. I exclude organizations and missing or implausible values.
recipient_ages <- awards |>
dplyr::left_join(laureates |>
dplyr::select(laureate_id, gender, birth_year), by = "laureate_id") |>
dplyr::filter(tolower(gender) %in% c("female", "male"), !is.na(birth_year)) |>
dplyr::mutate(age_at_award_approx = award_year - birth_year) |>
dplyr::filter(dplyr::between(age_at_award_approx, 15, 110))
ages_by_category <- recipient_ages |>
dplyr::group_by(category) |>
dplyr::summarise(recipients = dplyr::n(),
median_age = median(age_at_award_approx),
mean_age = mean(age_at_award_approx),
youngest_approx = min(age_at_award_approx),
oldest_approx = max(age_at_award_approx),
.groups = "drop") |>
dplyr::arrange(median_age)
knitr::kable(ages_by_category, digits = 1,
caption = "Approximate age at Nobel award, by category")| category | recipients | median_age | mean_age | youngest_approx | oldest_approx |
|---|---|---|---|---|---|
| Physics | 231 | 56 | 57.8 | 25 | 96 |
| Chemistry | 202 | 58 | 59.5 | 35 | 97 |
| Physiology or Medicine | 235 | 58 | 59.0 | 32 | 87 |
| Peace | 113 | 62 | 61.0 | 17 | 87 |
| Economic Sciences | 101 | 67 | 67.2 | 47 | 90 |
| Literature | 123 | 67 | 65.0 | 42 | 88 |
ggplot2::ggplot(recipient_ages,
ggplot2::aes(x = reorder(category, age_at_award_approx, median),
y = age_at_award_approx)) +
ggplot2::geom_boxplot(fill = "#B8D9E5", outlier.alpha = .55) +
ggplot2::coord_flip() +
ggplot2::labs(title = "Approximate age at award varies by category",
subtitle = "Award year minus birth year; individual recipients only",
x = NULL, y = "Approximate age (years)") +
ggplot2::theme_minimal(base_size = 11)The boxplots display medians, spread, and outliers; category differences should not be interpreted as causal effects of a field of study on age at recognition.
Question 4: Which birth countries appear most often with a different award-time affiliation country?
This question requires a join between laureate, award, and affiliation records. I compare birth country with the countries of listed affiliations for each award, while keeping only affiliations with a usable country. To avoid double-counting a laureate’s award in the same country pair, I keep one row per laureate–year–category–birth-country–affiliation-country combination. An award with affiliations in two different countries can still appear in two pairs; rankings therefore represent distinct laureate–award–country-pair associations, not unique people or migrations.
country_comparisons <- awards |>
dplyr::left_join(laureates |>
dplyr::select(laureate_id, gender, birth_country),
by = "laureate_id") |>
dplyr::inner_join(affiliations |>
dplyr::select(laureate_id, award_year, category,
affiliation_country),
by = c("laureate_id", "award_year", "category")) |>
dplyr::filter(tolower(gender) %in% c("female", "male"),
!is.na(birth_country), !is.na(affiliation_country)) |>
dplyr::mutate(birth_country = clean_text(birth_country),
affiliation_country = clean_text(affiliation_country)) |>
dplyr::filter(!is.na(birth_country), !is.na(affiliation_country)) |>
dplyr::distinct(laureate_id, award_year, category,
birth_country, affiliation_country)
# Case-insensitive comparison avoids counting capitalization differences.
different_country_pairs <- country_comparisons |>
dplyr::filter(tolower(birth_country) != tolower(affiliation_country))
country_pair_counts <- different_country_pairs |>
dplyr::count(birth_country, affiliation_country,
name = "laureate_award_country_pairs", sort = TRUE) |>
dplyr::slice_head(n = 15)
birth_country_counts <- different_country_pairs |>
dplyr::count(birth_country, name = "cross_country_associations", sort = TRUE) |>
dplyr::slice_head(n = 10)
knitr::kable(birth_country_counts,
caption = "Birth countries with most distinct cross-country associations")| birth_country | cross_country_associations |
|---|---|
| Germany | 27 |
| United Kingdom | 25 |
| Poland | 20 |
| Canada | 15 |
| France | 15 |
| Austria | 12 |
| Russia | 12 |
| the Netherlands | 10 |
| Hungary | 9 |
| Scotland | 9 |
knitr::kable(country_pair_counts,
caption = "Top 15 birth-country / affiliation-country pairs")| birth_country | affiliation_country | laureate_award_country_pairs |
|---|---|---|
| United Kingdom | USA | 19 |
| Canada | USA | 15 |
| Germany | USA | 14 |
| France | USA | 9 |
| Poland | Germany | 9 |
| Japan | USA | 8 |
| Scotland | United Kingdom | 7 |
| China | USA | 6 |
| Poland | USA | 6 |
| Russia | USA | 6 |
| Austria | Germany | 5 |
| Austria | USA | 5 |
| Hungary | USA | 5 |
| Italy | USA | 5 |
| Germany | Switzerland | 4 |
if (nrow(birth_country_counts) > 0) {
ggplot2::ggplot(birth_country_counts,
ggplot2::aes(x = reorder(birth_country, cross_country_associations),
y = cross_country_associations)) +
ggplot2::geom_col(fill = "#197A83") +
ggplot2::coord_flip() +
ggplot2::labs(title = "Birth countries associated with different affiliation countries",
subtitle = "Award-country associations; not evidence of citizenship or migration",
x = NULL, y = "Distinct associations") +
ggplot2::theme_minimal(base_size = 11)
}Interpretation: Country of an award-time institutional affiliation is not citizenship, and a difference from birth country does not establish when or why someone moved. The API can omit affiliations, especially for awards without a recorded institutional association. Historical borders, variations in country labels, and multiple institutions also limit comparisons.
Conclusions and Recommendations
This analysis demonstrates how a public JSON API can be converted into relational tidy data and used to study distinct prize events, award recipients, approximate age, and geographic associations. The results are deliberately computed from the API rather than hard-coded; the tables and charts above provide the answers for the retrieval date shown in the report.
Based on the records retrieved on 2026-11-08, the dataset contains 1028 unique laureates, 1036 laureate–award records, and 639 distinct year–category prize events. Among the individual recipients with recorded gender, 7% of laureate–award records are labeled female. The median approximate age at award in the eligible records is 61 years. The country comparison identifies 262 distinct cross-country laureate–award associations, with missing affiliation data explicitly excluded. These figures describe only the available API records and should be interpreted alongside the tables above.
The four questions require different units of analysis: distinct prize events for Question 1; individual laureate–award recipients for Questions 2 and 3; and deduplicated birth-country/affiliation-country associations for Question 4. Defining these units before grouping avoids misleading conclusions from shared prizes or multiple affiliations.
Sources:
- Nobel Prize Outreach. Nobel Prize API — Getting Started.
- Nobel Prize Outreach. Nobel Prize Developer Zone.
- Nobel Prize Outreach. Nobel Prize API changelog (version 2.1).