Skip to Content
DocumentationError Handling

Error Handling

The Relink API uses standardized HTTP status codes and a consistent error response format to indicate the success or failure of API requests. All error responses follow the same structure for easy parsing and handling.

Standardized Error Response Format

All API errors return a standardized JSON response:

{ "success": false, "error": { "code": "ERROR_CODE", "message": "Human readable error message", "details": [ { "path": "field.path", "message": "Field specific error message" } ] }, "timestamp": "2024-01-15T10:30:00.000Z" }

Response Fields

FieldTypeDescription
successbooleanAlways false for error responses
error.codestringMachine-readable error code
error.messagestringHuman-readable error description
error.detailsarrayOptional detailed validation errors
timestampstringISO 8601 timestamp of the error

Authentication Errors (401)

Missing Authorization Header

{ "success": false, "error": { "code": "UNAUTHORIZED", "message": "Authorization header missing" }, "timestamp": "2024-01-15T10:30:00.000Z" }

Invalid API Key Format

{ "success": false, "error": { "code": "UNAUTHORIZED", "message": "Invalid API key format" }, "timestamp": "2024-01-15T10:30:00.000Z" }

Invalid/Inactive API Key

{ "success": false, "error": { "code": "UNAUTHORIZED", "message": "Invalid API key" }, "timestamp": "2024-01-15T10:30:00.000Z" }

Permission & Subscription Errors (403)

Subscription Limit Reached

{ "success": false, "error": { "code": "SUBSCRIPTION_LIMIT_REACHED", "message": "Subscription limit reached" }, "timestamp": "2024-01-15T10:30:00.000Z" }

API Access Not Available for Plan

{ "success": false, "error": { "code": "SUBSCRIPTION_LIMIT_REACHED", "message": "API access is not available for Starter subscription. Please upgrade your plan to use API features." }, "timestamp": "2024-01-15T10:30:00.000Z" }

User Doesn’t Own Resource

{ "success": false, "error": { "code": "FORBIDDEN", "message": "You do not have permission to access this resource" }, "timestamp": "2024-01-15T10:30:00.000Z" }

Validation Errors (400)

Schema Validation Failed

{ "success": false, "error": { "code": "VALIDATION_FAILED", "message": "Request validation failed", "details": [ { "path": "configuration.smartlinkUrl", "message": "Smartlink URL can only contain latin characters and numbers" } ] }, "timestamp": "2024-01-15T10:30:00.000Z" }

Invalid URL Format

{ "success": false, "error": { "code": "VALIDATION_FAILED", "message": "Request validation failed", "details": [ { "path": "openGraph.imageUrl", "message": "Invalid URL format" } ] }, "timestamp": "2024-01-15T10:30:00.000Z" }

Reserved URL Error

{ "success": false, "error": { "code": "VALIDATION_FAILED", "message": "Request validation failed", "details": [ { "path": "configuration.smartlinkUrl", "message": "Smartlink URL cannot be one of the following: dashboard, welcome, pp, tos." } ] }, "timestamp": "2024-01-15T10:30:00.000Z" }

Missing Required Fields

{ "success": false, "error": { "code": "VALIDATION_FAILED", "message": "Request validation failed", "details": [ { "path": "configuration.smartlinkName", "message": "Smartlink name is required" } ] }, "timestamp": "2024-01-15T10:30:00.000Z" }
{ "success": false, "error": { "code": "VALIDATION_FAILED", "message": "Request validation failed", "details": [ { "path": "configuration.smartlinkType", "message": "Invalid smartlink type. Must be one of: App, Url, Landing, QRTag, DigiCard, TxtBin" } ] }, "timestamp": "2024-01-15T10:30:00.000Z" }

Resource Not Found Errors (404)

{ "success": false, "error": { "code": "NOT_FOUND", "message": "Smartlink not found" }, "timestamp": "2024-01-15T10:30:00.000Z" }

Resource Doesn’t Belong to User

{ "success": false, "error": { "code": "NOT_FOUND", "message": "Smartlink not found or doesn't belong to user" }, "timestamp": "2024-01-15T10:30:00.000Z" }

Conflict Errors (409)

{ "success": false, "error": { "code": "CONFLICT", "message": "Smartlink URL already exists" }, "timestamp": "2024-01-15T10:30:00.000Z" }

Rate Limiting Errors (429)

Too Many Requests

{ "success": false, "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Too many requests, please try again later" }, "timestamp": "2024-01-15T10:30:00.000Z" }

Rate Limits by Plan:

  • Professional: 1000 requests per hour
  • Enterprise: 5000 requests per hour

Server Errors (500)

Internal Server Error

{ "success": false, "error": { "code": "INTERNAL_SERVER_ERROR", "message": "Internal server error" }, "timestamp": "2024-01-15T10:30:00.000Z" }

Service Unavailable

{ "success": false, "error": { "code": "SERVICE_UNAVAILABLE", "message": "Service temporarily unavailable" }, "timestamp": "2024-01-15T10:30:00.000Z" }

