Provisioning a card is two stages. bulkCardGen reads a template and creates the cards on Tribe, logging the new ids to a file. Those ids then feed bulkCardImport, which reads each card back from Tribe and mirrors it into the cpm database. Gen writes only to Tribe; import is what populates our DB.
One row per kind of card. ~70 columns mapping to Tribe's create-card params; a card_count column says how many to mint from that row.
request_param,default_value pairs. Any column a row leaves blank falls back here. Unknown param names are rejected.
Named, reusable address blocks. A row references one via holder_address / delivery_address / bulk_address instead of repeating fields.
Pull each column for this card (row → defaults → address template), normalise ISO codes, and assemble the Tribe CreateCardAction request.
Card #1 runs synchronously (fail-fast — bad creds/program surface before the whole batch fires); the rest fan out across the pool, capped at 6 concurrent for Tribe.
new Cards(api).createCard(req) creates the card on Tribe and returns its ids. -rundry true fabricates a response and skips Tribe — for validating a template safely.
A Tribe rejection is counted; with -maxErrorCount at its default 0, the first error stops the batch. Pass a higher value to push through.
A single notifier thread appends the result — cardId,cardExtId,programId,designId,… on success, or seq,rootCause on failure. Nothing is written to cpm here — cards live on Tribe; import mirrors them in (stage 2).
^[0-9]{6,20}\s*,\s*[0-9]{6,20}.* — the first two numeric fields (spiCardId, externalId) are required; non-matching rows are silently skipped.getCardNumber call to fetch + mask + hash it."…importing N cards? [y/n]" — only y proceeds.out.csv reshaped (see the hand-off above): cardId→spiCardId, cardExtId→externalId.DEFAULT / VISA → selects the RSA keys for the calls below.
Reads the card from Tribe. Not on Tribe → VendorException (card fails). Returns program, holder, account, currency, status…
Fetches + masks + hashes the PAN when the CSV didn't supply one.
Find PartnerProgram by Tribe program id; look up existing card by SpiId / ExternalId.
Re-running the same list is safe.
Persist the entities (right) and commit this card's own transaction. One bad card rolls back alone.
Card #1 runs synchronously before the pool starts (no overlap); the output/notifier thread never calls Tribe. So the ceiling is exactly 6 per command.
gen's out.csv is the bridge — its card ids become import's input. Skip import and the cards exist on Tribe but never appear in cpm.