Skip to Content
Error Handling

Error Handling

The Snip URL API uses conventional HTTP status codes and returns structured JSON error responses.

Error Response Format

Every error response follows this structure:

{ "success": false, "error": { "code": "ERROR_CODE", "message": "Human-readable description of what went wrong", "details": {} } }
FieldTypeDescription
codestringMachine-readable error code (use for programmatic handling)
messagestringHuman-readable description (safe to display to users)
detailsobjectAdditional context (validation errors, limits, etc.) — optional

HTTP Status Codes

CodeMeaningWhen
400Bad RequestMalformed JSON, invalid parameters
401UnauthorizedMissing, invalid, expired, or revoked API key
403ForbiddenValid auth but insufficient permissions (e.g., link limit reached)
404Not FoundResource doesn’t exist or doesn’t belong to you
409ConflictResource already exists (e.g., alias taken)
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server failure

Error Codes Reference

Authentication Errors (401)

CodeDescription
UNAUTHORIZEDMissing or invalid API key
KEY_EXPIREDAPI key has passed its expiration date
KEY_REVOKEDAPI key has been revoked

Validation Errors (400)

CodeDescription
VALIDATION_ERRORRequest body or query parameters failed validation
BAD_REQUESTGeneric bad request (e.g., attempting to modify immutable fields)

Permission Errors (403)

CodeDescription
FORBIDDENLink limit reached or other account-level restriction

Resource Errors (404, 409)

CodeDescription
NOT_FOUNDResource not found or doesn’t belong to your account
CONFLICTCustom alias is already taken

Rate Limiting (429)

CodeDescription
RATE_LIMIT_EXCEEDEDToo many requests in the current window

Server Errors (500)

CodeDescription
INTERNAL_ERRORUnexpected server error

Handling Errors in Code

JavaScript / TypeScript

async function snipurlRequest(endpoint, options = {}) { const response = await fetch(`https://snipurl.click/api/v1${endpoint}`, { ...options, headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json', ...options.headers, }, }); const body = await response.json(); if (!body.success) { const { code, message, details } = body.error; switch (code) { case 'UNAUTHORIZED': case 'KEY_EXPIRED': case 'KEY_REVOKED': throw new Error(`Authentication failed: ${message}`); case 'RATE_LIMIT_EXCEEDED': const retryAfter = parseInt(response.headers.get('Retry-After') || '60'); await new Promise(r => setTimeout(r, retryAfter * 1000)); return snipurlRequest(endpoint, options); // Retry case 'VALIDATION_ERROR': console.error('Validation failed:', details); throw new Error(`Invalid input: ${message}`); case 'NOT_FOUND': return null; // Resource doesn't exist case 'CONFLICT': throw new Error(`Conflict: ${message}`); default: throw new Error(`API error [${code}]: ${message}`); } } return body; }

Python

import time import requests class SnipURLError(Exception): def __init__(self, code, message, details=None, status_code=None): self.code = code self.message = message self.details = details self.status_code = status_code super().__init__(f"[{code}] {message}") def snipurl_request(endpoint, method='GET', json=None, retry=True): response = requests.request( method, f'https://snipurl.click/api/v1{endpoint}', headers={ 'Authorization': f'Bearer {API_KEY}', 'Content-Type': 'application/json', }, json=json, ) body = response.json() if not body.get('success'): error = body['error'] code = error['code'] # Auto-retry on rate limit if code == 'RATE_LIMIT_EXCEEDED' and retry: retry_after = int(response.headers.get('Retry-After', 60)) time.sleep(retry_after) return snipurl_request(endpoint, method, json, retry=False) raise SnipURLError( code=code, message=error['message'], details=error.get('details'), status_code=response.status_code, ) return body

Validation Error Details

When you receive a VALIDATION_ERROR, the details field contains field-level error information:

{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Invalid request data.", "details": { "_errors": [], "url": { "_errors": ["Please enter a valid URL"] }, "expires_at": { "_errors": ["Invalid datetime string"] } } } }

Best Practices

  1. Always check success before accessing data
  2. Handle 429 with retry logic using the Retry-After header
  3. Don’t expose raw error messages to end users in production — use them for debugging
  4. Log code and details for debugging validation issues
  5. Handle 404 gracefully — resources may have been deleted
  6. Re-authenticate on 401 — your key may have expired or been revoked
Last updated on