Flonk
Flonk Docs

Errors

API error codes and handling

Last updated: 8/19/2026
5 min read

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):

{
"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"
}
json

Branch on code, not on message text (messages may change; codes are stable).

HTTP Status Codes

CodeDescription
200Success
400Bad Request - Invalid parameters
401Unauthorized - Invalid or missing API key
403Forbidden - Access denied
404Not Found - Resource doesn't exist
429Too Many Requests - Rate limit exceeded
500Internal Server Error

Error Codes

Authentication Errors

CodeDescription
invalid_api_keyAPI key is invalid or expired
missing_api_keyAuthorization header is missing
insufficient_permissionsKey doesn't have required permissions

Session Errors

CodeStatusDescription
session_not_found404Session ID doesn't exist or isn't in your project
session_expired400Session has passed its expiry
session_invalid_state400Session 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:

import { 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);
}
}
}
typescript

error.code is typed FlonkErrorCode (an open union), so a switch stays type-safe while tolerating codes added later.

Manual (fetch)

try {
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);
}
typescript

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:

async 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');
}
typescript