Smart Tags
Attach business labels to transactions and filter or aggregate them by any dimension
Smart tags let you attach labels to transactions at creation time, then filter your payments by campaign, product, team, channel, or any dimension you define. Query results stay scoped to your account with no extra setup required.
Setup
import { createNylonPay } from '@nile-squad/nylonpay-ts'
const nylonpay = createNylonPay({
apiKey: 'npk_test_your_key',
apiSecret: 'nps_test_your_secret',
})Attaching Tags
Pass tags to any payment-creation method:
// Collection
await nylonpay.collectPayment({
amount: 25000,
currency: "UGX",
customer: { name: "Jane", phoneNumber: "+256700000000" },
description: "Q2 promo order",
tags: ["campaign-q2", "product:pro", "channel:web"],
})
// Payout
await nylonpay.makePayout({
amount: 50000,
currency: "UGX",
customer: { name: "Jane", phoneNumber: "+256700000000" },
destination: { accountHolderName: "Jane Doe", accountNumber: "123456" },
description: "Partner payout",
tags: ["partner:acme", "batch:jun-2026"],
})
// Invoice
await nylonpay.createInvoice({
amount: 10000,
currency: "UGX",
description: "Monthly subscription",
tags: ["subscription", "plan:starter"],
})Tags appear on the transaction record. You can attach up to 10 tags per transaction.
Tag Format
Tags are normalized when attached:
| Rule | Example |
|---|---|
| Lowercased | "VIP" becomes "vip" |
| Whitespace trimmed | " web " becomes "web" |
| Max 50 characters per tag | longer tags are dropped |
| Max 10 tags per transaction | extras are dropped; first 10 are kept |
Allowed characters: letters a–z, digits 0–9, - _ : . | tags with other characters are dropped |
| Deduplicated | ["vip", "VIP"] becomes ["vip"] |
Reserved Tags
"live" and "test" mark the transaction's mode and are set automatically. Passing either in tags has no effect.
Filtering Transactions
listTransactions
// All "vip" transactions in the last 30 days
const result = await nylonpay.listTransactions({
tags: ["vip"],
createdAfter: new Date(Date.now() - 30 * 24 * 3600 * 1000).toISOString(),
})
if (result.isOk) {
const { transactions, count } = result.value
const totalRevenue = transactions.reduce((s, t) => s + t.amount, 0)
}Passing multiple tags returns only transactions carrying all of them. tags: ["vip", "campaign-q2"] matches transactions with both labels, not either.
getTransactionsByTag
A shorthand for filtering by a single tag:
const result = await nylonpay.getTransactionsByTag("campaign-q2", {
status: "successful",
limit: 50,
})Equivalent to listTransactions({ tags: ["campaign-q2"], status: "successful", limit: 50 }).
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
tags | string[] | none | Returns transactions carrying all listed tags |
status | string | none | pending, successful, failed, processing, cancelled |
type | string | none | collection, payout, invoice |
limit | number | 20 | Results per page (1–100) |
offset | number | 0 | Zero-based pagination offset |
createdAfter | string | none | ISO 8601 datetime — earliest creation time |
createdBefore | string | none | ISO 8601 datetime — latest creation time |
Dashboard Filter
The transaction history page shows a Tags dropdown when your account has tagged transactions. Selecting a tag shows only matching transactions. The filter works alongside the existing status, type, and source filters.
Common Patterns
Per-campaign revenue
const campaigns = ["campaign-q1", "campaign-q2", "campaign-q3"]
const revenues = await Promise.all(
campaigns.map(async (tag) => {
const result = await nylonpay.getTransactionsByTag(tag, {
status: "successful",
})
if (!result.isOk) return { tag, total: 0 }
return {
tag,
total: result.value.transactions.reduce((s, t) => s + t.amount, 0),
}
})
)Paginating a large set
async function* allByTag(tag: string) {
const PAGE = 100
let offset = 0
while (true) {
const result = await nylonpay.getTransactionsByTag(tag, {
limit: PAGE,
offset,
})
if (!result.isOk || result.value.transactions.length === 0) break
yield* result.value.transactions
if (result.value.count < PAGE) break
offset += PAGE
}
}
for await (const tx of allByTag("partner:acme")) {
console.log(tx.id, tx.amount)
}Multi-dimensional labeling
A single transaction can carry labels from multiple dimensions at once:
tags: [
"channel:mobile-app",
"product:premium",
"region:east-africa",
"cohort:2026-q2",
]Filter by any one dimension or combine labels to narrow results further.