flowon failureon cancelhotel_stay v1examples/hotel/temporal/hotel.flow · dandori doc
When a stay is booked, hold an amount on the card, and capture it on the day of check-out. A rule decides the amount and whether the front desk looks first; the payment is a Stripe PaymentIntent. Written for Temporal: the Stripe calls are activities dandori writes, and the Transport gives them the secret key; Stripe's webhook tells the workflow of the booking that the customer's 3-D Secure step is over, by the booking's id (an event); and a booking the guest cancels releases its hold (on cancel)
flowon failureon cancel| Line | Call | Calls | Retries | Timeout | When it fails | Case after |
|---|---|---|---|---|---|---|
| 75 | quote = hold(…) | rule hold_amount.rule | 2 times, after 1 second and 2 (failure) | — | timeout, failure → on failure | — |
| 78 | pi ← create_intent(…) | POST stripe /v1/payment_intents, starts payment_intent.payment then attach, key | 2 times every 2 seconds (failure, timeout) | — | timeout, failure → on failure | pi: requires_confirmation |
| 79 | pi ← confirm_intent(…) | POST stripe /v1/payment_intents/{intent}/confirm, sends confirm, key | — | — | card_declined → line 80unexpected_state, timeout, failure → on failure | pi: requires_payment_method, requires_action, requires_capture, canceled |
| 80 | pi ← get_intent(…) | GET stripe /v1/payment_intents/{intent}, observes, idempotent | 3 times every 2 seconds (failure, timeout) | — | timeout, failure → on failure | pi: requires_payment_method, requires_confirmation, requires_action, requires_capture, canceled |
| 83 | pi ← customer_authenticated() | event, observes | — | 1 hour | timeout → line 84failure → on failure | pi: requires_payment_method, requires_action, requires_capture, canceled |
| 84 | pi ← get_intent(…) | GET stripe /v1/payment_intents/{intent}, observes, idempotent | 3 times every 2 seconds (failure, timeout) | — | timeout, failure → on failure | pi: requires_payment_method, requires_action, requires_capture, canceled |
| 89 | pi ← cancel_intent(…) | POST stripe /v1/payment_intents/{intent}/cancel, sends cancel, key | — | — | unexpected_state → line 90timeout, failure → on failure | pi: canceled |
| 93 | pi ← capture_intent(…) | POST stripe /v1/payment_intents/{intent}/capture, sends capture, key | 2 times every 5 seconds (failure, timeout) | — | unexpected_state → line 94timeout, failure → on failure | pi: processing, succeeded |
| 100 | pi ← get_intent(…) | GET stripe /v1/payment_intents/{intent}, observes, idempotent | 3 times every 2 seconds (failure, timeout) | — | timeout, failure → on failure | pi: requires_payment_method, processing, succeeded |
| 112 | pi ← cancel_intent(…) | POST stripe /v1/payment_intents/{intent}/cancel, sends cancel, key | — | — | unexpected_state → line 113timeout, failure → line 114 | pi: canceled |
| 122 | pi ← cancel_intent(…) | POST stripe /v1/payment_intents/{intent}/cancel, sends cancel, key | — | — | unexpected_state → line 123timeout, failure → line 124 | pi: canceled |
| Line | End | pi |
|---|---|---|
| 77 | succeed outcome = awaiting_review | not started |
| 91 | fail CardDeclined "The card could not be held" | canceled |
| 92 | fail PaymentCanceled "The PaymentIntent was canceled" | canceled |
| 94 | fail HoldExpired "The hold had expired by check-out" | canceled |
| 96 | succeed outcome = stayed | succeeded |
| 105 | succeed outcome = stayed | succeeded |
| 106 | fail SettlementUnclear "The capture has no clear outcome; handing it over to staff" leaving pi | handed over as it is: requires_payment_method, processing, succeeded |
| 113 | fail CleanupFailed "Stripe refused to release the hold; the capture may have gone through. Handing it over to staff" leaving pi | handed over as it is: requires_payment_method, processing, succeeded, canceled |
| 114 | fail CleanupFailed "Releasing the hold failed; handing it over to staff" leaving pi | handed over as it is: requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded, canceled |
| 115 | fail SettlementUnclear "Failed in the middle of the capture; handing it over to staff" leaving pi | handed over as it is: requires_payment_method, processing, succeeded |
| 115 | on failure runs to its end, and the workflow fails with the error that started it | not started, or canceled |
| 123 | fail CleanupFailed "Stripe refused to release the hold; the capture may have gone through. Handing it over to staff" leaving pi | handed over as it is: requires_payment_method, processing, succeeded, canceled |
| 124 | fail CleanupFailed "Releasing the hold failed; handing it over to staff" leaving pi | handed over as it is: requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded, canceled |
| 125 | fail SettlementUnclear "Cancelled in the middle of the capture; handing it over to staff" leaving pi | handed over as it is: requires_payment_method, processing, succeeded |
| 125 | on cancel runs to its end, and the workflow ends cancelled | not started, or canceled |
Pick a step to see what the checker knows there. Pick a scenario on the left to light up the way its run goes; the number beside a step is how often the run passes it.
hotel_stay v1When a stay is booked, hold an amount on the card, and capture it on the day of check-out. A rule decides the amount and whether the front desk looks first; the payment is a Stripe PaymentIntent. Written for Temporal: the Stripe calls are activities dandori writes, and the Transport gives them the secret key; Stripe's webhook tells the workflow of the booking that the customer's 3-D Secure step is over, by the booking's id (an event); and a booking the guest cancels releases its hold (on cancel)
booking: Bookingoutcome: Outcomeexamples/hotel/temporal/hotel.flowquote = hold(…) line 75 75 let quote = hold(room: booking.room, nights: booking.nights)
pi: not startedhold_amount.ruletimeout, failure → on failure 4 use rule hold from "../rules/hold_amount.rule"
match quote.handling line 7676 match quote.handling 77 review => succeed outcome = awaiting_review 78 auto => pi <- create_intent(amount: quote.amount, currency: "jpy", payment_method: booking.card, capture_method: manual)
pi: not startedsucceed outcome = awaiting_review line 77 77 review => succeed outcome = awaiting_review
pi: not startedpi: not startedpi ← create_intent(…) line 78 78 auto => pi <- create_intent(amount: quote.amount, currency: "jpy", payment_method: booking.card, capture_method: manual)
pi: not startedPOST stripe /v1/payment_intents, starts payment_intent.payment then attach, keytimeout, failure → on failurepi: requires_confirmation27 task create_intent(amount: money[JPY, incl_tax] range >=50 <=99999999, currency: string, payment_method: string, capture_method: payment_intent.capture_method) -> PaymentIntent 28 http POST stripe "/v1/payment_intents" 29 starts payment_intent.payment then attach 30 key 31 retry 2 times every 2 seconds
pi ← confirm_intent(…) line 7979 pi <- confirm_intent(intent: pi.id) 80 on card_declined => pi <- get_intent(intent: pi.id)
pi: requires_confirmationPOST stripe /v1/payment_intents/{intent}/confirm, sends confirm, keycard_declined → line 80unexpected_state, timeout, failure → on failurepi: requires_payment_method, requires_action, requires_capture, canceled33 task confirm_intent(intent: string) -> PaymentIntent 34 http POST stripe "/v1/payment_intents/{intent}/confirm" 35 sends confirm 36 errors card_declined = 402, unexpected_state = 400 37 refused as unexpected_state 38 key
pi ← get_intent(…) line 80 80 on card_declined => pi <- get_intent(intent: pi.id)
pi: requires_payment_method, requires_confirmation, requires_action, requires_capture, canceledGET stripe /v1/payment_intents/{intent}, observes, idempotenttimeout, failure → on failurepi: requires_payment_method, requires_confirmation, requires_action, requires_capture, canceled55 task get_intent(intent: string) -> PaymentIntent 56 http GET stripe "/v1/payment_intents/{intent}" 57 observes 58 idempotent 59 retry 3 times every 2 seconds
match pi.status line 8181 match pi.status 82 requires_action => 85 requires_capture, requires_payment_method, requires_confirmation, canceled => pass
pi: requires_payment_method, requires_confirmation, requires_action, requires_capture, canceledpi ← customer_authenticated() line 8383 pi <- customer_authenticated() 84 on timeout => pi <- get_intent(intent: pi.id)
pi: requires_actionevent, observestimeout → line 84failure → on failurepi: requires_payment_method, requires_action, requires_capture, canceled61 # Stripe's webhook, handled by the shop, sends the PaymentIntent as it is now to the workflow of 62 # the booking once the customer's 3-D Secure step is over. 63 task customer_authenticated() -> PaymentIntent 64 event 65 observes 66 timeout 1 hour
pi ← get_intent(…) line 84 84 on timeout => pi <- get_intent(intent: pi.id)
pi: requires_actionGET stripe /v1/payment_intents/{intent}, observes, idempotenttimeout, failure → on failurepi: requires_payment_method, requires_action, requires_capture, canceled55 task get_intent(intent: string) -> PaymentIntent 56 http GET stripe "/v1/payment_intents/{intent}" 57 observes 58 idempotent 59 retry 3 times every 2 seconds
match pi.status line 8686 match pi.status 87 requires_capture => wait until booking.check_out 88 requires_payment_method, requires_confirmation, requires_action => 92 canceled => fail PaymentCanceled "The PaymentIntent was canceled"
pi: requires_payment_method, requires_confirmation, requires_action, requires_capture, canceledwait until booking.check_out line 87 87 requires_capture => wait until booking.check_out
pi: requires_capturepi ← cancel_intent(…) line 8989 pi <- cancel_intent(intent: pi.id) 90 on unexpected_state => pass
pi: requires_payment_method, requires_confirmation, requires_actionPOST stripe /v1/payment_intents/{intent}/cancel, sends cancel, keyunexpected_state → line 90timeout, failure → on failurepi: canceled48 task cancel_intent(intent: string) -> PaymentIntent 49 http POST stripe "/v1/payment_intents/{intent}/cancel" 50 sends cancel 51 errors unexpected_state = 400 52 refused as unexpected_state 53 key
fail CardDeclined line 91 91 fail CardDeclined "The card could not be held"
pi: canceledpi: canceledfail PaymentCanceled line 92 92 canceled => fail PaymentCanceled "The PaymentIntent was canceled"
pi: canceledpi: canceledpi ← capture_intent(…) line 9393 pi <- capture_intent(intent: pi.id) 94 on unexpected_state => fail HoldExpired "The hold had expired by check-out"
pi: requires_capturePOST stripe /v1/payment_intents/{intent}/capture, sends capture, keyunexpected_state → line 94timeout, failure → on failurepi: processing, succeeded40 task capture_intent(intent: string) -> PaymentIntent 41 http POST stripe "/v1/payment_intents/{intent}/capture" 42 sends capture 43 errors unexpected_state = 400 44 refused as unexpected_state 45 key 46 retry 2 times every 5 seconds
fail HoldExpired line 94 94 on unexpected_state => fail HoldExpired "The hold had expired by check-out"
pi: canceledpi: canceledmatch pi.status line 9595 match pi.status 96 succeeded => succeed outcome = stayed 97 processing =>
pi: processing, succeededsucceed outcome = stayed line 96 96 succeeded => succeed outcome = stayed
pi: succeededpi: succeededwait 1 hour line 99 99 wait 1 hour
pi: processingpi ← get_intent(…) line 100 100 pi <- get_intent(intent: pi.id)
pi: processingGET stripe /v1/payment_intents/{intent}, observes, idempotenttimeout, failure → on failurepi: requires_payment_method, processing, succeeded55 task get_intent(intent: string) -> PaymentIntent 56 http GET stripe "/v1/payment_intents/{intent}" 57 observes 58 idempotent 59 retry 3 times every 2 seconds
match pi.status line 101101 match pi.status 102 processing => pass 103 succeeded, requires_payment_method => break
pi: requires_payment_method, processing, succeededbreak line 103 103 succeeded, requires_payment_method => break
pi: requires_payment_method, succeededmatch pi.status line 104104 match pi.status 105 succeeded => succeed outcome = stayed 106 processing, requires_payment_method => fail SettlementUnclear "The capture has no clear outcome; handing it over to staff" leaving pi
pi: requires_payment_method, processing, succeededsucceed outcome = stayed line 105 105 succeeded => succeed outcome = stayed
pi: succeededpi: succeededfail SettlementUnclear line 106 106 processing, requires_payment_method => fail SettlementUnclear "The capture has no clear outcome; handing it over to staff" leaving pi
pi: requires_payment_method, processingpi: handed over as it is: requires_payment_method, processing, succeededend: succeedsThe flow runs to its end, and the workflow succeeds.
on failure line 108Runs when a call fails and nothing at the call handles the error. When it runs to its end, the workflow fails with that error. It comes here from the calls on lines 75, 78, 79, 80, 83, 84, 89, 93 and 100.
match pi.status line 109109 match pi.status 110 none => pass 111 requires_payment_method, requires_confirmation, requires_action, requires_capture => 115 processing => fail SettlementUnclear "Failed in the middle of the capture; handing it over to staff" leaving pi
pi: not started, or requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded, canceledpi ← cancel_intent(…) line 112112 pi <- cancel_intent(intent: pi.id) 113 on unexpected_state => fail CleanupFailed "Stripe refused to release the hold; the capture may have gone through. Handing it over to staff" leaving pi 114 on failure => fail CleanupFailed "Releasing the hold failed; handing it over to staff" leaving pi
pi: requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded, canceledPOST stripe /v1/payment_intents/{intent}/cancel, sends cancel, keyunexpected_state → line 113timeout, failure → line 114pi: canceled48 task cancel_intent(intent: string) -> PaymentIntent 49 http POST stripe "/v1/payment_intents/{intent}/cancel" 50 sends cancel 51 errors unexpected_state = 400 52 refused as unexpected_state 53 key
fail CleanupFailed line 113 113 on unexpected_state => fail CleanupFailed "Stripe refused to release the hold; the capture may have gone through. Handing it over to staff" leaving pi
pi: processing, succeeded, canceledpi: handed over as it is: requires_payment_method, processing, succeeded, canceledfail CleanupFailed line 114 114 on failure => fail CleanupFailed "Releasing the hold failed; handing it over to staff" leaving pi
pi: requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded, canceledpi: handed over as it is: requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded, canceledfail SettlementUnclear line 115 115 processing => fail SettlementUnclear "Failed in the middle of the capture; handing it over to staff" leaving pi
pi: processingpi: handed over as it is: requires_payment_method, processing, succeededfails with the same erroron failure runs to its end, and the workflow fails with the error that started it.
pi: not started, or canceledon cancel line 118Runs when the workflow is cancelled, from the call or the wait the run is at. When it runs to its end, the workflow ends cancelled.
match pi.status line 119119 match pi.status 120 none => pass 121 requires_payment_method, requires_confirmation, requires_action, requires_capture => 125 processing => fail SettlementUnclear "Cancelled in the middle of the capture; handing it over to staff" leaving pi
pi: not started, or requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded, canceledpi ← cancel_intent(…) line 122122 pi <- cancel_intent(intent: pi.id) 123 on unexpected_state => fail CleanupFailed "Stripe refused to release the hold; the capture may have gone through. Handing it over to staff" leaving pi 124 on failure => fail CleanupFailed "Releasing the hold failed; handing it over to staff" leaving pi
pi: requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded, canceledPOST stripe /v1/payment_intents/{intent}/cancel, sends cancel, keyunexpected_state → line 123timeout, failure → line 124pi: canceled48 task cancel_intent(intent: string) -> PaymentIntent 49 http POST stripe "/v1/payment_intents/{intent}/cancel" 50 sends cancel 51 errors unexpected_state = 400 52 refused as unexpected_state 53 key
fail CleanupFailed line 123 123 on unexpected_state => fail CleanupFailed "Stripe refused to release the hold; the capture may have gone through. Handing it over to staff" leaving pi
pi: processing, succeeded, canceledpi: handed over as it is: requires_payment_method, processing, succeeded, canceledfail CleanupFailed line 124 124 on failure => fail CleanupFailed "Releasing the hold failed; handing it over to staff" leaving pi
pi: requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded, canceledpi: handed over as it is: requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded, canceledfail SettlementUnclear line 125 125 processing => fail SettlementUnclear "Cancelled in the middle of the capture; handing it over to staff" leaving pi
pi: processingpi: handed over as it is: requires_payment_method, processing, succeededends cancelledon cancel runs to its end, and the workflow ends cancelled.
pi: not started, or canceledrepeat at most 12 times line 98 98 repeat at most 12 times
pi: processingquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: canceledmatch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → canceledfail PaymentCanceledquote = hold(…) failure failure failure → not handled hereon failurematch pi.status → nonequote = hold(…) okquote = hold(…) okquote = hold(…) cancelon cancelmatch pi.status → nonequote = hold(…) okmatch quote.handling → reviewsucceed outcome = awaiting_reviewquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure failure failure → not handled hereon failurematch pi.status → nonequote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() ok: requires_actionmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) ok: canceledfail CardDeclinedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_payment_methodquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) cancelon cancelmatch pi.status → nonequote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() ok: requires_payment_methodmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) unexpected_state → on unexpected_statefail CardDeclinedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_payment_methodmatch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) failure → not handled hereon failurematch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) ok: canceledquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) ok: succeededmatch pi.status → succeededsucceed outcome = stayedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) card_declined → on card_declinedpi ← get_intent(…) ok: requires_confirmationmatch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) ok: requires_payment_methodquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) failure → not handled hereon failurematch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) unexpected_state → on unexpected_statefail CleanupFailedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_confirmationquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) ok: canceledquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_payment_methodmatch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) ok: processingmatch pi.status → processingrepeat at most 12 timeswait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) ok: processingmatch pi.status → processingmatch pi.status → processing, requires_payment_methodfail SettlementUnclearquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) card_declined → on card_declinedpi ← get_intent(…) failure failure failure failure → not handled hereon failurematch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) failure → on failurefail CleanupFailedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) failure → not handled hereon failurematch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) ok: requires_payment_methodquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) unexpected_state → on unexpected_statefail CleanupFailedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() ok: requires_payment_methodmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) failure → on failurefail CleanupFailedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() ok: requires_capturematch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) unexpected_state → on unexpected_statefail HoldExpiredquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() ok: canceledmatch pi.status → canceledfail PaymentCanceledquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() timeout → on timeoutpi ← get_intent(…) ok: requires_actionmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) failure → on failurefail CleanupFailedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() failure → not handled hereon failurematch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) ok: requires_payment_methodquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() ok: requires_confirmationquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) ok: requires_payment_methodquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() ok: requires_actionmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) unexpected_state → on unexpected_statefail CardDeclinedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() ok: requires_actionmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) failure → not handled hereon failurematch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() ok: requires_actionmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() ok: requires_capturematch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) unexpected_state → on unexpected_statefail HoldExpiredquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() timeout → on timeoutpi ← get_intent(…) ok: requires_payment_methodmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) unexpected_state → on unexpected_statefail CardDeclinedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() failure → not handled hereon failurematch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) ok: canceledquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) unexpected_state → on unexpected_statefail CleanupFailedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) ok: processingmatch pi.status → processingrepeat at most 12 timeswait 1 hourpi ← get_intent(…) ok: succeededmatch pi.status → succeeded, requires_payment_methodbreakmatch pi.status → succeededsucceed outcome = stayedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) failure failure failure → not handled hereon failurematch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) unexpected_state → on unexpected_statefail CleanupFailedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) failure ok: succeededmatch pi.status → succeededsucceed outcome = stayedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) ok: requires_payment_methodquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) card_declined → on card_declinedpi ← get_intent(…) failure ok: requires_confirmationmatch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) failure → not handled hereon failurematch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) ok: requires_payment_methodquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) card_declined → on card_declinedpi ← get_intent(…) ok: processingquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) card_declined → on card_declinedpi ← get_intent(…) okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) ok: requires_confirmationpi ← confirm_intent(…) card_declined → on card_declinedpi ← get_intent(…) cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) ok: canceledquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) ok: processingmatch pi.status → processingrepeat at most 12 timeswait 1 hourpi ← get_intent(…) ok: requires_payment_methodmatch pi.status → succeeded, requires_payment_methodbreakmatch pi.status → processing, requires_payment_methodfail SettlementUnclearquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) ok: processingmatch pi.status → processingrepeat at most 12 timeswait 1 hourpi ← get_intent(…) failure failure failure failure → not handled hereon failurematch pi.status → processingfail SettlementUnclearquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) ok: processingmatch pi.status → processingrepeat at most 12 timeswait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingwait 1 hourpi ← get_intent(…) failure ok: processingmatch pi.status → processingmatch pi.status → processing, requires_payment_methodfail SettlementUnclearquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) ok: processingmatch pi.status → processingrepeat at most 12 timeswait 1 hourpi ← get_intent(…) ok: requires_confirmationquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) ok: processingmatch pi.status → processingrepeat at most 12 timeswait 1 hourpi ← get_intent(…) okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_capturematch pi.status → requires_capture, requires_payment_method, requires_confirmation, canceledmatch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) ok: processingmatch pi.status → processingrepeat at most 12 timeswait 1 hourpi ← get_intent(…) cancelon cancelmatch pi.status → processingfail SettlementUnclearquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() timeout → on timeoutpi ← get_intent(…) ok: requires_capturematch pi.status → requires_capturewait until booking.check_outpi ← capture_intent(…) failure failure failure → not handled hereon failurematch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) unexpected_state → on unexpected_statefail CleanupFailedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() timeout → on timeoutpi ← get_intent(…) ok: canceledmatch pi.status → canceledfail PaymentCanceledquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() timeout → on timeoutpi ← get_intent(…) failure failure failure failure → not handled hereon failurematch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) failure → on failurefail CleanupFailedquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() timeout → on timeoutpi ← get_intent(…) failure ok: requires_actionmatch pi.status → requires_payment_method, requires_confirmation, requires_actionpi ← cancel_intent(…) cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() timeout → on timeoutpi ← get_intent(…) ok: requires_confirmationquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() timeout → on timeoutpi ← get_intent(…) okquote = hold(…) okmatch quote.handling → autopi ← create_intent(…) failure ok: requires_confirmationpi ← confirm_intent(…) ok: requires_actionmatch pi.status → requires_actionpi ← customer_authenticated() timeout → on timeoutpi ← get_intent(…) cancelon cancelmatch pi.status → requires_payment_method, requires_confirmation, requires_action, requires_capturepi ← cancel_intent(…) unexpected_state → on unexpected_statefail CleanupFailed