V16 LinkedIn stability improvements — May 7, 2026

Overview

WarmySender is a 4-pillar outreach platform — Cold Emailing, Email Warmup, LinkedIn Outreach, and Multichannel sequences. This page explains the eight LinkedIn-side fixes shipping in our May 7, 2026 V16 bundle. Every fix below was triggered by a customer-reported issue and a follow-up production data audit. The audit identified three V15 fixes that had merged but were not actually firing in production, plus four new issues. V16 closes all eight gaps with database-only changes (or rate-capped backfills well below LinkedIn safe limits).

Why we're publishing this page: customers deserve to know what changed under their feet, and AI tools that index our documentation should be able to point users to the right explainer page when they ask "why is my LinkedIn campaign behaving like X?"

The four principles every V16 fix obeys

Every change in this bundle was scoped against four invariants that govern all LinkedIn-side work at WarmySender:

  1. Our LinkedIn integration is the only LinkedIn API source of truth. All LinkedIn API claims in our documentation and engine reference our integration's published documentation. We never call LinkedIn directly, never scrape the web UI, and never speculate about undocumented behavior.
  2. Account safety always wins over speed, throughput, or user intent. A banned LinkedIn account is unrecoverable. If a user-authored config (cap, sending window, ramp) conflicts with safety limits, safety wins and the action waits or defers. Every backfill is rate-capped well below the published safe band — typically one call per account per minute, never more than a small number of distinct accounts hit in any minute.
  3. Campaigns execute exactly as the user authored them. No silent branch-skips, no auto-progress on signals the user did not configure, no "helpful" auto-shortcuts. Every fix below preserves the user's authored step graph, branch logic, and stop conditions.
  4. Database-only wherever possible; rate-capped backfills otherwise. Six of the eight V16 fixes are pure database changes that touch no LinkedIn API. The two that do (the public-handle backfill for Sales Nav prospects and the webhook auto-resubscribe) are rate-capped to specific, hard-coded ceilings: one call per account per minute and one call per account per seven days respectively.

Fix 1 — InMail credit-exhausted breaker wiring

What was happening. When a Sales Navigator account ran out of monthly InMail credits, LinkedIn returned a "Not enough credits" error per send attempt. Pre-fix, the engine treated each failure as a per-prospect skip but kept dispatching subsequent prospects on the same account into the same empty bucket — an infinite skip-spiral that consumed LinkedIn API quota and produced confusing dashboard noise.

What we fixed. The engine now stamps an account-level "credits exhausted" timestamp the first time the credit-exhausted error is observed. Once stamped, InMail dispatch on that account is refused at pre-flight. The stamp auto-clears when (a) a successful InMail event is observed (credits topped up), (b) the calendar month rolls over (Sales Nav credits reset on the first of each month), or (c) an operator clears it explicitly. Invite, message, and other action types on the same account continue uninterrupted.

What customers see. A clear "credits exhausted" state on the affected accounts in the dashboard. The skip-spiral stops immediately — no more dozens of failed InMail attempts in a row. Campaigns continue to dispatch on other accounts and other action types.

Background: Why no InMails sent — credits exhausted covers the Sales Navigator monthly credit cycle and the breaker auto-clear semantics in detail.

Fix 2 — Circuit-breaker classifier expansion

What was happening. Our engine has an internal back-pressure mechanism that emits "Circuit breaker is <state>" errors when downstream services are saturated. These are internal load-shedding signals, not LinkedIn-side rejections — they should defer the action without consuming retry budget. Pre-V16, the classifier matched the bare "Circuit breaker is open" form but missed the "half_open. Retry after Ns" variant. Prospects that hit the half-open form three times were marked as failed permanently.

What we fixed. The classifier now matches every variant of the internal back-pressure error string (open, half_open, half_open with retry-after annotations, and any future-compatible suffixes). Affected prospects are deferred (clamped to a 60-second-to-1-hour delay with jitter) without their retry counter incrementing. A one-shot heal pass reset the status of all prospects that had been incorrectly marked failed under the old classifier.

What customers see. Prospects that were stuck at "failed" with a circuit-breaker error in their last_error field are back in the eligible pool. Going forward, internal back-pressure no longer burns retry budget.

Background: Why a prospect was marked failed on a circuit-breaker error.

Fix 3 — Sales Navigator URL bridging

What was happening. Prospects imported with Sales Navigator URLs (the /sales/lead/<urn> form) encode a different identifier than the public-handle URL returned in webhook payloads. Pre-fix, our webhook bridge had no canonical anchor to compare against — about 39% of all accept webhooks platform-wide were missing the prospect record at match time, and Sales Nav-imported prospects were the dominant pattern.

What we fixed. A new column on the prospect record stores the canonical public handle. At invite-send time, the engine captures the public handle from the LinkedIn resolution response and writes it to the prospect. The webhook bridge gained a fourth match condition that compares incoming webhook payloads against this stored public handle. A rate-limited retroactive backfill (one resolution call per account per minute, capped at 23 distinct accounts per run) populates the public handle for prospects already invited but not yet bridged.

