Skip to content

Runbook

When a backlink analyser workflow breaks: a runbook

Four failures cover almost every broken run. Find your symptom, read the cause, apply the fix. Each section ends with what to alert on next time.

Symptom, cause, first move

SymptomMost likely causeFirst move
HTTP 401Missing, malformed or revoked keyPrint the header your tool really sent
HTTP 402Credit balance is zeroTop up with USDT (TRC-20), rerun
HTTP 200 but empty rowsDomain unknown to the index, or a typoOpen the same domain in the free explorer
HTTP 200, fields missing in the next stepResponse shape differs from your testRe-run Test and re-map
Same numbers every weekIndex refreshes about monthlyNothing is broken; slow the schedule

Failure 1: 401, the key never arrived

Nine times in ten it is the header.

Check that the value reads Bearer sk_live_... with a single space, that the credential is attached to the right node, and that an expression like {{ $env.KEY }} did not resolve to an empty string on the production instance. In Zapier and Make the same error usually comes from a trailing space picked up when copying the key from the dashboard.

Alert rule: any 401 should stop the whole run, not just one item, because the next 400 items will fail the same way. Wiring that stop is covered in the n8n recipe, and in the pacing table for retries.

Failure 2: 402, the money ran out

This one is polite and final.

Retrying only repeats the refusal. A 402 means the balance can no longer cover the call, so branch on the status code and send yourself a message with the last _credits value you saw. Keep a rough floor, say a thousand credits, and warn when the balance drops under it. That gives you days of notice rather than minutes.

Top-up is USDT (TRC-20) from the account page, so build in a day for whoever holds the wallet.

Guard rails you can paste

An n8n IF condition for the error branch, and a Make filter in words. Both stop the loop cleanly and name the reason.

javascript
// n8n: Code node after HTTP Request (On Error: Continue)
const s = $json.statusCode ?? $json.status ?? 200;
if (s === 401) throw new Error('Deeplinkify key rejected, stop the run');
if (s === 402) return [{ json: { alert: 'Credit exhausted', last: $json._credits } }];
if ($json.ok === false) return [{ json: { alert: 'API said ok:false', body: $json } }];
return items;

// Make filter on the route after HTTP:
//   Status code  Equal to  402   ->  Slack: credit exhausted

Failure 3 and 4: empty rows and shape drift

Empty is not an error. Treat it as data.

A new or tiny domain may simply not be in our link index, which holds 181,132,097 domains and refreshes about monthly, so write an explicit not_found instead of a blank cell that later breaks a lookup.

Shape drift is different. Save one good response as a pinned sample, map your fields against it, and add a check that the keys you need are still present before writing to the sheet. If a key vanishes, stop and look. A run that silently writes empty strings into a client report is worse than a run that fails loudly.

Search Console makes a useful cross-check. If a link you know exists never shows in our output and also not in the Links report there, the page is probably new or blocked, and retrying will not change it. Ahrefs and Semrush crawl on their own schedules, so a disagreement between tools is normal, not a bug.

Quick answers

Can a bad key cost me credits?

No. A rejected request returns 401 and does nothing. The only way credits drain is a valid key calling a paid action, so if the balance drops unexpectedly, look for a loop that runs twice or a trigger that fires on every edit.

Why does the sheet show the same links as last month?

Because our index refreshes roughly once a month. Weekly jobs will often return identical data. Move the schedule to monthly, or keep it weekly only to catch rows you added by hand.

Where do I see the remaining balance in a workflow?

Every authenticated response includes _credits with the cost of that call and what is left. Free actions do not carry it. Write it into your log row after each paid call and chart it in the sheet.