Uh oh! We couldn’t find any match.

Please try other search keywords.

Bixby Developer Center

Guides

Transactional Workflows

At the heart of transactions within Bixby is the ability of an action to have external side effects, such as adding a product to an order, canceling an order, and finalizing an order.

There are three possible phases in a transactional workflow:

  1. The Transaction phase, where the user can do things like prepare a cart by adding, removing, and updating items.
  2. The Commit phase, where the user confirms the transaction, and Bixby completes the transaction like placing an order or confirming a reservation.
  3. The Activity phase, where the user can do things like interact with the order after it has been committed. For example, users can check their order status or cancel a dinner reservation.

Note that it is not necessary for a transaction to have all three phases to be considered a transaction. You can read an example of a transaction with only a Transaction and Commit phase in the Simple One-Step Transactional Sample Capsule.

When you want to include transactions as part of your capsule, you must tag your actions with appropriate action types and ensure that the related concepts include appropriate concept features. Additionally, you need to add the appropriate *-support files to your capsule, to handle the various states of the transaction.

Let's talk about each of these phases and how to implement a transaction using a simple shirt ordering capsule. You can download the full capsule to view all the files. You can also read the full walkthrough of the shirt capsule in the Basic Cart Transactional Sample Capsule.

This figure shows the actions that make up a transactional workflow for the shirt ordering capsule:

<center shirt order diagram

(Select the image to view a large version)

Here, the user starts the transaction in only one way through CreateOrder, which initializes the Transaction phase. From here, the user can change the size of the shirt through ChangeSize, which updates the transaction state. This UpdateTransaction object remains available until the transaction is concluded. The user must either commit or cancel the order through CommitOrder or CancelOrder, which are of type Commit and CancelTransaction, respectively. Finally, the user can use CheckStatus to check on the status of the shirt order during the Activity phase.

Action Types

When modeling actions, you must include an action type, as shown in the diagram above. Bixby has specific action types that you can use when there is a transaction state being held externally. Bixby doesn't hold state internally and you need special UX to let the user know how to deal with the external state.

The types are grouped by whether they happen pre, during, or post the Commit.

Before Commit Action Types

These are all action types that happen before a Commit happens, which are typically during the transaction phase. The models that use transaction action types should have a corresponding transaction-support model defined in a *.transaction.bxb file. The transaction-support information is primarily used to display the status bar and to handle any situation in which the user quits the transaction before committing. For more information, see Transaction and Activity States.

BeginTransaction

Let's start from the beginning with BeginTransaction, which is the action type that denotes the beginning of a transaction.

In the case of the shirt capsule, you want to start the order process with a shirt type and size:

action (CreateOrder) {
type (BeginTransaction)
collect {
input (items) {
type (Item)
min (Required)
max (Many)
default-init {
intent {
goal: CreateItem
value: SearchTerm("")
}
}
}
}
output (Order)
}
UpdateTransaction

Once a transactional flow has begun, use the UpdateTransaction action type to modify it.

If users want to change their shirt size for example, this action is triggered:

action (UpdateOrder) {
type (UpdateTransaction)
collect {
//the order that is updated
input (order) {
type (Order)
min (Required)
}
input-group (updates){
requires (OneOrMoreOf)
collect {
input (addedItems) {
type (AddedItem)
min (Optional)
max (Many)
}
input (changedItems) {
type (ChangedItem)
min (Optional)
max (Many)
}
input (removedItems) {
type (RemovedItem)
min (Optional)
max (Many)
}
}
}
}
//returns the updated order
output (Order) {
throws {
error(NoItems) {
on-catch {
halt {
dialog {
template-macro (NoItemsInCart)
}
}
}
}
}
}
}
CancelTransaction

If the user reconsiders and cancels the shirt order before completing the transaction, you can mark the termination of a transaction using CancelTransaction.

action (CancelOrder) {
type (CancelTransaction)
collect {
input (order) {
type (Order)
min (Required)
}
}
output (Receipt)
}

Commit Action Types

Notice that there is only one type of Commit action type.

Commit

If the user is happy with the shirt and completes the order, you can use Commit to mark the successful completion of the transaction. This action type accepts a transaction value and normally returns a receipt:

