TEASEDocs
ProductsClubHow-to

Verify a smart link before it goes live

Catch dead-end routes, unminted country links, and other silent routing gaps a green /validate can miss.

Who this is for: a workspace owner.

Four read-only endpoints show exactly what a smart link will actually serve, before you publish or hand out the link. They run the same production resolver the live /r route uses — a green result here means the real funnel is sound, not just that the database rows look plausible.

Validate: the health check

curl https://app.tease.link/api/admin/smartlinks/42/validate \
  -H "Authorization: Bearer $TEASE_API_KEY"
{
  "ok": false,
  "blocking": 1,
  "warnings": 0,
  "issues": [
    {
      "severity": "block",
      "code": "dead_route",
      "message": "Audience \"German\" leads here, but country DE has no working link — the fan lands nowhere. Add a destination link or turn this arm off for it.",
      "fix": { "type": "country", "country": "DE" }
    }
  ]
}
SeverityMeaning
blockA fan really would land nowhere — a dead route, or (on a creator-owned host) a route that quietly falls back to the platform owner's own OnlyFans link instead of the creator's. Fix before publishing.
warnSoft: an arm is on but serves nowhere, the link itself is switched off, or nothing is attached to it yet — traffic may still flow through a different audience or default.

An inactive smart link is reported once, as inactive — the check skips the per-country scan entirely for it (an off link resolving to nothing everywhere would otherwise flood the list with the same root cause repeated per country).

Routing: the enriched read-model

/validate runs the live resolver; /routing goes further — it also reads the raw inventory directly, so it catches gaps the resolver-based check can miss entirely.

curl https://app.tease.link/api/admin/smartlinks/42/routing \
  -H "Authorization: Bearer $TEASE_API_KEY"

Each country row reports both arms' honest statuslive, inactive, unminted (the row exists but its URL is empty), or none — plus the effective paid/ftl split for that country:

{
  "smartlink_id": 42, "domain": "yourdomain.com", "slug": "main", "active": true,
  "public_url": "https://yourdomain.com/r/main",
  "default": { "arm": "paid", "code": "c1091", "url": "https://onlyfans.com/...", "status": "live" },
  "countries": [
    { "cc": "AU", "paid": { "code": null, "status": "unminted", "effective": "c1091" },
      "ftl": { "code": null, "status": "none" }, "split": { "paid": 100, "ftl": 0 },
      "serves": "default" }
  ],
  "issues": [ { "code": "paid_unminted", "severity": "warn", "cc": "AU",
                "title": "AU: paid link not issued",
                "why": "The AU/paid row is in the inventory, but its URL is empty (not issued).",
                "impact": "Fans from AU go to c1091; AU merges into \"other\".",
                "fix_tool": "dress_country", "fix_args": { "domain": "yourdomain.com", "country": "AU", "arm": "paid" },
                "fix_call": "dress_country{domain: 'yourdomain.com', country: 'AU', arm: 'paid'}" } ],
  "health": { "ok": true, "blocking": 0, "warnings": 1, "publishable": true,
              "summary": "Found: 1 warning(s)." }
}

This is exactly the AU-style gap /validate misses

A country whose paid link is unminted (an inventory row exists with an empty url) still resolves — it silently falls to the default — so /validate stays green while that country's traffic and attribution quietly leaks into "other". /routing's paid_unminted / ftl_unminted issues are the only place this surfaces.

Every issue also carries fix_tool / fix_args / fix_call — a ready-to-run machine action (built for an agent to both explain and repair the gap), alongside why and impact in plain language for a human.

Geo map and resolve: two ways to spot-check

Geo map — the same country → {arm, destination} scan as /routing's table, without the enriched issues, and queryable for an arbitrary country list:

curl "https://app.tease.link/api/admin/smartlinks/42/geo-map?countries=DE,FR,US" \
  -H "Authorization: Bearer $TEASE_API_KEY"

Resolve — a one-off dry-run for a single country (and, optionally, a pinned arm), returning exactly what /r/main would hand that visitor right now:

curl "https://app.tease.link/api/admin/smartlinks/42/resolve?country=DE" \
  -H "Authorization: Bearer $TEASE_API_KEY"

Neither endpoint applies subnet stickiness (there is no real visitor in a dry run) — when both arms are eligible for a country, each is resolved deterministically and returned as its own row rather than collapsing to one ambiguous answer.

What's next

Fix a gap by filling in the missing destination by hand, or dress it from the free pool at no OnlyFans cost.

On this page