API reference
Two public JSON endpoints, no auth, no signup. Designed for the Phrasit embed widgets and for occasional use from your own scripts.
Overview
Phrasit exposes two POST endpoints. Both accept JSON, return JSON, and require no API key. Requests are rate-limited per IP at the platform edge; the free tier is comfortable for the occasional embed-driven lookup or a small batch script. For anything sustained or programmatic, see the roadmap note on API keys below.
Citation metadata
POST https://phrasit.com/api/citation
Takes one free-form string and resolves it to structured citation data. The endpoint auto-detects the source type. A DOI is sent to Crossref, an ISBN to Open Library, and an HTTP(S) URL is fetched and parsed for Open Graph and meta tags. Anything else returns a 422.
Request body
{
"input": "10.1037/edu0000512"
}input is required, 3 to 500 characters. Accepted formats: a DOI (e.g. 10.1037/edu0000512), an ISBN-10 or ISBN-13 with or without hyphens, or a full http:// or https:// URL.
Response (200)
{
"data": {
"sourceType": "journal-article",
"title": "Working memory load and reading comprehension",
"authors": ["Rita K. Patel", "Min Liu"],
"year": "2021",
"month": "July",
"day": "1",
"containerTitle": "Journal of Educational Psychology",
"publisher": null,
"volume": "113",
"issue": "4",
"pages": "720-734",
"doi": "10.1037/edu0000512",
"url": "https://doi.org/10.1037/edu0000512",
"isbn": null
}
}The data object follows the CitationData shape. Every field except sourceType, title, authors, and year is optional and may be null when the upstream source did not provide it. sourceType is one of journal-article, book, webpage, newspaper, or unknown.
Errors
400 for malformed JSON or input outside the 3 to 500 character range. 422 when the input cannot be resolved to citation metadata, with an error string suggesting the caller paste a DOI, ISBN, or URL instead.
Example: curl
curl -X POST https://phrasit.com/api/citation \
-H "Content-Type: application/json" \
-d '{"input":"10.1037/edu0000512"}'Example: fetch
const res = await fetch("https://phrasit.com/api/citation", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ input: "10.1037/edu0000512" }),
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(error);
}
const { data } = await res.json();
console.log(data.title, data.authors);Notes
- Cache: Crossref responses are cached for 24 hours, Open Library for 7 days. Webpage fetches are not cached and time out after 8 seconds.
- Rate limit: per-IP throttling at the edge. Expect to be comfortable with a few requests per second from a browser; treat sustained server-to-server use as out of scope until API keys ship.
- Fail modes: if Crossref or Open Library is down, or the URL returns non-HTML or a non-2xx status, you get a 422 with a human-readable error message rather than upstream details.
Grammar check
POST https://phrasit.com/api/grammar
Proxies your text to LanguageTool's public API and returns a trimmed list of matches. This is the same backend that powers /writing/grammar-checker.
Request body
{
"text": "She dont like the new policy.",
"language": "auto"
}text is required, 1 to 20,000 characters. language is optional and defaults to "auto". Pass a BCP-47 code such as en-US, en-GB, de-DE, or frto skip LanguageTool's detection step.
Response (200)
{
"matches": [
{
"message": "Did you mean \"doesn't\"?",
"shortMessage": "Grammar",
"replacements": ["doesn't"],
"offset": 4,
"length": 4,
"context": { "text": "She dont like the new policy.", "offset": 4, "length": 4 },
"rule": {
"id": "HE_VERB_AGR",
"description": "Subject-verb agreement",
"category": "Grammar",
"issueType": "grammar"
}
}
],
"language": { "name": "English (US)", "code": "en-US" },
"software": { "name": "LanguageTool" }
}Each match exposes a human-readable message, up to five suggested replacements, the zero-based offset and length in your original text, the surrounding context, and the LanguageTool rule that fired. Responses are returned with Cache-Control: no-store.
Errors
400 for malformed JSON or input outside the size limits. 429 when LanguageTool rate-limits the proxy; wait a few seconds and retry. 502 if LanguageTool is unreachable or returns a non-2xx status.
Example: curl
curl -X POST https://phrasit.com/api/grammar \
-H "Content-Type: application/json" \
-d '{"text":"She dont like the new policy.","language":"auto"}'Example: fetch
const res = await fetch("https://phrasit.com/api/grammar", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: "She dont like the new policy.",
language: "auto",
}),
});
const result = await res.json();
for (const match of result.matches) {
console.log(match.message, match.replacements);
}Notes
- Upstream: this endpoint is a thin proxy over
api.languagetool.org/v2/check. LanguageTool's public tier applies its own per-IP rate limit (roughly 20 requests per minute, 80 KB per minute at time of writing). Sustained use should self-host LanguageTool or buy a LanguageTool Premium key directly. - Timeout: the proxy aborts the upstream request after 15 seconds.
- Privacy: the proxy does not log request bodies. Text is sent to LanguageTool over HTTPS and not persisted by Phrasit.
Embed widgets
Every embeddable tool is a self-contained route under /embed/. Drop the iframe into any HTML page. Adjust height to 360 for a compact layout or 720 for the full experience.
Word counter
<iframe
src="https://phrasit.com/embed/word-counter"
width="100%"
height="520"
style="border:0;border-radius:12px"
title="Word counter by Phrasit"
loading="lazy">
</iframe>Character counter
<iframe
src="https://phrasit.com/embed/character-counter"
width="100%"
height="520"
style="border:0;border-radius:12px"
title="Character counter by Phrasit"
loading="lazy">
</iframe>Reading time estimator
<iframe
src="https://phrasit.com/embed/reading-time-estimator"
width="100%"
height="520"
style="border:0;border-radius:12px"
title="Reading time estimator by Phrasit"
loading="lazy">
</iframe>Citation generator
<iframe
src="https://phrasit.com/embed/citation-generator"
width="100%"
height="520"
style="border:0;border-radius:12px"
title="Citation generator by Phrasit"
loading="lazy">
</iframe>Bibliography converter
<iframe
src="https://phrasit.com/embed/bibliography-converter"
width="100%"
height="520"
style="border:0;border-radius:12px"
title="Bibliography converter by Phrasit"
loading="lazy">
</iframe>Status
There is no dedicated status page yet. As a health check, hit https://phrasit.com/api/citation with an empty POST. A 400 response with {"error":"Invalid JSON"} confirms the route is up. A 5xx or timeout means the platform edge is having a bad day.
Roadmap
- API keys:planned for higher-volume use, with a free tier that matches today's anonymous limits and paid tiers for sustained programmatic access.
- Webhook notifications: not on the roadmap. The endpoints are synchronous request/response and will stay that way.
- GraphQL: not on the roadmap. Two endpoints do not need a schema layer.