Skip to main content
Documentation
API Reference

Links

Links API endpoints to create, list, retrieve, update, and delete deep links, including destinations, fallbacks, and UTM parameters.

POST/links

Create a link

Request Body

FieldTypeDescription
destination_url*string
slugstringCustom slug. Auto-generated if omitted.
namestringThe link's name in the dashboard. Shows the slug if omitted.
domainstringDomain to serve this link from. A link with an app defaults to the app's default_link_domain. A web-only link (no app) defaults to aplnk.to, and an existing link with no app keeps aplnk.to. A legacy app (legacy_apex_enabled) can use aplnk.to, its subdomain (link_domain) or a live custom domain. A new app can use its subdomain or a live custom domain, never aplnk.to (422 INVALID_DOMAIN). An explicit domain is never replaced. The slug test is reserved on an app subdomain. An app's previous subdomain (previous_link_domain) never takes new links.
ios_urlstring
ios_fallback_urlstring
android_urlstring
android_fallback_urlstring
og_titlestring
og_descriptionstring
og_image_urlstring
tagsstring[]
expires_atstringMust be in the future.
passwordstring
app_idstring
utm_sourcestringAdded to the redirect URL as utm_source when no higher source supplies one. Order for utm_source: an injected utm_source in "always" mode wins; otherwise the visitor's own utm_source when parameters.forwarding passes it, then a utm_source already in the destination URL, then an injected utm_source in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_mediumstringAdded to the redirect URL as utm_medium when no higher source supplies one. Order for utm_medium: an injected utm_medium in "always" mode wins; otherwise the visitor's own utm_medium when parameters.forwarding passes it, then a utm_medium already in the destination URL, then an injected utm_medium in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_campaignstringAdded to the redirect URL as utm_campaign when no higher source supplies one. Order for utm_campaign: an injected utm_campaign in "always" mode wins; otherwise the visitor's own utm_campaign when parameters.forwarding passes it, then a utm_campaign already in the destination URL, then an injected utm_campaign in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
match_window_hoursintegerDeferred deep link attribution match window in hours.
parametersobject | nullPer-link query-parameter rules. `injected` params are appended to the destination URL; `forwarding` controls which incoming params pass through. Org-level defaults are inherited and merged with link-level config (link wins on key conflict). Precedence: link > org. Send `null` (or omit) to clear/inherit the org defaults.

Responses

201Link created
FieldTypeDescription
idstring
short_urlstringe.g. https://aplnk.to/abc123
slugstringe.g. abc123
namestring | nullThe link's own name in the dashboard. Null shows the slug.e.g. Summer sale
domainstringe.g. aplnk.to
destination_urlstring
ios_urlstring | null
ios_fallback_urlstring | null
android_urlstring | null
android_fallback_urlstring | null
og_titlestring | null
og_descriptionstring | null
og_image_urlstring | null
app_idstring | null
utm_sourcestring | nullAdded to the redirect URL as utm_source when no higher source supplies one. Order for utm_source: an injected utm_source in "always" mode wins; otherwise the visitor's own utm_source when parameters.forwarding passes it, then a utm_source already in the destination URL, then an injected utm_source in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_mediumstring | nullAdded to the redirect URL as utm_medium when no higher source supplies one. Order for utm_medium: an injected utm_medium in "always" mode wins; otherwise the visitor's own utm_medium when parameters.forwarding passes it, then a utm_medium already in the destination URL, then an injected utm_medium in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_campaignstring | nullAdded to the redirect URL as utm_campaign when no higher source supplies one. Order for utm_campaign: an injected utm_campaign in "always" mode wins; otherwise the visitor's own utm_campaign when parameters.forwarding passes it, then a utm_campaign already in the destination URL, then an injected utm_campaign in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
match_window_hoursinteger | null
expires_atstring | null
is_activeboolean
tagsstring[]
parametersobject | nullPer-link query-parameter rules. `injected` params are appended to the destination URL; `forwarding` controls which incoming params pass through. Org-level defaults are inherited and merged with link-level config (link wins on key conflict). Precedence: link > org. Send `null` (or omit) to clear/inherit the org defaults.
created_atstring
updated_atstring
redirected_fromobject[]Old URLs of this link that redirect to it with a permanent 301, oldest first. Present only on GET /v1/links/{id} (and the get_link MCP tool), not on list, update, activate or deactivate responses.
400Validation error
FieldTypeDescription
error*object
401Unauthorized
FieldTypeDescription
error*object
403Forbidden. APP_REQUIRED: the organization has no registered app yet. Create an app with POST /apps, then create the link. LINK_LIMIT_EXCEEDED: the plan's link limit has been reached.
FieldTypeDescription
error*object
409SLUG_TAKEN: the slug is already taken on that domain, it is the old address of a moved link, or it is held for a link of the same app that still waits to move there (details.slug and details.domain, plus details.held_by with the old domain and slug for a held address). A slug must be unique only on the domain you pick. DEFAULT_DOMAIN_UNAVAILABLE: the request names no domain and the app's saved default is a custom domain that is no longer live (details.allowed_link_domains lists what to choose instead). APP_LINK_STATE_CHANGED: the app's address or default changed while the link was being created; read the app and retry.
FieldTypeDescription
error*object
422INVALID_DOMAIN: the domain is not allowed for this link. A new app cannot use aplnk.to. Use the app's subdomain or a live custom domain.
FieldTypeDescription
error*object
429Rate limit exceeded
FieldTypeDescription
error*object
GET/links

