Skip to main content

Update Link

Modify an existing link's properties including URLs, UTM parameters, targeting rules, and activation status.

Endpoint

PUT /api/links/:id

Authentication

Requires authentication via:

  • Bearer token (user session)
  • API key in Authorization header

Path Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesLink ID to update

Request Body

All fields are optional - only include the fields you want to update.

FieldTypeDescription
originalUrlstring (URL)Default destination URL
titlestringLink title/name
descriptionstringLink description
iosUrlstring (URL)iOS-specific redirect URL
androidUrlstring (URL)Android-specific redirect URL
webFallbackUrlstring (URL)Web fallback URL
utmParametersobjectUTM tracking parameters
utmParameters.sourcestringUTM source
utmParameters.mediumstringUTM medium
utmParameters.campaignstringUTM campaign
utmParameters.termstringUTM term
utmParameters.contentstringUTM content
targetingRulesobjectGeographic/device targeting
targetingRules.countriesstring[]ISO country codes (e.g., ["US", "CA"])
targetingRules.devicesstring[]Device types: "ios", "android", "web"
targetingRules.languagesstring[]Language codes (e.g., ["en", "es"])
attributionWindowHoursnumberHours for install attribution (1-2160)
expiresAtstring (ISO 8601)Expiration timestamp
isActivebooleanWhether link is active
templateIdstring (UUID)Link template to use
projectIdstring (UUID)Project ID

Note: You cannot update the shortCode - it's immutable after creation.

Response

Returns the updated link object:

{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"shortCode": "abc123",
"originalUrl": "https://example.com/products/new-headphones",
"title": "Updated: Wireless Headphones",
"iosUrl": "https://apps.apple.com/app/id123456789",
"androidUrl": "https://play.google.com/store/apps/details?id=com.app",
"utmParameters": {
"source": "facebook",
"medium": "cpc",
"campaign": "summer-sale-2024"
},
"attributionWindowHours": 336,
"isActive": true,
"updatedAt": "2024-03-15T14:30:00Z"
}

Examples

1. Update Destination URL

curl -X PUT https://api.linkforty.com/api/links/abc123-def456 \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"originalUrl": "https://example.com/new-product-page"
}'

Use case: Product link changed to different product.

2. Update UTM Parameters

curl -X PUT https://api.linkforty.com/api/links/abc123-def456 \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"utmParameters": {
"source": "twitter",
"medium": "social",
"campaign": "summer-sale-2024",
"content": "tweet-1"
}
}'

Use case: Change campaign tracking for different channel.

3. Extend Attribution Window

curl -X PUT https://api.linkforty.com/api/links/abc123-def456 \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"attributionWindowHours": 720
}'

Use case: Extend attribution from 7 days (168h) to 30 days (720h) for longer consideration purchases.

4. Update Platform URLs

curl -X PUT https://api.linkforty.com/api/links/abc123-def456 \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"iosUrl": "https://apps.apple.com/app/id999999",
"androidUrl": "https://play.google.com/store/apps/details?id=com.newapp"
}'

Use case: App store URLs changed after app relaunch.

curl -X PUT https://api.linkforty.com/api/links/abc123-def456 \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"isActive": false
}'

Use case: Temporarily disable link without deleting (campaign ended).

6. Add Expiration Date

curl -X PUT https://api.linkforty.com/api/links/abc123-def456 \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"expiresAt": "2024-12-31T23:59:59Z"
}'

Use case: Set expiration for limited-time offer.

7. Update Multiple Fields

curl -X PUT https://api.linkforty.com/api/links/abc123-def456 \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Black Friday Sale - Wireless Headphones",
"originalUrl": "https://example.com/black-friday/headphones",
"utmParameters": {
"campaign": "black-friday-2024",
"content": "hero-banner"
},
"expiresAt": "2024-11-30T23:59:59Z"
}'

Use case: Update link for seasonal campaign.

8. Update Targeting Rules

curl -X PUT https://api.linkforty.com/api/links/abc123-def456 \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"targetingRules": {
"countries": ["US", "CA", "GB"],
"devices": ["ios", "android"]
}
}'

Use case: Expand campaign to additional countries.

TypeScript Example

interface UpdateLinkRequest {
originalUrl?: string;
title?: string;
description?: string;
iosUrl?: string;
androidUrl?: string;
webFallbackUrl?: string;
utmParameters?: {
source?: string;
medium?: string;
campaign?: string;
term?: string;
content?: string;
};
targetingRules?: {
countries?: string[];
devices?: ('ios' | 'android' | 'web')[];
languages?: string[];
};
attributionWindowHours?: number;
expiresAt?: string;
isActive?: boolean;
templateId?: string;
projectId?: string;
}

