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.
2. Recreate links with /sdk/links
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"
}'
domainmust be one of the verified hosts returned byGET /projects/:id/domains. If multiple domains exist and you omit it, the API returns an error (see service logic insdk-links.controller.ts).type: "unified"expectsiosUrl/androidUrlinstead 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 futureresolverequests.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"
4. Resolve links the same way the redirect service does
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
- Export Firebase link inventory to CSV/JSON.
- Map each record to the
CreateSdkLinkDtopayload (choosedynamicvsunified, set verifieddomain, copy metadata/UTMs). - Call
/sdk/linksfor each entry; retry on rate-limit errors with exponential backoff. - Optionally bootstrap installations by replaying device data via
/sdk/installations/trackor/sdk/bootstrapif you stored it historically. - Use
/sdk/resolveto 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.