Widget Integration

With the widget style of integration, you retrieve and inject a Tilia-supplied script into your page, which provides an API to interact with our widget. You then “execute” the desired flow, passing an element id to indicate where the Tilia UI will appear in your page and callback functions to handle specific messages returned from the widget.

The diagram below illustrates the flow of information within a widget integration.

General Widget Flow

To integrate the Tilia widget

Widget integration involves the following steps:

Step 1: User authorization

Step 2: Add the widget script to your page

Step 3: Retrieve redirect url and execute the flow

Step 4: Handle the flow result

The rest of this document walks you through the basics of integrating a flow using the widget method.

Step 1: User authorization

All flows start with an OAuth2 authorization of the end user by passing an account_id. The response will include a redirect URL with a generated nonce that authorizes the user to interact with the Tilia UIs.

Your server should contain an api endpoint that passes the 'redirect' payload to your frontend.

Creating the nonce requires an Access Token with the scope write_user_tokens.

Copy
Copied
curl --location --request POST https://auth.tilia-inc.com/authorize/user \
--header 'Authorization: Bearer <Access_Token>' \
--header 'Content-Type: application/json' \

Request body

Copy
Copied
{
	"account_id": "<tilia_account_id>"
}

Sample response

Copy
Copied
{
    "status": "Success",
    "message": [],
    "codes": [],
    "payload": {
        "redirect": "https://web.tilia-inc.com/ui/appauth/ed8ff1e9-9256-4205-918a-b9ca23ec00ec"
    }
}

The response includes a redirect URL that is used in the next step.

attention

The nonce is valid for 24 hours. We recommend generating a nonce immediately before sending the user to a Tilia UI. Each nonce may only be used once.

Step 2: Add the widget script to your page

Copy
Copied
/**
 * Load widget script in your page.
 * This should happen early within the page load so it is ready when needed.
 */
const widget = document.createElement("script");
widget.src = `https://web.tilia-inc.com/ui/v1/widget`;
widget.onload = () => {
    // Use this to ensure the widget is
    // loaded before using it.
};
document.body.appendChild(widget);

Step 3: Retrieve redirect url and execute the flow

Next, you will retrieve the redirect url (from Step 1) and pass that with the desired flow name to the Tilia widget.

Copy
Copied
/**
 * 1: Setup your callback functions
 * 2: Call your endpoint to retrieve redirect payload
 * 3: Execute widget with your desired Flow
 */
function handleWidgetReady(e) {
    console.log('handleWidgetReady:', e);
    // handle the ‘ready’ message
}

function handleWidgetError(e) {
    console.error('handleWidgetError', e);
    // handle error
}

function handleWidgetComplete(e) {
    console.log('handleWidgetComplete:', e);
    // handle the ‘complete’ message
}

function triggerTiliaWidgetFlow() {
    const yourEndpointThatReturnsRedirectPayload = "/PATH/TO/YOUR/API/ENDPOINT/THAT/RETURNS/REDIRECT/PAYLOAD";
    fetch(yourEndpointThatReturnsRedirectPayload)
        .then(response => {
            /**
             * For this example we will assume your endpoint is
             * passing back the full payload from step one:
             * {
             *      "status": "Success",
             *      "message": [],
             *      "codes": [],
             *      "payload": {
             *          "redirect": "https://web.tilia-inc.com/ui/appauth/ed8ff1e9-9256-4205-918a-b9ca23ec00ec"
             *      }
             *  }
             */
            window.Tilia.execute({
                //required parameters
                rootId: < your.element.id > ,
                flow: < flow.name > , // for example: "tos", "kyc", "purchase", "payout"
                redirect: response.payload.redirect, // this could be different based on what your server is sending as a response.  Expects a URL string.
                onComplete: handleWidgetComplete,
                onError: handleWidgetError,
                // optional parameters
                debug: true, 
                onReady: handleWidgetReady,
            });
        })
        .catch(e => {
            console.error('error retrieving redirect payload', e);
            // handle error
        });
}

triggerTiliaWidgetFlow(); // call when ready.

Your onComplete handler function will be called when the user completes the flow. The function will pass results specific to the flow.

Full HTML Example...

Copy
Copied
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style type="text/css">
        html, body { width: 100%; height: 100%; }
        body {
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        #my-widget-wrapper {
            width: 480px;
            height: 700px;
            padding: 4px;
            border: 1px solid black;
            border-radius: 8px;
        } 
    </style>
    <script type="text/javascript">
        var widgetLoaded = false;
        var callTriggerFlowAfterWidgetLoaded = false;

        function loadWidget() {
            /**
             * Load widget script in your page.
             * This should happen early within the page load so it is ready when needed.
             */
            var widget = document.createElement("script");
            widget.src = "https://web.tilia-inc.com/ui/v1/widget"; // if using the staging environment, you will want to change this to match staging URL
            widget.onload = () => {
                // Use this to ensure the widget is
                // loaded before using it.
                widgetLoaded = true;
                console.log('widget loaded');
                if (callTriggerFlowAfterWidgetLoaded) {
                    triggerTiliaWidgetFlow();
                }
            };
            document.body.appendChild(widget);
        }

        /**
         * Your callback handlers
        */
        function handleWidgetReady(e) {
            console.log('handleWidgetReady:', e);
            // handle the ‘ready’ message
        }

        function handleWidgetError(e) {
            console.error('handleWidgetError', e);
            // handle error
        }

        function handleWidgetComplete(e) {
            console.log('handleWidgetComplete:', e);
            // handle the ‘complete’ message
        }
        /* ----------------- */

        function triggerTiliaWidgetFlow() {
            if (!widgetLoaded) {
                // in this basic example, we are likely calling this function before the widget is ready.
                // to get around this, we are setting a variable to re-call this function when the widget has loaded. 
                callTriggerFlowAfterWidgetLoaded = true;
                return;
            }
            const yourEndpointThatReturnsRedirectPayload = "/PATH/TO/YOUR/API/ENDPOINT/THAT/RETURNS/REDIRECT/PAYLOAD";
            fetch(yourEndpointThatReturnsRedirectPayload)
                .then(response => {
                    /**
                     * For this example we will assume your endpoint is
                     * passing back the full payload from step one:
                     * {
                     *      "status": "Success",
                     *      "message": [],
                     *      "codes": [],
                     *      "payload": {
                     *          "redirect": "https://web.tilia-inc.com/ui/appauth/ed8ff1e9-9256-4205-918a-b9ca23ec00ec"
                     *      }
                     *  }
                     */
                    window.Tilia.execute({
                        //required parameters
                        rootId: "my-widget-wrapper",
                        flow: "purchase", // for example: "tos", "kyc", "purchase", "payout"
                        redirect: response.payload.redirect, // this could be different based on what your server is sending as a response.  Expects a URL string.
                        onComplete: handleWidgetComplete,
                        onError: handleWidgetError,
                        // optional parameters
                        debug: true, 
                        onReady: handleWidgetReady,
                    });
                })
                .catch(e => {
                    console.error('error retrieving redirect payload', e);
                    // handle error
                });
        }
    
        window.addEventListener('load', function() {
            loadWidget();
            triggerTiliaWidgetFlow();
        }, false);
    </script>
</head>
<body>
    <div id="my-widget-wrapper"></div>
</body>
</html>

Step 4: Handle the flow result

Upon completing the flow, the onComplete function returns a result. Refer to the flow-specific documentation for details.