List links

Parameters

NameTypeInDescription
limitintegerquery
offsetintegerquery
tagstringquery
is_active"true" | "false"query
searchstringquery

Responses

200List of links
FieldTypeDescription
dataobject[]
paginationobject
401Unauthorized
FieldTypeDescription
error*object
403Forbidden
FieldTypeDescription
error*object
GET/links/{id}

Get a link

Parameters

NameTypeInDescription
id*stringpath

Responses

200Link details
FieldTypeDescription
idstring
short_urlstringe.g. https://aplnk.to/abc123
slugstringe.g. abc123
namestring | nullThe link's own name in the dashboard. Null shows the slug.e.g. Summer sale
domainstringe.g. aplnk.to
destination_urlstring
ios_urlstring | null
ios_fallback_urlstring | null
android_urlstring | null
android_fallback_urlstring | null
og_titlestring | null
og_descriptionstring | null
og_image_urlstring | null
app_idstring | null
utm_sourcestring | nullAdded to the redirect URL as utm_source when no higher source supplies one. Order for utm_source: an injected utm_source in "always" mode wins; otherwise the visitor's own utm_source when parameters.forwarding passes it, then a utm_source already in the destination URL, then an injected utm_source in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_mediumstring | nullAdded to the redirect URL as utm_medium when no higher source supplies one. Order for utm_medium: an injected utm_medium in "always" mode wins; otherwise the visitor's own utm_medium when parameters.forwarding passes it, then a utm_medium already in the destination URL, then an injected utm_medium in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_campaignstring | nullAdded to the redirect URL as utm_campaign when no higher source supplies one. Order for utm_campaign: an injected utm_campaign in "always" mode wins; otherwise the visitor's own utm_campaign when parameters.forwarding passes it, then a utm_campaign already in the destination URL, then an injected utm_campaign in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
match_window_hoursinteger | null
expires_atstring | null
is_activeboolean
tagsstring[]
parametersobject | nullPer-link query-parameter rules. `injected` params are appended to the destination URL; `forwarding` controls which incoming params pass through. Org-level defaults are inherited and merged with link-level config (link wins on key conflict). Precedence: link > org. Send `null` (or omit) to clear/inherit the org defaults.
created_atstring
updated_atstring
redirected_fromobject[]Old URLs of this link that redirect to it with a permanent 301, oldest first. Present only on GET /v1/links/{id} (and the get_link MCP tool), not on list, update, activate or deactivate responses.
401Unauthorized
FieldTypeDescription
error*object
403Forbidden
FieldTypeDescription
error*object
404Not found
FieldTypeDescription
error*object
PATCH/links/{id}

Update a link

Parameters

NameTypeInDescription
id*stringpath

Request Body

