Links for every item
URL templates
Resource types, URL patterns, id formats and destinations.
Resource types#
A resource type names what you share: challenge, submission, product. It has a key
(lower case letters, digits and _, starting with a letter, 2 to 32 characters) and a name. The key
appears in payloads, reports and the metadata API URL, and cannot be changed. A type can be
archived but not deleted, because links, templates and click history refer to it. One environment can
have 20 types.
URL templates#
A URL template belongs to a resource type and describes the URL.
| Field | Meaning |
|---|---|
path_pattern | One to three fixed segments, then {id}: /c/{id}, /shared/challenge/{id}. The pattern cannot be changed later. A first segment such as api, admin or healthz is not allowed |
id_format | What an id may look like (below). The id is checked before anything else, so a wrong shape is a plain 404 |
deep_link_path | The route your app opens, for example /challenge/{id} |
data | Custom JSON your app receives; {id} and {type} work inside text values |
redirects | Optional destinations per platform: ios, android, web, desktop, fallback |
allow_param_passthrough | Whether query parameters (?ref=…) reach your app and are stored with the click |
status | active, disabled (the pattern stays taken and shows a status page) or archived (frees the pattern) |
Id formats#
| Format | Accepts |
|---|---|
numeric | Digits, up to 20 |
alnum | Letters and digits, up to 64 |
uuid, ulid | Exactly that shape |
base64url | Letters, digits, - and _ (use this for base64 ids; standard base64 uses /, which cannot be in one path segment) |
| Character set | Any of digits, lower, upper, dash, underscore, dot, equals, plus, with a minimum and maximum length (1 to 128) |
There are no custom regular expressions: a hand-written pattern can be slow on hostile input, and the redirect checks every request.
Placeholders#
{id} and {type} work in the app route, in text values of the data and in the platform URLs. The id
is percent-encoded wherever it lands in a URL, so an id can never add a path segment, a query
parameter or change the host, and a destination can never become an open redirect.
{query} is available at the end of the web, desktop and fallback URLs only. It appends the
click's parameters (?ref=U7K2X9AB&utm_source=ad), so your website receives them:
{ "web": "https://www.example.com/open/c/{id}{query}" }It only appends something when allow_param_passthrough is on, at most 1,024 characters are forwarded
(more: none), and a URL without {query} never receives the query.
Example#
{
"resource_type_id": "01HZX3Q8W5T7M9N2P4R6S8V0AB",
"path_pattern": "/c/{id}",
"id_format": { "kind": "preset", "preset": "numeric" },
"deep_link_path": "/challenge/{id}",
"data": { "kind": "{type}" },
"redirects": { "web": "https://www.example.com/open/c/{id}{query}" },
"allow_param_passthrough": true
}How a click is resolved#
Single-segment paths (/summer) are ordinary links. A path with two to four segments is matched
against your templates by its fixed prefix, then its id format. No match gives a 404 without a click
record. The match is booked on one hidden link per template, with the item id stored on the click, so
statistics by template and by item need no row per item.
Verify it works#
In Resources, Test a URL with a path such as /c/4521?ref=A, or through the API:
curl -X POST https://api.becklinks.com/v1/url-templates/test \
-H "Authorization: Bearer $SECRET_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"path":"/c/4521?ref=A"}'The answer says match, invalid_id or no_template, with the destinations rendered for that id.