Skip to main content

Error Handling

LinkForty API uses conventional HTTP status codes and returns detailed error information in JSON format.

Error Response Format

All errors follow this structure:

{
"error": "Error Type",
"message": "Human-readable description",
"statusCode": 400,
"validation": {
"field": "Specific field error"
}
}
FieldTypeDescription
errorstringError type/category
messagestringHuman-readable error message
statusCodenumberHTTP status code
validationobjectField-specific validation errors (optional)

HTTP Status Codes

2xx Success

CodeNameDescription
200OKRequest succeeded
201CreatedResource created successfully
204No ContentRequest succeeded, no response body

4xx Client Errors

CodeNameWhen It Happens
400Bad RequestInvalid request format or validation error
401UnauthorizedMissing or invalid API key
403ForbiddenInsufficient permissions
404Not FoundResource doesn't exist
409ConflictResource already exists (e.g., duplicate short code)
422Unprocessable EntityRequest valid but semantically incorrect
429Too Many RequestsRate limit exceeded

5xx Server Errors

CodeNameWhen It Happens
500Internal Server ErrorUnexpected server error
502Bad GatewayUpstream service unavailable
503Service UnavailableTemporary maintenance or overload
504Gateway TimeoutRequest timeout

Common Errors

400 Bad Request

Cause: Invalid request data or validation failure.

Example: Missing required field

{
"error": "Bad Request",
"message": "Validation failed",
"statusCode": 400,
"validation": {
"originalUrl": "Original URL is required",
"templateId": "Template ID must be a valid UUID"
}
}

How to fix:

  • Check all required fields are present
  • Verify field formats (URLs, UUIDs, numbers)
  • Review API documentation for endpoint

401 Unauthorized

Cause: Missing or invalid API key.

Example: No Authorization header

curl https://api.linkforty.com/api/links
# No Authorization header provided

Response:

{
"error": "Unauthorized",
"message": "Missing or invalid API key",
"statusCode": 401
}

How to fix:

curl https://api.linkforty.com/api/links \
-H "Authorization: Bearer lf_live_a1b2c3d4e5f6g7h8"

Example: Invalid API key

{
"error": "Unauthorized",
"message": "Invalid API key",
"statusCode": 401
}

How to fix:

  • Verify API key is correct
  • Check key hasn't been deleted
  • Ensure using correct environment (test vs live)

403 Forbidden

Cause: Authenticated but lacking permissions.

Example: Accessing another organization's resource

{
"error": "Forbidden",
"message": "You do not have access to this resource",
"statusCode": 403
}

How to fix:

  • Verify you're in the correct organization
  • Check your role (Owner/Admin/Member/Viewer)
  • Ensure resource belongs to your organization

404 Not Found

Cause: Resource doesn't exist.

Example: Link not found

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

Response:

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

How to fix:

  • Verify resource ID is correct
  • Check resource hasn't been deleted
  • Ensure resource exists in your organization

409 Conflict

Cause: Resource already exists.

Example: Duplicate custom short code

curl -X POST https://api.linkforty.com/api/links \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "template_123",
"originalUrl": "https://example.com",
"customCode": "summer-sale"
}'

Response:

{
"error": "Conflict",
"message": "Short code 'summer-sale' is already in use",
"statusCode": 409
}

How to fix:

  • Use a different custom code
  • Let LinkForty generate a random code (omit customCode)
  • Check if link was already created

422 Unprocessable Entity

Cause: Request valid but can't be processed.

Example: Invalid URL format

{
"error": "Unprocessable Entity",
"message": "Invalid URL format",
"statusCode": 422,
"validation": {
"originalUrl": "Must be a valid URL starting with http:// or https://"
}
}

How to fix:

  • Verify URL format is correct
  • Ensure URL is reachable
  • Check for typos

429 Too Many Requests

Cause: Rate limit exceeded.

Response:

{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Try again in 42 seconds.",
"statusCode": 429,
"retryAfter": 42
}

Headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1642531200
Retry-After: 42

How to fix:

  • Wait for retryAfter seconds
  • Implement exponential backoff
  • Use bulk endpoints
  • See Rate Limits for details

500 Internal Server Error

Cause: Unexpected server error.

Response:

{
"error": "Internal Server Error",
"message": "An unexpected error occurred. Please try again.",
"statusCode": 500
}

How to fix:

  • Retry the request
  • If persistent, contact support
  • Check status page: status.linkforty.com

Validation Errors

Validation errors include field-specific details:

{
"error": "Bad Request",
"message": "Validation failed",
"statusCode": 400,
"validation": {
"originalUrl": "Must be a valid URL",
"attributionWindowHours": "Must be between 1 and 2160",
"customCode": "Must be 4-30 characters, alphanumeric only"
}
}

Common validation errors:

FieldErrorFix
originalUrl"Must be a valid URL"Include http:// or https://
templateId"Must be a valid UUID"Use proper template ID format
attributionWindowHours"Must be between 1 and 2160"Set value in allowed range
customCode"Already in use"Choose different code
expiresAt"Must be a future date"Set date in future

Error Handling Best Practices

1. Always Check Status Code

const response = await fetch('https://api.linkforty.com/api/links', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(linkData)
});

if (!response.ok) {
const error = await response.json();
console.error(`Error ${error.statusCode}: ${error.message}`);
throw new Error(error.message);
}

const link = await response.json();

2. Handle Specific Errors