FieldTypeDescription
destination_urlstring
namestring | nullRename the link. Send null to show the slug again.
ios_urlstring | null
ios_fallback_urlstring | null
android_urlstring | null
android_fallback_urlstring | null
og_titlestring | null
og_descriptionstring | null
og_image_urlstring | null
tagsarray | null
expires_atstring | null
passwordstring | null
app_idstring | null
utm_sourcestring | nullAdded to the redirect URL as utm_source when no higher source supplies one. Order for utm_source: an injected utm_source in "always" mode wins; otherwise the visitor's own utm_source when parameters.forwarding passes it, then a utm_source already in the destination URL, then an injected utm_source in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_mediumstring | nullAdded to the redirect URL as utm_medium when no higher source supplies one. Order for utm_medium: an injected utm_medium in "always" mode wins; otherwise the visitor's own utm_medium when parameters.forwarding passes it, then a utm_medium already in the destination URL, then an injected utm_medium in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_campaignstring | nullAdded to the redirect URL as utm_campaign when no higher source supplies one. Order for utm_campaign: an injected utm_campaign in "always" mode wins; otherwise the visitor's own utm_campaign when parameters.forwarding passes it, then a utm_campaign already in the destination URL, then an injected utm_campaign in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
match_window_hoursinteger | null
parametersobject | nullPer-link query-parameter rules. `injected` params are appended to the destination URL; `forwarding` controls which incoming params pass through. Org-level defaults are inherited and merged with link-level config (link wins on key conflict). Precedence: link > org. Send `null` (or omit) to clear/inherit the org defaults.

Responses

200Updated link
FieldTypeDescription
idstring
short_urlstringe.g. https://aplnk.to/abc123
slugstringe.g. abc123
namestring | nullThe link's own name in the dashboard. Null shows the slug.e.g. Summer sale
domainstringe.g. aplnk.to
destination_urlstring
ios_urlstring | null
ios_fallback_urlstring | null
android_urlstring | null
android_fallback_urlstring | null
og_titlestring | null
og_descriptionstring | null
og_image_urlstring | null
app_idstring | null
utm_sourcestring | nullAdded to the redirect URL as utm_source when no higher source supplies one. Order for utm_source: an injected utm_source in "always" mode wins; otherwise the visitor's own utm_source when parameters.forwarding passes it, then a utm_source already in the destination URL, then an injected utm_source in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_mediumstring | nullAdded to the redirect URL as utm_medium when no higher source supplies one. Order for utm_medium: an injected utm_medium in "always" mode wins; otherwise the visitor's own utm_medium when parameters.forwarding passes it, then a utm_medium already in the destination URL, then an injected utm_medium in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_campaignstring | nullAdded to the redirect URL as utm_campaign when no higher source supplies one. Order for utm_campaign: an injected utm_campaign in "always" mode wins; otherwise the visitor's own utm_campaign when parameters.forwarding passes it, then a utm_campaign already in the destination URL, then an injected utm_campaign in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
match_window_hoursinteger | null
expires_atstring | null
is_activeboolean
tagsstring[]
parametersobject | nullPer-link query-parameter rules. `injected` params are appended to the destination URL; `forwarding` controls which incoming params pass through. Org-level defaults are inherited and merged with link-level config (link wins on key conflict). Precedence: link > org. Send `null` (or omit) to clear/inherit the org defaults.
created_atstring
updated_atstring
redirected_fromobject[]Old URLs of this link that redirect to it with a permanent 301, oldest first. Present only on GET /v1/links/{id} (and the get_link MCP tool), not on list, update, activate or deactivate responses.
400Validation error
FieldTypeDescription
error*object
401Unauthorized
FieldTypeDescription
error*object
403Forbidden
FieldTypeDescription
error*object
404Not found
FieldTypeDescription
error*object
422INVALID_DOMAIN: the link's domain is not one the new app_id uses, for example aplnk.to for a new app. A link's domain never changes, so create a new link for that app.
FieldTypeDescription
error*object

UTM Fields

utm_source, utm_medium and utm_campaign on a link add those query parameters to the URL a visitor is redirected to, including for links created before you set them. The same fields on the MCP create_link and update_link tools behave the same way.