URL Safety Errors (400)

The API automatically checks all URLs against Google Safe Browsing API for security.

Single Unsafe URL

{ "success": false, "error": { "code": "UNSAFE_URL_DETECTED", "message": "Unsafe URL detected: https://malicious-site.com" }, "timestamp": "2024-01-15T10:30:00.000Z" }

Multiple Unsafe URLs

{ "success": false, "error": { "code": "UNSAFE_URL_DETECTED", "message": "Multiple unsafe URLs detected in configuration" }, "timestamp": "2024-01-15T10:30:00.000Z" }

Error Code Reference

HTTP StatusError CodeDescription
400VALIDATION_FAILEDRequest validation failed
400UNSAFE_URL_DETECTEDURL failed security check
401UNAUTHORIZEDAuthentication failed
403FORBIDDENInsufficient permissions
403SUBSCRIPTION_LIMIT_REACHEDPlan limits exceeded
404NOT_FOUNDResource not found
409CONFLICTResource already exists
429RATE_LIMIT_EXCEEDEDRate limit exceeded
500INTERNAL_SERVER_ERRORServer error
503SERVICE_UNAVAILABLEService temporarily down

Handling Errors in Code

JavaScript Example

async function handleApiRequest(url, options) { try { const response = await fetch(url, options); const data = await response.json(); if (!data.success) { // Handle different error types switch (data.error.code) { case 'UNAUTHORIZED': console.error('Authentication failed:', data.error.message); // Redirect to login or refresh API key break; case 'VALIDATION_FAILED': console.error('Validation errors:'); data.error.details?.forEach(detail => { console.error(`${detail.path}: ${detail.message}`); }); break; case 'SUBSCRIPTION_LIMIT_REACHED': console.error('Subscription limit reached:', data.error.message); // Show upgrade prompt break; case 'RATE_LIMIT_EXCEEDED': console.error('Rate limit exceeded, retrying in 60 seconds...'); // Implement retry logic setTimeout(() => handleApiRequest(url, options), 60000); return; default: console.error('API Error:', data.error.message); } throw new Error(data.error.message); } return data; } catch (error) { console.error('Request failed:', error.message); throw error; } } // Usage try { const result = await handleApiRequest('https://relink.is/api/v1/smartlink', { method: 'POST', headers: { 'Authorization': 'Bearer rlk_your_api_key_here', 'Content-Type': 'application/json' }, body: JSON.stringify({ configuration: { smartlinkName: "Test App", smartlinkType: "App" } }) }); console.log('Success:', result.data); } catch (error) { // Error already handled in handleApiRequest }

Python Example

import requests import time from typing import Dict, Any class RelinkAPIError(Exception): def __init__(self, error_data: Dict[str, Any]): self.code = error_data.get('code') self.message = error_data.get('message') self.details = error_data.get('details', []) super().__init__(self.message) def handle_api_request(url: str, **kwargs) -> Dict[str, Any]: try: response = requests.request(**kwargs, url=url) data = response.json() if not data.get('success', False): error = data.get('error', {}) # Handle specific error types if error.get('code') == 'RATE_LIMIT_EXCEEDED': print("Rate limit exceeded, waiting 60 seconds...") time.sleep(60) return handle_api_request(url, **kwargs) elif error.get('code') == 'VALIDATION_FAILED': print("Validation errors:") for detail in error.get('details', []): print(f" {detail.get('path')}: {detail.get('message')}") raise RelinkAPIError(error) return data except requests.RequestException as e: print(f"Request failed: {e}") raise # Usage try: result = handle_api_request( url="https://relink.is/api/v1/smartlink", method="POST", headers={ "Authorization": "Bearer rlk_your_api_key_here", "Content-Type": "application/json" }, json={ "configuration": { "smartlinkName": "Test App", "smartlinkType": "App" } } ) print("Success:", result['data']) except RelinkAPIError as e: print(f"API Error [{e.code}]: {e.message}") if e.details: for detail in e.details: print(f" {detail.get('path')}: {detail.get('message')}")

Best Practices

Error Handling Strategy

  1. Always check the success field in responses
  2. Implement specific handling for different error codes
  3. Log error details for debugging and monitoring
  4. Provide user-friendly messages for validation errors
  5. Implement retry logic for rate limiting and server errors

Validation Error Handling

  • Parse the details array for field-specific errors
  • Highlight problematic fields in your UI
  • Show specific validation messages to users
  • Validate data client-side before API calls when possible

Rate Limiting

  • Implement exponential backoff for rate limit errors
  • Cache responses when appropriate to reduce API calls
  • Monitor your API usage to avoid hitting limits
  • Consider upgrading your plan if you consistently hit limits

Security

  • Never expose API keys in client-side code
  • Rotate API keys regularly
  • Monitor for unauthorized access attempts
  • Handle authentication errors gracefully without exposing sensitive information