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" }
}
]
}| Severity | Meaning |
|---|---|
block | A 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. |
warn | Soft: 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 status — live, 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.
Fill in a smart link's destinations
Point each (arm, country) pair of a smart link at a concrete OnlyFans link, or set the arm-wide default.
Auto-fill a country slot from the free pool
Reuse a spare, already-minted OnlyFans link for a new (domain, country, arm) slot instead of minting a new one — one confirm, or a whole country pack at once.