Skip to main content

Projects

Organize links into projects for better management and campaign tracking.

Overview

Projects are folders that help you organize links within your organization. They're perfect for:

  • Grouping links by campaign
  • Separating client work
  • Organizing by department or team
  • Tracking project-specific analytics

Key Benefits:

  • 📁 Organization - Group related links together
  • 📊 Analytics - View aggregated metrics per project
  • 🔍 Filtering - Quickly find links by project
  • 👥 Collaboration - Share project context with team

Creating Projects

Via Dashboard

  1. Go to Projects in the sidebar
  2. Click "New Project"
  3. Enter project name
  4. (Optional) Add description
  5. Click "Create"

Via API

curl -X POST https://api.linkforty.com/api/projects \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Spring Sale 2024",
"description": "Instagram and email marketing campaign for Q1 spring sale"
}'

Response:

{
"id": "proj_abc123",
"user_id": "user_456",
"organization_id": "org_789",
"name": "Spring Sale 2024",
"description": "Instagram and email marketing campaign for Q1 spring sale",
"created_at": "2024-03-15T10:30:00Z",
"updated_at": "2024-03-15T10:30:00Z"
}

Requires: Member, Admin, or Owner role

Managing Projects

Viewing All Projects

Dashboard:

  • Click "Projects" in sidebar
  • See all projects with link counts

API:

curl https://api.linkforty.com/api/projects \
-H "Authorization: Bearer $LINKFORTY_API_KEY"

Response:

[
{
"id": "proj_123",
"name": "Spring Sale 2024",
"description": "Q1 spring sale campaign",
"created_at": "2024-03-15T10:30:00Z",
"updated_at": "2024-03-15T10:30:00Z"
},
{
"id": "proj_456",
"name": "Product Launch",
"description": "New product launch links",
"created_at": "2024-02-01T14:00:00Z",
"updated_at": "2024-02-10T09:15:00Z"
}
]

Getting Project Details

API:

curl https://api.linkforty.com/api/projects/proj_abc123 \
-H "Authorization: Bearer $LINKFORTY_API_KEY"

Response:

{
"id": "proj_abc123",
"user_id": "user_456",
"organization_id": "org_789",
"name": "Spring Sale 2024",
"description": "Instagram and email marketing campaign for Q1 spring sale",
"created_at": "2024-03-15T10:30:00Z",
"updated_at": "2024-03-15T10:30:00Z"
}

Updating Projects

Dashboard:

  1. Go to Projects
  2. Click project name
  3. Click "Edit"
  4. Update name or description
  5. Click "Save"

API:

curl -X PUT https://api.linkforty.com/api/projects/proj_abc123 \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Spring Sale 2024 - Extended",
"description": "Extended through April due to success"
}'

Requires: Member, Admin, or Owner role

Deleting Projects

⚠️ Warning: Deleting a project does NOT delete the links inside. Links are unassigned and remain in your organization.

Dashboard:

  1. Go to Projects
  2. Click project
  3. Click "Settings""Delete Project"
  4. Confirm deletion

API:

curl -X DELETE https://api.linkforty.com/api/projects/proj_abc123 \
-H "Authorization: Bearer $LINKFORTY_API_KEY"

Response:

{
"success": true
}

Requires: Admin or Owner role (for deletion)

Dashboard:

  1. Click "Create Link"
  2. Select project from dropdown
  3. Fill in link details
  4. Click "Create"

API:

curl -X POST https://api.linkforty.com/api/links \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"originalUrl": "https://shop.example.com/spring-sale",
"projectId": "proj_abc123",
"title": "Instagram Story - Spring Sale"
}'

Dashboard:

  1. Go to Links
  2. Click link to edit
  3. Select project from dropdown
  4. Click "Save"

API:

curl -X PUT https://api.linkforty.com/api/links/link_xyz789 \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"projectId": "proj_abc123"
}'

Dashboard:

  1. Go to Links
  2. Use project filter dropdown
  3. Select project

API:

curl "https://api.linkforty.com/api/links?projectId=proj_abc123" \
-H "Authorization: Bearer $LINKFORTY_API_KEY"

Project Analytics

View aggregated analytics for all links in a project.

Via Dashboard

  1. Go to Projects
  2. Click project name
  3. View analytics tab

Via API

curl "https://api.linkforty.com/api/analytics/projects/proj_abc123?days=30" \
-H "Authorization: Bearer $LINKFORTY_API_KEY"

Response:

