Skip to main content
This guide covers how to handle errors from the Triqai API, including common error codes, troubleshooting tips, and best practices.

Error Response Format

All error responses follow a consistent structure:
{
  "success": false,
  "error": {
    "code": "error_code",
    "message": "Human-readable description",
    "details": { /* optional additional info */ }
  },
  "meta": {
    "generatedAt": "2026-01-19T10:30:00Z",
    "requestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a123",
    "version": "1.1.9"
  }
}

Error Codes

Authentication Errors (401)

CodeMessageSolution
authentication_errorInvalid or missing API keyCheck your X-API-Key header
authentication_errorInvalid API key formatEnsure key starts with triq_
import { AuthenticationError } from "triqai";

try {
  await triqai.transactions.enrich({ title: "TEST", country: "US", type: "expense" });
} catch (err) {
  if (err instanceof AuthenticationError) {
    console.error("API key invalid. Please check your configuration.");
  }
}

Payment Errors (402)

CodeMessageSolution
insufficient_creditsInsufficient creditsEnable overages or upgrade plan
import { InsufficientCreditsError } from "triqai";

try {
  await triqai.transactions.enrich({ title: "TEST", country: "US", type: "expense" });
} catch (err) {
  if (err instanceof InsufficientCreditsError) {
    console.log("Top up credits at https://triqai.com/dashboard");
  }
}

Not Found Errors (404)

CodeMessageSolution
not_foundResource not foundVerify the ID exists
import { NotFoundError } from "triqai";

try {
  await triqai.transactions.get("nonexistent-id");
} catch (err) {
  if (err instanceof NotFoundError) {
    console.error("Resource not found");
  }
}

Validation Errors (422)

CodeMessageDetails
validation_errorValidation failedfieldErrors object with per-field errors
{
  "error": {
    "code": "validation_error",
    "message": "Validation failed",
    "details": {
      "fieldErrors": {
        "title": ["Title is required"],
        "country": ["Invalid country code. Use ISO 3166-1 alpha-2 format."],
        "type": ["Type must be 'expense' or 'income'"]
      }
    }
  }
}
import { ValidationError } from "triqai";

try {
  await triqai.transactions.enrich({ title: "", country: "INVALID", type: "expense" });
} catch (err) {
  if (err instanceof ValidationError) {
    console.log("Field errors:", err.fieldErrors);
    // { title: ["Title is required"], country: ["Invalid country code"] }
  }
}

Rate Limit Errors (429)

CodeMessageHeaders
rate_limitedRate limit exceededRetry-After, X-RateLimit-*
import { RateLimitError } from "triqai";

try {
  await triqai.transactions.enrich({ title: "TEST", country: "US", type: "expense" });
} catch (err) {
  if (err instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${err.rateLimitInfo.retryAfter}s`);
  }
}
Rate-limited requests are automatically retried with exponential backoff, so you typically don’t need to handle 429 errors manually.

Server Errors (500)

CodeMessageSolution
internal_errorAn unexpected error occurredRetry with exponential backoff
import { InternalServerError } from "triqai";

// 500 errors are retried automatically (up to 3 times by default).
// You can customize this behavior:
const triqai = new Triqai(process.env.TRIQAI_API_KEY!, {
  maxRetries: 5,
  retryDelay: 1000,
});

Automatic Retries

Retries are handled automatically with exponential backoff. You can customize the retry behavior:
import Triqai from "triqai";

const triqai = new Triqai(process.env.TRIQAI_API_KEY!, {
  maxRetries: 3,       // max retry attempts (default: 3)
  retryDelay: 500,     // base delay in ms (default: 500)
  maxRetryDelay: 30_000, // max delay cap (default: 30000)
});
Retry behavior:
  • GET and DELETE requests are always retried on transient errors
  • POST requests are only retried when an idempotencyKey is provided
  • The Retry-After header from 429 responses is respected automatically
  • Retried status codes: 429, 500, 503, 504, and network errors
To disable retries entirely:
const triqai = new Triqai(process.env.TRIQAI_API_KEY!, { maxRetries: 0 });

Complete Error Handling Pattern

Here’s a complete error handling example using typed error classes:
import Triqai, {
  TriqaiError,
  AuthenticationError,
  ValidationError,
  RateLimitError,
  InsufficientCreditsError,
  NotFoundError,
} from "triqai";

const triqai = new Triqai(process.env.TRIQAI_API_KEY!);

try {
  const result = await triqai.transactions.enrich({
    title: "STARBUCKS NYC",
    country: "US",
    type: "expense",
  });
} catch (err) {
  if (err instanceof AuthenticationError) {
    console.error("Invalid API key — check your configuration");
  } else if (err instanceof ValidationError) {
    console.log("Validation errors:", err.fieldErrors);
  } else if (err instanceof RateLimitError) {
    console.log(`Rate limited — retry after ${err.rateLimitInfo.retryAfter}s`);
  } else if (err instanceof InsufficientCreditsError) {
    console.log("No credits remaining — top up at triqai.com/dashboard");
  } else if (err instanceof NotFoundError) {
    console.log("Resource not found");
  } else if (err instanceof TriqaiError) {
    console.log(`API error ${err.statusCode}: ${err.message} [${err.code}]`);
    console.log("Request ID:", err.requestId);
  }
}
See the error handling reference for the full list of error classes.

Logging and Monitoring

Request Logging

Use built-in debug hooks for observability:
const triqai = new Triqai(process.env.TRIQAI_API_KEY!, {
  onRequest: (info) => {
    console.log(`→ ${info.method} ${info.url}`);
  },
  onResponse: (info) => {
    console.log(`← ${info.status} in ${info.durationMs}ms`);
  },
});
Or wrap calls for custom logging:
async function enrichWithLogging(transaction: { title: string; country: string; type: string }) {
  const startTime = Date.now();

  try {
    const result = await triqai.transactions.enrich(transaction);
    console.log({ event: "enrichment_success", duration: Date.now() - startTime });
    return result;
  } catch (err) {
    if (err instanceof TriqaiError) {
      console.error({ event: "enrichment_error", code: err.code, requestId: err.requestId });
    }
    throw err;
  }
}

Error Tracking

import { TriqaiError } from "triqai";

function trackError(error: TriqaiError, context: Record<string, unknown> = {}) {
  errorTracker.captureException(error, {
    tags: {
      service: "triqai",
      errorCode: error.code,
    },
    extra: {
      requestId: error.requestId,
      statusCode: error.statusCode,
      ...context,
    },
  });
}

Best Practices

The meta.requestId helps with debugging and support requests.
If errors persist, temporarily stop requests to prevent cascading failures.
Partial results (partial: true) are successes with some failures handle them differently from full failures.
Catch validation errors client-side when possible to reduce failed API calls.
Create error classes that make it easy to check error types and extract details.

Next Steps

API Reference

Complete API documentation with error codes

Rate Limits

Understand and manage rate limits