action (CommitOrder) {
type (Commit)
collect {
input (order) {
type (Order)
min (Required)
}
}
confirmed-by (core.Confirmation) {
mode (Transactional)
confirm-label {
template ("Pay[ #{value(order.totalPrice)}]")
}
expire-after (order.holdTime)
expiration-text {
template ("You ran out of time on that order, but we remember your choices.")
}
retry-intent {
goal: CommitOrder
subplan {
goal: CreateOrder
value: $expr(order.items)
}
}
}

output (Receipt)
}

After Commit Action Types

These are all the action types for after a user has committed, which typically happen during the Activity phase.

Activities are all events and interactions with the user that happen after a commit has occurred. You must create an activity when defining a concept you need to track after a Commit occurs. For the shirt example, you see this when the user wants to track a shirt order. All Activity concepts must have a corresponding activity-support model defined in an *.activity.bxb file. This file displays information depending on the current state of the activity and are not necessarily defined by your defined state of the Activity. For more information, see Transaction and Activity States.

RefreshActivity

After the transaction is complete, you can continue to refresh the activity value by checking on the external system. For the shirt ordering example, the user has the option of checking on an existing shirt order. For more information on refreshing, see Refreshing Your Content.

action (CheckStatus) {
type (RefreshActivity)
collect {
input (receipt) {
type (Receipt)
min (Required)
default-init {
intent {
goal: FindLastReceipt
}
}
}
}
output (Receipt)
}
CancelActivity

Finally, if the user decides to cancel the transaction after it is complete, you can use CancelActivity. Your capsule then ceases to track activity values after they have been canceled.

action (CancelCommittedOrder) {
type (CancelActivity)
confirmed-by (core.Confirmation) {
mode (PositiveEmphasis)
on-abort {
intent { //The intent to execute when user aborts the confirmation
goal {CheckStatus}
}
}
confirm-label {
if (exists(receipt)) {
template ("Cancel Order}")
}
}

abort-label {
template ("Keep it")
}
}
collect {
input(receipt){
type(Receipt)
min (Optional)

default-init {
intent {
goal: FindLastReceipt
}
}

validate {
if (!exists(receipt)) {
halt {
dialog {
template("Not sure what to cancel. I didn't find any recent shirt orders.")
}
}
}
if (receipt.orderState != 'Ordered') {
halt {
dialog{
template("This order is already ${value (receipt.orderState)}!")
}
}
}
}
}
}

output(Receipt)
}

Concept Features

For structure and structure-enum concepts, you need to tag them with the corresponding transaction or activity features.

For example, in the shirt ordering example, the following structure representing an order includes a features key indicating that this concept should be tracked as part of an ongoing transaction:

structure (Order) {
property (shirt) {
type (Shirt)
min (Required)
}
property (size) {
type (Size)
min (Required)
}
property (holdTime) {
type (HoldTime)
min (Required)
}
features {transaction}
}

On the other side of the transaction, the shirt ordering example provides a receipt, which needs to be tagged as an activity, since it is used after the transaction is complete.

structure (Receipt) {
property (order) {
type (Order)
min (Required)
}
property (orderState) {
type (OrderState)
min (Required)
}
property(statusRefreshTime) {
type (time.DateTime)
visibility (Private)
min (Required)
}
features { activity }
}

Transaction and Activity States

Along with tagging concepts for features indicating that the concept state, you need to define those concept states.

Within a Transaction file (*.transaction.bxb), you can define transaction-support, for ongoing transactions. Within an Activity file (*.activity.bxb), you can define activity-support, for completed transactions.

For example, in the shirt ordering example, one of the structure concepts is a shirt order (Order), as shown in this example:

transaction-support {
match {
Order (this)
}
status-bar {
expiration {
timeoutMessage {
template("You ran out of time on that order, but we remember your choices.") // VIV-10309
}
timer (this.holdTime)
}
label {
template ("Buy")
}
price {
value {
template ("#{value (this.totalPrice)}")
}
}
on-user-click {
intent {
goal {
CommitOrder
}
}
}
}
}

In this Transaction, you see a transaction-support for a status bar, which provides a button the user can select to commit the order. The transaction-support indicates that a concept is part of an ongoing transactional flow.

The counterpart to transaction-support is activity-support, which indicates that a concept is part of a completed transactional flow:

