Skip to main content

Errors

ClinikAPI uses standard HTTP status codes and returns structured error responses.

Error Response Format

{
  "error": "Validation Error",
  "code": "VALIDATION_ERROR",
  "requestId": "req_k8f3a7x2",
  "issues": [
    {
      "severity": "error",
      "code": "invalid",
      "diagnostics": "firstName: Required"
    }
  ]
}

HTTP Status Codes

StatusMeaning
400Bad Request — malformed JSON or invalid parameters
401Unauthorized — missing or invalid API key
403Forbidden — key doesn’t have required scope
404Not Found — resource doesn’t exist or belongs to another tenant
409Conflict — resource version conflict
422Validation Error — request body failed Zod validation
429Rate Limited — too many requests for your plan
500Internal Error — something went wrong on our end

Error Codes

CodeDescription
UNAUTHORIZEDMissing x-api-key header
INVALID_KEY_FORMATKey doesn’t match clk_live_* or clk_test_* pattern
INVALID_KEYKey not found in the database
KEY_REVOKEDKey has been revoked
KEY_EXPIREDKey has passed its expiration date
VALIDATION_ERRORRequest body failed schema validation
RATE_LIMITEDPlan request limit exceeded
NOT_FOUNDResource not found
INTERNAL_ERRORUnexpected server error

SDK Error Handling

The SDK throws typed errors that you can catch:
import { Clinik } from '@clinikapi/sdk';

const clinik = new Clinik(process.env.CLINIKAPI_SECRET_KEY!);

try {
  const { data } = await clinik.patients.create({
    firstName: 'Jane',
    lastName: 'Doe',
  });
} catch (err) {
  if (err.name === 'ClinikValidationError') {
    console.error('Validation issues:', err.issues);
  } else if (err.name === 'ClinikRateLimitError') {
    console.error('Rate limited. Retry after:', err.retryAfter, 'seconds');
  } else if (err.name === 'ClinikApiError') {
    console.error('API error:', err.code, err.message);
    console.error('Request ID:', err.requestId);
  }
}

Automatic Retries

The SDK automatically retries on 5xx errors and 429 (rate limit) responses with jittered exponential backoff:
  • Default: 2 retries
  • Backoff: random jitter up to min(1000 * 2^attempt, 10000) ms
  • Configurable via retries option:
const clinik = new Clinik(process.env.CLINIKAPI_SECRET_KEY!, {
  retries: 3,      // max retry attempts
  timeout: 15000,  // request timeout in ms
});

Rate Limits

Rate limits are plan-based and returned in response headers:
HeaderDescription
X-RateLimit-LimitTotal requests allowed per window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetSeconds until the window resets
The SDK exposes these in meta:
const { data, meta } = await clinik.patients.search();
console.log(meta.rateLimitRemaining); // 498

PHI Sanitization

Error responses never contain Protected Health Information (PHI). Field values are stripped from validation error messages — only field names and constraint descriptions are included.