⭐ Comparing our old user API to new user API

Yes, this (and the shopify option) is only suggested as a short-term alternative to building the membership processing described in the user-membership api requirements (as per our rulebook, and current process in wordpress)… just looking at the ‘landscape’ of possible solutions out there to see if there’s anything we might have missed or could learn from.

Adapting a ‘commodity’ membership process that works for others seems a good option to me, even if that plugin isn’t the one. There are lots of possible solutions out there that would seen to match this pattern, especially from Stripe, and perhaps also from Xero. Take a look at this discussion about using the fuller functions of the Stripe API, for example, which includes products, plans, subscriptions and invoices, in this case for an API billing scenario:

In this way we might use this ‘richer’ stripe functionality to do a lot more for us.

image

In the model above, stripe plans (and products) could be used to implement membership classes and all the user membership and share transaction information could be implemented in additional metadata associated with stripe subscriptions.

We use Stripe today as a generic payment for top-ups, and then again via a wordpress /gravity forms / ultimate member solution for memberships. We haven’t used it to implement important things like recurring top-ups or membership renewals. The pattern above would help us to do that, and the flexibility of the ‘plan and product’ objects. It might easier for the Resonate platform to introduce (simple) new products and services by configuration… on a no code / low code basis.

Is it expensive? …only in the longer term.
Does it lock us in to Stripe? …only in the short term… it’s a solid pattern that buys us some time to do something more ‘provider-agnostic’

1 Like

Resonate Stripe API - Existing

Yes, we already have stripe feeds implemented in our Xero, but the implementation appears ‘dumb’ at the Stripe end as ‘Stripe Income’ - you have to infer what the payment is for manually by looking at / decoding the payment intent… not a viable effort at scale, and also fails to account properly for failed payments and of course payments via bank, or Wise, for example.

Resonate Stripe API in Development

@auggod has done a great job in refactoring the (existing PHP) stripe API for the tracks API v2, using the ORDERS table:

https://github.com/resonatecoop/tracks-api/blob/main/src/user/payment/api-doc.js
https://github.com/resonatecoop/tracks-api/tree/main/src/user/payment

…so depending on the data passed from that to Stripe, it may improve the intelligibility of the Stripe Data when it comes back in via the Xero accounting feed. There’s a ‘product’ attribute in the payment intent API which in @auggod 's tracks-api code can be set to “credits” (for credit top ups) or to “membership” presumably intended for future re-use for membership payments?

Stripe API futures

Using the Stripe SAAS API’s more fully might bring the additional benefit of a ‘richer’ Stripe to Xero integration feed, where income (streaming credits and subscriptions), currency conversions and tax (particularly VAT) and membership share purchases (these are not ‘income’) are correctly accounted for - automatically. There’s a lot of work involved in doing this correctly at the Resonate end. which is why a proper accounting component, or fuller use of an SAAS service can be attractive.

Xero

However, rather than use the Stripe API directly, I think we should at least consider a short-term use of Xero as a ‘white label’ to create Resonate ‘invoices’ and handle all the associated statement, payments and accounting for us. We could then have Stripe and add a choice of other (cheaper) payment services, especially bank payment, direct debit recurring payments, apple pay (Xero would handle the API’s for and customer payment portal for all these for us). Maybe this is simplistic - it is a small business solution, not intended as an e-commerce solution at scale - but it could be a stepping stone?

Interestingly, In 2017-18 Resonate was invoicing from Xero (presumably for crowdfunding / membership campaigns) - it already has invoices set up, which at that time automatically posted to Stripe or Paypal income, depending on the payment method used to settle them.

Here’s the API:

https://developer.xero.com/documentation/api/accounting/invoices/#overview

…and here is a Golang SDK with examples:

Here’s a little more investigation of the SAAS options:

Understood. I would note that half of this is “where their contributions have landed”, which is more around the narrative of where the money is being spent, rather than the accounting per se, but point taken.

I would say though that the minimal version of this would be achievable by just storing a couple of foreign keys for that user, rather than modelling the data ourselves.

Using the relevant stripe package (e.g. the npm package for the nodejs based id app), we’d just need the customer id and product id in order to pull their subscription data from the stripe api to display on the relevant profile view.

This is how the Discourse Subscriptions Plugin works. That plugin doesn’t store the product, plan, subscription and invoice data locally, it just stores a few foreign keys, and then when each relevant view is loaded it pulls their data directly from stripe using those keys. It uses stripe itself as a database and model. The easiest way to see this is in the db migrations used to set up the tables the plugin uses

This approach is less performant than storing the data locally, but works fine for light to medium use, which would cover us.

As you say, our initial approach will assume the use of Stripe, however I think we can be even more minimal, by allowing pretty much all the data modelling to be handled by Stripe itself.