activity-support {
match {
Receipt (this)
}
states {
if (orderState == 'Ordered') {
state (Scheduled) {
expires (statusRefreshTime)
summary-view {
message {
template ("#{value(orderState)}")
}
title{
template ("#{value (order)}")
}
details{
template("Enjoy your order!")
}
}
detail-view {
layout-match (this) {
mode (Details)
}
}
}
} else-if (orderState == 'Shipped') {
state (Relevant) {
expires (statusRefreshTime)
summary-view {
message {
template ("#{value(orderState)}")
}
title{
template ("#{value(order)}")
}
details{
template("Enjoy your order!")
}
}
detail-view {
layout-match (this) {
mode (Details)
}
}
}
} else-if (orderState == 'Delivered' || orderState == 'Cancelled') {
state (Recent) {
summary-view {
message {
template ("#{value(orderState)}")
}
title{
template ("#{value(order)}")
}
details{
template("Enjoy your order!")
}
}
detail-view {
layout-match (this) {
mode (Details)
}
}
}
}
}
}

In this transaction for Receipt, you see an activity-support that has a control flow for post-order statuses: "Ordered", "Shipped", and "Delivered". You also see the Scheduled, Relevant, and Recent states, which are Bixby-specific values that indicate that an activity is scheduled, in progress, or complete, respectively. If the user wants to get the latest status of a shirt order using RefreshActivity, these statuses help to inform the user of the various external states.

You do not need to define a specific order state for the control flow. Instead, you might want to use expression language. For example, you can check if the time that a reservation was made for is upcoming, current, or past and match it to a corresponding state.

You can learn more about transaction, activity, and related concept states in reference documentation.

Selection Prompts

If more than one function implements an action that has external effects, the execution cannot proceed without a selection being made. Bixby shows a prompt asking them to choose the implementation they would like to use for the transaction. Once the user makes a choice, execution can continue using the chosen function. To learn how to automatically make selections on behalf of the user, refer to Selection Rules.

You can learn more about Selection Prompts in Fundamentals documentation.

Giving Updates with Activity Cards

As briefly described in the Sample Capsule Walkthrough for the shirt capsule, there are three distinct phases during a transactional workflow: the transaction, commit, and activity phase. The activity phase, and the accompanying Activity Card, gives you an opportunity to provide updates in a receipt to the user about their upcoming event, such as a party they've RSVPed to, a hotel they've booked, or an item they've ordered. Essentially, any transaction that represents a "receipt" state is now considered an Activity.

The corresponding look-and-feel of the activity (with dialogs and layouts) primarily lets you do one of two things:

  • Give updated information, in case the previous state of the user's receipt is stale. For example, if a user ordered a ride share, they would want regular updates on where the car is and how soon they will be picked up.
  • Give more information that is relevant to users that wasn't available or relevant before. For example, if a user is checking their flight status 4 hours before the flight, they just want to know if it's on time. Once they're closer to the flight's departure, they can refresh the activity to show the flight time and the gate.

What Is Displayed in an Activity Card

When in a summary-view for Activity Cards, there is a primary slot, a secondary slot, and dialog for Activity Cards in the Assistant Home. The content for these various slots is determined by the message, title, and details keys in summary-view. The Timestamp slot is determined by the required time key. You can also add images to your Activity Card with image-url.

Assistant Home layout of an Activity Card

The look-and-feel of an Activity Card changes depending on the keys that have content as well as the card's position in the Assistant Home. The following list shows which slots show which information (and the key it pulls that information from) in the Summary View of your activity.

  • If a card is listed first, the message content is shown as the Bixby Dialog, while the primary slot displays title, and the secondary slot displays details:

Assistant Home layout of an Activity Card

  • All the cards below the first card have their information displayed dependent on if the message key has content:
    • If message is specified, then the primary slot displays message, and the secondary slot displays title and details.
    • If message is not specified, then the primary slot displays title and the secondary slot displays details.
      Note

      Because the message location can change in Assistant Home, you need to make sure that the message content is a complete sentence. For example:

      • Do: "you have a dentist appointment at 3pm". Bixby's dialog reads Hi Anne, you have a dentist appointment at 3pm.
      • Don't: "3pm dentist" Bixby's dialog reads Hi Anne, 3pm dentist

The Assistant Home displays the detail-view in a few situations:

  • When displaying a Receipt, at the very end of the transaction.
  • If a user clicks on an Activity Card for more information.
  • If a user clicks on a past transaction in their Transaction History.

