Hacker News new | past | comments | ask | show | jobs | submit login
Building Payments for an Insurance Startup (moderntreasury.com)
133 points by saarons on July 31, 2019 | hide | past | favorite | 36 comments



> Insurance firms sometimes cover extremely “long-tail” risks, such as alien abduction insurance.

That's not what "long tail" means in insurance. It does not mean unlikely, it means the claim might need to be paid out years after the period coverage was paid for. (Think current lawsuits about asbestos exposure from the 1970s).

https://www.investopedia.com/terms/l/longtail-liability.asp


The alien abduction insurance was clearly described as a gag gift.


That's a secondary issue (the writer (CEO?) tried to give an example of a insurance policy that covers a very remote event). So fine, doubly nonsensical.

I would have also done a separate article separating paying premiums to the carrier from the carrier paying out claims. Those are basically two totally different parts of the insurance company, with different systems (usually) and definitely from different bank accounts.


Well, maybe the aliens will keep returning to earth and at unpredictable intervals demanding money in exchange for keeping the hostage alive.


This is a great read from Modern Treasury. One thing highlighted in this article that the industries not always talk about, is the concept of "Payment Ops". This is critical in FinServ organizations from my own experience. Any good and reliable payments infra is a function of technology, people, and process, and you need good tooling to streamline the whole workflow that involves engineering, finance, credit and compliance teams. Integrating with a payments API is only half of the definition of done.


One thing they don’t get into, but which becomes a significant pain, is what happens if history is wrong — for example, a policy is mis-entered and you need to adjust past financials. I architected precisely one insurance finance system, and trying to recall the data model and logic for overlapping timelines (what was, what should have been, what we thought it was...) still breaks my brain.


Stripe Connect makes all of this stuff veeeeery easy. No need to test up trust/FBO bank accounts/etc. for client money - just allocate money to accounts held in the name of the correct parties.

Source: built a fairly large insurance company with zero client money accounts by using Stripe Connect

Disclosure - we are locked into processing card payments with Stripe only, but have no incentive to say nice things about them


just to clarify the last part: but have no incentive to say nice things about them.

with this you mean you don't get money from them to promote them. Please correct me if I'm wrong.


It means no incentive of any kind - monetary or otherwise


I'm honestly surprised that Know Your Customer (KYC) and OFAC regulation aren't mentioned with respect to Claims. Besides solving for PCI complexity on the front end of payments, Stripe has a solution for both of these things issues on outward payments. Stripe is used by both Hippo, Lemonade and a few other more established insurance companies.


Why do you use integers to represent monetary values? It seems like $600 is represented as 60000. Or is that a typo?


CTO of Modern Treasury here, like the other replies said it's much safer to use integers so we can bypass all the complexity (and gotchas) of floating point.


Seems to me it would be even safer to represent it as an object: amount: { dollars: 60, cents: 00 }

or some such. In addition to being ready for foreign currencies, you can build in type safety to ensure that nobody does something meaningless like "60 dollars times 90 dollars", and prevents you from accidentally asking for $6,000 when you meant $60. It's less efficient, to be sure, and you have to implement all of those operations like "addition", but it's a case where being excruciatingly, provably correct seems more important than a few extra bucks on servers.


If you store integer amounts of the smallest currency subdivision, you're already ready for foreign currencies. You just need to specify how each currency converts from a representation like `$60` to an integer count like `6000`. This even accounts for non-decimal currencies (which basically aren't in modern use) - just set a conversion factor of 500 or 60 or whatever instead of 100.


Probably worth noting that in some cases the currency alone isn't enough information.

For example, gas stations using USD often use more than 2 digits of precision.

I suspect (and hope) that situation is reasonably rare, though.


They can’t bill that way though and this is a monetary transfer api

Just like how the complex algorithm of determining insurance rates is likely to yield a long decimal, it has to be rounded to translate to a currency. Heck even things like sales tax being a % requires a rounding calc to be done on majority of transactions before the monetary units are tallied for the “total”


That's a price, not a balance or amount transferred. Any sub-cent stuff is handled internally by the gas station, then rounded to the nearest cent and transferred to external banking APIs. The gas station is free to use whatever representation it wants for the price and quantity, so long as it rounds to the nearest cent before pushing to the API.


Sure, I probably should have specified that I meant in general when handling money, not necessarily specifically for handling payment API calls. I've worked on a system that kept track of arbitrary precision separately while using integers to store the values. Worked reasonably well, all things considered.

