Skip to main content

SDK Specification

Last updated: May 1, 2026

This document defines what every LinkForty SDK must implement. It is the canonical reference for contributors building SDKs in new languages or platforms.

The full specification is maintained in the Core repository. This page provides the same content in a browsable format.

Want to build a LinkForty SDK?

We welcome community SDKs for any platform. If you're building one, open an issue on GitHub to coordinate with the team and avoid duplicate work.

Overview

A LinkForty SDK must support 13 feature areas:

#FeatureDescription
1InitializationSDK setup, first launch detection
2Deferred Deep LinkingMatch installs to prior link clicks
3Direct Deep LinkingHandle links when app is already installed
4Server-Side URL ResolutionResolve Universal/App Links server-side
5Event TrackingIn-app conversion events
6Revenue TrackingStructured purchase tracking
7Link CreationCreate short links from the app
8User IdentityAssociate a user ID with SDK operations
9Attribution Data AccessRead cached attribution data locally
10Data ManagementClear data and reset SDK state
11ConfigurationRequired and optional settings
12Error HandlingExpected failure behaviors
13Offline ResilienceEvent queuing and retry

1. Initialization

The SDK must be initialized before any other functionality is used. Initialization performs these steps:

  1. Validate configuration (base URL, attribution window bounds, HTTPS enforcement)
  2. Set up internal components (networking, storage, fingerprint collection, deep link handling)
  3. Detect first launch and persist that state
  4. On first launch: collect a device fingerprint and report the install to the server
  5. On subsequent launches: load cached attribution data from local storage

Behavioral requirements

  • Initialization must be idempotent or guard against double-init
  • Methods that require initialization must fail clearly if called before init
  • The SDK should be usable as a singleton or single shared instance

2. Deferred Deep Linking

Matches a new app install back to the link click that drove it, using probabilistic device fingerprinting.

What the SDK must do

  1. On first launch, collect a device fingerprint containing:
    • User agent string
    • Timezone identifier
    • Device language
    • Screen dimensions (native pixels)
    • Platform (iOS / Android)
    • Platform version
    • App version
    • Optional device ID (IDFA/GAID, only if user consented)
  2. Send the fingerprint to the server
  3. Receive an attribution response containing: install ID, whether attributed, confidence score, matched factors, and deep link data (if attributed)
  4. Persist the install ID and deep link data locally
  5. Deliver the result to a registered callback (or null/nil for organic installs)
  6. Allow the callback to be registered before or after initialization (if registered after and data is already available, invoke immediately)

API endpoint: POST /api/sdk/v1/install

App token (Cloud only)

The SDK should accept an optional appToken during initialization and include it in the /api/sdk/v1/install request body. The app token is a public, workspace-scoped identifier that lets LinkForty Cloud attribute installs to the right workspace — including organic (unattributed) installs that wouldn't otherwise be tied to any workspace.

  • Where to find it: Dashboard → Workspace Settings → App Token
  • Format: at_<32 hex chars>
  • Safety: The token is public — designed to ship inside your app bundle. It only identifies which workspace owns the install; it cannot authenticate API actions or expose private data.
  • Self-hosted (Core): The endpoint accepts the field but ignores it. Self-hosted single-tenant deployments don't need it.
  • Without a token: Attributed installs (deeplink click → app open) still work via the existing fingerprint matcher. Organic installs (App Store discovery, social mentions, etc.) won't be visible in your workspace's analytics until the token is configured.

Example request body:

{
"userAgent": "...",
"platform": "ios",
"platformVersion": "17.4",
"deviceId": "...",
"appToken": "at_a1b2c3d4e5f6....",
"sdkName": "ios",
"sdkVersion": "1.4.0"
}

