How it works

Your users should never have to read a bank's shorthand

Send us the line your feed gives you. Get back a name a person recognises, a category you can group by, and a number saying how sure we are. One call. No SDK, no model to train, no rules to maintain.

What the feeds send
Card networkMULTICHOICE NIGERIA LTD
Payment gatewayPAYSTACK*DSTV
Instant transferNIP/GTB/DSTV NIGERIA/DEC SUB
Card terminalPOS/DSTV/LAGOS NG
Biller referenceDSTV/BOX OFFICE/07031234567

One television subscription, on a Nigerian feed, arriving through a different rail each time. Every rail writes it differently.

What Kederi returns, for every one of them
MerchantDStv (MultiChoice)
CategoryTV
MCC4899
CountryNigeria · NGN
RecurringMonthly
ChannelVaries, as sent

One name, so it groups. One category, so it budgets. The channel is kept, because how they paid is real information rather than noise.

Grouped by the raw string, every one of those is a separate merchant and a separate category. Your user just sees their TV bill, again and again.

The call

Three things happen, and they take about as long as this sentence

We read it

The line comes apart into the part that names something and the part that is plumbing: references, terminal ids, phone numbers, branch and city tags.

So two payments to the same person stop looking like two different people.

We name it

What is left is resolved against a directory of 662 merchants, billers and counterparty organisations. When there is no merchant, because the payment is a transfer, we name the counterparty and what the sender said it was for.

Most of what arrives on a Nigerian feed is that second case.

We explain it

Category and MCC, country and currency, the channel it arrived through, whether it repeats, and a confidence score.

Enough to group, budget, reconcile or flag without ever touching the raw string again.

Nothing is a black box

Every answer shows its working

A label on its own cannot be checked: when one is wrong there is nothing to look at. Every result we return carries the full list of decisions that produced it, in the order they happened, so a wrong answer is something you can diagnose rather than only report.

One descriptor, and what the engine did with it
RawSQ *BLUE BOTTLE 8005551234 CA
NormalizeSQ *BLUE BOTTLE 8005551234 CA
Channelprocessor Square, via Card / POS
Strip noiseBLUE BOTTLE CA
Matchdictionary hit Blue Bottle Coffee (11 chars)

The third line is where a wrong answer usually starts. If the noise we stripped took part of the merchant name with it, you can see that in the same response, without asking anyone.

This is the whole trace, not a summary. It comes back on every result, including the ones we could not resolve, which is where you need it most. See it documented.

When we are not sure

A blank field is a better answer than a confident wrong one

Every answer says how sure it is

A confidence score comes back with each result, and it means the same thing across every kind of transaction. Anything we are not confident about is marked, so you can decide whether to show it, hold it, or ask the user.

A wrong answer is one you can fix

Send us the correction. It is reviewed, folds into the directory, and is added to the benchmark, so the next feed carrying that string gets the right answer and the mistake cannot come back unnoticed. GET /feedback shows you what became of it.

We would rather say nothing than guess. Returning a merchant we cannot stand behind is the failure that costs you a support ticket and your user their trust, so precision is measured separately from recall: a separate set of 106 narrations must resolve to no merchant at all.

Why there is no accuracy percentage on this site

Most vendors quote a score on their own test set. That score says how well an engine reads the banks it was built with, and it is not the number you need.

The one you need is how it reads your feed. Every bank writes its narrations a little differently, so check a bank that is not on our coverage page on your own feed before you rely on it.

So this site gives the size of our test sets and no scores. Ask us and you get the numbers and the method, in writing. Better still, the playground runs the real engine on whatever you paste into it, and the API will run a batch of your own narrations. A number you produced from your own feed settles the question; ours cannot.

If you have Nigerian statements and are willing to share a handful of narrations, that is the single most useful thing anyone can give us. How to send one.

Contributing a statement

What we need is formats, not volume

Five to twenty narration lines from one bank is enough. Not a full statement, not a year of history, and never a file from an account that is not yours to share. What makes a bank readable is the shape its narrations take, and a handful of lines shows that as well as a thousand do.

Most useful, in order: a Nigerian bank we have not listed on coverage, then a wallet or neobank, then anywhere else in Africa. If you are not sure whether yours helps, it probably does.

What happens to it

Account numbers, phone numbers and references are scrambled before anything is stored, and the result is never committed to a repository, never published, and never sent to another vendor. It is used to check whether the engine reads that bank, and to fix it where it does not. If you would rather redact the amounts before sending, the formats still work without them.

We will tell you what it said about your bank, which is usually the interesting part for the person who sent it.

How to send one

Paste the lines into the contact form, or ask us there and we will send the consent wording first. Pasted text is easier for both of us than a PDF, and it means you can see exactly what you are sending.

Only send narrations from an account you hold, or one whose holder has agreed. We do not accept statements found online: whoever they belong to did not agree to anything, and a set collected that way is not one we would publish a number from.

Then it gets more useful

Send an account's history and different questions get answered

One string can only be enriched. A history has patterns in it.

What repeats

Subscriptions and bills, what they cost a month, which one has quietly gone up, and which has stopped being paid.

What was charged twice

The same payment, twice, minutes apart. Told apart from two genuine payments that merely look alike.

What is coming

A cash-flow view of the month ahead, as a range rather than a single number, saying how much of it is known and how much is estimated.

Evaluating it

Answer “how good is it on my feed” without writing code

Sign up and drop a statement on the console. It is the fastest honest answer to the only question that matters, and it is the same API this page describes: there is nothing on the console the API cannot do.

The file never leaves your machine

Your browser reads the statement and posts the parsed rows to the enrichment endpoint, naming no account. There is no upload endpoint, because there is nothing to upload to.

Every panel names its call

Each one says which report produced it, and opens a log of the requests your browser actually made. What you are reading is the API’s answer, rendered.

It is a console, not an app

It is where you evaluate the API and manage your keys. We do not sell a personal finance product, and your users never see this: they see yours.

Try it on a line from your own feed

The playground calls the same API this page describes, with no key and no account, and shows you exactly what comes back.