AlfaLinks
AlfaLinksGet $100 free

Recipe

Check page backlinks through an API and cache it honestly

Our index moves once a month, so most lookups can be served from memory. A recipe for caches that save credits without showing users stale lies.

The rule

Cache until the next index refresh, not for a fixed hour

Because the data changes roughly monthly, an hourly TTL buys you nothing but cost. A month-scoped key gives the same answer all month and invalidates in one move.

  • Key: action + domain + params + index month
  • TTL: until the month ends, plus a day of grace
  • Never cache an error response

Why a short TTL is just a donation to your credit balance

Teams new to link data copy habits from rank trackers. Habit one: they set a one-hour cache because positions move. Link graphs do not move like that.

A 2-credit backlinks call costs $0.0002. That sounds like nothing until a list view fires 50 of them per page load across 400 active workspaces, repeating every hour for identical answers.

The worked numbers below are an example, not a measurement of anyone's traffic. Assume 400 workspaces, 20 domain views each per day, 2 credits per view, and a 1-hour cache that hits maybe a fifth of the time. Credits burn roughly 5x faster than with a month key.

Keyword research tools need fresher data, and for those the big suites remain the better choice. For link context, monthly is the product.

TTL by action

Suggested, not mandated. All actions read the same monthly index.
ActionCreditsSuggested TTLWhy
overview, stats0Until month endFree, but your server still saves latency
bulk_dr1Until month endWhole customer table in one call
refdomains, backlinks2Until month end, per page paramInclude page, per, sort in the key
anchors, toppages2Until month endStable between refreshes
search, keyword37 daysRarely repeated, cheap to skip caching

Request example: warm the cache for a customer table

Call bulk_dr once per customer, not once per row. Up to 2,000 domains fit in one POST body and cost one credit.

bash
curl -X POST "https://alfalinks.net/api.php?action=bulk_dr&key=sk_live_..." \
  -d "domains=stripe.com,notion.so,linear.app,figma.com,vercel.com"

# billed once, whatever the row count

Stampede protection and other small things

  • Single-flight: if ten users open the same domain, make one upstream call and share the promise.
  • Warm on the first of the month with a background job, not at 9am when users arrive.
  • Store the response _credits.remaining and alert below a threshold you choose.
  • Cache the negative result 'domain not found' for a day, not a month.
  • Expose the cache age in the UI so support can answer 'when was this fetched?'.

Where this connects

The cache is the middle layer in the counter setup. Once it works, the cost per seat becomes predictable and you can price a plan around it with the per-seat comparison. Short pages deserve a clear end. This one has it.

Cache questions we see in code review

Should the cache live in the browser too?

A short browser cache helps back-button navigation, but the shared cache on your server does the real saving. Keep client-side storage to minutes, since users on different machines would otherwise see different numbers for the same domain on the same day.

What if a customer says a new link is missing?

Check the index month shown in your UI. If the link was added after the last refresh, it will appear after the next one. Offer a note, not a refund, because nothing is broken.

Can I bypass the cache on demand?

You can, but each bypass costs credits for an answer that is likely identical. Offer it to admins only, and rate-limit it per workspace to avoid accidental loops.

Pagination and the cache key

Pagination bites everyone once. Include it in the key.

The backlinks and refdomains actions return up to 1,000 rows per call, with page and per between 10 and 5000, and deep paging is capped at 50,000 rows, so a key without those parameters will serve page one for every request.

Sorting belongs in the key as well. A user who flips from DR descending to alphabetical expects a different list, and the cache has to oblige without a new upstream call when the full set is already stored.

Plan the export button separately: one background job, one stored file, and one notification when it is ready.