try {
const response = await createLink(linkData);
return response;
} catch (error) {
if (error.statusCode === 409) {
// Duplicate short code - try with different code
return createLink({ ...linkData, customCode: generateRandomCode() });
} else if (error.statusCode === 429) {
// Rate limited - wait and retry
await sleep(error.retryAfter * 1000);
return createLink(linkData);
} else if (error.statusCode === 400) {
// Validation error - show to user
throw new ValidationError(error.validation);
} else if (error.statusCode >= 500) {
// Server error - retry with backoff
return retryWithBackoff(() => createLink(linkData));
} else {
// Other error - propagate
throw error;
}
}

3. Implement Retry Logic

async function retryWithBackoff(fn, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxRetries || error.statusCode < 500) {
throw error;
}

const delay = Math.min(1000 * Math.pow(2, attempt), 32000);
console.log(`Retry ${attempt}/${maxRetries} in ${delay}ms`);
await sleep(delay);
}
}
}

4. Log Errors Properly

async function createLink(data) {
try {
const response = await fetch('https://api.linkforty.com/api/links', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});

if (!response.ok) {
const error = await response.json();
logError({
endpoint: '/api/links',
method: 'POST',
statusCode: error.statusCode,
message: error.message,
requestData: data,
timestamp: new Date().toISOString()
});
throw error;
}

return await response.json();
} catch (error) {
throw error;
}
}

5. User-Friendly Error Messages

function getUse rMessage(error) {
switch (error.statusCode) {
case 400:
return `Invalid input: ${Object.values(error.validation || {}).join(', ')}`;
case 401:
return 'Authentication failed. Please check your API key.';
case 403:
return 'You don\'t have permission to perform this action.';
case 404:
return 'The requested resource was not found.';
case 409:
return 'This short code is already in use. Please choose another.';
case 429:
return `Too many requests. Please wait ${error.retryAfter} seconds.`;
case 500:
case 502:
case 503:
case 504:
return 'Server error. Please try again later.';
default:
return 'An unexpected error occurred. Please try again.';
}
}

SDK Error Handling

Official SDKs provide typed errors:

JavaScript/TypeScript

import { LinkFortySDK, LinkFortyError } from '@linkforty/sdk';

try {
const link = await client.links.create({
templateId: 'template_123',
originalUrl: 'https://example.com'
});
} catch (error) {
if (error instanceof LinkFortyError) {
console.error(`LinkForty Error ${error.statusCode}: ${error.message}`);

if (error.validation) {
console.error('Validation errors:', error.validation);
}
} else {
console.error('Unexpected error:', error);
}
}

Python

from linkforty import LinkForty, LinkFortyError, ValidationError

try:
link = client.links.create(
template_id='template_123',
original_url='https://example.com'
)
except ValidationError as e:
print(f"Validation failed: {e.validation}")
except LinkFortyError as e:
print(f"LinkForty error {e.status_code}: {e.message}")
except Exception as e:
print(f"Unexpected error: {e}")

Debugging Errors

Enable Debug Logging

const client = new LinkFortySDK({
apiKey: API_KEY,
debug: true // Logs all requests/responses
});

Check Request/Response

const response = await fetch('https://api.linkforty.com/api/links', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(linkData)
});

console.log('Status:', response.status);
console.log('Headers:', Object.fromEntries(response.headers));

const body = await response.text();
console.log('Body:', body);

Test with cURL

curl -v -X POST https://api.linkforty.com/api/links \
-H "Authorization: Bearer $LINKFORTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "template_123",
"originalUrl": "https://example.com"
}'

Production Error Monitoring

1. Centralized Error Tracking

import * as Sentry from '@sentry/node';

Sentry.init({
dsn: 'your-sentry-dsn'
});

async function createLink(data) {
try {
return await client.links.create(data);
} catch (error) {
Sentry.captureException(error, {
tags: {
endpoint: 'create_link',
statusCode: error.statusCode
},
extra: {
requestData: data
}
});
throw error;
}
}

2. Error Metrics

const errorCounts = {
400: 0,
401: 0,
404: 0,
429: 0,
500: 0
};

function trackError(error) {
errorCounts[error.statusCode] = (errorCounts[error.statusCode] || 0) + 1;

// Send to monitoring service
metrics.increment('linkforty.api.error', {
statusCode: error.statusCode,
endpoint: error.endpoint
});
}

3. Alert on Error Spikes

if (errorCounts[500] > 10) {
alert('High rate of 500 errors from LinkForty API!');
}

if (errorCounts[429] > 5) {
alert('Hitting rate limits frequently - consider upgrading plan');
}

Troubleshooting Guide

Error: "Invalid API key"

Check:

  1. API key starts with lf_live_ or lf_test_
  2. Key hasn't been deleted from dashboard
  3. Using correct environment (dev vs prod)

Fix:

  • Generate new API key from dashboard
  • Update environment variables

Error: "Template not found"

Check:

  1. Template ID is correct
  2. Template belongs to your organization
  3. Template hasn't been deleted

Fix:

  • List templates: GET /api/templates
  • Create new template if needed
  • Use correct template ID

Error: "Short code already in use"

Check:

  1. Custom code is globally unique
  2. Code hasn't been used by your org before

Fix:

  • Choose different custom code
  • Omit customCode to auto-generate
  • Check existing links: GET /api/links

Next Steps

Support

Having trouble with errors?