Reference
Gotchas
The muddy list. Words that carry more than one meaning, fields that lie, and conventions with no schema behind them. Check here before debugging anything strange.
Terminology drift
| Trap | Reality |
|---|---|
| "Card" means two things | iQpay card = one clip (CardId). InComm card = a customer (ingenId + PAN). Full page. |
| "Offer" means two things | An InComm offer is the numbered contract at InComm. But half the portal calls products offers: the Send cards wizard, Advanced Offers, and the member's wallet all say offer while handling products. "Send an offer" and "send a card" are used interchangeably, and both send a product. See Products. |
| "Sponsors" and "Recipients" | Portal-only words. Sponsors are organizations; Recipients are members. The code and DB never use the portal words. |
| Three names, one concept | Menu "Recurring products", page "Create Advanced Offer", code "advanced product". All the same ProductType=advanced row. Full page. |
| Activity vs Transactions vs Redemptions | One page, one endpoint, one table (cardevents). The title switches by role; only the Excel export differs (redemptions export filters Purchase/Return/Void). |
| "Offer type" means two things | incommoffers.OfferType is InComm's SPEND/DISCOUNT. But product report filters named OfferType actually filter ProductType (original/advanced/marketplace). Same words, different axis. |
| "Banner" is not a table | Banners live as rows in retailers. The join table incommoffer_x_banner is the only place the word survives in the schema. |
| "Redeem At" is not a column | The admin form field Redeem At is stored as products.RedeemOptions. |
CardIssuer vs CardIssuerType | CardIssuer = who mints (incomm, walmart, open_mastercard). CardIssuerType = acceptance scope for open-loop cards. Unrelated fields with sibling names. |
| "Advanced Offer" vs "advanced product" | Same thing. The UI says Advanced Offers, the schema says ProductType = advanced. |
Schema traps
| Trap | Reality |
|---|---|
The X- prefix lives on the tag | Exclusion is decided by the catalog's tag, not its name: the platform tests whether the tag starts with X-, and no schema column backs it up. The prefix is necessary on every exclusion catalog's tag. Full page. |
| Money in cents | InComm-facing values are cents: incommoffers.Value = 9200 is $92. Fields named AmountUsd are dollars. |
cards.AmountRemoved is not spend | It is the leftover balance clawed back at expiry or deactivation. Real spend is in card events. |
| No card→program key | Route through cards → orderproducts → orders → ProgramId. |
membereligibilities has no MemberId | Match on ExternalId. |
| Catalog items join on the local id | incommcatalogitems.IncommCatalogId → local incommcatalogs.Id, not the InComm-side IncommId. |
| Card data is not in MongoDB | cardevents.SourceData is a JSON document stored as text in a MySQL column, which makes people assume Mongo. All card, member, and transaction data is MySQL; the Mongos hold only scraped and reference product data. |
Behavioral traps
| Trap | Reality |
|---|---|
Empty items[] on a decline | Not diagnostic. Unqualified items are never echoed back. Full page. |
| Pre-July-2025 decline records | The code and description fields are swapped in old SourceData. Query both. |
| PAN looks like an InComm number | iQpay mints it and registers it with InComm. Walmart PANs come from Walmart's processor. |
| Walmart cards reuse InComm columns | On CardIssuer = walmart rows, AccountId holds a Fiserv trace number (the processor's reference for that issuance) and SecurityCode holds the EAN. Do not read them as ingenId and CVV. See Trace number in the glossary. |
| Walmart data is a day late | Walmart redemptions arrive by settlement file, not webhook. Missing "today" is normal. |
| Clip-deleted orphan | Two overlapping monthly cards on one customer: the old card's expiry can delete the shared clip and everything declines. Careful re-clip required. Full page. |
| The wallet scanner is a preview, not the verdict | InComm decides at the register; our scanner mirrors catalogs only and skips limits, windows, balances, and secondary catalogs. Known divergence table in Inclusion vs exclusion. |
| A second, inclusion-only scanner endpoint exists | The admin-only per-product ProductScanner endpoint uses a lookup with no X- handling. Nothing member-facing calls it; do not use it to test exclusion offers. |
| Catalog sync to InComm is one-way | We push catalogs; pulling InComm's state back is a manual admin action. No scheduled reconciliation exists, so mirrors can drift. |
| Dead billing surfaces | /payments/list is a stub page; the paymentmethods table (BlueSnap) is empty. Real payments run through Stripe invoices. |
| Albertsons banners share one id | All Albertsons-family banners carry the same InComm retailer identifier, 26471. Do not use it to tell Safeway from Jewel-Osco. |
ℹ️
Found a new one?
Send it to Tunc and it gets added here. This page only works if it stays current.