Email workspaceVirtual card created
Source: App\Mail\CardCreatedNotification, app/Mail/CardCreatedNotification.php; resources/views/emails/CardCreated.blade.php. Caller: MapleradController::handleWebhook, app/Http/Controllers/Wallet/MapleradController.php:142.
Existing effective subject: Card Created Notification. No explicit subject override exists; Laravel derives it from the class basename. Preserve native behavior rather than adding a new subject silently. Suggested preheader: Your virtual card {{masked_card_number}} was created.
Required portable values
| Token | Existing source | Handling |
|---|---|---|
| {{card_name}} | card.name | Escaped holder/display name. |
| {{masked_card_number}} | card.card_pan_masked | Only original masked display; never card_pan, CVV or expiry. Keep as text. |
| {{card_type}} | card.card_type | Escaped original issuer/type value; no inferred card brand. |
| {{card_balance}} | card.amount | Raw existing display, preserving zero. Original has no currency prefix or number_format; do not silently introduce one or divide by 100. |
| {{login_url}} | Fixed https://app.built.africa | Validated original app-root URL, escaped attribute. Log in to Built does not directly classify an expense. |
| {{preheader}} | Suggested masked-card summary above | Escaped text; no unmasked account information. |
Default logo/optional {{logo_url}} and actual CID/approved HTTPS footer images follow [shared-footer](../shared-footer.md). No optional body section or legacy duplicate link exists.
Trigger and native behavior
handleWebhook's issuing.created.successful branch fetches the remote card, updates the local card, handles an existing funding service, reloads the real card and calls Mail::to(wallet-user.email)->send(new CardCreatedNotification(realCard)). Preserve that order, remote/local ID resolution and existing error handling. Push notification is a separate channel; it is not another email. Do not infer that creation guarantees card balance/funding or every active-status property.
The body prints only name, masked number, card type and raw balance, followed by the original instruction to log in and classify the expense in the books. The model contains more sensitive card fields; none belongs in this redesign's contract or fixtures. The provider balance/amount units should be reviewed as an explicit target-project decision if behavior is changed later.
There is no explicit From/Reply-To override, PDF or business attachment. Preserve configured headers, native subject and send(); Queueable is not proof of queued sending. Underlying transport/outbox may still be asynchronous. API owns the body even though a provider webhook triggers it.
Integration and safety
Use the existing Mailable with a complete HTML Blade view and a proposed text alternative. Portable {{placeholder_name}} tokens are not automatically Blade variables. Escape values/attributes, validate approved app-root and image URLs separately, and use one pass for replacements. Never read/fetch live card data to populate previews. No expiry, PAN, CVV, activation, funding, dispute or reversal action is added.
Three fictional states cover created, zero balance and long masked/display values. Files: public/ready/virtual-card-created.html/.txt and previews/virtual-card-created-*.html/.txt. No separate project-owned plain-text alternative was found. Browser checks do not verify actual card/provider behavior, Gmail/Outlook/iOS Mail, CID delivery or production delivery.