{
"totalClicks": 5432,
"uniqueClicks": 3821,
"clicksByDate": [
{
"date": "2024-03-15",
"clicks": 245
},
{
"date": "2024-03-14",
"clicks": 198
}
],
"clicksByCountry": [
{
"country": "US",
"clicks": 2341
},
{
"country": "CA",
"clicks": 987
}
],
"clicksByDevice": [
{
"device": "mobile",
"clicks": 3876
},
{
"device": "desktop",
"clicks": 1234
},
{
"device": "tablet",
"clicks": 322
}
],
"clicksByPlatform": [
{
"platform": "iOS",
"clicks": 2145
},
{
"platform": "Android",
"clicks": 1731
},
{
"platform": "Windows",
"clicks": 1556
}
]
}

Query Parameters:

  • days - Number of days to include (default: 30, max: 365)

Common Workflows

1. Campaign Organization

Setup:

async function setupCampaignProjects() {
const campaigns = [
{ name: 'Q1 Email Campaign', description: 'Weekly newsletter links' },
{ name: 'Instagram Ads - March', description: 'Paid social media ads' },
{ name: 'Product Launch', description: 'New product announcement' },
];

for (const campaign of campaigns) {
await fetch('https://api.linkforty.com/api/projects', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(campaign),
});
}
}

2. Agency Client Organization

Pattern:

Organization: Marketing Agency
├── Project: Client - Nike
├── Project: Client - Adidas
├── Project: Client - Under Armour
└── Project: Internal - Agency Website

Code:

async function createClientProject(clientName: string) {
const response = await fetch('https://api.linkforty.com/api/projects', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: `Client - ${clientName}`,
description: `All links and campaigns for ${clientName}`,
}),
});

return response.json();
}

3. Department Organization

Pattern:

Organization: Acme Corp
├── Project: Marketing Team
├── Project: Sales Team
├── Project: Product Team
└── Project: Customer Success

4. Time-Based Projects

Pattern:

Organization: E-commerce Store
├── Project: January 2024
├── Project: February 2024
├── Project: March 2024
└── Project: Q1 Summary

TypeScript Examples

interface Project {
id: string;
name: string;
description?: string;
created_at: string;
updated_at: string;
}

interface Link {
id: string;
shortCode: string;
originalUrl: string;
projectId?: string;
title?: string;
}

async function createProjectWithLinks(
projectName: string,
links: Array<{ url: string; title: string }>
): Promise<{ project: Project; links: Link[] }> {
// Create project
const projectResponse = await fetch('https://api.linkforty.com/api/projects', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: projectName }),
});

const project = await projectResponse.json();

// Create links assigned to project
const createdLinks = [];
for (const link of links) {
const linkResponse = await fetch('https://api.linkforty.com/api/links', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
originalUrl: link.url,
title: link.title,
projectId: project.id,
}),
});

createdLinks.push(await linkResponse.json());
}

return { project, links: createdLinks };
}

// Usage
const campaign = await createProjectWithLinks('Spring Sale', [
{ url: 'https://shop.com/sale', title: 'Instagram Story 1' },
{ url: 'https://shop.com/sale', title: 'Email Newsletter' },
{ url: 'https://shop.com/sale', title: 'Facebook Ad' },
]);

console.log(`Created project: ${campaign.project.name}`);
console.log(`Created ${campaign.links.length} links`);

2. Compare Project Performance

