IOSOR Learn
End-user send still hits one prepaid ledger
Embedded Send still debits the ISV prepaid wallet. Do not invent a second ledger the product does not fund — holds, retries, and idempotency stay honest.
Embedded messaging feels free to the end user: they tap Send inside the SaaS UI and see a green check. Under the glass, every successful submit still hits one prepaid ledger owned by the ISV. There is no second wallet that appears because the product embedded an API. If the ISV does not fund holds, send must fail with an honest product error — not a fake delivered state.
Fiction accounting is the failure mode: an in-app credit meter not backed by the IOSOR wallet, SaaS refunds while the prepaid ledger burns, or retries without idempotency that double-debit one OTP. Embed hides the console; the ISV remains the funded party.
Architecture doc line: end-user send ≡ ISV prepaid debit. Every design review starts there.
One ledger, even when the UI shows product credits
Message packs sold to tenants are an ISV commercial layer. They must map to prepaid holds and debits on the single IOSOR wallet the ISV funds. A tenant balance that never reconciles to ledger rows is a support debt bomb. Export tenant usage weekly against wallet lines so finance sees the same burn product sees.
Do not open a second IOSOR account per tenant unless Partner isolation is the explicit contract. Embed pilots almost always stay on one ISV account with internal fair-share caps.
Holds and idempotency still bind on embed paths
Server-side send must use idempotency keys for OTP and transactional SMS. A double-click in the SaaS UI must not create two debits for one user action. Retries after timeout follow the same key until a terminal DLR or a mapped failure.
When the wallet cannot hold, return a product-native insufficient-funds or paused-send status. Never return HTTP 200 with delivered semantics when the hold failed.
Map product errors to ledger truth
| SaaS UI signal | Ledger truth | Allowed next step |
|---|---|---|
| Sent / delivered | Debit + DLR path exists | Show receipt id |
| Queued | Hold open or submit accepted | Poll status |
| Failed / paused | Hold rejected or stop gate | Retry only with new intent |
| Fake success | No debit / no hold | Forbidden |
Train support on the middle column. Tickets about UI greens without ledger rows waste the pilot week.
Channel handovers stay on the same wallet
If the product later adds email or voice beside SMS, spend still lands on the same prepaid ledger unless you run a second-channel handover with finance sign-off. Embed does not create a free side channel. Read Wallet adjacency before flipping another Live tile in SaaS settings.
Related ops paths
- Second-channel spend handover on one wallet
- API idempotency, retries, and money
- Subtenant rate limits and fair share
Start with IOSOR
Open the IOSOR Console and map your tenant credit system directly to the primary prepaid wallet ledger. Ensure all server-side embed requests pass a deterministic idempotency key before placing a hold on the master wallet. Configure your webhook endpoint to process incoming DLRs so that open holds resolve cleanly to final ledger debits or releases.
IOSOR takeaway
An embedded SaaS interface can present custom message credits to end users, but every real dispatch binds to the single prepaid ledger funded by the ISV. Retries, channel expansions, and user status signals must reconcile directly against wallet holds rather than unbacked UI abstractions.
Do enforce strict server-side idempotency keys and map every tenant UI state to true ledger DLR responses. Don't invent unbacked secondary wallets or allow tenant UI retries to execute without concrete ledger holds.
Was this guide helpful?
Related guides
- Embedding the API vs a white-label partner portal
SaaS products that embed messaging stay on the ISV surface. White-label partner portals stay under Partner — do not mix brand, keys, and ops ownership.
- When an embedded tenant cap must stop send
Fair-share caps inside an ISV product must hard-stop send for that tenant — never return a fake delivered API 200 when the cap is hit.