Skip to main content

Handling Errors Gracefully

Robust error handling is essential for production We-Link integrations. This guide covers patterns for every error category.

Error Handling Strategy

Complete Error Handler

class WeLinkClient {
constructor(apiKey, apiSecret) {
this.apiKey = apiKey;
this.apiSecret = apiSecret;
this.baseUrl = "https://api.we-link.ai/api/v1";
}

async request(endpoint, body, retries = 3) {
for (let attempt = 0; attempt <= retries; attempt++) {
try {
const response = await fetch(`${this.baseUrl}/${endpoint}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": this.apiKey,
"x-api-secret": this.apiSecret,
},
body: JSON.stringify(body),
});

// Rate limited
if (response.status === 429) {
const retryAfter = parseInt(
response.headers.get("retry-after") || "3600",
);
console.warn(`⏳ Rate limited. Waiting ${retryAfter}s...`);
await sleep(retryAfter * 1000);
continue;
}

// Server error — retry with backoff
if (response.status >= 500) {
if (attempt < retries) {
const delay = Math.pow(2, attempt) * 1000;
console.warn(`🔄 Server error. Retry in ${delay}ms...`);
await sleep(delay);
continue;
}
}

// Client error — don't retry
if (response.status >= 400) {
const error = await response.json();
throw new WeLinkError(error.error, response.status, error);
}

return await response.json();
} catch (err) {
if (err instanceof WeLinkError) throw err;
if (attempt === retries) throw err;
}
}
}
}

class WeLinkError extends Error {
constructor(code, status, details) {
super(`WeLink API Error: ${code}`);
this.code = code;
this.status = status;
this.details = details;
}
}

Webhook Error Handling

Handle different failure scenarios in your webhook receiver:

app.post("/webhook", (req, res) => {
res.status(200).send("OK");

const payload = req.body;

if (payload.status === "FAILED") {
switch (payload.error) {
case "WRONG_PASSWORD":
// Notify user to update credentials
notifyUser(payload.accountId, "Please update your LinkedIn password");
break;

case "SESSION_EXPIRED":
// Attempt re-authentication
reAuthenticate(payload.accountId);
break;

case "STATUS_429":
// LinkedIn rate limit — pause this account
pauseAccount(payload.accountId, 60 * 60 * 1000); // 1 hour
break;

case "PROXY_ERROR":
// Check and reactivate proxy
checkProxy(payload.accountId);
break;

case "RECRUITER_ACKNOWLEDGEMENT_REQUIRED":
// Alert user — manual action needed
notifyUser(
payload.accountId,
"LinkedIn Recruiter requires acknowledgement",
);
break;

default:
console.error(`Unhandled error: ${payload.error}`);
alertOps(payload);
}
}
});

Best Practices Summary

PracticeWhy
Always validate webhook signaturesPrevent processing tampered data
Use idempotent handlersHandle at-least-once delivery
Log all errors with request_idEnable debugging and support
Set up alerts for recurring errorsCatch systemic issues early
Implement circuit breakersPrevent cascading failures
Queue failed actions for retryDon't lose work on transient failures