Card-routing decision engine · UAE

Every purchase, routed to the right card.

The best card, the exact reward, and the reason it won — from one deterministic call.

Deterministic No PANs Stateless Your perimeter
0.08 ms
p99 decision latency, over 20,000 runs
16
verified UAE cards, 5 issuing banks
202
merchant patterns, 7 categories
0
cardholder records stored, ever

One call

Merchant, amount, wallet. One decision.

The request carries card names, a merchant descriptor and an amount. No PAN, no track data, no CVV — there is nothing in this call that puts you in PCI scope.

POST /v1/decisionrequest
{
  "merchant": "CARREFOUR MOE DUBAI",  // raw descriptor
  "amountAed": 420,
  "cards": [                           // names, never PANs
    "Dubai First Cashback",
    "ADCB TouchPoints Infinite",
    "ADCB Traveller"
  ]
}
200 OKresponse
{
  "bestCard": "Dubai First Cashback",
  "bestRewardAed": 21,
  "bestRatePct": 5,
  "category": "groceries",
  "categoryResolved": true,
  "deltaVsRunnerUpAed": 19.99,
  "reason": "5% on groceries — the best of your 3 cards.",
  "perCard": [],              // all cards, best first
  "rulebookVersion": "2.0.0",    // replay this decision
  "rulebookReviewedAt": "2026-07-17",
  "latencyMs": 0.02
}
CARREFOUR MOE DUBAI AED 420 3 cards

Use this card

Dubai First Cashback

5% on groceries. The best of the 3 cards in this wallet.

Earns

AED 21.00

on AED 420 · groceries

+AED 19.99 vs next-best

Dubai First CashbackAED 21.00 · 5%
ADCB TouchPoints InfiniteAED 1.01 · 0.24%
ADCB TravellerAED 0.00 · no verified rule

this call: 0.02 ms · across 20,000 mixed calls: median 0.03 ms, p99 0.08 ms · Rulebook 2.0.0

AED 1 on the wrong card. AED 21 on the right one.

That gap repeats on every purchase your cardholders make. Sikka closes it in the moment, and keeps your cards top of wallet.

What it is

Six properties, no asterisks.

Deterministic

No model in the path. Same inputs and same Rulebook version give the same answer, every time.

Verified Rulebook

Rates read from published T&Cs and signed off by a human. No verified rule means a card earns zero — never an estimate.

Stateless

Nothing is written. Run it inside your own perimeter and the call makes no outbound connection.

Explainable

Every decision carries the reason, the rate, the category, and the value against the next-best card.

Merchant resolver

202 descriptor patterns resolve noisy transaction text to one of 7 categories. Unresolved merchants are flagged, not guessed.

Multi-issuer

One neutral layer across portfolios. 16 verified UAE cards today, from 5 issuing banks.

How it decides

Three steps, one function.

1

Resolve

The raw descriptor maps to a category — groceries, fuel, dining. Anything unresolved routes at the everyday base and is flagged.

2

Score

Every held card is scored at its highest verified rate for that category. A monthly cap is applied to this purchase alone — see the note below on what stateless costs you.

3

Route

Return the winner, the gap to the runner-up, and the reason. Points and cashback compare on one AED scale.

Buy, not build

The one question every team asks.

The maintenance grind

Rates, caps and exclusions change constantly. Keeping the Rulebook true is a permanent job. It is ours, not your roadmap.

The accuracy gap

Resolving noisy merchant descriptors is the hard part, and it is the part that is never finished.

Neutral by design

One shared layer, credible across portfolios. An in-house build is captive to a single book.

Live today

Deterministic, demoable, ready to pilot. Every number on this page comes from the running engine.

Integration

A drop-in decision call.

Send the wallet and the purchase

POST /v1/decision with the raw merchant, the amountAed, and the card names held.

Get the decision back

Deterministic JSON: best card, reward, gap to runner-up, reason, and the Rulebook version it was computed against.

Surface it on your rails

A pre-purchase "use this card" nudge, a post-authorisation reward attribution, or a statement line.

Host it in your perimeter

Stateless, with no outbound calls. The Rulebook ships versioned and freshness-checked.

integrationfail-open
const decision = await decide(txn, { timeoutMs: 40 })
  .catch(() => null);   // timeout or unreachable

if (decision === null) {
  // authorise anyway. The nudge is dropped,
  // the payment is never held up.
  return authorise(txn);
}

if (decision.deltaVsRunnerUpAed > 1) {
  nudge(cardholder, decision.bestCard, decision.reason);
}