(will follow up regarding accounting a bit later in the week)

Have a look at the deck, option 2b. I’m proposing we allow pretty much all the data modelling to be done in Xero, not Stripe. There’s even less to model (we make a ‘contact’ and the invoice references to the ‘products’ the user has selected). We’d use our Stripe account indirectly, with a payment button on the Xero-rendered invoice. Everything would automatically reconcile into the correct revenue / equity accounts.

The Golang API example app looks interesting, but presumably we’d have to refactor this to fit in with * GRPC-Gateway and OpenAPIV2 workflow? So maybe instead we should use the GitHub - XeroAPI/xero-node: Xero Node SDK for OAuth 2.0 generated from XeroAPI/Xero-OpenAPI SDK?

Isn’t this more steps? If I want to “top up” now, I tap a button and enter my payment info into a stripe-powered form. What happens after is irrelevant to me as a user.

The Xero version would be to pick my selections, view an invoice, tap another button, then pay the invoice.

Perhaps this is better for accounting reasons but it does seem to add another layer of friction to the user?

No, we still have to show some form of ‘here’s what you need to pay’ page. We could form the Xero URL and then use the standard rendering for something we would otherwise have had to build. I’m not sure about the return URL though. Xero also handles the item pricing, different currencies and conversion rates as well as the mapping to the correct account. Also you have all the manual reversals / credit functions available to you that you would expect in any sales/service order processing system.

OK, I guess I don’t understand the issue enough to opine, since it seems like all the benefits an end-user or investor would want (being able to view a list of transactions, recurring subscriptions, CC management) are possible with Stripe, and having an “invoice step” - to me - would give me pause.

I would of course like to see either an invoice, list of transactions, or some sort of confirmation email that I purchased something, but this seems more of “why are there no automated emails” / “what’s going on with the reporting API” discussion.

Right now I do have a “this is how much you have to pay” in which I pick the level of top-up, before I enter my credit card.

1 Like

Yes, you’re right, for top-ups it’s pretty clear what is selected, but there still needs to be some sort of final adding up and totalling, especially if the user is buying a membership share, an annual membership renewal fee, a supporter share and maybe even a donation. At the moment Stripe is invoked in different messy ways (for example, for membership signup via a wordpress form, gravity forms, ultimate member and then stripe…and there are separate custom forms for each of these …each constituting an order/invoice for a product.

In the end, I guess an invoice is just a product offered to someone, with a price, taxes and conditions… and it becomes a contract, with obligations on both sides.

All this sales order processing payments and accounting stuff is pretty standard, and right now I’d be happy to take a lot of it “out of the box”, and be consistent in the way we did it, even it initially the default is perhaps a bit ugly, until we can refine it, and build our own screens that customise more, using the rich API’s available.

Xero have API equivalents for being able to view a list of transactions, recurring subscriptions, CC management) too, without the lock-in to Stripe, which has pretty high fees… this gives us more choice of payments provider without a lot of dev work to do.

I’d rather spend our dev time and resources on a cool player and the playlisting and search API’s that will make us look great. I’d also like to get out of the back office nightmare we live in now!

My biggest concern here is privacy… I’d want to minimise the amount of customer / product information we share with these SAAS services. I think in future, with Community Credentials we may be able to securely package user information and expose far less data to these hungry platforms than they would like us to.

Edit: @boopboop @angus

Revisiting this to focus more on the short term. For the co-op right now it is more important to be ready as soon as possible to collect new memberships and renewals asap, with lowest technical risk, never mind about accounting for them. Let’s use the Stripe API we know, and not do an ambitious Payment and Accounting SAAS at this stage.

There are a couple of options on how to do that. One of them involves quite a lot of work in building our ‘checkout’ , with the advantage of better control over the UX flows. The other uses some Stripe SaaS services which reduce the dev effort but do involve a handoff to a Stripe SAAS checkout. In the short term we’ll have to rely on giving worker access to ‘default’ stripe dashboard services to support and account for payments. We would have to allow some Dev time to help with admin and membership queries. We also need to think about extracts for mailshot campaigns to promote renewals.

Where we are now:

Today, Resonate suffers from ‘Dumb’ / manual account mapping and the task of reconciling thousands of individual income transactions - labelled ‘Stripe Income’ or similar with unfriendly ‘Payment Intent’ codes.
To manage membership, there are potentially insecure extracts of membership data to spreadsheets and tedious reconciliation with the payments and accounting treatment of the income / share issues. Non-stripe income from bank payment has much lower transaction fees but involves tedious manual reconciliation.