A field applies to the URL the redirect sends the visitor to when that URL is an http or https URL. This covers the web destination and any http or https iOS or Android URL you set. It does not apply to pages on apps.apple.com, itunes.apple.com, play.google.com or apps.microsoft.com, or to custom-scheme deep links such as myapp://. Each field sets only its own key.

For one key, up to four sources can supply a value. The one that wins depends on the mode of an injected parameter for that key (in the link's parameters.injected or the organization's injected parameters):

  • An injected parameter in always mode wins over everything, including the visitor's own value.
  • Otherwise, the first of these that has a value wins:
    1. The visitor's own value, when parameters.forwarding passes that key. The default forwarding rule passes five keys: utm_source, utm_medium, utm_campaign, utm_term and utm_content. Other keys, such as utm_id, are not forwarded by default.
    2. A value already in the destination URL.
    3. An injected parameter in default mode. When one exists for the key, the link field is not used for that key.
    4. The link field.

So when the visitor, the destination URL, a default injected parameter and the link field all supply utm_source, the visitor's value is the one sent.

A key is never added twice. An empty or blank field adds nothing. Clearing a field (null on update) stops the tag on the next redirect. Clicks to a web destination record the UTM values the visitor was sent, read from the final URL, so an applied link field appears in analytics. App store and app scheme destinations keep the values from the tap.

DELETE/links/{id}

Delete a link

Permanently deletes the link. This is not reversible: it also removes the link's click history and frees the slug for reuse. To pause a link instead while keeping its data, send a PATCH with `is_active` set to `false`.

Parameters

NameTypeInDescription
id*stringpath

Responses

200Deleted link
FieldTypeDescription
idstring
short_urlstringe.g. https://aplnk.to/abc123
slugstringe.g. abc123
namestring | nullThe link's own name in the dashboard. Null shows the slug.e.g. Summer sale
domainstringe.g. aplnk.to
destination_urlstring
ios_urlstring | null
ios_fallback_urlstring | null
android_urlstring | null
android_fallback_urlstring | null
og_titlestring | null
og_descriptionstring | null
og_image_urlstring | null
app_idstring | null
utm_sourcestring | nullAdded to the redirect URL as utm_source when no higher source supplies one. Order for utm_source: an injected utm_source in "always" mode wins; otherwise the visitor's own utm_source when parameters.forwarding passes it, then a utm_source already in the destination URL, then an injected utm_source in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_mediumstring | nullAdded to the redirect URL as utm_medium when no higher source supplies one. Order for utm_medium: an injected utm_medium in "always" mode wins; otherwise the visitor's own utm_medium when parameters.forwarding passes it, then a utm_medium already in the destination URL, then an injected utm_medium in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
utm_campaignstring | nullAdded to the redirect URL as utm_campaign when no higher source supplies one. Order for utm_campaign: an injected utm_campaign in "always" mode wins; otherwise the visitor's own utm_campaign when parameters.forwarding passes it, then a utm_campaign already in the destination URL, then an injected utm_campaign in "default" mode (this field is then not used), then this field. Applies to http and https URLs only; not to apps.apple.com, itunes.apple.com, play.google.com, apps.microsoft.com or custom-scheme URLs.
match_window_hoursinteger | null
expires_atstring | null
is_activeboolean
tagsstring[]
parametersobject | nullPer-link query-parameter rules. `injected` params are appended to the destination URL; `forwarding` controls which incoming params pass through. Org-level defaults are inherited and merged with link-level config (link wins on key conflict). Precedence: link > org. Send `null` (or omit) to clear/inherit the org defaults.
created_atstring
updated_atstring
redirected_fromobject[]Old URLs of this link that redirect to it with a permanent 301, oldest first. Present only on GET /v1/links/{id} (and the get_link MCP tool), not on list, update, activate or deactivate responses.
401Unauthorized
FieldTypeDescription
error*object
403Forbidden
FieldTypeDescription
error*object
404Not found
FieldTypeDescription
error*object

Move Choice