Fail-open

The engine sits beside authorisation, never inside it. On timeout or unavailability the caller authorises and drops the nudge. It cannot decline a payment, and it is not a dependency of your uptime.

PCI scope: zero

The request carries a merchant descriptor, an amount, and card names. No PAN, no track data, no CVV, no cardholder identifier crosses the boundary — so nothing here enters your card-data environment.

Auditable

Every response carries rulebookVersion and rulebookReviewedAt. Replay the same inputs against the same version and you get the same decision — so any nudge can be defended months later.

Sikka provides

  • The maintained UAE Rulebook — rates, caps and exclusions, versioned and freshness-checked.
  • The merchant resolver — descriptor to category, no model in the path.
  • The routing engine — the decision, the value gap, and the reason.
  • Multi-issuer neutrality, and the maintenance grind off your roadmap.

You provide

  • The rails — BIN, scheme, PCI, tokenisation, the authorisation flow.
  • The wallet context — which cards a cardholder holds.
  • The surface — nudge, statement, or product.
  • The distribution to cardholders.

API reference

The decision contract.

POST /v1/decision — request

POST /v1/decision request fieldsPOST /v1/decision response fields
FieldTypeDescription
merchantstringThe raw merchant descriptor from the transaction feed. Passed through as-is; the resolver handles the noise.
amountAednumberThe purchase amount in AED.
cardsstring[]The wallet, as card names. A catalog entry matches when its key is contained in the name you send, case-insensitively — so "ADCB TouchPoints Infinite Credit Card" resolves. Never a PAN or a token.

200 /v1/decision — response

FieldTypeDescription
bestCardstring | nullnull when no held card earns a verified reward here. A null answer is a real answer.
bestRewardAednumberThe AED the winning card earns on this purchase.
bestRatePctnumberThe effective reward rate as a percentage.
categorystringThe resolved category. Falls back to everyday.
categoryResolvedbooleanfalse when the descriptor could not be resolved. Routed at base, never guessed.
deltaVsRunnerUpAednumberThe AED gap to the next-best card — what a wrong tap would have cost.
reasonstringA human-readable explanation, ready for a nudge or a statement line.
perCardobject[]Every card scored, best first. Each entry is { card, rewardAed, ratePct, condition }, where condition is the min-spend or cap gate on that rate, or null. Render it: a gated rate the cardholder has not unlocked will not pay out.
rulebookVersionstringThe Rulebook release the decision was computed against. Required to replay it.
rulebookReviewedAtstringISO date that release was last reviewed.
latencyMsnumberTime to compute, measured live on the call.

Deployment

The engine runs inside your perimeter — /v1/decision is the contract it exposes there, not a public endpoint we host. It is a pure function over the Rulebook: no database, no outbound connection, no shared state between calls.

Categories

groceriesfueldiningtravelonlineeducationeveryday

Coverage, as of 13 August 2026

Engine coverage as of 13 August 2026
DimensionNowDetail
MarketUAEThe engine itself is market-agnostic. Only the UAE catalog is published here.
Verified cards16Across 5 issuing banks: FAB including the Dubai First brand (7), ADCB (4), HSBC (2), Mashreq (2), Wio (1).
Merchant patterns202A case-insensitive substring table, resolving to 7 categories. No fuzzy matching: a descriptor that matches nothing returns unresolved. The table is shared across markets, so it also carries non-UAE brands.
Decision latency0.03 msMedian. p99 0.08 ms, p99.9 0.15 ms, worst observed 4.2 ms — over 20,000 decisions on wallets of 3 to 16 cards. The integration budget is 100 ms, which is why fail-open costs you nothing.
Rulebook2.0.0Last reviewed 2026-07-17. Returned on every decision.
What is not on this page. There is no resolver-accuracy figure here, because we have not built the hand-labelled set required to compute one honestly. When we do, the number goes here whatever it says. Also unspecified so far: authentication, error codes, and input validation — the engine is a pure function today and rejects nothing, so a malformed request returns a wrong answer rather than a 4xx. Rates publish only after a human signs them off against the issuer's own published terms, and card coverage is shown at its true current count.

Talk to us

Send us a wallet. We will route it, live.

Then decide whether to buy it or build it. Either answer is useful. What we are proposing is a paid, non-exclusive pilot on one card portfolio — fixed scope, a named integration owner, and a path measured in weeks.

praneet@usesikka.com

Built by engineers from low-latency exchange systems, where deterministic sub-millisecond lookups are the everyday.