Skip to content
    All updates

    Errors You Can Act On: Specific Messages, Stable Codes, Request IDs

    2026-10-26

    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.code is stable and machine-readable. Branch on it.
    • error.message names the specific problem in plain English. Log it and show it to developers.
    • error.details echoes the offending input when there is one, so you know exactly which parameter to fix.
    • request_id identifies the request. The same value is in the X-Request-Id header of every response, successful or not.

    Messages that point at the fix

    Each message names what was wrong with the request:

    RequestStatus and codemessage
    tz=Mars/Olympus400 INVALID_PARAMETERInvalid timezone.
    unix=abc400 INVALID_TIMESTAMPInvalid unix timestamp.
    /v1/time/convert with no target400 MISSING_TARGETMissing target selector.
    tz=Europe/Paris&ip=8.8.8.8400 AMBIGUOUS_TARGETAmbiguous target selectors. Provide only one of tz, ip, lat/lon, offset, auto_tz.
    holiday_country=LK400 INVALID_PARAMETERUnsupported holiday calendar.
    POST instead of GET405 METHOD_NOT_ALLOWEDOnly 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 and details tell 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 the request_id if 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.