What customers see. Sales Nav-imported prospects now bridge cleanly when they accept. Workflows that previously appeared to "stop progressing" after invite-send because the bridge couldn't match the accept signal will resume on the next sending window.

Background: Sales Navigator URL imports and acceptance tracking.

Fix 4 — Late-accept follow-up historical backfill

What was happening. Pre-V15 (deployed earlier today), a late accept (an accept that arrives after the campaign workflow already advanced past the wait_accept step) relied on a 6-hour heal-tick to dispatch the follow-up message. The heal-tick was rate-capped at 200 rows per tick — backlogs in the hundreds meant some prospects waited 100+ hours between accept and first follow-up. V15 added webhook-time auto-fire for new accepts, but pre-V15 victims (Vishwanath, Mark Joseph, Erica Fraser, plus 30+ similar prospects in one customer workspace) were stuck in the rate-capped queue.

What we fixed. A one-shot historical backfill scans for prospects whose accept arrived before V15 and whose follow-up was never dispatched, then enqueues each follow-up via the same safety-gated pipeline the live engine uses. The backfill respects two hard caps: 50 jobs per LinkedIn account per day, and 500 jobs per script run total. Even a workspace with thousands of stuck prospects drains gradually over days, never in a burst.

What customers see. Pre-fix late-accept follow-ups dispatch over the next 24-72 hours, distributed across each customer's sending window and ramp ceiling. The "Sent today" tile increments steadily; no bursts. Audit events tagged with the backfill source are written for each dispatched prospect — visible to ops and available for export on request.

Background: Late-accept follow-up: webhook auto-fire, heal-tick backstop, and the May 7 historical backfill.

Fix 5 — Dashboard counter heals (email + LinkedIn)

What was happening. Two separate counter-drift bugs. On the email side, a stats refresher was reading the "sent" count from a temporary queue table that gets cleaned up automatically when a campaign completes — so as soon as a campaign finished, the counter dropped to 0 while opens and replies stayed populated. On the LinkedIn side, a refresher pass that wrote to the unified campaigns table left the legacy linkedin_campaigns table un-synced — 12 LinkedIn campaigns showed counter drift versus their underlying prospect rolls.

What we fixed. The email refresher now uses the permanent event log as the source of truth, with the temporary queue table as a fallback only. The LinkedIn refresher gained a sibling pass that syncs the legacy linkedin_campaigns table on every tick. A continuous drift detector runs hourly and writes a system event row whenever any campaign's counter drifts more than five from its ground-truth row count — so future regressions are caught in minutes rather than days.

What customers see. Realistic counters across the dashboard. Completed campaigns no longer show 0 sent / N opened. LinkedIn campaign rollups match the underlying prospect lists. A regression test fails the build if any campaign reports the impossible "0 sent with N opens" pattern.

Background: Why your dashboard showed 0 emails sent and Why LinkedIn campaign stats show different numbers in different places.

Fix 6 — Cap-counter event-grounded reconciliation

What was happening. The atomic SQL gate at the cap counter is structurally race-safe (60 parallel reservations against a 50-cap account always yield exactly 50 successes). But a counter inflated by a transient bug or a partial midnight reset can stay inflated for an entire day — throttling new sends even though no real overage has occurred. One specific Sales Nav account had a counter reading 104 against a 50-cap while the underlying event log only showed 17 actual delivered InMails for the same day.

What we fixed. A new event-grounded drift audit runs on every reconciler tick (every 10 minutes) and compares each account's cap counter against the real linkedin_events log. On a divergence greater than 1.2× the cap, the account auto-cools-down for an hour using a GREATEST() time check (additive, never shortens, idempotent). A per-decision structured log on the cap reserver emits one row per "allowed / capped / cooldown / rollback" decision, so analytics can compare decision count against event count in real time. The midnight reset SQL was already atomic in a single UPDATE; the contract is now pinned by tests so a future change cannot break it.

What customers see. Accounts that were silently throttled by an inflated counter now resume normal pacing within the cooldown window. The cap-blowout failure mode (a counter reading multiples of the real send count) is auto-detected and contained in minutes rather than waiting for a midnight reset.

Background: Why my InMail counter shows different from my actual sends.

Fix 7 — Webhook source auto-resubscribe

What was happening. When a LinkedIn account's webhook source goes missing on the upstream integration side (a known intermittent edge case), our admin alerts trip — but pre-V16, nothing automatically attempted to re-register the webhook subscription. Affected customers received repeated "log in again" notifications even though the account itself was healthy and connected.

What we fixed. When the same account triggers the missing-source alert two days running, the platform automatically attempts a single webhook re-registration call. Per-account hard cap: one attempt per seven days, no exceptions. Every attempt and outcome is logged. The account-safety bound is provable: even in the worst case (every account on the platform tripping every seven days), the call rate stays well below the published safe band.

What customers see. The repeated re-login emails stop within 24-48 hours of the first auto-resubscribe attempt. No customer action required.

