Skip to main content

Automate Firebase Dynamic Links migration

Some teams created Firebase links via backend jobs. This guide shows how to recreate those slugs with the ULink REST surface that ships out of the apps/api/src/modules/sdk-links module.


1. Generate an API key

Inside the dashboard open Project → API Keys → Generate Key. The key maps to a single project ID and is sent via the X-App-Key header on every /sdk/* request.


The DTO matches CreateSdkLinkDto in apps/api/src/modules/sdk-links/dto/create-sdk-link.dto.ts. Each call enforces the same domain + verification checks you see in the dashboard.

curl -X POST "https://api.ulink.ly/sdk/links" \
-H "Content-Type: application/json" \
-H "X-App-Key: YOUR_ULINK_API_KEY" \
-d '{
"type": "dynamic",
"slug": "summer-offer",
"iosFallbackUrl": "https://apps.apple.com/app/id000000000",
"androidFallbackUrl": "https://play.google.com/store/apps/details?id=com.example.app",
"fallbackUrl": "https://example.com/campaign",
"parameters": {
"utm_source": "email",
"utm_campaign": "sunshine"
},
"metadata": {
"owner": "growth-team"
},
"domain": "links.shared.ly"
}'
  • domain must be one of the verified hosts returned by GET /projects/:id/domains. If multiple domains exist and you omit it, the API returns an error (see service logic in sdk-links.controller.ts).
  • type: "unified" expects iosUrl / androidUrl instead of fallback URLs.
  • All metadata persists and surfaces in Links → Analytics and exports.

3. Attach installations & sessions

ULink tracks MAU via /sdk/bootstrap, /sdk/installations/track, and /sdk/sessions/*. This telemetry is required so we can count monthly active users and enforce free-tier usage limits. If you previously forwarded Firebase analytics events, move them to these endpoints:

curl -X POST "https://api.ulink.ly/sdk/bootstrap" \
-H "Content-Type: application/json" \
-H "X-App-Key: YOUR_ULINK_API_KEY" \
-d '{
"installationId": "device-123",
"deviceModel": "iPhone16,2",
"osName": "iOS",
"osVersion": "18.0",
"appVersion": "3.4.1",
"metadata": {
"source": "ios-app"
}
}'

The response includes:

  • installationId — persisted per device.
  • installationToken — signed token you can attach to future resolve requests.
  • sessionId + sessionCreated — rolling 60-minute windows used in usage limits.

If you need to close sessions manually (the SDKs call this for you, but backend automation can also use it):

curl -X POST "https://api.ulink.ly/sdk/sessions/{sessionId}/end" \
-H "X-App-Key: YOUR_ULINK_API_KEY"

Use /sdk/resolve?url= to validate any migrated slug. This endpoint enforces domain/project matching plus usage limits:

curl "https://api.ulink.ly/sdk/resolve?url=https://links.shared.ly/example" \
-H "User-Agent: cli-test" \
-H "X-ULink-Client: migration-script" \
-i

Inspect the JSON payload to ensure per-platform destinations and metadata match your expectations before flipping DNS or campaign URLs.


5. Suggested migration script

  1. Export Firebase link inventory to CSV/JSON.
  2. Map each record to the CreateSdkLinkDto payload (choose dynamic vs unified, set verified domain, copy metadata/UTMs).
  3. Call /sdk/links for each entry; retry on rate-limit errors with exponential backoff.
  4. Optionally bootstrap installations by replaying device data via /sdk/installations/track or /sdk/bootstrap if you stored it historically.
  5. Use /sdk/resolve to smoke-test a sample of the imported slugs.

With these APIs wired up, all automation previously built on Firebase Dynamic Links will point entirely at ULink’s backend.