Skip to main content

Smart routing (Business+)

Smart routing lets one short link resolve to different destinations based on rules you attach to it — by geography, device, time of day, or an A/B split. Rules are managed with a JWT (they are account-management operations) under the link's /routing sub-resource.

Reads and deletes stay available even after a downgrade, so you can inspect and clean up existing rules; creating rules requires the Business tier or above.

Rule types​

conditions is a JSON object whose shape depends on type:

typeRoutes onExample conditions
geoVisitor country/city{ "countries": ["US", "CA"], "cities": ["Austin"], "excludeCountries": ["RU"] }
deviceDevice type{ "devices": ["mobile", "tablet"] } (types: mobile, tablet, desktop, bot)
timeTime window{ "timezone": "UTC", "startTime": "09:00", "endTime": "17:00", "daysOfWeek": [1,2,3,4,5] }
ab_testA/B split{ "percentage": 50 } — matches ~50% of visitors

For geo, country codes are matched case-insensitively; for time, startTime / endTime are HH:mm (overnight ranges are allowed) and daysOfWeek is 0=Sunday … 6=Saturday. For ab_test, assignment is deterministic per visitor IP — a given visitor always lands in the same bucket, so a rule with percentage: 50 consistently serves the same variant to the same person.

Create a rule​

curl -X POST https://api.short.leonai.io/api/v1/links/<linkId>/routing \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "US shoppers",
"type": "geo",
"priority": 10,
"conditions": { "countries": ["US"] },
"destinationUrl": "https://example.com/us",
"weight": 100,
"enabled": true
}'

REST: POST /api/v1/links/:linkId/routing

FieldNotes
typegeo | device | time | ab_test (required)
conditionsJSON object interpreted per type (required)
destinationUrlWhere matching traffic goes (required)
priority0–1000; higher priority rules are evaluated first (default 0)
weight0–100 (default 100). Present on the model; A/B splitting is driven by conditions.percentage, not weight
nameOptional label
enabledDefault true

Manage rules​

# List all rules on a link
curl https://api.short.leonai.io/api/v1/links/<linkId>/routing \
-H "Authorization: Bearer <jwt>"

# Get one rule
curl https://api.short.leonai.io/api/v1/links/<linkId>/routing/<ruleId> \
-H "Authorization: Bearer <jwt>"

# Update a rule
curl -X PATCH https://api.short.leonai.io/api/v1/links/<linkId>/routing/<ruleId> \
-H "Authorization: Bearer <jwt>" -H "Content-Type: application/json" \
-d '{ "enabled": false }'

# Delete a rule
curl -X DELETE https://api.short.leonai.io/api/v1/links/<linkId>/routing/<ruleId> \
-H "Authorization: Bearer <jwt>"

How resolution works​

On each redirect, enabled rules are evaluated in priority order (highest first). The first rule whose conditions match wins and its destinationUrl is served. If no rule matches, the link's default longUrl is used.