Error Handling
Flonk API uses standard HTTP status codes and returns detailed error information.
Error Response Format
Error bodies are flat. statusCode and message are always present; code is a
stable, machine-branchable identifier present on the documented failures below
(and expanding over time):
json{"statusCode": 404,"code": "session_not_found","message": "Session sess_123 not found or does not belong to your project","timestamp": "2026-06-03T00:00:00.000Z"}
Branch on code, not on message text (messages may change; codes are stable).
HTTP Status Codes
| Code | Description |
|---|---|
200 | Success |
400 | Bad Request - Invalid parameters |
401 | Unauthorized - Invalid or missing API key |
403 | Forbidden - Access denied |
404 | Not Found - Resource doesn't exist |
429 | Too Many Requests - Rate limit exceeded |
500 | Internal Server Error |
Error Codes
Authentication Errors
| Code | Description |
|---|---|
invalid_api_key | API key is invalid or expired |
missing_api_key | Authorization header is missing |
insufficient_permissions | Key doesn't have required permissions |
Session Errors
| Code | Status | Description |
|---|---|---|
session_not_found | 404 | Session ID doesn't exist or isn't in your project |
session_expired | 400 | Session has passed its expiry |
session_invalid_state | 400 | Session can't be used/updated in its current state (completed/failed/non-pending) |
The code field is also exposed by the SDK as error.code (typed
FlonkErrorCode, an open union) — see below.
Handling Errors
Using the SDK
The SDK throws typed error classes that you can catch and handle:
typescriptimport { FlonkKYCServer } from '@flonkid/kyc/server';import {FlonkAuthenticationError,FlonkValidationError,FlonkAPIError,} from '@flonkid/kyc/types';const flonk = new FlonkKYCServer({ secretKey: '...' });try {const session = await flonk.createSession({clientMetadata: { email: 'user@example.com' },});} catch (error) {if (error instanceof FlonkAuthenticationError) {console.error('Invalid API key');} else if (error instanceof FlonkValidationError) {console.error('Invalid request:', error.message);} else if (error instanceof FlonkAPIError) {// Branch on the stable code, not the message text.switch (error.code) {case 'session_not_found': /* … */ break;case 'session_expired': /* re-create the session */ break;default: console.error(`API error ${error.statusCode}:`, error.message);}}}
error.code is typed FlonkErrorCode (an open union), so a switch stays
type-safe while tolerating codes added later.
Manual (fetch)
typescripttry {const response = await fetch('https://api.flonk.id/v1/sessions', {method: 'POST',headers: {'Authorization': `Bearer ${secretKey}`,'Content-Type': 'application/json'},body: JSON.stringify(data)});if (!response.ok) {const error = await response.json();switch (response.status) {case 401:console.error('Invalid API key');break;case 429:console.error('Rate limited, retry later');break;default:console.error('API error:', error.error.message);}}} catch (error) {console.error('Network error:', error);}
Retry Strategy
The SDK retries transient errors (429 / 5xx / network) for you with jittered
exponential backoff, honouring Retry-After. GETs always retry; writes retry
only when idempotent. Tune or disable via new FlonkKYCServer({ maxRetries }).
If you call the API manually, implement backoff yourself:
typescriptasync function fetchWithRetry(url, options, maxRetries = 3) {for (let i = 0; i < maxRetries; i++) {const response = await fetch(url, options);if (response.status === 429 || response.status >= 500) {const delay = Math.pow(2, i) * 1000;await new Promise(r => setTimeout(r, delay));continue;}return response;}throw new Error('Max retries exceeded');}