The user experience in the current WordPress is disjointed and broken - forms are not rendering history of shares and payments in a recognisable ‘statement’. Occasional payment failures are difficult to trace and rectify, and system administrator privileges and valuable developer time is consumed in creating extracts / debugging.

Exchange rates (and VAT rates) are hard coded and are incorrect / out of date. We do not systematically track location / country of income in the accounting.

Payment and Accounting for Short Term - Relaunch

Short Term Option 1


In this short-term option, we extract the previous year’s (ie only the current) memberships and put them in a temporary membership table. We create a new version of the checkout we used to have on WordPress. We continue to make very simple use of the stripe payment intent API, as we have today, for the credit top ups, but we add metadata to record in the PI ‘what this payment was for’ - to make reconciling the Stripe payment extracts easier later on. (still manual). There is quite a lot of checkout and pricing code to write, test and secure if we are adding all the memberships. For more discussion on this and pro’s and con’s see the deck, slide 5.

Short Term Option 2


This short term option makes use of the Stripe api (user, product. prices and the checkout) and also uses of a Stripe-hosted checkout page. Pricing and tax (and promotions, discounts etc) are all handled by Stripe. This reduces the amount of code we ahve to write, test, host and secure.
As a by-product, it also makes the stripe extract data better for reconciliation and makes it easier for workers using the Stripe dashboard to find what they need to fix problems in one place. It’s true there is a UX hand-off after the order ‘preview’ but the Stripe pre-built checkout page is widely used and is familiar to consumers, and can be branded/styled/customised.
How would we handle conversion and migration of existing memberships for a ‘renew now’ campaign? We could upload legacy membership details (only the current ones) to the orders and accompanying user tables on Stripe.
See the deck, slide 6.

Mid Term Option

There is a possible mid-term solution that would allow us to bill and account for all our credit top-ups, membership and supporter share products and would be a Xero-specific simplification of @auggod’s stripe api code. It involve the creation of a contact in the Xero SAAS corresponding to a Resonate user, then the creation of an invoice for the products they have ordered (products and pricing all in prior set-up in Xero). We’d use our Stripe account via Xero to make more sense of the payments.
It could provide a wider choice of payment methods for the user, including bank payments and recurring renewals.

However, this SAAS solution is not suitable for a fix to native Resonate credits accounting - no credit transfers yet. Nor does it provide any local ‘cacheing’ of all the data held in the SAAS.

See https://developer.xero.com/documentation/guides/how-to-guides/how-to-integrate-my-pos-system-with-xero/#overview

These API’s are new to us (=risk) and would need some research and investigation. See the deck, slide 7.

Payment and Accounting API Roadmap (post-relaunch)

See the deck, slide 8.

After settling in with the relaunch solution we would evolve a longer term, fuller solution. In addition to handling credit top-ups, membership and supporter share products it would feature a ‘future-proofed’ non-SAAS-specific API gateway. (Such an API gateway could also be a connection point to other coop back end accounting systems, making it easy for them to sell our products on their systems.) It provides better handling of listening credit accounting, including transfers and donations. The user account would be presented from API responses from the SAAS with some ‘cacheing’ and more ‘custom’ rendering to improve on the default SAAS payment model.

1 Like

Can you put me in touch with these Supporters?

@hakanto has already handled the specific queries that came in members correspondence. I checked share details from the spreadsheet. There’s a thread on basecamp I think.

1 Like

@angus @boopboop see update to post above. N

Can Stripe/Resonate support currency localization?

Yes. https://stripe.com/docs/currencies

Our products are ‘priced’ in € (presentment currency) and our settlement currency is €. Customer credit cards may be in different currencies, and in that case the customer will be charged the fx conversion fee by their cc provider.

We could arrange to ‘present’ in different currencies for users in different locations (check?) and also add settlement accounts in those currencies so that we avoided Stripe fx charges at our end.

I would recommend the co-op sets up a Wise account (if it does not have one already @peter ?) and then we could collect easily in multiple currencies and accept bank transfer income into the same account(s)

@zetto.plus recommended this. Also, location is often relevant to content licenses.

Would the check be from the user (cc bank or billing address)? Do devices or routers provide national level location?

Resonate has one. Though we need to register our @directors members for it to be operable.

I wouldn’t bother with the check other than what is declared by the user in the flow. Anyone really determined will use a VPN and if so they are probably using that for good anti-surveillance reasons anyway.

Looked into the stripe docs as well… does seem to be all about having an account in the local currency, which in this case means WISE. Yay. More identity tedium for the board. Although this seems inevitable because we’ll need local currencies to operate at scale.

My suggestion is that we don’t do any of this until we have liability insurance for the board. Too great a risk in case we miss some obscure clause that makes us personally liable in some extreme case.

1 Like

I’m pressing to get a quote ASAP.