> ## Documentation Index
> Fetch the complete documentation index at: https://docs.triqai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Best Practices

> Optimize your Triqai integration for performance and reliability

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:

<Tabs>
  <Tab title="Good">
    ```json theme={null}
    {
      "title": "POS 4392 STARBUCKS STORE #1234 NEW YORK NY 10001",
      "country": "US",
      "type": "expense"
    }
    ```
  </Tab>

  <Tab title="Bad">
    ```json theme={null}
    {
      "title": "Starbucks",
      "country": "US",
      "type": "expense"
    }
    ```
  </Tab>
</Tabs>

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

| Transaction               | Type      |
| ------------------------- | --------- |
| Purchases, payments, fees | `expense` |
| Salary, refunds, deposits | `income`  |

## Performance Optimization

### Deduplicate Similar Transactions

Group identical transactions before enriching to save credits:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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

```typescript theme={null}
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:

```typescript theme={null}
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:

| Metric                      | Why It Matters                |
| --------------------------- | ----------------------------- |
| **Success rate**            | Detect issues early           |
| **Latency (p50, p95, p99)** | Identify performance problems |
| **Partial result rate**     | Track data quality            |
| **Error rate by code**      | Understand failure patterns   |
| **Credit consumption**      | Manage costs                  |

### Structured Logging

Use the debug hooks for structured logging:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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

<CardGroup cols={2}>
  <Card title="Error Handling" icon="triangle-exclamation" href="/guides/error-handling">
    Comprehensive error handling guide
  </Card>

  <Card title="Rate Limits" icon="gauge" href="/platform/rate-limits">
    Manage request limits effectively
  </Card>
</CardGroup>
