Create a smart link
Set up one /r/<slug> link with a paid/free-trial policy — no OnlyFans write, one link to hand out per domain.
Who this is for: a workspace owner or traffer.
A Route-Spine smart link
is one URL — https://yourdomain.com/r/main — that holds both your paid offer and your
free-trial offer and decides per visitor which to serve. Creating it is a pure database write:
POST /api/admin/smartlinks never touches OnlyFans.
curl -X POST https://app.tease.link/api/admin/smartlinks \
-H "Authorization: Bearer $TEASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "domain": "yourdomain.com", "name": "Main link" }'Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
domain | string | yes | Must already be a registered domain, and in the caller's scope. |
slug | string | no | 1–32 chars from [a-z0-9_-]. paid, ftl, and qr are reserved. Left empty, a unique slug is derived from name (transliterated, lowercased, --joined). |
name | string | no | A label to recognize it by. |
policy | object | no | The routing policy. Omitted, it defaults to a 50/50 split with the trial arm gated to countries that have their own trial link. |
Response
{
"id": 42,
"domain": "yourdomain.com",
"slug": "main",
"name": "Main link",
"policy": { "v": 1, "arms": { "paid": { "enabled": true, "weight": 50, "label": "Платная" },
"ftl": { "enabled": true, "weight": 50, "label": "Триал",
"require_country_link": true } }, "geo": [] },
"active": true,
"url": "https://yourdomain.com/r/main",
"created_at": 1751280000,
"updated_at": 1751280000
}url is the public address — hand it out as-is. A POST with a slug already taken on that
domain answers 400 slug_taken.
/r/paid and /r/ftl are retired addresses
They used to be two separate fixed links. Today they're aliases that fall through to the
domain's own smart-link policy — an old posted link keeps working, but you can't create new
ones under those slugs, and /r/ftl no longer guarantees a trial.
The policy shape
The policy is what makes the link "smart":
{
"v": 1,
"arms": {
"paid": { "enabled": true, "weight": 50, "label": "Платная" },
"ftl": { "enabled": true, "weight": 70, "label": "Триал", "require_country_link": true }
},
"geo": [
{ "countries": ["DE", "AT"], "arms": { "ftl": { "weight": 70 }, "paid": { "weight": 30 } } }
]
}arms.weight— an integer 1–1000; a weighted, sticky-by-subnet split betweenpaidandftl. A returning visitor keeps the arm they were first given.arms.ftl.require_country_link— defaultstrue. The trial arm only actually fires for a country that has its own trial destination in the inventory; every other country falls through to paid rather than getting a foreign trial by accident.geo— up to 200 per-country override rules, each replacing the base arm weights for the listed ISO codes.
Change it any time with PATCH /api/admin/smartlinks/{id} — routing picks up the new policy
within about a minute. Unknown fields anywhere in the policy are a validation error, not a
silently-ignored typo — 400 bad_policy lists every problem found.
Pin a single arm
https://yourdomain.com/r/main/paid or /r/main/ftl always serves that one arm, bypassing the
split — useful when a specific placement should never rotate. The plain /r/main link keeps
splitting by policy.
Turning a live link off needs a confirm
PATCH { "active": false } on a smart link that published buttons still point at answers
409 deactivate_confirm_required instead of silently 404-ing fans. Repeat the call with
"confirm": true once you've verified that's what you want.
A freshly created smart link has a policy but no destinations yet — every arm/country pair resolves to nothing until you fill them in.
What's next
Fill in where each arm points, then verify routing before you publish.