Creating an Activity Card

The Activity Card is essentially the user's anchor for following the Activity's life cycle. It will be displayed at the end of the commit phase and the start of the activity phase, normally in the form of a receipt. Additionally, it can be displayed in the Assistant Home, to provide more information to users.

You can create an Activity Card by defining what layouts and dialogs are created with the summary-view and details-view keys in your *.activity.bxb file. While you can use any layout within the Details View, it's recommended you use a Card when possible.

Additionally, you should consider the states that the Activity is in (scheduled, relevant, and recent) to determine what information is displayed and when an activity card displays certain information.

Note

If the activity is in state recent, no Activity Card displays. Users can see their past activities in their transaction history.

Within the structures that you create for an Activity, such as a Receipt model, you must set an $id. This $id will help differentiate between different activities for the user. For example, a user might have booked a hotel in November for Thanksgiving and a separate hotel in December for Christmas. In order to keep the reservations distinct, make sure the Activity IDs in the resulting Receipt models for the hotel bookings are unique.

Be aware that a unique $id corresponds to a single Activity Card. Users will see exactly one Activity Card on their device for each unique Activity.

Note

It is highly recommended that the id you use in your activity concepts are consistent with the internal systems that you have. This makes Activities easier to keep track of and will help with any potential debugging.

There are two serialization issues to keep in mind when updating your capsule.

  • If you make changes to your Activity models, they need to be backwards compatible in the Bixby system. While it's okay to add new optional properties, deleting any properties or adding new required properties might interfere with older Activities and Bixby will not be able to read these older receipts.
  • Details View for existing receipts can only be computed and rendered if you keep the models of those receipts compatible with new model changes on your end.

When an Activity Card is Displayed

You determine when an Activity Card is displayed and how often it refreshes during the refresh state of an activity through the expires key defined in your *.activity.bxb file.

Because you can pass an expression to the expires key, you can set it to refresh at a consistent interval or make it dependant on another state. The shirt capsule, for example, sets a constant status_refresh_time to 600 seconds (10 minutes) in the capsule.properties file. You need to be mindful of what expression you set, because a lower interval corresponds to higher traffic to the client server for updates. You should also consider user experience. If a user booked a hotel eight months in advance, they don't necessarily need a daily reminder that their trip is coming up until much closer to the actual event.

You additionally control what is displayed with conditionals and the various states that the Activity is in. For example, an activity for a hotel booking should be set to scheduled state 7 days before the time and should change to relevant state 3 days before the time of the booking. In another example, with shirt, conditionals help determine what state the Order structure is in, and the various states determine what information actually gets displayed.

    states {
if (orderState == 'Ordered') {
state (Scheduled) {
expires(statusRefreshTime)
summary-view {
message {
template("#{value(orderState)}")
}
title{
template("#{value(order)}")
}
details{
template("Thanks for your order!")
}
}
detail-view {
layout-match(this) {
mode(Details)
}
}
}
} else-if (orderState == 'Shipped') {
state (Relevant) {
expires(statusRefreshTime)
summary-view {
message {
template("#{value(orderState)}")
}
title{
template("#{value(order)}")
}
details{
template("Thanks for your order!")
}
}
detail-view {
layout-match(this) {
mode(Details)
}
}
}
} else-if (orderState == 'Delivered' || orderState == 'Cancelled') {
state (Recent) {
summary-view {
message {
template("#{value(orderState)}")
}
title{
template("#{value(order)}")
}
details{
template("Thanks for your order!")
}
}
detail-view {
layout-match(this) {
mode(Details)
}
}
}
}
}
Note

The Activity Card is only refreshed if the user is currently in Bixby. If the user exits Bixby, then they will not continue to get updates unless they re-open the Assistant Home. This means there is no auto-refresh happening in the background. As a service, you should not expect web-service calls to your systems every 5 minutes for a user just because you set the expiry key in the *.activity-support.bxb file to 5 minutes. For each user, Bixby calls your web-service no more than once within a period of expiry seconds. For more information, see Refreshing Your Content.

Here are some Activity Cards in the Scheduled state:

Activity Card in Scheduled state

Here are those Activity Cards in the Relevant state:

Activity Card in Scheduled state