Timeout & Retry Guide
This guide covers how Langbly handles timeouts, what client settings to use, and how to implement retry logic.
Server Processing Timeout
| Setting | Value | Description |
|---|---|---|
REQUEST_TIMEOUT_MS | 60,000 ms | Maximum server-side processing time per request |
| Per-LLM-call timeout | Dynamic | 8s base + 1s per 500 chars (max 60s) |
The server enforces an absolute deadline via AbortController. The request deadline auto-scales with input text length: short texts use the 60s base, but longer texts automatically get up to 120s. The per-LLM-call timeout also scales (8s base + 1s per 500 chars, max 90s). You never need to configure anything — the system adapts to your text size.
Client Timeout Override
You can control the server-side deadline per request using the x-timeout-ms request header:
| Header | Type | Default | Max |
|---|---|---|---|
x-timeout-ms | integer (ms) | 60,000 | 120,000 |
Example: send x-timeout-ms: 90000 to allow up to 90 seconds for a long text.
Recommended Client Timeout
Set your HTTP client timeout to 90 seconds.
This accounts for worst-case scenarios:
- ~12s permit acquisition (during high load)
- ~60s LLM response (long text)
- ~10s network overhead + safety margin
In practice, most requests complete in 1-5 seconds. The 90s timeout is a ceiling, not an expectation.
Character Limits by Plan
| Plan | Max chars per request | Header |
|---|---|---|
| Trial / Free | 10,000 | x-chars-limit: 10000 |
| Pay-As-You-Go | 50,000 | x-chars-limit: 50000 |
| API Paid (Starter/Growth/Scale) | 100,000 | x-chars-limit: 100000 |
The x-chars-limit header is included in every response so your client can auto-configure.
Retry Strategy
| Status | Meaning | Action |
|---|---|---|
| 200 | Success | No retry needed. Check x-quality-warning header for quality notes. |
| 400 | Bad request | Do not retry. Fix the request (check limits, format, params). |
| 401 | Unauthorized | Do not retry. Check API key. |
| 429 | Rate limit / quota | Respect Retry-After header. Use exponential backoff starting at 1s. |
| 502 | Translation failed | Retry once with the same request. |
| 503 | Capacity saturated | Respect Retry-After header. Retry after the indicated seconds. |
| 504 | Gateway Timeout | Retry with exponential backoff. Consider sending x-timeout-ms: 90000 header for long texts. |
| 5xx | Server error | Retry with exponential backoff (1s, 2s, 4s). Max 3 attempts. |
| Timeout | No response | Retry with exponential backoff. Consider increasing client timeout. |
Response Headers Reference
The following headers are included on every response — both success (200) and error (400, 502, 503, 504). They are always present, not only when an error occurs. A timeout is reflected in the HTTP status code (504), while x-timeout-ms always shows the configured deadline.
Always-present headers:
| Header | Example | Description |
|---|---|---|
x-request-id | abc-123-def | Unique request identifier for support |
x-processing-time-ms | 3842 | Server-side processing time in milliseconds |
x-timeout-ms | 60000 | Effective server timeout (default or from x-timeout-ms request header) |
x-chars-in | 1976 | Total input characters processed |
x-chars-out | 2104 | Total output characters produced |
x-chars-limit | 10000 | Your plan's character limit per request |
x-provider | gemini | Translation provider used |
x-cache-status | hit or miss | Whether response came from cache |
Conditional headers:
| Header | When | Description |
|---|---|---|
x-quality-warning | Quality gate failed | true when translation has known quality issues |
x-quality-checks-failed | Quality gate failed | Comma-separated list of failed checks |
x-glossary-entries-total | Glossary used | Total glossary entries provided |
x-glossary-entries-matched | Glossary used | Entries that matched input text |
Retry-After | 429 or 503 | Seconds to wait before retrying |
Code Examples
C# (.NET HttpClient)
using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient { Timeout = TimeSpan.FromSeconds(90) };
client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY");
async Task<string> TranslateWithRetry(string text, string target, int maxRetries = 3)
{
for (int attempt = 0; attempt < maxRetries; attempt++)
{
try
{
var payload = new { q = text, target };
var content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.langbly.com/language/translate/v2", content);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
return result;
}
if ((int)response.StatusCode == 429 || (int)response.StatusCode == 503)
{
var retryAfter = response.Headers.RetryAfter?.Delta
?? TimeSpan.FromSeconds(Math.Pow(2, attempt));
await Task.Delay(retryAfter);
continue;
}
if ((int)response.StatusCode == 400 || (int)response.StatusCode == 401)
throw new Exception($"Non-retriable error: {response.StatusCode}");
// 502 or 5xx: retry once
if (attempt == 0) continue;
throw new Exception($"Server error: {response.StatusCode}");
}
catch (TaskCanceledException) when (attempt < maxRetries - 1)
{
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
}
}
throw new Exception("Max retries exceeded");
}
Python (requests)
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.langbly.com/language/translate/v2"
def translate_with_retry(text: str, target: str, max_retries: int = 3) -> dict:
for attempt in range(max_retries):
try:
response = requests.post(
BASE_URL,
json={"q": text, "target": target},
headers={"x-api-key": API_KEY},
timeout=90,
)
if response.ok:
return response.json()
if response.status_code in (429, 503):
retry_after = int(response.headers.get("Retry-After", 2 ** attempt))
time.sleep(retry_after)
continue
if response.status_code in (400, 401):
raise ValueError(f"Non-retriable: {response.status_code} {response.text}")
# 502/5xx: retry
if attempt == 0:
continue
response.raise_for_status()
except requests.Timeout:
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
continue
raise
raise RuntimeError("Max retries exceeded")
JavaScript (fetch)
const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://api.langbly.com/language/translate/v2";
async function translateWithRetry(text, target, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 90000);
const response = await fetch(BASE_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY,
},
body: JSON.stringify({ q: text, target }),
signal: controller.signal,
});
clearTimeout(timeout);
if (response.ok) return response.json();
if (response.status === 429 || response.status === 503) {
const retryAfter = parseInt(response.headers.get("Retry-After") || "1");
await new Promise((r) => setTimeout(r, retryAfter * 1000));
continue;
}
if (response.status === 400 || response.status === 401) {
throw new Error(`Non-retriable: ${response.status}`);
}
if (attempt === 0) continue; // retry 502/5xx once
throw new Error(`Server error: ${response.status}`);
} catch (err) {
if (err.name === "AbortError" && attempt < maxRetries - 1) {
await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
continue;
}
throw err;
}
}
throw new Error("Max retries exceeded");
}