openactive / open-booking-api

Repository for the Open Booking API specification
Other
2 stars 3 forks source link

Reduce number of calls for critical path #66

Closed nickevansuk closed 4 years ago

nickevansuk commented 6 years ago

Source

Netpulse

Feedback

While booking a class, right now we have to do several API calls: a) When no purchase needed for the booking: create order -> add class to order -> get order -> complete order b) When purchase is needed: create order -> add class to order -> get order -> add payment -> complete order (not supported by Netpulse standard API flows)

It would be great if we could do the above mentioned in just one API call at least for the case a). Since our app allows users to book a class in just one click, the more API calls involved, the longer user is waiting for a booking result (and also there might be unexpected errors that break the whole API requests chain).

peter-dolkens commented 6 years ago

I think there needs to be two approaches to the Booking API spec.

I think the booking spec should be able to indicate which of these flows are available, as not all systems will support the more complex multi-purchase flow, or have the ability to reserve capacity until completion.

I don't think it would be too hard to create aliases in implementations that support the multi-purchase flow, to also support the single-purchase flow.

The multi-purchase flow would then become used only by the more advanced systems.

nickevansuk commented 6 years ago

Totally agree with this, and bringing in feedback from a review of Google Reserve, please see the following proposal which effortlessly satisfies these additional constraints, by using a create+pay flow for all use-cases, with an optional check/create+pay for multi-purchases:

Revisiting the function and importance of the "lease"

Revisiting the Problem Statement

Because both payment and booking must succeed, a two-phase commit is required on at least one side to avoided unnecessary reverting transactions. Specifically, given that the "confirmation" of either side is likely to trigger emails to the user, we prefer "reserve+commit" to "commit+revert" approach, as the former allows error cases to be handled without needing to send "cancellation" emails.

Solution Options

Two approaches in common use, which represent the two-phase commit happening on either the booking system or payment provider side, respectively.

A) Two-step booking

1) Lease Order 2) Capture Payment 3) Book Order

B) Two-step payment

1) Auth Payment 2) Book Order 3) Capture Payment

The current spec uses (A), this proposal suggests (B) as a simpler approach.

Solution Proposal

Given that all major payment providers already support (B) (and indeed according to CardStream p. 108 this is the more common approach), we can simplify implementation for the many OpenActive booking systems by leveraging this.

This changes our flow from: 1) Create Order, lease OrderItems and receive totalPaymentDue 2) Capture Payment 3) Complete order with Payment taken

And instead becomes: 1) Booking System: Check Order (see https://github.com/openactive/open-booking-api/issues/87), and return totalPaymentDue (can be done without including customer details, and may not be needed if the feed contents is reliable) 2) Payment Provider: Authorize totalPaymentDue amount 3) Booking System: Create Order request including Authorised Amount and customer details, book OrderItems, return totalPaymentDue (if less than Authorised Amount, otherwise error) 4) Payment Provider: Capture Payment for totalPaymentDue

Note that in the unlikely event that the amount that the user is expecting to pay increases from what they have seen at the "Check Order Availability" stage of booking, the user needs to be notified of the new price and the payment reconfirmed anyway, and the error potentially returned from step (3) above fits with this - so there is not a case where this new flow limits any desired behaviour.

Such a simplification also reduces the number of calls on the critical path to an absolute minimum. If the broker is already confident in the price (from the Opportunity API, or directly from the open feed), they can simply authorise that amount with the payment provider, and skip step 1 - hence the minimal case here requires just a single API call.

The other advantage of this is that it doesn't require any type of lease state on the booking system side, which simplifies the simple implementation case.

Additionally, for future "shopping basket" usecases, as a user adds items to their basket, a single call can be made to check order availability for the basket each time the basket is updated, so the user can be notified if anything within the basket is no longer available. This proposal is effectively scrapping the idea of incrementally adding items to an order before paying it, and instead add all items at the point of order creation. This also makes an order immutable during the booking process, and reserves mutability for post-order-completion item cancellation.

Finally for the most critical error case - interruption before final commit ("paid but not booked" in the existing spec) - this new proposal's equivalent ("authed and booked but not captured") can be easily monitored for MVP scenarios using the payment providers own tooling (e.g. in Stripe the report https://dashboard.stripe.com/payments?captured=false returns all authed-not-captured charges), and the error can be recovered easily by simply capturing the payment manually via the Stripe dashboard within 7 days.

Another advantage is that for free bookings, step (3) can be used in isolation, creating the simplest possible flow.

nickevansuk commented 4 years ago

The calls required to complete any booking have been rationalised to just three for all cases: C1, C2 and B. The reason that C2 and B alone are not sufficient is due to the potential for explicit consent being required before the customer's details can be provided to C2.

They are best summarised as: