Overview
Most Mobaro API endpoints return a consistent set of HTTP status codes. Your integration should detect these responses and react appropriately (fix auth, adjust queries, or retry safely). The common responses include 401 Unauthorized, 404 Not Found, 429 Too Many Requests, and 503 Service Unavailable (plus 400/500) across endpoints like Users, Timesheets, Webhooks, etc.
Quick reference: what each code means & what to do
Code | What it means | Action you should take |
401 Unauthorized | Missing/invalid | Verify header, key validity, and environment; do not retry until fixed. mobaro (2) |
404 Not Found | Resource or route not found | Check IDs, routes, and filters; do not blind-retry. mobaro (2) |
429 Too Many Requests | You hit a rate limit | Implement exponential backoff and retry after a delay. mobaro (2) |
503 Service Unavailable | Temporary service issue | Retry with backoff; add jitter; give up after a few attempts. mobaro (2) |
Tip: Many list endpoints support Limit and Offset. Use them to paginate and avoid hitting limits when fetching large datasets.
Handling each error in practice
401 Unauthorized
Ensure the header is exactly
X-Api-Key: YOUR_SECRET_TOKEN.Confirm the key hasn’t been rotated or restricted.
Only retry after fixing credentials. Blind retries waste quota and time.
404 Not Found
Re-check the resource path and the ID you’re requesting (e.g.,
/users/{id},/timesheets/{id}).If looking up by filters, verify the record actually exists first (list → pick ID → get).
429 Too Many Requests (rate limits)
Back off and retry. Use exponential backoff (e.g., 1s, 2s, 4s, 8s) with jitter to avoid thundering herds.
Break large exports into pages using
Limit/Offset.Stagger scheduled jobs and avoid concurrent high-volume calls.
503 Service Unavailable
Treat as temporary. Retry with exponential backoff + jitter.
Stop after a capped number of attempts (e.g., 3–6 tries) and alert your team.
Safe retry pattern (pseudocode)
maxAttempts = 5
delay = 1s
for attempt in 1..maxAttempts:
resp = call_api()
if resp.status in [200..299]: return resp
if resp.status == 401 or resp.status == 404:
abort (fix config/IDs; do not auto-retry)
if resp.status in [429, 503]:
sleep(delay + random_jitter())
delay *= 2
continue -> raise error with context
Minimal, copy-paste retry helpers
Python (requests)
import time, random, requests
API = "https://app.mobaro.com/api/customers/users"
HEADERS = {"X-Api-Key": "YOUR_SECRET_TOKEN"}
def get_with_retry(url, headers, attempts=5, base=1.0):
delay = base
for i in range(attempts):
r = requests.get(url, headers=headers)
if 200 <= r.status_code < 300:
return r
if r.status_code in (401, 404):
raise RuntimeError(f"Non-retryable {r.status_code}: {r.text}")
if r.status_code in (429, 503):
time.sleep(delay + random.uniform(0, 0.5))
delay *= 2
continue
r.raise_for_status()
raise TimeoutError("Max retries exceeded")
resp = get_with_retry(API, HEADERS)
print(resp.json())
Node.js (fetch)
import fetch from "node-fetch";
async function getWithRetry(url, opts = {}, attempts = 5, base = 1000) {
let delay = base;
for (let i = 0; i < attempts; i++) {
const res = await fetch(url, opts);
if (res.ok) return res;
if (res.status === 401 || res.status === 404) {
throw new Error(`Non-retryable ${res.status}`);
}
if (res.status === 429 || res.status === 503) {
await new Promise(r => setTimeout(r, delay + Math.random() * 250));
delay *= 2;
continue;
}
throw new Error(`${res.status} ${await res.text()}`);
}
throw new Error("Max retries exceeded");
}
const res = await getWithRetry(
"https://app.mobaro.com/api/customers/users",
{ headers: { "X-Api-Key": "YOUR_SECRET_TOKEN" } }
);
console.log(await res.json());
Observability checklist
Log: endpoint, status code, attempt number, and delay used.
Alert on repeated 401s (key/config problem) and spikes of 429/503 (load or scheduling issue).
Record last successful page/ID so your job can resume after a failure.
Make creates/updates idempotent (e.g., “upsert by external ID”) to be safe on retries.
Frequently asked questions
Q: Why am I getting 429s during large exports?
A: Likely too many requests in a short window. Paginate with Limit/Offset, and add backoff between pages.
Q: Should I ever retry 401 or 404?
A: No. Fix credentials (401) or identifiers/paths (404) first; then try again.
Q: Are these codes consistent across endpoints?
A: Yes—endpoints like Users, Timesheets, and Webhooks list the same 400/401/404/429/500/503 patterns.