async function updateLink(linkId: string, updates: UpdateLinkRequest) {
const response = await fetch(`https://api.linkforty.com/api/links/${linkId}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(updates),
});

if (!response.ok) {
throw new Error(`Failed to update link: ${response.statusText}`);
}

return response.json();
}

// Usage
const updated = await updateLink('link_id', {
title: 'New Product Launch',
utmParameters: {
campaign: 'product-launch-2024',
},
});

console.log('Updated:', updated.shortCode);

Common Use Cases

1. Seasonal Campaign Updates

Update links when campaigns change:

// Summer → Fall transition
await updateLink(linkId, {
title: 'Fall Sale - Wireless Headphones',
utmParameters: {
campaign: 'fall-sale-2024',
},
expiresAt: '2024-11-30T23:59:59Z',
});

2. A/B Test Different Destinations

Test different landing pages:

// Variant A
await updateLink('link_a', {
originalUrl: 'https://example.com/landing-page-a',
utmParameters: { content: 'variant-a' },
});

// Variant B
await updateLink('link_b', {
originalUrl: 'https://example.com/landing-page-b',
utmParameters: { content: 'variant-b' },
});

// After 1 week, check analytics and update losing variant

3. Update App Store URLs After Release

When new app version releases:

await updateLink(linkId, {
iosUrl: 'https://apps.apple.com/app/id123456789',
androidUrl: 'https://play.google.com/store/apps/details?id=com.app.v2',
});

4. Pause Campaign

Temporarily disable without deleting:

// Pause
await updateLink(linkId, { isActive: false });

// Resume later
await updateLink(linkId, { isActive: true });

Error Responses

{
"statusCode": 404,
"error": "Not Found",
"message": "Link not found"
}

Possible causes:

  • Link ID doesn't exist
  • Link belongs to different organization

No Updates Provided

{
"statusCode": 400,
"error": "Bad Request",
"message": "No updates provided"
}

Cause: Empty request body with no fields to update.

Invalid URL

{
"statusCode": 400,
"error": "Bad Request",
"message": "Validation error: Invalid URL format"
}

Cause: originalUrl, iosUrl, androidUrl, or webFallbackUrl is not a valid URL.

Invalid Attribution Window

{
"statusCode": 400,
"error": "Bad Request",
"message": "Attribution window must be between 1 and 2160 hours"
}

Cause: attributionWindowHours outside valid range (1-2160 hours = 1 hour to 90 days).

Best Practices

1. Update Only What Changed

Don't send entire object - only changed fields:

✅ Good:

await updateLink(linkId, {
title: 'New Title',
});

❌ Bad:

// Don't re-send unchanged fields
await updateLink(linkId, {
title: 'New Title',
originalUrl: link.originalUrl, // unchanged
iosUrl: link.iosUrl, // unchanged
androidUrl: link.androidUrl, // unchanged
// etc...
});

2. Validate Before Updating

function validateUrl(url: string): boolean {
try {
new URL(url);
return true;
} catch {
return false;
}
}

async function safeUpdateLink(linkId: string, updates: UpdateLinkRequest) {
// Validate URLs before sending
if (updates.originalUrl && !validateUrl(updates.originalUrl)) {
throw new Error('Invalid originalUrl');
}

return updateLink(linkId, updates);
}

3. Handle Optimistic Updates

Update UI immediately, rollback on error:

async function optimisticUpdate(link: Link, updates: UpdateLinkRequest) {
const originalLink = { ...link };
const updatedLink = { ...link, ...updates };

try {
// Update UI immediately
setLink(updatedLink);

// Send to server
const result = await updateLink(link.id, updates);

// Sync with server response
setLink(result);
} catch (error) {
// Rollback on error
setLink(originalLink);
showError('Failed to update link');
}
}

4. Batch Updates

If updating multiple fields, send one request:

✅ Good:

await updateLink(linkId, {
title: 'New Title',
originalUrl: 'https://example.com/new',
utmParameters: { campaign: 'new-campaign' },
});

❌ Bad:

await updateLink(linkId, { title: 'New Title' });
await updateLink(linkId, { originalUrl: 'https://example.com/new' });
await updateLink(linkId, { utmParameters: { campaign: 'new-campaign' } });

5. Track Update History

Log updates for audit trail:

async function updateLinkWithHistory(
linkId: string,
updates: UpdateLinkRequest,
reason: string
) {
const updatedLink = await updateLink(linkId, updates);

// Log update
await logUpdate({
linkId,
updates,
reason,
timestamp: new Date(),
updatedBy: currentUser.id,
});

return updatedLink;
}

Limitations

  • Short code cannot be changed - It's immutable after creation
  • Template change - Changing templateId doesn't retroactively apply template defaults
  • Click count - Cannot be manually modified (read-only)
  • Timestamps - createdAt cannot be changed, updatedAt is automatic

Guides