But you're right, we wouldn't have expected to be able to call something like stripe with that same arbitrary precision. It was all internal pricing.


Not every currency has a decimal amount. For example, there are no decimals in the Japanese yen.

Not to mention then you need to translate that for all the currencies, {pounds: 60, <whatever a decimal of a pound is>: 00 }


Yes, exactly. That's the advantage. You need to display pounds different from yen and dollars and bitcoins. It's good to have the code say, "Whoops, I was only expecting dollars and cents, and I'm not prepared for this thing you handed me" rather than accidentally displaying the wrong thing.

At the very least I'd want the currency marked. And once you're representing currency as a structure/object rather than a bare integer, you've got a lot more opportunities to ensure safety.


Or just use strings. That's what we do for basic webshop math - any naive attempt at doing eg a multiplication will break, requiring you to use the supplied math library (just like with objects...)

But: with strings you still have pass-by-value. So you can pass the values anywhere without worrying that whoever received the values will be modifying your object. And we still have the infinite range that integers can't give, which is especially useful when doing the multiplications for VAT and coupon codes etc..

The only remaining danger is that '+' works on strings, but we should notice those fast enough - it hasn't been a real issue yet.

(And if we need to start optimizing things at some point, I'd expect to have a better starting point when the data is already in a string than if we have to copy around objects all the time)


Using floats to store monetary data is considered 'a very bad idea' in the financial world. Mostly due to how floating point numbers are rounded up/down based on the precision.

https://stackoverflow.com/a/3730040/5536001


Across major payment processors and subscription management systems like Stripe and through most of the stack, integers are used to represent how much to charge in the smallest currency unit. [1]

With that said, it's better not to reinvent the wheel here and follow the flow, and it's also the safer option— it's better to charge a customer $10 when you meant to charge them $1000, than it is to charge them $1000 when you meant to charge them $10.

[1] https://stripe.com/docs/api/charges/object#charge_object-amo...


this isn't re-inventing the wheel. This is how money is safely represented because floating point math is inexact. You end up with cases where the transaction is off ±1¢ (at least)


Work in fintech, I second everyone else saying integers is the way to go.


Fixed-point vs floating-point arithmetic! In scientific applications, you want to preserve precision regardless of the system of units (i.e. scale). For example, 1.23 meters is 1.23e2 cm or 1.23e-3 km. The side effect of this is the roundoff error of arithmetic operations. Floating point operations are not commutative or associative.

In financial transactions on the other hand, we always need only 2 decimal places. So there is no benefit in using floating point.


Also in Fintech. In some cases it is actually necessary to have more than 2 decimal places.

For example, interest accrued daily, but only ‘compounded’ monthly. In those cases, it is necessary to maintain far more than the 2 decimal places for the daily accruals.

The best type to use here would be BigDecimal or equivalent. These ultimately serialise to infinite length strings.


Totally agree on the interest use case, that's exactly where precision beyond 2 decimal places is needed. For payments specifically it makes sense to keep it at 2 because all the payment systems in the US have that precision. When we do build support for ledgers we've considered a few approaches for how that might be serialized. For example we sometimes deal with MasterCard data that tags every amount with an exponent field so something like 1.2345 might be serialized as

  { "amount": 12345, "exponent": 4 }
We could do that or something like:

  { "amount": "1.2345" }


At Google Payments we tend to operate in micros. It makes it so we never have to worry about floats.

https://developers.google.com/standard-payments/reference/gl...


It's standard practice from my experience. Same with Stripe.


Dunno why you guys are so married with integers.. With even slightest increase of financial process complexity, only BigDecimal or such works. With explicit exceptions when math is done without predefined rounding rules and no catastrophes when some money orders start to come in 1/100 of previously relevant units


It's a pain in the butt, but I've realized integers are a good practice. Especially due with oddities of conversions and "maths" like Javascript perform.


Integer cents is certainly less of a pain in the butt than floating point dollars; I worked on an advertising project where I couldn't convince people to use integer cents, and the result was predictable madness where floating point values didn't line up.


Fixed precision decimal works as well and may (or may not) require less cognitive load. The nice thing (imho) about using decimal types in code is that since they're uncommon they act as a signal to treat things carefully.


By using integers they can avoid a person rounding off fractions of pennies and putting it into their own bank account.

Really, it’s about rounding and floating point math.


For the record, lemonade and hippo both use stripe.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: