Build with Wordly API.
Use a server-side API key, make HTTPS requests, and track every call through a predictable credit-based billing model. This reference documents the endpoints currently available in production and clearly marks endpoints that are still being prepared.
Quickstart
Create a free account, verify your email using the six-digit code, and copy the API key shown once in your developer dashboard.
- 1Create an account
Register with only an email address and password.
- 2Verify your email
Enter the code sent by
[email protected]. Verification grants 50 free credits. - 3Store your API key
Copy the generated
wly_live_...key and keep it in a server-side environment variable. - 4Make a test request
Call the account endpoint to verify authentication and see the remaining balance.
curl "https://api.wordlyenglish.com/v1/account" \
-H "Authorization: Bearer $WORDLY_API_KEY" \
-H "Accept: application/json"{
"data": {
"message": "Authenticated",
"credits_remaining": 50
},
"meta": { "lang": "en" }
}Base URL and versioning
All production endpoints are served from the following versioned base URL:
https://api.wordlyenglish.com/v1Breaking response or behavior changes will use a new path version. Additive fields may be introduced within v1, so clients should ignore response properties they do not recognize.
Authentication
Authenticated endpoints require an API key in the HTTP Authorization header using the Bearer scheme.
Authorization: Bearer wly_live_your_api_keyNever place a live key in browser JavaScript, public Git repositories, screenshots, logs, or a distributed mobile application. Call Wordly API from your backend and let your own application communicate with that backend.
Localized API messages
Set the response language with ?lang=tr or the standard Accept-Language header. Query parameters take precedence. Every JSON response declares the selected locale in Content-Language and meta.lang. Error codes remain stable in English for programmatic handling; only the human-readable message is localized.
curl "https://api.wordlyenglish.com/v1/account?lang=tr" \
-H "Authorization: Bearer $WORDLY_API_KEY" \
-H "Accept-Language: tr-TR"Supported language codes: en, tr, de, fr, es, it, pt, nl, pl, ru, uk, ar, fa, he, hi, bn, ur, zh, ja, ko, id, ms, vi, th, sv, no, da, fi, cs, ro.
Credits and billing
Each successful metered request consumes the documented number of credits. Email-verified accounts receive 50 free credits once. Credits are deducted atomically, so concurrent requests cannot spend the same balance twice. Balance lookup through GET /v1/account is free.
| Operation | Credit cost | Availability |
|---|---|---|
GET /v1/status | 0 | Live |
GET /v1/account | 0 | Live |
GET /v1/words/{word} | 1–5 | Live |
GET /v1/words/search | 1 | Live |
GET /v1/words/random | 1 per word | Live |
POST /v1/words/batch | Based on returned records | Live |
Use GET /v1/account when you need the current balance. Other endpoint responses include the operation charge but omit the remaining balance. When the balance is insufficient, the API returns HTTP 402 and does not process the operation.
{
"error": {
"code": "credits_exhausted",
"message": "Your credit balance is exhausted. Add a package or enable pay-as-you-go to continue.",
"upgrade_url": "/app.php?page=billing"
}
}API key lifecycle
Create separate keys for development, staging, and production. Wordly stores only a cryptographic hash of each key; the complete value is displayed once at creation.
- Name keys by environment or service.
- Use environment variables or a managed secret store.
- Revoke a key immediately if it may have been exposed.
- Rotate keys without reusing old values.
- Do not send keys in query strings.
Response format
Successful responses use a top-level data object and may include a meta object. Errors always use a top-level error object with a stable machine-readable code and a human-readable message.
{
"data": { ... },
"meta": {
"credits_used": 1,
"request_id": "..."
}
}{
"error": {
"code": "invalid_api_key",
"message": "..."
}
}Keep the request_id when contacting support about a successful billed request. JSON is UTF-8 encoded and clients should send Accept: application/json.
Wordly caches shared vocabulary data on the server, never API keys, account identities, balances, rate-limit state, or request identifiers. Public status and language responses advertise shared-cache lifetimes. Authenticated responses remain private, no-store; applications may cache the stable data value in their own trusted backend when appropriate.
Production endpoints
/v1/statusLiveReturns public service health and API version information. This endpoint does not require authentication and costs zero credits.
Example request
curl "https://api.wordlyenglish.com/v1/status" \
-H "Accept: application/json"200 · Success
{
"data": { "status": "ok", "version": "v1" },
"meta": { "lang": "en" }
}/v1/accountLive · 0 creditsValidates the supplied key and returns the current account balance without charging a credit.
Headers
| Name | Required | Description |
|---|---|---|
Authorization | Yes | Bearer wly_live_... |
Accept | Recommended | application/json |
Response headers
X-Credits-Remaining is returned only by this balance endpoint.
200 · Success
{
"data": { "message": "Authenticated", "credits_remaining": 1250 },
"meta": { "lang": "en" }
}Vocabulary endpoints
Every record reports its completeness as catalog, translated, or enriched. Fields that are not available are returned as null or an empty object instead of invented data.
GET /v1/words/{word}
Returns an exact word match. Use languages=tr,de,fr to return only requested translations. Catalog or translated records cost 1 credit; fully enriched profiles cost 5 credits.
curl "https://api.wordlyenglish.com/v1/words/water?languages=tr,de" \
-H "Authorization: Bearer $WORDLY_API_KEY"GET /v1/words/search
Search with q and optional level, part_of_speech, category, limit, and cursor. Limits range from 1 to 50. Pass meta.next_cursor into the next request.
curl "https://api.wordlyenglish.com/v1/words/search?q=app&level=advanced&limit=20" \
-H "Authorization: Bearer $WORDLY_API_KEY"GET /v1/words/random
Returns 1–20 random words. Filter by level, part_of_speech, or category. Each returned slot costs one credit.
POST /v1/words/batch
Looks up between 1 and 50 unique words in a single request. The response preserves request order and marks every item with found.
curl -X POST "https://api.wordlyenglish.com/v1/words/batch?lang=tr" \
-H "Authorization: Bearer $WORDLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"words":["water","opportunity"],"languages":["tr","de"]}'GET /v1/languages
Returns all 30 supported interface and API-message locales. Vocabulary translations are returned only when available. This endpoint is public and costs zero credits.
Rate limit
Each API key is limited to 120 accepted requests per rolling minute. Responses include X-RateLimit-Limit and X-RateLimit-Remaining. A 429 rate_limit_exceeded response includes Retry-After: 60.
/v1/languagesLive · 0 creditsLists all supported interface and API-message locales. Vocabulary translations are returned only when a record contains them.
Query parameters
| Name | Type | Required | Rules | Description |
|---|---|---|---|---|
lang | string | No | Supported locale code | Language for human-readable messages. |
Example request
curl "https://api.wordlyenglish.com/v1/languages?lang=tr"200 · Success
{
"data": [{
"code": "tr",
"name": "Türkçe",
"message_localization": true,
"vocabulary_translation": "when_available"
}],
"meta": { "count": 30, "lang": "tr" }
}/v1/words/{word}Live · 1–5 creditsReturns one exact vocabulary record. Catalog and translated records cost 1 credit; enriched records cost 5 credits.
Parameters
| Name | Location | Type | Required | Rules and meaning |
|---|---|---|---|---|
word | Path | string | Yes | Exact word or slug; maximum 120 characters. URL-encode special characters. |
languages | Query | string | No | Comma-separated translation codes, for example tr,de,fr. |
lang | Query | string | No | Human-readable message language; not a vocabulary filter. |
Example request
curl "https://api.wordlyenglish.com/v1/words/water?languages=tr,de" \
-H "Authorization: Bearer $WORDLY_API_KEY" \
-H "Accept: application/json"200 · Success
{
"data": {
"id": "water",
"word": "water",
"part_of_speech": "noun",
"level": "basic",
"definition": "A clear liquid essential for life.",
"example": "Please drink enough water every day.",
"translations": { "tr": "su", "de": "Wasser" },
"categories": ["nature", "daily-life"],
"media": {
"image_url": "https://media.example/water.webp",
"audio_url": "https://media.example/water.mp3",
"attribution": {}
},
"completeness": "enriched"
},
"meta": {
"credits_used": 5,
"request_id": "5ebac760-cdc5-4a73-a87b-22463d81483c",
"lang": "en"
}
}404 · Word unavailable
{
"error": { "code": "word_not_found", "message": "The requested word was not found." },
"meta": { "lang": "en" }
}/v1/words/searchLive · 1 creditSearches active vocabulary in alphabetical order. Use the returned cursor for stable forward pagination.
Query parameters
| Name | Type | Required | Default / limit | Description |
|---|---|---|---|---|
q | string | No | Max 120 chars | Case-insensitive contained text. |
level | string | No | Max 30 chars | Exact level filter. |
part_of_speech / pos | string | No | Max 40 chars | Exact grammatical-class filter. |
category | string | No | Max 80 chars | Category-array filter. |
limit | integer | No | 20; min 1, max 50 | Maximum returned records. |
cursor | string | No | Max 120 chars | Previous meta.next_cursor. |
languages | string | No | Comma-separated | Translations to include. |
Example request
curl "https://api.wordlyenglish.com/v1/words/search?q=app&level=advanced&languages=tr&limit=2" \
-H "Authorization: Bearer $WORDLY_API_KEY"200 · Success
{
"data": [{
"id": "application",
"word": "application",
"part_of_speech": "noun",
"level": "advanced",
"definition": null,
"example": null,
"translations": { "tr": "uygulama" },
"categories": [],
"media": { "image_url": null, "audio_url": null, "attribution": {} },
"completeness": "translated"
}],
"meta": { "credits_used": 1, "request_id": "...", "lang": "en", "count": 1, "next_cursor": null }
}/v1/words/randomLive · 1 credit per requested slotReturns random active words for quizzes, discovery feeds, and practice sessions.
Query parameters
| Name | Type | Required | Default / limit | Description |
|---|---|---|---|---|
count | integer | No | 1; min 1, max 20 | Requested slots and credit cost. |
level | string | No | Exact value | Level filter. |
part_of_speech / pos | string | No | Exact value | Grammatical-class filter. |
category | string | No | Exact value | Category filter. |
languages | string | No | Comma-separated | Translations to include. |
Example request
curl "https://api.wordlyenglish.com/v1/words/random?count=3&level=basic&languages=tr" \
-H "Authorization: Bearer $WORDLY_API_KEY"200 · Success
{
"data": [{ "id": "water", "word": "water", "part_of_speech": "noun", "level": "basic", "definition": null, "example": null, "translations": { "tr": "su" }, "categories": [], "media": { "image_url": null, "audio_url": null, "attribution": {} }, "completeness": "translated" }],
"meta": { "credits_used": 3, "request_id": "...", "lang": "en", "count": 1 }
}/v1/words/batchLive · calculatedLooks up 1–50 unique words while preserving request order. Each enriched result costs 5 credits, another found result costs 1, and the minimum request charge is 1.
Headers
| Name | Required | Value |
|---|---|---|
Authorization | Yes | Bearer wly_live_... |
Content-Type | Yes | application/json |
Accept | Recommended | application/json |
JSON body
| Field | Type | Required | Rules | Description |
|---|---|---|---|---|
words | string[] | Yes | 1–50 items; each max 120 chars | Words to resolve; duplicates are normalized and removed. |
languages | string[] | No | Supported locale codes | Translations to include. |
Example request
curl -X POST "https://api.wordlyenglish.com/v1/words/batch?lang=tr" \
-H "Authorization: Bearer $WORDLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"words":["water","not-a-word"],"languages":["tr","de"]}'200 · Success
{
"data": [
{ "query": "water", "found": true, "word": { "id": "water", "word": "water", "part_of_speech": "noun", "level": "basic", "definition": null, "example": null, "translations": { "tr": "su", "de": "Wasser" }, "categories": [], "media": { "image_url": null, "audio_url": null, "attribution": {} }, "completeness": "translated" } },
{ "query": "not-a-word", "found": false, "word": null }
],
"meta": { "credits_used": 1, "request_id": "...", "lang": "tr", "count": 2 }
}422 · Invalid body
{
"error": { "code": "invalid_request", "message": "Provide between 1 and 50 words." },
"meta": { "lang": "en" }
}Response field reference
Every stable response variable is described below. Additive fields may appear later, so clients should ignore fields they do not recognize.
Vocabulary object
| Field | Type | Nullable | Description |
|---|---|---|---|
id | string | No | Stable URL-safe slug. |
word | string | No | Canonical English word. |
part_of_speech | string | Yes | Grammatical class. |
level | string | Yes | Learning difficulty or catalog level. |
definition | string | Yes | Concise English definition. |
example | string | Yes | Natural example sentence. |
phonetic | string | Yes | Pronunciation transcription when available. |
translations | object<string,string> | No | Locale codes mapped to translations; may be empty. |
synonyms | string[] | No | Available synonyms. |
antonyms | string[] | No | Available antonyms. |
categories | string[] | No | Learning or semantic categories. |
media.image_url | URL string | Yes | Learning image URL. |
media.audio_url | URL string | Yes | Pronunciation audio URL. |
media.attribution | object | No | Required media attribution metadata. |
completeness | enum | No | catalog, translated, or enriched. |
Meta object
| Field | Type | When present | Description |
|---|---|---|---|
credits_used | integer | Metered responses | Credits charged by this request. |
request_id | UUID string | Metered success | Support and billing trace ID. |
lang | string | Always | Selected message locale. |
count | integer | List responses | Number of response items. |
next_cursor | string or null | Search | Next page cursor; null means final page. |
Error object
| Field | Type | Description |
|---|---|---|
error.code | string | Stable machine-readable code. |
error.message | string | Localized human-readable explanation. |
error.upgrade_url | string | Relative billing URL on a 402 result. |
meta.lang | string | Error-message locale. |
Errors
| HTTP | Code | Meaning | Client action |
|---|---|---|---|
| 401 | invalid_api_key | Missing, malformed, revoked, or inactive key. | Check the Bearer header or replace the key. |
| 402 | credits_exhausted | The account lacks credits for the operation. | Stop retries and direct the customer to billing. |
| 404 | not_found | The requested endpoint is not available. | Check the path and API version. |
| 404 | word_not_found | The requested vocabulary entry is unavailable. | Check spelling or use search. |
| 422 | invalid_request | A parameter or batch body is invalid. | Correct the request before retrying. |
| 405 | method_not_allowed | The endpoint does not accept the HTTP method. | Use the documented GET or POST method. |
| 413 | payload_too_large | The JSON request body exceeds 64 KB. | Reduce the batch body. |
| 415 | unsupported_media_type | The batch request is not JSON. | Send Content-Type: application/json. |
| 429 | rate_limit_exceeded | The API key exceeded 120 requests per minute. | Wait for Retry-After. |
| 5xx | server_error | An unexpected server-side failure. | Retry with backoff; contact support if persistent. |
Recommended retry policy
Do not retry 401, 402, or 404 automatically. For transient 5xx responses, use exponential backoff with jitter and a strict retry cap. Never create an unbounded retry loop because each accepted authenticated request may consume credits.
JavaScript / Node.js
const response = await fetch('https://api.wordlyenglish.com/v1/account', {
headers: {
Authorization: `Bearer ${process.env.WORDLY_API_KEY}`,
Accept: 'application/json'
}
});
const body = await response.json();
if (!response.ok) {
throw new Error(`${body.error.code}: ${body.error.message}`);
}
console.log(body.data.credits_remaining);Python
import os
import requests
response = requests.get(
'https://api.wordlyenglish.com/v1/account',
headers={
'Authorization': f'Bearer {os.environ["WORDLY_API_KEY"]}',
'Accept': 'application/json',
},
timeout=15,
)
response.raise_for_status()
print(response.json()['data']['credits_remaining'])PHP
$curl = curl_init('https://api.wordlyenglish.com/v1/account');
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('WORDLY_API_KEY'),
'Accept: application/json',
],
]);
$body = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
if ($status >= 400) {
throw new RuntimeException('Wordly API request failed');
}
$data = json_decode($body, true, flags: JSON_THROW_ON_ERROR);Dart / Flutter
Do not ship the Wordly key inside a Flutter application. The example belongs in a trusted Dart backend or server function.
final response = await http.get(
Uri.parse('https://api.wordlyenglish.com/v1/account'),
headers: {
'Authorization': 'Bearer ${Platform.environment['WORDLY_API_KEY']}',
'Accept': 'application/json',
},
);
final body = jsonDecode(response.body) as Map<String, dynamic>;
if (response.statusCode >= 400) {
throw Exception((body['error'] as Map)['code']);
}Production checklist
- Proxy Wordly requests through a trusted backend.
- Set connection and response timeouts.
- Handle
401,402,404, and5xxseparately. - Query
GET /v1/accountwhen your application needs the current balance. - Log endpoint, status, latency, and
request_idwithout logging the API key. - Use separate keys per environment and rotate them periodically.
- Cache stable vocabulary responses in your backend when appropriate.
Ready to make your first request?
Create an account, verify your email, and receive 50 free credits.
Need integration help? Email [email protected].