Error Handling

Handle API errors gracefully with detailed error codes and messages.

Pro Feature

The Kanman API uses standard HTTP status codes and returns detailed error information in JSON format.

Error Response Format

All errors follow this structure:

{
  "error": {
    "code": "error_code",
    "message": "Human-readable error description",
    "details": {}
  }
}
Field Type Description
code string Machine-readable error code
message string Human-readable description
details object Additional context (optional)

HTTP Status Codes

Success Codes

Status Meaning
200 OK - Request succeeded
201 Created - Resource created

Client Error Codes

Status Meaning
400 Bad Request - Invalid input
401 Unauthorized - Invalid or missing token
403 Forbidden - Insufficient permissions
404 Not Found - Resource doesn’t exist
429 Too Many Requests - Rate limit exceeded

Server Error Codes

Status Meaning
500 Internal Server Error - Something went wrong
503 Service Unavailable - Temporary outage

Common Error Codes

Authentication Errors

invalid_token

{
  "error": {
    "code": "invalid_token",
    "message": "The provided API token is invalid"
  }
}

Cause: Token doesn’t exist or is malformed

Solution: Check token is correct, hasn’t been revoked

token_expired

{
  "error": {
    "code": "token_expired",
    "message": "The API token has expired",
    "details": {
      "expired_at": "2024-01-15T00:00:00Z"
    }
  }
}

Cause: Token past expiration date

Solution: Create a new token

insufficient_scope

{
  "error": {
    "code": "insufficient_scope",
    "message": "Token lacks required scope",
    "details": {
      "required": "write",
      "provided": ["read"]
    }
  }
}

Cause: Token doesn’t have permission for this operation

Solution: Create token with required scope

Resource Errors

board_not_found

{
  "error": {
    "code": "board_not_found",
    "message": "Board not found or access denied",
    "details": {
      "board_id": "550e8400-e29b-41d4-a716-446655440000"
    }
  }
}

project_not_found

{
  "error": {
    "code": "project_not_found",
    "message": "Project not found or access denied"
  }
}

task_not_found

{
  "error": {
    "code": "task_not_found",
    "message": "Task not found or access denied"
  }
}

Validation Errors

invalid_request

{
  "error": {
    "code": "invalid_request",
    "message": "Request validation failed",
    "details": {
      "fields": {
        "label": "Label is required",
        "status": "Status must be 0, 1, or 2"
      }
    }
  }
}

invalid_uuid

{
  "error": {
    "code": "invalid_uuid",
    "message": "Invalid UUID format",
    "details": {
      "field": "projectId",
      "value": "not-a-uuid"
    }
  }
}

Quota Errors

quota_exceeded

{
  "error": {
    "code": "quota_exceeded",
    "message": "Monthly API quota exceeded",
    "details": {
      "limit": 12000,
      "used": 12000,
      "reset": "2024-02-01T00:00:00Z"
    }
  }
}

resource_limit_exceeded

{
  "error": {
    "code": "resource_limit_exceeded",
    "message": "Task limit reached for your plan",
    "details": {
      "resource": "tasks",
      "limit": 500,
      "current": 500
    }
  }
}

Handling Errors

JavaScript Example

async function apiRequest(url, options = {}) {
  const response = await fetch(url, {
    ...options,
    headers: {
      'Authorization': `Bearer ${API_TOKEN}`,
      'Content-Type': 'application/json',
      ...options.headers
    }
  });

  const data = await response.json();

  if (!response.ok) {
    const error = new Error(data.error?.message || 'API request failed');
    error.code = data.error?.code;
    error.status = response.status;
    error.details = data.error?.details;
    throw error;
  }

  return data;
}

// Usage
try {
  const task = await apiRequest('https://api.kanman.de/v1/tasks/123');
  console.log(task);
} catch (error) {
  switch (error.code) {
    case 'task_not_found':
      console.log('Task does not exist');
      break;
    case 'token_expired':
      console.log('Please refresh your API token');
      break;
    case 'quota_exceeded':
      console.log(`Quota reset at ${error.details.reset}`);
      break;
    default:
      console.error('API error:', error.message);
  }
}

Python Example

import requests

class KanmanAPIError(Exception):
    def __init__(self, code, message, status, details=None):
        self.code = code
        self.message = message
        self.status = status
        self.details = details or {}
        super().__init__(message)

def api_request(method, endpoint, **kwargs):
    response = requests.request(
        method,
        f'https://api.kanman.de/v1{endpoint}',
        headers={'Authorization': f'Bearer {API_TOKEN}'},
        **kwargs
    )

    data = response.json()

    if not response.ok:
        error = data.get('error', {})
        raise KanmanAPIError(
            code=error.get('code', 'unknown'),
            message=error.get('message', 'API error'),
            status=response.status_code,
            details=error.get('details')
        )

    return data

# Usage
try:
    task = api_request('GET', '/tasks/123')
except KanmanAPIError as e:
    if e.code == 'task_not_found':
        print('Task does not exist')
    elif e.code == 'quota_exceeded':
        print(f"Quota resets at {e.details['reset']}")
    else:
        print(f'Error: {e.message}')

Retry Strategy

For transient errors (5xx), implement exponential backoff:

async function apiRequestWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      // Don't retry client errors
      if (response.status >= 400 && response.status < 500) {
        return response;
      }

      // Retry server errors
      if (response.status >= 500) {
        throw new Error(`Server error: ${response.status}`);
      }

      return response;
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;

      // Exponential backoff: 1s, 2s, 4s
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

Last updated: January 1, 0001

Try Kanman