Skip to main content
This guide walks through the complete process of enriching transactions, from preparing your data to processing the results.

Preparing Transaction Data

Required Fields

Every enrichment request needs three fields:
{
  "title": "AMAZON MKTPLACE PMTS AMZN.COM/BILL WA",
  "country": "US",
  "type": "expense"
}
FieldTypeDescription
titlestringRaw transaction description (1-256 characters)
countrystringISO 3166-1 alpha-2 country code
typestringexpense or income

Transaction Title Best Practices

Don’t truncate or pre-process the transaction title. Include everything from the bank statement:
✓ "POS 4392 STARBUCKS STORE #1234 NEW YORK NY 10001"
✗ "STARBUCKS"
The full string contains valuable signals (store numbers, locations, dates) that improve accuracy.
Keep the original case, spacing, and punctuation:
✓ "AMAZON.COM*2K4X9T3H2 AMZN.COM/BILL WA"
✗ "Amazon"
If your transaction source provides additional description fields, concatenate them:
const title = [
  transaction.description,
  transaction.merchantName,
  transaction.locationInfo
].filter(Boolean).join(' ');

Country Code

The country code should be:
  • ISO 3166-1 alpha-2 format (2 letters)
  • The country where the transaction originated
  • Uppercase or lowercase (both work)
// Valid country codes
"US"  // United States
"NL"  // Netherlands
"GB"  // United Kingdom
"DE"  // Germany
"FR"  // France
If you’re unsure of the country, use the account holder’s primary country. Transaction strings often contain location hints that Triqai can use for more accurate matching.

Transaction Type

Set type based on the transaction direction:
TypeWhen to Use
expenseMoney leaving the account (purchases, payments, fees)
incomeMoney entering the account (salary, refunds, transfers in)
This affects how Triqai interprets the transaction and which categories it considers.

Making the Request

Basic Request

import Triqai from "triqai";

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

const result = await triqai.transactions.enrich({
  title: "NETFLIX.COM",
  country: "US",
  type: "expense",
});

Processing Multiple Transactions

For multiple transactions, make individual requests. Retries and rate limits are handled automatically:
import Triqai from "triqai";

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

async function enrichTransactions(transactions: Array<{ description: string; country: string; amount: number }>) {
  const results = [];

  for (const tx of transactions) {
    const result = await triqai.transactions.enrich({
      title: tx.description,
      country: tx.country,
      type: tx.amount < 0 ? "expense" : "income",
    });
    results.push(result);
  }

  return results;
}
Transient errors (429, 500, 503) are automatically retried with exponential backoff, so you don’t need to implement retry or rate-limit logic yourself.

Processing the Response

Successful Response

A successful enrichment returns structured data with an entities array:
{
  "success": true,
  "partial": false,
  "data": {
    "transaction": {
      "category": {
        "primary": { "name": "Entertainment", "code": { "mcc": 4899, "sic": 7841, "naics": 532230 } },
        "secondary": { "name": "Streaming Services", "code": { "mcc": 4899, "sic": 7841, "naics": 532230 } },
        "tertiary": null,
        "confidence": { "value": 98, "reasons": ["merchant_category_match"] }
      },
      "subscription": { "recurring": true, "type": "streaming" },
      "channel": "online",
      "confidence": { "value": 96, "reasons": [] }
    },
    "entities": [
      {
        "type": "merchant",
        "role": "organization",
        "confidence": { "value": 99, "reasons": ["name_closely_matched", "results_consensus"] },
        "data": {
          "id": "...",
          "name": "Netflix",
          "icon": "https://logos.triqai.com/images/netflixcom",
          "website": "https://www.netflix.com"
        }
      }
    ]
  },
  "meta": {
    "generatedAt": "2026-01-19T10:30:00Z",
    "requestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a123",
    "version": "1.1.9",
    "categoryVersion": "triqai-2026.01"
  }
}

Extracting Key Data

import Triqai from "triqai";

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

const result = await triqai.transactions.enrich({
  title: "STARBUCKS STORE #1234 NEW YORK NY",
  country: "US",
  type: "expense",
});

const { data } = result;
const { entities } = data;

const findEntity = (type: string) => entities.find(e => e.type === type);

const merchant = findEntity("merchant");
const location = findEntity("location");
const intermediary = findEntity("intermediary");

const processed = {
  category: data.transaction.category.primary.name,
  subcategory: data.transaction.category.secondary?.name,
  confidence: data.transaction.confidence.value,

  merchantName: merchant?.data.name,
  merchantLogo: merchant?.data.icon,

  location: location?.data.formatted,

  intermediary: intermediary?.data.name,
  intermediaryRole: intermediary?.role,

  isSubscription: data.transaction.subscription.recurring,
  channel: data.transaction.channel,
};

Handling Different Transaction Types

Regular Purchases

Most transactions identify a merchant directly:
{ "title": "STARBUCKS STORE 1234", "country": "US", "type": "expense" }

Intermediary Transactions

When a payment processor or platform is involved:
{ "title": "STRIPE* ACME INC", "country": "US", "type": "expense" }
Triqai identifies the intermediary (Stripe, role processor) and attempts to identify the underlying merchant (Acme Inc).

P2P Transfers

Peer-to-peer payments return both an intermediary and a person entity:
{ "title": "VENMO PAYMENT TO JOHN DOE", "country": "US", "type": "expense" }
Returns the P2P platform as an intermediary (role p2p) and the recipient as a person entity.

Income Transactions

Refunds, salary, and other income:
{ "title": "PAYROLL ACME CORP", "country": "US", "type": "income" }
Uses income-specific categories and classification logic.

Next Steps

Handling Responses

Learn to process different response types

Error Handling

Handle errors and edge cases

API Reference

See the full API documentation

Best Practices

Optimization tips and patterns