Every install and event request should also include sdkName (one of ios, android, flutter, react-native, expo) and sdkVersion (the SDK's own semantic version). These let LinkForty report which SDKs and versions are in use and flag outdated integrations. Both are optional and backward-compatible — older SDKs that omit them simply store null.


3. Direct Deep Linking

Handles the case where a user taps a LinkForty link and the app is already installed. The OS opens the app directly (via Universal Links on iOS, App Links on Android, or custom URL schemes).

What the SDK must do

  1. Accept an incoming URL from the app's deep link handler
  2. Parse the URL to extract the short code, UTM parameters, and custom query parameters
  3. If the SDK is configured with a server connection, resolve the URL server-side for enriched data
  4. Deliver the URL and parsed data to a registered callback
  5. Support multiple callback registrations

Platform notes

  • iOS: The app must manually pass the URL to the SDK (from onOpenURL or AppDelegate)
  • Android: Same -- the app passes the intent URL to the SDK
  • React Native / Expo: The SDK may automatically listen via the platform's linking API, but must still support explicit URL handling

4. Server-Side URL Resolution

When a Universal Link or App Link bypasses the redirect server (the OS opens the app directly), the SDK must resolve the link server-side to get the full link metadata.

What the SDK must do

  1. Extract path segments from the URL to determine the resolve path:
    • Single segment: /api/sdk/v1/resolve/{shortCode}
    • Two segments: /api/sdk/v1/resolve/{templateSlug}/{shortCode}
  2. Collect a device fingerprint and send it as query parameters (fp_tz, fp_lang, fp_sw, fp_sh, fp_platform, fp_pv)
  3. Return the enriched deep link data from the server response
  4. Fall back to local URL parsing if the server request fails (network error, timeout, etc.)

5. Event Tracking

Tracks in-app events for conversion attribution. Events are tied to the install ID so the server can correlate them with the original link click.

What the SDK must do

  1. Accept an event name and optional properties dictionary
  2. Send the event to the server with the install ID and timestamp
  3. Stamp the last-click attribution context on every event (see below)
  4. Include sdkName and sdkVersion (as on the install request)
  5. Handle failures gracefully (see Offline Resilience)

API endpoint: POST /api/sdk/v1/event

Last-click attribution

Every event should be credited to the deep link that most recently opened the app — a deferred install open or a direct re-engagement open — so the server can attribute in-app activity to the link that drove it. The SDK keeps an "active attribution context" that the newest deep-link open supersedes, persists it across app restarts, and stamps these fields onto every event:

FieldDescription
attributedLinkIdThe link currently credited (last-click). Omitted for organic activity (no deep link has opened the app).
attributedClickIdThe originating click id, when known.
linkOpenedAtISO 8601 timestamp of when that deep link opened the app.
sessionIdA per-app-open session id (generated on cold start, rotated on each new deep-link open) used to group a visit's screens.

The conversion window (how long a stamped event still counts) and session grouping are applied server-side at query time — the SDK only reports the active link, when it opened, and the current session.

Example request body:

{
"installId": "...",
"eventName": "add_to_cart",
"eventData": { "productId": "123" },
"timestamp": "2026-06-11T12:00:00.000Z",
"sdkName": "ios",
"sdkVersion": "1.4.0",
"attributedLinkId": "...",
"attributedClickId": "...",
"linkOpenedAt": "2026-06-11T11:58:00.000Z",
"sessionId": "..."
}

Screen views

Screen views are reported as a regular event named screen_view, with the screen name in eventData.screen (and the previously tracked screen in eventData.previousScreen when known). They flow through the same pipeline and carry the same attribution stamp, which powers the per-link screen-flow funnel.


6. Revenue Tracking

A convenience for tracking revenue-specific events with structured amount and currency fields. The Events dashboard aggregates revenue using this convention.

What the SDK must do

  1. Provide a trackRevenue(amount, currency, properties?) method
  2. Validate that amount is non-negative
  3. Send as an event via trackEvent with these exact fields:
    • Event name: revenue
    • Event data: { revenue: <amount as number>, currency: <ISO 4217 code>, ...properties }

Convention (all SDKs must follow this exactly)

FieldValueExample
Event name"revenue"
eventData.revenueNumeric amount (double/float)29.99
eventData.currencyISO 4217 currency code"USD"

The Events dashboard computes total revenue as SUM(event_data->>'revenue') WHERE event_name = 'revenue'. If an SDK uses a different event name or field name, revenue will not be aggregated correctly.


Allows apps to create short links on behalf of the user (e.g., for sharing content).

What the SDK must do

  1. Accept link creation options including an optional template ID, deep link parameters, title, description, custom code, UTM parameters, and external user ID
  2. Require an API key to be configured
  3. Send to POST /api/sdk/v1/links with an optional templateId in the request body:
    • With templateId: Uses the specified template (must belong to the organization; falls back to default if not found)
    • Without templateId: Uses the organization's default template (is_default = true), or the most recently created template if no default is set
  4. Return the created link's URL, short code, link ID, and deduplication status
  5. If an SDK-level external user ID is set (see User Identity), include it in the request body unless overridden per-call
warning

This feature requires an API key. SDKs must fail clearly if no API key is configured.


8. User Identity

Allows apps to associate an external user identifier with SDK operations, primarily link creation. This enables per-user deduplication and share attribution on the dashboard.

What the SDK must do

  1. Provide a method to set an external user ID (any string: UUID, email, integer, etc.)
  2. Provide a method to get the current external user ID
  3. Passing null/nil clears the stored ID
  4. The stored ID is automatically attached to all createLink() calls unless overridden per-call via CreateLinkOptions.externalUserId
  5. The ID is stored in memory only (not persisted to disk)
  6. Clearing SDK data or resetting the SDK also clears the external user ID

Behavioral requirements

  • The external user ID does not require initialization — it can be set before or after initialize()
  • Per-call externalUserId in CreateLinkOptions takes precedence over the SDK-level value
  • The value is not sent to any endpoint automatically — it is only included in link creation requests

9. Attribution Data Access

The SDK must provide access to cached attribution data from local storage without requiring a network call.

What the SDK must expose

  • Install ID -- the server-assigned UUID for this install
  • Install data -- the deep link data from attribution (null if organic)
  • First launch status -- whether this is the first launch of the app

10. Data Management

What the SDK must support

  • Clear data -- wipe all locally stored SDK data (install ID, attribution data, cached deep links, event queue). Used for testing and GDPR compliance.
  • Reset -- return the SDK to an uninitialized state so it can be re-initialized. This is separate from clearing data.

11. Configuration

Required configuration

FieldDescription
Base URLThe LinkForty server URL (e.g., https://go.yourdomain.com)

Optional configuration

FieldDescriptionDefault
API keyRequired for link creation and Cloud featuresNone
App tokenPublic workspace identifier for Cloud install scoping (format: at_<32 hex>). See Section 2 → App token. Self-hosted Core ignores this field.None
Debug modeEnable verbose loggingOff
Attribution windowHow far back to match installs to clicks7 days (168 hours)

Validation requirements

  • Base URL must be HTTPS (except localhost / 127.0.0.1 for local development)
  • Attribution window must be between 1 hour and 2160 hours (90 days)

12. Error Handling

SDKs must handle these error scenarios. The mechanism (typed enums, error codes, exceptions) is platform-specific.

ScenarioExpected behavior
Method called before initializationThrow/return an error
Double initializationWarn or throw
Network failure during install reportTreat as organic install, deliver null to callback
Network failure during URL resolutionFall back to local URL parsing
Network failure during event trackingQueue the event for retry
Link creation without API keyThrow/return an error
Server returns error responseSurface the error to the caller
Invalid configurationThrow/return an error during initialization

13. Offline Resilience

Event queue

Events should be queued locally when the network is unavailable and retried when connectivity is restored.

  • Maximum queue size: 100 events
  • Queue must persist across app restarts (local storage)
  • Provide a way to manually flush the queue
  • Provide a way to clear the queue without sending
  • Provide a way to check the queue size

Other operations

  • Install reporting: if the network call fails on first launch, treat as organic. The install can be re-attributed on a subsequent launch if the SDK detects it hasn't successfully reported yet.
  • URL resolution: fall back to local parsing (never block the deep link flow on a network call)

API Endpoints Reference

All endpoints are relative to the configured base URL.

Core endpoints (available in both self-hosted Core and Cloud)

MethodPathAuthPurpose
POST/api/sdk/v1/installNoneReport install, get deferred deep link. Body accepts optional appToken for Cloud workspace scoping.
GET/api/sdk/v1/resolve/:shortCodeNoneResolve link without redirect
GET/api/sdk/v1/resolve/:templateSlug/:shortCodeNoneResolve template link without redirect
POST/api/sdk/v1/eventNoneTrack in-app events
GET/api/sdk/v1/healthNoneHealth check

Cloud-only endpoints

MethodPathAuthPurpose
POST/api/sdk/v1/linksAPI keyCreate link (optional templateId; uses default template if omitted)

Authentication

When an API key is configured, send it as: Authorization: Bearer <api_key>


Data Models

Canonical field names for cross-SDK data models. SDKs should use platform-appropriate naming conventions (camelCase for Swift/Kotlin/JS/TS) but the data must map to these fields.

DeepLinkData

FieldTypeRequiredDescription
shortCodestringYesThe link's short code
iosUrlstringNoiOS destination URL
androidUrlstringNoAndroid destination URL
webUrlstringNoWeb fallback URL
utmParametersUTMParametersNoUTM tracking parameters
customParametersmapNoCustom query parameters
deepLinkPathstringNoIn-app routing path (e.g., /product/123)
appSchemestringNoApp URI scheme (e.g., myapp)
clickedAtdatetimeNoWhen the link was clicked (ISO 8601)
linkIdstringNoLink UUID from the backend

InstallResponse

FieldTypeRequiredDescription
installIdstringYesServer-assigned install UUID
attributedbooleanYesWhether install was matched to a click
confidenceScorenumberYesMatch confidence (0-100)
matchedFactorsstring[]YesWhich fingerprint factors matched
deepLinkDataDeepLinkDataNoLink data if attributed (null if organic)

CreateLinkOptions

FieldTypeRequiredDescription
templateIdstringNoTemplate UUID (uses organization's default template if omitted or not found)
templateSlugstringNoTemplate slug (for URL construction)
deepLinkParametersmapNoIn-app routing parameters
titlestringNoLink title
descriptionstringNoLink description
customCodestringNoCustom short code
utmParametersUTMParametersNoCampaign tracking parameters
externalUserIdstringNoIdentifier for the app user creating the link (enables per-user deduplication and share attribution)

CreateLinkResult

FieldTypeRequiredDescription
urlstringYesFull shareable URL
shortCodestringYesGenerated short code
linkIdstringYesLink UUID
deduplicatedbooleanNoTrue if an existing link was returned instead of creating a new one

UTMParameters

FieldTypeRequired
sourcestringNo
mediumstringNo
campaignstringNo
termstringNo
contentstringNo

DeviceFingerprint

FieldTypeRequiredDescription
userAgentstringYesApp/version + OS/version
timezonestringNoIANA timezone identifier
languagestringNoDevice language/locale
screenWidthnumberNoNative screen width in pixels
screenHeightnumberNoNative screen height in pixels
platformstringNoiOS, Android, etc.
platformVersionstringNoOS version string
appVersionstringNoHost app version
deviceIdstringNoIDFA/GAID (only if user consented)
attributionWindowHoursnumberNoAttribution window in hours

Feature Parity Matrix

Current status across existing SDKs. Update this table when adding features or SDKs.

#FeatureiOSReact NativeAndroidExpo
1InitializationDoneDoneDoneDone
2Deferred deep linkingDoneDoneDoneDone
3Direct deep linkingDoneDoneDoneDone
4Server-side URL resolutionDoneDoneDoneDone
5Event trackingDoneDoneDoneDone
6Revenue trackingDoneDoneDoneDone
7Link creationDoneDoneDoneDone
8User identityDoneDoneDoneDone
9Attribution data accessDonePartialDoneDone
10Data managementDonePartialDoneDone
11Configuration validationDoneMissingDoneDone
12Error handlingDonePartialDoneDone
13Offline resilienceDoneMissingDoneDone

React Native parity notes

  • Attribution data access: isFirstLaunch() is private, not exposed to consumers
  • Data management: No reset() method (only clearData())
  • Error handling: Uses generic Error throws instead of typed error cases
  • Configuration validation: No HTTPS enforcement or attribution window bounds checking
  • Offline resilience: Events are fire-and-forget; no queue, no retry on failure

Getting Started as a Contributor

Building your SDK

  1. Read the React Native SDK source as a reference implementation
  2. Implement the 13 feature areas in order (initialization first)
  3. Use the API endpoints and data models as your contract
  4. Test against a local LinkForty Core instance (quick start)

Submission requirements

Before an SDK can be listed on the LinkForty docs, we verify it works end-to-end. Please provide:

  1. Repository link and intended package registry name (npm, pub.dev, Maven, CocoaPods, etc.)
  2. Example app or /example folder demonstrating the core flows: initialization, deferred deep linking, direct deep linking, and link creation
  3. CI pipeline with linting and tests (GitHub Actions or equivalent)
  4. Install and quickstart documentation in the README

How SDKs are listed

TierRequirementsListed as
CommunityPasses end-to-end verification, meets submission requirements"Community SDK" on the docs site with link to your repo
OfficialMultiple stable releases, co-maintained with LinkForty team, transferred to the LinkForty GitHub org"Official SDK" with full documentation on the docs site

To get started, open an issue on GitHub to coordinate with the team and avoid duplicate work.