async function compareProjectPerformance(
projectIds: string[],
days: number = 30
) {
const results = await Promise.all(
projectIds.map(async id => {
const analyticsResponse = await fetch(
`https://api.linkforty.com/api/analytics/projects/${id}?days=${days}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
const analytics = await analyticsResponse.json();

const projectResponse = await fetch(
`https://api.linkforty.com/api/projects/${id}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
const project = await projectResponse.json();

return {
projectId: id,
projectName: project.name,
totalClicks: analytics.totalClicks,
uniqueClicks: analytics.uniqueClicks,
clickThroughRate: (
(analytics.uniqueClicks / analytics.totalClicks) * 100
).toFixed(1) + '%',
};
})
);

// Sort by total clicks
return results.sort((a, b) => b.totalClicks - a.totalClicks);
}

// Usage
const comparison = await compareProjectPerformance([
'proj_123',
'proj_456',
'proj_789',
]);

console.table(comparison);

3. Archive Old Projects

async function archiveOldProjects(monthsOld: number = 6) {
const response = await fetch('https://api.linkforty.com/api/projects', {
headers: { 'Authorization': `Bearer ${API_KEY}` },
});

const projects: Project[] = await response.json();

const cutoffDate = new Date();
cutoffDate.setMonth(cutoffDate.getMonth() - monthsOld);

const oldProjects = projects.filter(project => {
const createdAt = new Date(project.created_at);
return createdAt < cutoffDate;
});

for (const project of oldProjects) {
// Check if project has any links
const linksResponse = await fetch(
`https://api.linkforty.com/api/links?projectId=${project.id}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
const links = await linksResponse.json();

if (links.length === 0) {
// Delete empty old projects
await fetch(`https://api.linkforty.com/api/projects/${project.id}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${API_KEY}` },
});

console.log(`✅ Deleted empty project: ${project.name}`);
} else {
// Rename to mark as archived
await fetch(`https://api.linkforty.com/api/projects/${project.id}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: `[ARCHIVED] ${project.name}`,
}),
});

console.log(`📦 Archived project: ${project.name}`);
}
}
}

4. Generate Project Report

async function generateProjectReport(projectId: string) {
// Get project details
const projectResponse = await fetch(
`https://api.linkforty.com/api/projects/${projectId}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
const project = await projectResponse.json();

// Get project analytics
const analyticsResponse = await fetch(
`https://api.linkforty.com/api/analytics/projects/${projectId}?days=30`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
const analytics = await analyticsResponse.json();

// Get all links in project
const linksResponse = await fetch(
`https://api.linkforty.com/api/links?projectId=${projectId}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
const links = await linksResponse.json();

return {
project: {
name: project.name,
description: project.description,
created: new Date(project.created_at).toLocaleDateString(),
},
summary: {
totalLinks: links.length,
totalClicks: analytics.totalClicks,
uniqueClicks: analytics.uniqueClicks,
avgClicksPerLink: (analytics.totalClicks / links.length).toFixed(1),
avgClicksPerDay: (analytics.totalClicks / 30).toFixed(1),
},
topCountries: analytics.clicksByCountry.slice(0, 5),
deviceBreakdown: analytics.clicksByDevice,
platformBreakdown: analytics.clicksByPlatform,
};
}

// Usage
const report = await generateProjectReport('proj_abc123');
console.log(JSON.stringify(report, null, 2));
async function moveLinksToProject(
linkIds: string[],
projectId: string
): Promise<{ success: number; failed: number }> {
let success = 0;
let failed = 0;

for (const linkId of linkIds) {
try {
await fetch(`https://api.linkforty.com/api/links/${linkId}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ projectId }),
});

success++;
} catch (error) {
console.error(`Failed to move link ${linkId}:`, error);
failed++;
}
}

return { success, failed };
}

// Usage
const result = await moveLinksToProject(
['link_1', 'link_2', 'link_3'],
'proj_abc123'
);

console.log(`✅ Moved ${result.success} links`);
console.log(`❌ Failed ${result.failed} links`);

Best Practices

1. Clear Naming Conventions

✅ Good:

  • "Q1 2024 - Email Marketing"
  • "Client: Nike - Spring Campaign"
  • "Product Launch - New Widget"
  • "Instagram Ads - March 2024"

❌ Bad:

  • "Project 1"
  • "Test"
  • "Links"
  • "Stuff"

2. Use Descriptions

const project = {
name: 'Spring Sale 2024',
description: 'Instagram stories and email newsletter links for Q1 spring sale promotion. Target: 10K clicks.'
};

3. Regular Cleanup

// Monthly cleanup
async function monthlyProjectCleanup() {
// Archive old projects
await archiveOldProjects(6);

// Delete empty archived projects older than 1 year
await archiveOldProjects(12);
}

4. Consistent Organization Scheme

Pick one pattern and stick to it:

Option A - By Time:

- Q1 2024
- Q2 2024
- Q3 2024

Option B - By Campaign:

- Spring Sale
- Summer Launch
- Black Friday

Option C - By Client (Agencies):

- Client: Nike
- Client: Adidas
- Client: Puma

Option D - By Channel:

- Email Marketing
- Instagram Ads
- LinkedIn Posts

5. Don't Over-Organize

When NOT to use projects:

  • You have less than 10 links
  • All links are for one campaign
  • You're a solo user with simple needs

When to use projects:

  • Managing 50+ links
  • Multiple campaigns or clients
  • Team collaboration
  • Need separate analytics per campaign

Troubleshooting

"Project not found"

Cause: Project ID doesn't exist or not in your organization

Fix:

  1. List all projects: GET /api/projects
  2. Verify project ID
  3. Check organization context

Can't Delete Project

Cause: Insufficient permissions

Fix:

  1. Check your role (Admin or Owner required for deletion)
  2. Ask admin to delete project
  3. Note: Members can create but not delete projects

Cause: Links not assigned to project

Fix:

  1. Edit link
  2. Select project from dropdown
  3. Save changes

Project Analytics Empty

Possible causes:

  • No links in project
  • Links have no clicks yet
  • Filtering by too short time period

Fix:

  1. Verify links are assigned: GET /api/links?projectId=proj_123
  2. Check link analytics individually
  3. Increase days parameter

Next Steps

  1. Create your first project
  2. Assign existing links to projects
  3. Set up a naming convention
  4. Review project analytics regularly
  5. Archive old projects quarterly