API Management
API Basics
API Endpoints
API Examples
API Basics
API Introduction
The Readable.com API is a simple interface for passing text and URLs to Readable.com from your application and getting back readability and keyword density statistics.
You can see your usage of the API in your account administration area.
All responses from the API are in JSON format. Each response contains a field called "result", which will contain either "error" or "success". If the "result" is "error", more information about the error will be contained in the "messages" array field. Every response also contains a "response_timestamp" field.
API Authentication
Authentication of all requests is done with a pair of (case-insensitive) HTTP headers - API_SIGNATURE
and API_REQUEST_TIME
.
API_REQUEST_TIME
is the UNIX timestamp of the current time and API_SIGNATURE
is an MD5 hash of an API key and this exact timestamp (example). API keys can be generated in your account administration area (you can have as many as you want).
You should never send your API key directly with a request.
HEADER Parameters
-
API_REQUEST_TIME
RequiredThe
API_REQUEST_TIME
header is sent with every request to the API, and is the UNIX timestamp of the request (in the UTC timezome). The request will be rejected if theAPI_REQUEST_TIME
is not within the last 30 seconds. -
API_SIGNATURE
RequiredThe
API_SIGNATURE
header is an MD5 hash of an API key and the time you set in theAPI_REQUEST_TIME
header. It should change with every request.
API Testing
If you want to test the API, you can use the following testing API key.
Test API Key: THISISATESTKEYTHEREAREMANYLIKEIT
Please note that the requests made with the test key return the same results in the same format as a normal request, but the API will not analyse the text you send; it analyses pre-set test text (if you're curious, the first paragraph of Moby Dick). There is no charge for test requests.
API Endpoints
Analyse Text
You can pass any plain text to the site to score.
POST https://api.readable.com/api/text/
POST Parameters
-
text
RequiredType: Plain text string, with UTF-8 encoding
Description: The text you wish to score.
Analyse a URL
You can pass any URL to the site to score. We recommend sending all URLs encoded as UTF-8. If a URL is resolved to a file, that will automatically be added to the file queue to process as though it were uploaded through the website.
POST https://api.readable.com/api/url/
POST Parameters
-
url
RequiredType: URL string, with UTF-8 encoding
Description: The URL you wish to score. -
extract
OptionalType: boolean, true or false (defaults to false)
Description: If set to true, we will attempt to automatically extract the body copy from the URL, removing navigation, headers, footers and so on.
Retrieve Highlighted Issues and Content from a Scored Item
When you score a piece of text or a URL with the API, the API response will include a score_id
. You can pass this back to the API highlight endpoint to retrieve a highlighted version of that content, showing possible issues to address.
Text highlights are only available for six hours after scoring a URL or piece of text.
The highlighted version of the text is provided in HTML, with spans wrapped around items of interest. The API response includes a key for the classes for those spans to indicate what they mean.
POST https://api.readable.com/api/highlight/
POST Parameters
-
score_id
RequiredType: score ID string, with UTF-8 encoding
Description: The score ID, returned with the results of a previous call to either the text or URL endpoint.
Profanity Detector
You can pass any plain text to the API to be examined for profanity. You can also specify how sensitive you would like the profanity detector to be.
POST https://api.readable.com/api/profanity/
POST Parameters
-
text
RequiredType: Plain text string, with UTF-8 encoding
Description: The text you wish to analyse. -
level
OptionalType: A number - 1, 2 or 3 (defaults to 1)
Description: The sensitivity you want to set the profanity detection systems to. 1: Highlight strong profanity only (e.g., "fuck", "arse", racism and other discriminatory language). 2: Highlight strong and medium profanity including mildly offensive words (e.g., "idiot", "dammit", "wanker"). 3: Highlight all potential profanity, including words which are usually fine but can be profane or objectionable in certain circumstances (e.g., "black", "yank", "addict").
API Examples
API Postman Example
Please click the button below to load an example of our API using Postman (please note that this uses a test key for the API and returns example data in response to each query).
API Text Request Example (PHP)
<?php
$api_key = 'THISISATESTKEYTHEREAREMANYLIKEIT'; // Generate this in your Readable.com account.
$url = 'https://api.readable.com/api/text/'; // The API endpoint you want to interact with
$request_time = time(); // Time of request
$api_signature = md5($api_key . $request_time); // Generate signature
$text = 'The quick brown fox jumps over the lazy dog.'; // The text you want to score
// Fetch URL with CURL
$postItems = array('text' => $text);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postItems));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('API_SIGNATURE: ' . $api_signature, 'API_REQUEST_TIME: ' . $request_time));
$json = curl_exec($ch);
curl_close($ch);
$results = json_decode($json, true);
var_dump($results);
API Text Response Example
{
"paragraph_count": 1,
"sentence_count": 8,
"sentence_count_flesch": 11,
"letter_count": 884,
"word_count": 201,
"lensear_word_count": 122,
"syllable_count": 301,
"unique_word_count": 134,
"word_with_three_syllables": 22,
"word_with_three_syllables_common_only": 20,
"dale_chall_difficult_words": 38,
"spache_difficult_words": 51,
"cefr_level": "B1",
"ielts_level": "4-5",
"composition_adjective_count": 15,
"composition_adverb_count": 11,
"composition_conjunction_count": 17,
"composition_determiner_count": 30,
"composition_interjection_count": 1,
"composition_noun_count": 48,
"composition_preposition_count": 25,
"composition_pronoun_count": 32,
"composition_proper_noun_count": 3,
"composition_qualifier_count": 5,
"composition_verb_count": 18,
"composition_unknown_count": 0,
"composition_nonword_count": 0,
"flesch_reading_ease": "61.6",
"flesch_kincaid_grade_level": "9.2",
"gunning_fog_score": "11.3",
"powers_sumner_kearl_score": "6.3",
"coleman_liau_index": "8.9",
"automated_readability_index": "11.8",
"smog_index": "12.6",
"dale_chall_readability_score": "4.2",
"spache_readability_score": "5.8",
"forcast_grade": "9.9",
"lix_score": 45,
"rix_score": 10,
"lensear_write": "72.6",
"raygor_grade": 9,
"fry_grade": 9,
"longest_word_syllables": "6 ([\"involuntarily\"])",
"longest_word_letters": "13 ([\"involuntarily\",\"philosophical\"])",
"longest_sentence_words": "87 ([\"whenever i find myself growing grim about the mouth; whenever it is a damp drizzly november in my soul; whenever i find myself involuntarily pausing before coffin warehouses and bringing up the rear of every funeral i meet and especially whenever my hypos get such an upper hand of me that it requires a strong moral principle to prevent me from deliberately stepping into the street and methodically knocking people's hats off then i account it high time to get to sea as soon as i can\"]])",
"tone_number": 50,
"sentiment": "Positive",
"sentiment_number": 74,
"personal_number": 0,
"gender_number": 30,
"rating": "D",
"sentences_per_paragraph": "8.0",
"words_per_paragraph": "201.0",
"words_per_sentence": "25.1",
"words_per_sentence_flesch": "18.3",
"syllables_per_word": "1.5",
"letters_per_word": "4.4",
"average_grade_level": "10.8",
"reading_time": "0:53",
"speaking_time": "1:36",
"gender": "Female",
"tone": "Neutral",
"personal": "Impersonal",
"keyword_density": {
"1 word": {
"0000000009-I": {
"item": "I",
"count": 9,
"percentage": "4.48"
},
"0000000004-is": {
"item": "is",
"count": 4,
"percentage": "1.99"
},
"0000000002-time": {
"item": "time",
"count": 2,
"percentage": "1.00"
},
"0000000002-little": {
"item": "little",
"count": 2,
"percentage": "1.00"
},
"0000000002-get": {
"item": "get",
"count": 2,
"percentage": "1.00"
},
"0000000002-find": {
"item": "find",
"count": 2,
"percentage": "1.00"
}
},
"2 words": {
"0000000004-find myself": {
"item": "find myself",
"count": 2,
"percentage": "1.00"
},
"0000000004-I find": {
"item": "I find",
"count": 2,
"percentage": "1.00"
}
},
"3 words": {
"0000000006-I find myself": {
"item": "I find myself",
"count": 2,
"percentage": "1.00"
}
}
},
"reach": "91",
"reach_public": "77",
"flesch_kincaid_reading_ease": "61.6",
"score_id": "373150f3762e359f19f0",
"server_reference": "web3",
"result": "success",
"response_timestamp": 1650614743
}
API URL Request Example (PHP)
<?php
$api_key = 'THISISATESTKEYTHEREAREMANYLIKEIT'; // Generate this in your Readable.com account.
$api_url = 'https://api.readable.com/api/url/'; // The API endpoint you want to interact with
$request_time = time(); // Time of request
$api_signature = md5($api_key . $request_time); // Generate signature
$url = 'http://www.example.com/'; // The url you want to score
$extract = true; // Whether or not to extract the text from the url (removing nav, header, footer, etc.)
// Fetch URL with CURL
$postItems = compact('url', 'extract');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postItems));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('API_SIGNATURE: ' . $api_signature, 'API_REQUEST_TIME: ' . $request_time));
$json = curl_exec($ch);
curl_close($ch);
$results = json_decode($json, true);
var_dump($results);
API URL Response Example
{
"paragraph_count": 1,
"sentence_count": 8,
"sentence_count_flesch": 11,
"letter_count": 884,
"word_count": 201,
"lensear_word_count": 122,
"syllable_count": 301,
"unique_word_count": 134,
"word_with_three_syllables": 22,
"word_with_three_syllables_common_only": 20,
"dale_chall_difficult_words": 38,
"spache_difficult_words": 51,
"cefr_level": "B1",
"ielts_level": "4-5",
"composition_adjective_count": 15,
"composition_adverb_count": 11,
"composition_conjunction_count": 17,
"composition_determiner_count": 30,
"composition_interjection_count": 1,
"composition_noun_count": 48,
"composition_preposition_count": 25,
"composition_pronoun_count": 32,
"composition_proper_noun_count": 3,
"composition_qualifier_count": 5,
"composition_verb_count": 18,
"composition_unknown_count": 0,
"composition_nonword_count": 0,
"flesch_reading_ease": "61.6",
"flesch_kincaid_grade_level": "9.2",
"gunning_fog_score": "11.3",
"powers_sumner_kearl_score": "6.3",
"coleman_liau_index": "8.9",
"automated_readability_index": "11.8",
"smog_index": "12.6",
"dale_chall_readability_score": "4.2",
"spache_readability_score": "5.8",
"forcast_grade": "9.9",
"lix_score": 45,
"rix_score": 10,
"lensear_write": "72.6",
"raygor_grade": 9,
"fry_grade": 9,
"longest_word_syllables": "6 ([\"involuntarily\"])",
"longest_word_letters": "13 ([\"involuntarily\",\"philosophical\"])",
"longest_sentence_words": "87 ([\"whenever i find myself growing grim about the mouth; whenever it is a damp drizzly november in my soul; whenever i find myself involuntarily pausing before coffin warehouses and bringing up the rear of every funeral i meet and especially whenever my hypos get such an upper hand of me that it requires a strong moral principle to prevent me from deliberately stepping into the street and methodically knocking people's hats off then i account it high time to get to sea as soon as i can\"]])",
"tone_number": 50,
"sentiment": "Positive",
"sentiment_number": 74,
"personal_number": 0,
"gender_number": 30,
"rating": "D",
"sentences_per_paragraph": "8.0",
"words_per_paragraph": "201.0",
"words_per_sentence": "25.1",
"words_per_sentence_flesch": "18.3",
"syllables_per_word": "1.5",
"letters_per_word": "4.4",
"average_grade_level": "10.8",
"reading_time": "0:53",
"speaking_time": "1:36",
"gender": "Female",
"tone": "Neutral",
"personal": "Impersonal",
"keyword_density": {
"1 word": {
"0000000009-I": {
"item": "I",
"count": 9,
"percentage": "4.48"
},
"0000000004-is": {
"item": "is",
"count": 4,
"percentage": "1.99"
},
"0000000002-time": {
"item": "time",
"count": 2,
"percentage": "1.00"
},
"0000000002-little": {
"item": "little",
"count": 2,
"percentage": "1.00"
},
"0000000002-get": {
"item": "get",
"count": 2,
"percentage": "1.00"
},
"0000000002-find": {
"item": "find",
"count": 2,
"percentage": "1.00"
}
},
"2 words": {
"0000000004-find myself": {
"item": "find myself",
"count": 2,
"percentage": "1.00"
},
"0000000004-I find": {
"item": "I find",
"count": 2,
"percentage": "1.00"
}
},
"3 words": {
"0000000006-I find myself": {
"item": "I find myself",
"count": 2,
"percentage": "1.00"
}
}
},
"reach": "91",
"reach_public": "77",
"flesch_kincaid_reading_ease": "61.6",
"score_id": "4ed236d922b6e30365b6",
"result_note": "We could not extract the text content of this page so we scored the entire page.",
"server_reference": "web1",
"result": "success",
"response_timestamp": 1650616274
}
API Highlight Request Example (PHP)
<?php
$api_key = 'THISISATESTKEYTHEREAREMANYLIKEIT'; // Generate this in your Readable.com account.
$url = 'https://api.readable.com/api/highlight/'; // The API endpoint you want to interact with
$request_time = time(); // Time of request
$api_signature = md5($api_key . $request_time); // Generate signature
$score_id = '4ed236d922b6e30365b6'; // The score ID, returned with the results of a previous call to either the text or URL endpoint
// Fetch URL with CURL
$postItems = array('score_id' => $score_id);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postItems));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('API_SIGNATURE: ' . $api_signature, 'API_REQUEST_TIME: ' . $request_time));
$json = curl_exec($ch);
curl_close($ch);
$results = json_decode($json, true);
var_dump($results);
API Highlight Response Example
{
"db_table": "result",
"very_long_sentence_count": 3,
"spelling_error_count": 0,
"grammar_error_count": 0,
"long_sentence_count": 5,
"passive_voice_count": 0,
"adverb_count": 12,
"cliche_count": 0,
"hedge_count": 0,
"transition_count": 0,
"profanity_count": 0,
"buzzwords_count": 0,
"names_count": 0,
"lazy_count": 0,
"stopwords_count": 0,
"long_word_count": 0,
"high_syllable_word_count": 4,
"highlighted_text": "Call me Ishmael. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen, and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people's hats off - then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball. With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me.",
"highlighted_text_key": {
"highlight_warn": "Long sentence (more than 20 syllables)",
"highlight_bad": "Very long sentence (more than 30 syllables)",
"highlight_long_word": "Long word (more than 12 letters)",
"highlight_hard_word": "Hard word (more than 4 syllables)",
"highlight_adverb": "Possible adverb",
"highlight_cliche": "Possible cliche",
"highlight_passive": "Possible passive voice",
"highlight_hedge": "Possible Hedge Word",
"highlight_transition": "Possible Transition Word",
"highlight_profanity": "Possible Profanity",
"highlight_buzzwords": "Possible Buzzword",
"highlight_stopwords": "Possible Stop Word",
"highlight_lazy": "Possible Lazy Words",
"highlight_names": "Possible Names"
},
"score_id": "4ed236d922b6e30365b6",
"server_reference": "web1",
"result": "success",
"response_timestamp": 1650616693
}
API Profanity Detector Request Example (PHP)
<?php
$api_key = 'THISISATESTKEYTHEREAREMANYLIKEIT'; // Generate this in your Readable.com account.
$url = 'https://api.readable.com/api/profanity/'; // The API endpoint you want to interact with
$request_time = time(); // Time of request
$api_signature = md5($api_key . $request_time); // Generate signature
$text = 'You should definitely not use words like idiot or wanker in a business setting.'; // The text you want to score
$level = 3; // The level of profanity you want to check for
// Fetch URL with CURL
$postItems = compact('text', 'level');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postItems));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('API_SIGNATURE: ' . $api_signature, 'API_REQUEST_TIME: ' . $request_time));
$json = curl_exec($ch);
curl_close($ch);
$results = json_decode($json, true);
var_dump($results);
API Profanity Detector Response Example
{
"profanities": [
{
"profanity": "idiot",
"type": "misc / other",
"source": "idiot",
"start": 41,
"length": 5
},
{
"profanity": "wanker",
"type": "sexual",
"source": "wanker",
"start": 50,
"length": 6
}
],
"profanity_count": 2,
"server_reference": "web1",
"result": "success",
"response_timestamp": 1650617482
}
API Response Fields
Our API calls return various fields and an explanation of each is below.
Common Response Fields
-
score_id
A unique ID for the request (used when subsequent processing is required on a piece of text).
-
result
Either "success" or "failure".
-
response_timestamp
A UNIX timestamp indicating the time the response was sent by the server.
Readability Algorithms
-
rating
Our proprietary readability score, from A to E.
-
flesch_reading_ease
flesch_kincaid_grade_level
gunning_fog_score
coleman_liau_index
smog_index
automated_readability_index
forcast_grade
fry_grade
raygor_grade
lensear_write
lix_score
rix_score
dale_chall_readability_score
spache_readability_score
powers_sumner_kearl_score
cefr_level
ielts_level
cefr_scoreReadability scores, for which more details can be found here.
-
average_grade_level
A deprecated average measure of grade scores. We do not recommend using this score, unless you were already conducting research using this measure.
Basic Statistics
-
paragraph_count
sentence_count
letter_count
word_count
unique_word_count
word_with_three_syllables
syllable_countSimple counts of items within the text.
-
sentence_count_flesch
The sentence count as used in various readability scores (where a semi-colon is taken to be a sentence terminator).
-
lensear_word_count
The number of words in the text which appear in the Lensear word list.
-
word_with_three_syllables_common_only
Common words with three syllables.
-
dale_chall_difficult_words
spache_difficult_wordsThe number of words found in the content which do not appear on the respective word lists for each algorithm.
-
words_per_sentence
sentences_per_paragraph
words_per_paragraph
words_per_sentence_flesch
syllables_per_word
letters_per_wordPre-calculated averages of some of the basic statistics from the text.
-
composition_adjective_count
composition_adverb_count
composition_conjunction_count
composition_determiner_count
composition_interjection_count
composition_noun_count
composition_proper_noun_count
composition_preposition_count
composition_pronoun_count
composition_qualifier_count
composition_verb_count
composition_unknown_count
composition_nonword_countThe composition of the text, including the number of nouns, number of verbs, and so on. The "unknown" items refer to words we did not have a classification for. The "nonword" items include numbers, symbols and other non-words.
-
reading_time
speaking_timeThe reading or speaking time for the text, in the format M:SS (e.g., "2:05" - two minutes and five seconds).
-
longest_word_letters
The longest word by letter count.
-
longest_word_syllables
The longest word by syllable count.
-
longest_sentence_words
The longest sentence by word count.
Analysis
-
sentiment
sentiment_numberThe sentiment as text and as a number from 0 to 100 (where 0 is very negative and 100 is very positive).
-
tone
tone_numberThe tone as text and as a number from 0 to 100 (where 0 is very formal and 100 is very informal).
-
personal
personal_numberThe personalism as text and as a number from 0 to 100 (where 0 is very impersonal and 100 is very personal).
-
gender
gender_numberThe gender as text and as a number from 0 to 100 (where 0 is very female and 100 is very male).
-
reach
reach_publicThe reach as as percentage of your addressable audience and the reach as a percentage of the general public.
Highlighting Issues
-
highlighted_text
A string of HTML with issues and highlighted items wrapped in spans.
-
highlighted_text_key
A JSON-encoded array of the span classes used in the highlighted HTML.
-
spelling_error_count
grammar_error_count
very_long_sentence_count
long_sentence_count
long_word_count
high_syllable_word_count
cliche_count
adverb_count
passive_voice_count
hedge_count
transition_count
profanity_count
buzzwords_count
names_count
lazy_count
stopwords_countThe number of issues of each type we found and highlighted.