Skip to main content
Follow these best practices to get the most out of the Triqai API while building reliable, efficient integrations.

Data Quality

Send Complete Transaction Data

Include the full, original transaction string:
{
  "title": "POS 4392 STARBUCKS STORE #1234 NEW YORK NY 10001",
  "country": "US",
  "type": "expense"
}

Use Accurate Country Codes

The country code significantly affects matching accuracy:
  • Use the transaction’s origin country, not user’s country
  • Use ISO 3166-1 alpha-2 codes (US, NL, GB)
  • Default to account country if unknown

Set Correct Transaction Type

The type field affects category selection:
TransactionType
Purchases, payments, feesexpense
Salary, refunds, depositsincome

Performance Optimization

Deduplicate Similar Transactions

Group identical transactions before enriching to save credits:
import Triqai from "triqai";

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

interface Transaction {
  id: string;
  title: string;
  country: string;
  type: "expense" | "income";
}

async function enrichBatch(transactions: Transaction[]) {
  const groups = new Map<string, { representative: Transaction; all: Transaction[] }>();

  for (const tx of transactions) {
    const key = `${tx.title.toUpperCase()}|${tx.country}|${tx.type}`;
    if (!groups.has(key)) {
      groups.set(key, { representative: tx, all: [] });
    }
    groups.get(key)!.all.push(tx);
  }

  const results = new Map();

  for (const [, group] of groups) {
    const result = await triqai.transactions.enrich({
      title: group.representative.title,
      country: group.representative.country,
      type: group.representative.type,
    });
    for (const tx of group.all) {
      results.set(tx.id, result);
    }
  }

  return results;
}

Rate Limit Management

Rate limits are handled automatically via retries and Retry-After header support. You can monitor usage through the debug hook:
const triqai = new Triqai(process.env.TRIQAI_API_KEY!, {
  onResponse: (info) => {
    // info.headers contains X-RateLimit-* values
    console.log(`Request completed in ${info.durationMs}ms`);
  },
});
For full rate limit details on a response, use raw requests:
const resp = await triqai.rawGet("/v1/categories");
console.log(resp.rateLimitInfo.remaining);
console.log(resp.rateLimitInfo.concurrencyRemaining);

Error Handling

Built-In Retry Logic

Retries are handled automatically with exponential backoff on transient errors (429, 500, 503, 504). You can customize the behavior:
const triqai = new Triqai(process.env.TRIQAI_API_KEY!, {
  maxRetries: 5,          // increase from default 3
  retryDelay: 1000,       // base delay in ms
  maxRetryDelay: 60_000,  // max delay cap
});
For POST requests, retries only happen when an idempotencyKey is provided:
const result = await triqai.transactions.enrich(
  { title: "STARBUCKS", country: "US", type: "expense" },
  { idempotencyKey: "unique-key-123" },
);

Handle Partial Results

Don’t discard partial results — use available data:
const result = await triqai.transactions.enrich({
  title: "SOME TRANSACTION",
  country: "US",
  type: "expense",
});

const { entities } = result.data;

const merchant = entities.find(e => e.type === "merchant");
const location = entities.find(e => e.type === "location");

const processed = {
  category: result.data.transaction.category,
  merchant: merchant?.data ?? null,
  location: location?.data ?? null,
};

if (result.partial) {
  console.warn("Partial result — some enrichers failed");
}

Security

Protect API Keys

  • Store keys in environment variables
  • Never commit keys to version control
  • Use separate keys for dev/staging/prod
  • Rotate keys periodically
import Triqai from "triqai";

// Good: Environment variable
const triqai = new Triqai(process.env.TRIQAI_API_KEY!);

// Bad: Hardcoded — never do this!
// const triqai = new Triqai("triq_abc123...");

Make Requests Server-Side

Never expose your API key in client-side code:
import Triqai from "triqai";

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

app.post("/api/enrich", async (req, res) => {
  const result = await triqai.transactions.enrich({
    title: req.body.title,
    country: req.body.country,
    type: req.body.type,
  });

  res.json(result);
});

Monitoring and Observability

Track Key Metrics

Monitor these metrics for your integration:
MetricWhy It Matters
Success rateDetect issues early
Latency (p50, p95, p99)Identify performance problems
Partial result rateTrack data quality
Error rate by codeUnderstand failure patterns
Credit consumptionManage costs

Structured Logging

Use the debug hooks for structured logging:
const triqai = new Triqai(process.env.TRIQAI_API_KEY!, {
  onResponse: (info) => {
    console.log(JSON.stringify({
      event: "triqai_request",
      timestamp: new Date().toISOString(),
      status: info.status,
      durationMs: info.durationMs,
    }));
  },
});

Architecture Patterns

Async Processing for Bulk Data

For large volumes, process asynchronously:
import Triqai from "triqai";

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

// Producer: Queue transactions
async function queueTransactions(transactions: Array<{ id: string; title: string; country: string; type: "expense" | "income" }>) {
  for (const tx of transactions) {
    await messageQueue.send({ type: "enrich", payload: tx });
  }
}

// Consumer: Process from queue
async function processQueue() {
  while (true) {
    const message = await messageQueue.receive();
    const result = await triqai.transactions.enrich(message.payload);
    await saveResult(message.payload.id, result);
  }
}

Graceful Degradation

Design for partial failures:
async function getTransactionDisplay(tx: { title: string; country: string; type: "expense" | "income" }) {
  try {
    const enrichment = await triqai.transactions.enrich(tx);
    return formatEnrichedTransaction(tx, enrichment);
  } catch (error) {
    console.error("Enrichment failed:", error);
    return formatRawTransaction(tx);
  }
}

Checklist

Use this checklist when building your integration:
  • API key stored securely in environment
  • Full transaction strings sent, not truncated
  • Caching implemented for duplicate transactions
  • Retry logic with exponential backoff
  • Rate limiting handled gracefully
  • Partial results processed correctly
  • Errors logged with requestId
  • Metrics and monitoring in place
  • Credit usage tracked

Next Steps

Error Handling

Comprehensive error handling guide

Rate Limits

Manage request limits effectively