Skip to main content

Resolution API

These endpoints are public: no API key is required. They run in two places:

  • Your link domain (the host your short URLs use): the redirect page, the /data JSON twin, and the /.well-known/* association files. The host header selects the organization's configuration.
  • Your API host: POST /match, the endpoint the mobile SDKs call on first open.

How a click turns into an app open is explained in Routing & fallbacks and Deferred deep linking & the match flow; this page is the wire contract.

MethodPathPurpose
GET/:orgKey/:shortCodeRedirect page (HTML) for browsers
GET/:orgKey/:shortCode/dataLink data as JSON, for app-direct opens
POST/matchDeferred deep-link match (SDK first open)
GET/.well-known/apple-app-site-associationiOS Universal Links configuration
GET/.well-known/assetlinks.jsonAndroid App Links configuration

orgKey is exactly 4 alphanumeric characters; anything else returns 400 before any link lookup.

Resolve the redirect page​

GET /:orgKey/:shortCode

Statuses:

StatusBodyWhen
200text/htmlThe interactive redirect page
404error envelopeNo link with this code and org key
410error envelopeLink deactivated, link expired, or organization suspended
429error envelopeOver 500 requests/second from one IP

The 200 never carries an HTTP redirect status. Routing happens inside the page: the server returns HTML tailored to the User-Agent, and the page or the OS moves the visitor to app, store, or web fallback. The full decision tree: Routing & fallbacks.

Response headers worth knowing:

HeaderValueMeaning
Cache-Controlno-storeBrowsers get a fresh page every time; deferred tokens are single-use
Cache-Controlpublic, max-age=60Link-preview crawlers get a static page, cached 60 seconds
Accept-CHSec-CH-TimezoneAsks returning browsers for the timezone hint used in deferred matching

If the link has deferred deep linking enabled, the page also carries a one-time match token (opl_…): the page copies it to the clipboard and, on Android, embeds it in the Play Store referrer, so it survives the install. The token lives for the link's match window.

Known link-preview crawlers (WhatsApp, Facebook, X/Twitter, Telegram, LinkedIn, Slack, Discord, Skype previews, Snapchat, Pinterest, and others) get a static HTML page: OpenGraph and Twitter card tags, no JavaScript, no redirect, noindex. Social metadata falls back link → template → organization defaults.

GET /:orgKey/:shortCode/data

When a Universal Link or App Link opens your app directly, the OS verifies the domain and skips the redirect page entirely. The SDK fetches this endpoint to turn the URL into link data:

{
"linkId": "b1c2d3e4-5f6a-7890-abcd-ef1234567890",
"path": "/product/123",
"params": { "utm_source": "newsletter", "color": "blue" }
}

path and params are the effective values: template defaults merged under the link's own overrides. An optional ?deviceId= query parameter registers the device with your organization for analytics.

Statuses match the redirect page exactly (200, 404, 410, 429); the success body is JSON instead of HTML. The open also counts as a click.

Match a first open​

POST /match

Called by the mobile SDK on first app launch to recover the original click. No key is required. Sending your Mobile SDK key (opl_sdk_…) in an X-API-Key header attributes even failed matches to your organization.

Request body, all fields optional:

FieldTypeConstraintsPurpose
clipboardTokenstringmax 100 charsThe opl_… token copied by the redirect page
installReferrerstringmax 100 charsPlay Store install referrer token (Android)
deviceIdstring8–100 charsYour stable device ID; registers the device
platformstring—"iOS" or "Android"
osVersionstring—e.g. "17.4.1"
deviceModelstring—e.g. "iPhone16,1"
languagestring—e.g. "en-US"
timezonestring—IANA name, e.g. "America/New_York"

The backend tries signals in order and returns the strongest match: clipboard token, then install referrer (both deterministic), then exact fingerprint, then weighted scoring across device attributes, then same-IP as a last resort.

Matched:

{
"matched": true,
"matchMethod": "CLIPBOARD",
"matchConfidence": "exact",
"linkId": "b1c2d3e4-5f6a-7890-abcd-ef1234567890",
"path": "/product/123",
"params": { "color": "blue" }
}
FieldContents
matchMethodCLIPBOARD, INSTALL_REFERRER, FINGERPRINT_EXACT, FINGERPRINT_SCORED, IP_FUZZY, or NONE
matchConfidenceexact, high, medium, low, or none
matchScorePresent only for FINGERPRINT_SCORED; 0–100 weighted score

No match is still a 200:

{ "matched": false, "matchMethod": "NONE" }

What the tiers mean for your numbers: Attribution & match confidence. Statuses: 200, 400 (validation), 429 (30 requests/minute per IP).

A matched token is single-use: after a successful match the record is consumed (with a 30-second grace period for SDK retries), so a second open can't match the same click twice.

Association files​

Both files are served from every link domain and are scoped by the Host header. They are what makes OS-verified linking work; the portal's app configuration is their source. See Set up your organization.

EndpointServesMissing configuration
GET /.well-known/apple-app-site-associationApple App Site Association JSON404
GET /.well-known/assetlinks.jsonAndroid Digital Asset Links JSON404

On the OptoLink default domain, one file covers every organization: the AASA lists an appIDs entry per active organization with a complete iOS config, each scoped to /<orgKey>/*; assetlinks emits one statement per configured Android app. On a verified custom domain the files describe only that domain's organization. Both responses carry Cache-Control: public, max-age=3600, because Apple's and Google's CDNs re-fetch them periodically: expect up to an hour of delay after changing your app configuration.

Rate limits and caching on this path​

Rate limits: 500 requests/second per IP for the redirect page and /data, 30 requests/minute per IP for /match. Details and the 429 body: Rate limits & errors. Caching: no-store for browsers (match tokens are single-use), 60 seconds for crawler pages, one hour for association files.