If an app's links later move to its subdomain, a link whose slug is taken on the target stays where it is. Choose a new slug (used if the link moves, and its old URL then redirects to it) or keep the link where it is. Owners and admins can set the choice for any link, members for their own. DELETE clears the choice.

PUT/links/{id}/move-choice

Choose how a link moves

For a link that cannot move with its slug: move it with a new slug (the old URL redirects to it), or keep it where it is. Owners and admins may set it for any link, members for their own. Needs the links:write scope.

Parameters

NameTypeInDescription
id*stringpath

Responses

200The saved choice
FieldTypeDescription
link_idstring
choice"keep" | "new_slug"
new_slugstring | null
400Invalid link ID or body. SLUG_UNCHANGED when new_slug equals the link's current slug.
FieldTypeDescription
error*object
401Unauthorized
FieldTypeDescription
error*object
403Forbidden. A member can only change their own links.
FieldTypeDescription
error*object
404Not found
FieldTypeDescription
error*object
409SLUG_TAKEN when new_slug is held by a link or by an old URL on the target subdomain, or is the slug another link on the previous subdomain would use there, whether it chose it or keeps its own (details.slug and details.domain). LINK_MOVE_NOT_PENDING when the link does not use an app's previous subdomain.
FieldTypeDescription
error*object
DELETE/links/{id}/move-choice

Clear a link's move choice

Removes the choice, so the link moves with its slug when it can. Needs the links:write scope.

Parameters

NameTypeInDescription
id*stringpath

Responses

204Cleared
400Invalid link ID
FieldTypeDescription
error*object
401Unauthorized
FieldTypeDescription
error*object
403Forbidden. A member can only change their own links.
FieldTypeDescription
error*object
404Not found
FieldTypeDescription
error*object
409LINK_MOVE_NOT_PENDING when the link does not use an app's previous subdomain.
FieldTypeDescription
error*object

A link that has moved returns redirected_from on GET /v1/links/{id}: the old URLs that redirect to it, with the date each began. The field is not on the list, update, activate or deactivate responses.

GET/links/resolve/{slug}

Resolve a link by slug

Looks up a link by its slug and optional domain. Returns the link's deep link configuration for SDK use. A resolve that returns link data to the WarpLink SDK on a device records one click with the source `app_open`, so an in-app open appears in analytics and counts toward your plan's click allowance. Nothing else records a click: not a refusal, not a known bot, and not a server script or CI job calling this endpoint with a standard API key, which still receives the link data. `destination_url` and the platform URLs are normalized exactly the way the redirect path normalizes them, so a bare origin comes back with its trailing slash, and `custom_params` includes the query parameters already on the stored destination. A resolve that carries the same `X-WarpLink-Tap-Id` as an earlier one records one click, not two, so a client may safely retry a request whose response it never received. A slug that is the old address of a moved link resolves to the moved link: the response carries the link's current domain and slug, and the old address keeps working for as long as the link exists.

Parameters

NameTypeInDescription
slug*stringpath
domainstringqueryDomain to resolve the slug against. Defaults to aplnk.to.
paramsstringqueryThe tapped URL's raw query string, without the leading question mark. Applied to the returned destination and platform URLs the same way the redirect path applies it.
X-WarpLink-Tap-IdstringheaderA UUID identifying one tap. The WarpLink SDKs mint one per tap and send the same value on every bounded retry of that tap, so a request whose response was lost does not record a second click. Used as the click's id when it is a valid UUID; an absent or malformed value is ignored and an id is generated instead.

Responses

200Resolved link
FieldTypeDescription
idstring
slugstring
domainstring
destination_urlstring
ios_urlstring | null
ios_fallback_urlstring | null
android_urlstring | null
android_fallback_urlstring | null
custom_paramsobject
created_atstring
400Validation error
FieldTypeDescription
error*object
401Unauthorized
FieldTypeDescription
error*object
403The link is password protected (`PASSWORD_REQUIRED`). No destination or platform URLs are returned. Open the short URL in a browser to enter the password.
FieldTypeDescription
error*object
404Not found. A link on a suspended custom domain also returns this, so that a suspended domain cannot be told apart from a missing link.
FieldTypeDescription
error*object
410Link has expired
FieldTypeDescription
error*object