API/Attribution and Events

Attribution and Events

Install first-party attribution, identify customers, and ingest trusted conversions or revenue.

LinkQuick connects redirects, external customer identifiers, events, conversions, and revenue through first-party last-touch attribution. Browser events use a publishable site key. Trusted server events use a secret Admin API key. Never put an Admin API key in browser code.

Create a tracking site

Open Organization → Attribution, then create one tracking site for each destination application or group of applications that share the same allowed origins.

  • Give the site a recognizable name.
  • Add every production hostname that may send browser events. Enter hostnames without paths; full URLs are accepted and normalized.
  • Add preview, staging, or local hostnames explicitly when they need tracking. Wildcards are not accepted.
  • Choose an attribution window from 7 to 90 days. The default is 30 days.

LinkQuick creates a publishable key and a copy-ready configuration snippet immediately. The key is intentionally public and allowed origins protect ordinary browser use; they are not proof that an event is trusted. Treat browser events as product telemetry, and send conversions, entitlements, and revenue from your authenticated backend. Disable the tracking site to revoke browser ingestion without deleting historical attribution.

Install the browser SDK

Copy the generated snippet from Organization → Attribution. The hosted, framework-free client works in any browser application without a package-registry login or build dependency:

<script src="https://linkquick.melvynx.dev/linkquick.js"></script>
<script>
  const linkquick = LinkQuick.create({
    endpoint: "https://YOUR-CONVEX-DEPLOYMENT.convex.site",
    publishableKey: "lq_pk_YOUR_PUBLISHABLE_KEY",
    attributionWindowDays: 30,
  });
</script>

By default, initialization captures lf_id from the current URL, stores it in first-party localStorage, and removes only that parameter from the visible URL. Other query parameters and the URL fragment are preserved.

Load the script in the browser before initializing it. You can also pass a compatible storage implementation. Set captureOnInit: false only when the application calls linkquick.capture() itself.

Identify a customer

Call identify after the destination application knows its stable internal customer identifier. Do not use an email address as the identifier.

const result = await linkquick.identify(currentUser.id, {
  idempotencyKey: `identify:${currentUser.id}`,
});

if (!result.ok) {
  console.error(result.code, result.retryAfter);
}

The SDK attaches the most recent eligible click and remembers the customer ID for subsequent browser events.

Track a browser event

await linkquick.track("signup.completed", {
  metadata: {
    plan: "pro",
    source: "onboarding",
  },
  idempotencyKey: `signup.completed:${currentUser.id}`,
});

Browser ingestion accepts named product events, but it deliberately rejects trusted conversion revenue. Send conversions and money from a server.

Verify the installation

  1. Open an active short link in a new browser session.
  2. Confirm the destination initially receives lf_id and the SDK then removes it from the visible address.
  3. Confirm linkquick:attribution exists in first-party local storage.
  4. Sign in or complete the identified action in the destination application.
  5. Open the LinkQuick parent link. Its detail page shows whether attribution is configured, and its Analytics page shows identified users and events.
  6. Open Customers to inspect the attributed journey.

An invalid_key response means the key does not exist or the site is disabled. A forbidden_origin response means the request's exact hostname is missing from the tracking site. A rate_limited response includes retryAfter in milliseconds.

List customers

curl "https://linkquick.melvynx.dev/api/v1/customers?limit=50" \
  -H "Authorization: Bearer $LINKQUICK_API_KEY"

Add linkId=LINK_ID to return customers currently attributed to one link.

Read a customer journey

The path uses your application's stable external customer ID, URL encoded when necessary:

curl "https://linkquick.melvynx.dev/api/v1/customers/customer_123" \
  -H "Authorization: Bearer $LINKQUICK_API_KEY"

The response includes the customer aggregate and their events in descending order with cursor pagination.

Ingest a trusted conversion

Trusted conversions and revenue must be sent from a server with an Admin API key created under Organization → API Keys, never from browser code.

curl -X POST https://linkquick.melvynx.dev/api/v1/events \
  -H "Authorization: Bearer $LINKQUICK_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "externalCustomerId": "customer_123",
    "clickId": "CLICK_ID",
    "eventName": "subscription.created",
    "kind": "conversion",
    "revenueMinor": 9900,
    "currency": "EUR",
    "metadata": {"plan":"pro"},
    "idempotencyKey": "subscription-sub_123-created"
  }'

If clickId is absent or outside the attribution window, LinkQuick keeps a valid customer event without fabricating a link attribution.

Reuse a stable idempotencyKey for retries of the same business event. Revenue uses minor currency units, so 9900 EUR represents €99.00.

Audit recent events

curl "https://linkquick.melvynx.dev/api/v1/events?limit=100" \
  -H "Authorization: Bearer $LINKQUICK_API_KEY"
Analytics APIDomains and Imports API