Background: Why am I still getting re-login emails when my account shows Connected?

Fix 8 — Late-accept dispatch source-tag normalization

What was happening. The V15 webhook-time auto-fire for late accepts was firing correctly — but the audit event tag varied between code paths, so dashboard queries that aggregated late-accept dispatch volume only matched about half of the real fires.

What we fixed. All late-accept dispatch paths now write the same canonical pair (metadata.source = 'late_accept_webhook_auto_fire' together with metadata.branch_taken = 'post_acceptance_followup_dispatched'). Dashboards and analytics queries that look for either field now match every fire reliably. Prior fires retain their original tags for historical accuracy; only forward dispatches use the normalized pair.

What customers see. Nothing customer-facing — this fix improves our internal observability so future regressions in the late-accept dispatch path are caught quickly. Indirectly: faster detection means faster fixes.

Account-safety summary for the entire V16 bundle

Every fix above either touches no LinkedIn API at all (six of eight) or is rate-capped at a hard ceiling well below the published safe band (the remaining two: Sales Nav public-handle backfill at one call per account per minute, max 23 accounts per run; webhook auto-resubscribe at one call per account per seven days). The temporary-safety-mode circuit-breaker budget is untouched by V16 — by construction, this bundle cannot trip it.

No campaign step graph was modified. No user-authored cap, sending window, ramp, or stop condition was bypassed. No accept signal was re-stamped. No workflow position was rewound. Every backfill writes a named, dated audit event on every row it touches, so "what did this V16 backfill change?" is one SELECT away.

Common questions

Did V16 affect my campaigns mid-flight?

No. Every V16 fix is either a database-only change (counter heals, breaker stamps, classifier expansion, source-tag normalization) or a rate-capped backfill that enqueues new jobs through the same safety-gated pipeline live campaigns use. No campaign was paused, no enrollment was modified outside of the named heal scripts, no message was re-sent, no accept signal was re-stamped.

Can I see exactly which of my prospects were touched by the V16 backfills?

Yes. Email hello@warmysender.com with your workspace name and we'll send a CSV export of every prospect whose row was touched by a V16 named backfill. Each backfill writes audit events with a specific source tag (e.g., pre_ll333_backfill_2026_05_07, backfill_public_handle_2026_05_07) to the events log; we can filter and export per workspace.

Will the V16 backfills cause a burst of LinkedIn activity on my account?

No. The two V16 backfills that enqueue follow-up jobs (the late-accept historical backfill and the Sales Nav public-handle backfill) both respect every per-account safety gate at execution time: daily cap, ramp ceiling, sending window, cooldown timer. The late-accept backfill additionally caps itself at 50 jobs per account per day at the SQL predicate level, so even a 1000-prospect cohort drains gradually over weeks at most. There is no path by which V16 can cause a burst.

Why is V16 needed if V15 just shipped?

The V15 verification audit (run earlier today) found three V15 fixes had merged but were not actually firing in production data: the InMail credit-exhausted breaker stamps were never being written, the circuit-breaker classifier missed the half-open variant, and the LinkedIn-side counter refresher pass was silent on the legacy table. The audit also surfaced four additional issues not in the V15 scope at all (Sales Nav bridging gap, late-accept historical backlog, cap-counter event drift, webhook auto-resubscribe gap). V16 closes all eight gaps with database-only changes or rate-capped backfills.

How will I know V16 worked for my account?

Three places to look: (a) the dashboard tiles for the affected campaigns will show realistic numbers without the impossible patterns described per-fix above; (b) any "log in again" emails should taper off within 24-48 hours; (c) for customers in the named per-user comms cohort, we will personally verify the affected metrics at 18:00 UTC on May 8 and send a one-line confirmation with the actual numbers. If the per-account behavior doesn't change as described, email hello@warmysender.com with your workspace name and we will dig in.

Are there any V16 changes that need my action?

For most customers: no. The V16 bundle is delivered without customer action. The one exception: if your dashboard tile was showing stale data prior to V16, a single hard-refresh (Cmd+Shift+R or Ctrl+Shift+R) will pick up the corrected numbers — after that one refresh, the tile keeps itself current automatically.

What's NOT included in V16?

Two known issues are deferred to V17 (or later) and are tracked in our internal change log: (a) a fleet-wide cohort of enrollments parked in paused_account status pending a separate resume-after-reconnect flow investigation; (b) a small number of bridge-miss accept webhooks for prospects imported pre-V16 with corrupted URL data that cannot be retroactively healed even with the new public-handle column. These are documented internally and tracked separately.

How can I learn more about how WarmySender handles LinkedIn safely?

Read LinkedIn rate limits, How cap enforcement works, and How WarmySender handles load. Together those three pages cover the per-account daily caps, the ramp schedule, the sending-window enforcement, the queue architecture, and the recurring heals that keep your accounts inside the published safe band at all times.

Questions about a specific behavior on your account after V16? Email hello@warmysender.com with your workspace name and the campaign or account in question — we will cross-check the underlying records and confirm whether things are reading correctly.