Errors You Can Act On: Specific Messages, Stable Codes, Request IDs
A good error answers three questions without a trip to the docs: what went wrong, which input caused it, and how do I tell support about this exact request. TimeLogic API errors now answer all three, every time.
One shape for every error
{
"error": {
"code": "INVALID_PARAMETER",
"message": "Invalid timezone.",
"details": { "tz": "Mars/Olympus" }
},
"request_id": "7b118d04-2dba-413d-bd5d-2d855d01b9bb"
}
error.codeis stable and machine-readable. Branch on it.error.messagenames the specific problem in plain English. Log it and show it to developers.error.detailsechoes the offending input when there is one, so you know exactly which parameter to fix.request_ididentifies the request. The same value is in theX-Request-Idheader of every response, successful or not.
Messages that point at the fix
Each message names what was wrong with the request:
| Request | Status and code | message |
|---|---|---|
tz=Mars/Olympus | 400 INVALID_PARAMETER | Invalid timezone. |
unix=abc | 400 INVALID_TIMESTAMP | Invalid unix timestamp. |
/v1/time/convert with no target | 400 MISSING_TARGET | Missing target selector. |
tz=Europe/Paris&ip=8.8.8.8 | 400 AMBIGUOUS_TARGET | Ambiguous target selectors. Provide only one of tz, ip, lat/lon, offset, auto_tz. |
holiday_country=LK | 400 INVALID_PARAMETER | Unsupported holiday calendar. |
POST instead of GET | 405 METHOD_NOT_ALLOWED | Only GET and HEAD are supported. |
The AMBIGUOUS_TARGET message even lists the selector families you can choose from.
Try one:
curl -i "https://api.timelogicapi.com/v1/time/convert?unix=1782000000&tz=Europe/Paris&ip=8.8.8.8" \
-H "Authorization: Bearer $TIMELOGIC_API_KEY"
Handle errors in a few lines
Because the shape never changes, one handler covers every endpoint. In Node 18+ (save as check.mjs, run node check.mjs):
const res = await fetch(
"https://api.timelogicapi.com/v1/time/convert?unix=1782000000&tz=Mars/Olympus",
{ headers: { Authorization: `Bearer ${process.env.TIMELOGIC_API_KEY}` } }
);
if (!res.ok) {
const { error, request_id } = await res.json();
console.error(res.status, error.code, error.message, error.details ?? {}, request_id);
// 400 INVALID_PARAMETER Invalid timezone. { tz: 'Mars/Olympus' } 7b118d04-...
} else {
console.log(await res.json());
}
A sensible retry policy falls straight out of the status code:
4xx: don't retry unchanged. The message anddetailstell you what to fix.429 QUOTA_EXCEEDED: the monthly quota is used up. Retrying won't help until the next period or a plan change.5xx: retry with exponential backoff, and quote therequest_idif it persists.
Request IDs make support fast
Log request_id (or the X-Request-Id header) with every failed call. When you contact us, that one value lets us find your exact request: no reproduction steps, no guessing at timestamps.
The full list
All error codes, the response headers and quota behaviour are documented on Errors & rate limits. Bulk requests use the same shape per item, so a single bad value doesn't fail the whole batch; see Bulk mode.
Clear errors are a feature. Treat them like one.