Code Repo

https://github.com/SphereGlobal/WebSDK

Supported Platforms

  • React (can be used for both ReactJs and NextJs also)

Installing the SDK

At present, the SphereOne WebSDK is not available through the NodePackage Manager (NPM) as a standard Node Package.

Developers are required to employ an alternative installation method by directly utilizing Node. This involves specifying both the SphereOne's GitHub organization and the library name during the installation process.

npm install github:SphereGlobal/WebSDK#main

Or yarn:

yarn add github:SphereGlobal/WebSDK#main

Getting Latest Updates

To get the latest updates from the SDK, developers would need to manually run the installation command again:

npm install github:SphereGlobal/WebSDK#main

This should pull the latest changes and update the .lock file.

Initializing the SDK

To initialize the WebSDK in a new project or existing project, we need to import and instantiate the WebSDK.

import WebSDK, { LoginBehavior } from "websdk";

const clientId = "your-client-id";
const redirectUri = "your-website-redirect-uri";
const apiKey = "your-merchant-api-key";

export const sphereoneSdk = new WebSDK(clientId, redirectUri, apiKey, LoginBehavior.REDIRECT);

To obtain many of the values essential for initializing the WebSDK, please engage in communication with SphereOne to secure the accurate values.

Key Values for WebSDK Initialization:

  • your-client-id - This value is indispensable for SphereOne to authenticate that the invoker is associated with a specific client.
  • setLoginType - This value is crucial to determine the nature of the login experience. SphereOne recommends setting this value to REDIRECT.
  • your-merchant-api-key - This key is vital for certain WebSDK API calls, serving to identify the invoker as a legitimate merchant within SphereOne's system.
  • your-website-redirect-url - This URL is essential for the login process to discern where to dispatch the authentication response back.

Login

After initializing the WebSDK, to login the user, developer can call the WebSDK method: login()

import { sphereoneSdk } from "./your-implementation-file";

// login function for button onClick
const login = async () => {
  try {
    await sphereoneSdk.login();
  } catch (e: any) {
    console.error(e);
  }
};

This will trigger the login functionality with the WebSDK. It will redirect user to SphereOne's login screen, and user can proceed from there, with similar experience as SphereOne's applications.

To listen and get the response back from the authentication and also know if user is signed in or not:

// something to track user's sign-in state with SphereOne on client-side
const [isLoggedIn, setIsLoggedIn] = useState(false);

// hook to listen for authentication response
useEffect(() => {
  const handleAuth = async () => {
    const authResult: any = await sphereoneSdk.handleCallback();
    if (authResult.access_token) {
      const { access_token, profile } = authResult;
      setIsLoggedIn(true); // handle authentication with your database
    } else {
      setIsLoggedIn(false);
    }
  };
  handleAuth();
}, []);

The WebSDK will internally store and keep track of the accessToken returned from the authentication. So, there's no need for developers to explicitly store the accessToken.

But if developer wants to use the accessToken for making a SphereOne API call that's not within the SDK, then there are getter methods in the SDK to get the accessToken and IdToken.

// `getAccessToken` and `getIdToken` will return an empty string if user is not logged in. 
const accessToken:string  = sphereoneSdk.getAccessToken();
const idToken:string = sphereoneSdk.getIdToken();

Get User Data

Once user is successfully signed in, all user information, wallets, and their balances will be loaded into the SDK.

To get user info, developer can call the WebSDK method: getUserInfo()

const getUserInfo = async () => {
  const userInfo = await sphereoneSdk.getUserInfo({ forceRefresh: false });
  console.log("userInfo", JSON.stringify(userInfo));
};

The example simply prints out the userInfo of the current signed-in user to the console.

If developers want to pull latest updates for user wallets, they can utilize the same call as above and pass { forceRefresh: true } as a parameter.

If { forceRefresh: true } is not passed, then what's returned by getUserInfo will be what's currently stored/cached in the WebSDK.

const getUserInfo = async (refresh: boolean) => {
  const userInfo = await sphereoneSdk.getUserInfo({ forceRefresh: refresh });
  console.log("userInfo", JSON.stringify(userInfo));
};

Get User Wallets

To get user wallets, developer can call the WebSDK method: getWallets()

const getUserWallets = async () => {
  const userWallets = await sphereoneSdk.getWallets({ forceRefresh: false });
  console.log("userWallets", JSON.stringify(userWallets));
}

This method follows similarly to the getUserInfo example above.

Get User Total Balances

To get user total balances, developer can call the WebSDK method: getBalances()

const getUserTotalBalance = async () => {
  const userTotalBalance = await sphereoneSdk.getBalances();
  console.log("userTotalBalance", JSON.stringify(userTotalBalance));
};

This method follows similarly to the getUserInfo example above.

Create a Charge/Transaction

To create a charge, or payment transaction , in order to proceed with payments within SphereOne, developer would need to create a charge object, which contains all the necessary information pertaining to the purchase such as the individual making the purchase, the item of the purchase, the total amount, etc.

To create a charge, we need to use the WebSDK's method: createCharge

// importing the initialized WebSDK
import { sphereoneSdk } from "your-imported-file";
// an enum class of Chains that SphereOne supports
import { SupportedChains } from "websdk";

// ...

const [chargeId, setChargeId] = useState("");
const [paymentLink, setPaymentLink] = useState("");

const createCharge = async () => {
  try {
    const charge = await sphereoneSdk.createCharge({
      chain: SupportedChains.SOLANA,
      symbol: "SOL",
      amount: 0.9, // total amount for entire charge
      tokenAddress: "So11111111111111111111111111111111111111112",
      successUrl: "https://your-website.com/success",
      cancelUrl: "https://your-website.com/cancel",
      items: [
        {
          name: "Your Item",
          image: "https://your-image-url.somewhere.com",
          amount: 0.9, // amount of the individual item
          quantity: 1
        }
      ]
    });
    setChargeId(charge.chargeId);
    setPaymentLink(charge.paymentUrl);
  } catch (e: any) {
    console.error(e);
  }
};

// ...

createCharge has a set of parameters that must be set. More info can be found here at SphereOne API references - Create Charge.

In the above code example, a charge is created for a purchase involving SOLANA. To create a successful charge, we must pass a list of items that users want to purchase, the tokenAddress for SOLANA Chain, followed by successUrl and cancelUrl.

NOTE: It's a bit inconvenient right now, but more updates will come to make this easier and more convenient.

If the charge is successful, the response for charge in the above example, should be:

{
  chargeId: "a-charge-id",
  paymentUrl: "https://a-payment-link/a-charge-id"
}

What is absolutely needed is the chargeId returned by createCharge since that is the reference to the actual purchase that's going to be made, in the next step.

Once the chargeId is retrieved or saved for later usage, you can continue with making payments in WebSDK.

As for the paymentUrl returned by createCharge, it is a dynamic link that can take user to SphereOne's Checkout Page, similar to Stripe, where similar functionality for paying for the charge is implemented.

Pay for the Created Charge/Transaction

There are two ways to pay for the charge in the previous example.

  • Use WebSDK method payCharge and pass in the chargeId.
  • Open a popup or redirect user with the paymentUrl to SphereOne's Checkout Page, where functionality for payCharge is also implemented.

Note: To use the first option (payCharge method) we must first have the user enter their pin code. If we do not do this, the payment will not be triggered.

Below is an example of how to prompt the pin code popup.

First in the page where the button that triggers the popup for the user to enter his pin code is located, we must add this piece of code, to receive the pin code response and store it inside the SDK.

// importing the initialized WebSDK
import { sphereoneSdk } from "your-imported-file";

// ...
useEffect(() => {
  sdk.pinCodeHandler()
}, [])

// ...

The method that opens the popup with the pin code display is called openPinCode()we must pass as a parameter the chargeId we want to pay, below is an example of the complete code to open the popup and get the response.

// importing the initialized WebSDK
import { sphereoneSdk } from "your-imported-file";

// ...
// these are from previous section from: https://docs.sphereone.xyz/docs/create-charge#web-sdk
const [chargeId, setChargeId] = useState("");
// ... refer to `Create a Charge/Transaction` Section example

// we need this piece of code to handle the callback for pin code popup
useEffect(() => {
  sdk.pinCodeHandler()
}, [])

const pincode = () => {
  try {
    // passing in the `chargeId` set
    sdk.openPinCode(chargeId)
  } catch (e: any) {
    console.error(e)
  }
}
// ...

Once the user has entered the pin code, we are ready to call the payCharge function to complete the payment of the previously created transaction.

Below is example of how to call payCharge in WebSDK:

// importing the initialized WebSDK
import { sphereoneSdk } from "your-imported-file";

// ...
// these are from previous section from: https://docs.sphereone.xyz/docs/create-charge#web-sdk
const [chargeId, setChargeId] = useState("");
const [paymentLink, setPaymentLink] = useState("");

// ... refer to `Create a Charge/Transaction` Section example

const pay = async () => {
  try {
    // passing in the `chargeId` set
    await sphereoneSdk.payCharge(chargeId);
  } catch (e: any) {
    console.error(e);
  }
};

// ...

If payCharge fails because consumer don't have or have enough funds in their Wallets, then payCharge will return an error code, which frontend-client can consume to determine what to do.

Below is an example response returned by payCharge, if user doesn't have or have enough funds for completing the transaction.

{
  "data": {
    "status": "FAILURE",
    "onrampLink": "https://sphereone-on-ramp-link/12345"
  },
  "error": {
    "code": "sphereone-error-code",
    "message": "sphereone error message"
  }
}

To handle for this error, the simple payCharge example can be modified to handle this error flow.

// importing the initialized WebSDK
import { sphereoneSdk } from "your-imported-file";
// ...
const pay = async () => {
  try {
    // trigger `pay` and listen for `result`
    const result = await sphereoneSdk.payCharge(chargeId);
    alert("Payment successful");
    // you can also show the route created
    console.log("route created =>", result.route)
    
  } catch (e: any) {
    // the error could be related to the user not having sufficients funds
    // in that case the error contains a link to our PWA to easily onramp money
    if(e.onrampLink){
      alert(
        "Not enough funds to pay with SphereOne. We will redirect you to the onramp page."
      );
      window.open(e.onrampLink, "Popup", 'width=800, height=850'); // open a pop-up
      }
  	// the error is not solved with an onrampLink
  	else alert(`${e.message}`);
  }
};
// ...

As shown in the code example above for payCharge, if payCharge fails because consumer doesn't have any or enough funds in Sphere Wallets to make the purchase, then payCharge will return an error, which frontend-client can consume to determine what to do.

As shown in the code example above for payCharge, frontend-client can check for the error.onrampLink in the JSON response and utilize it in the JSON response to redirect or show a popup for consumer to proceed.

The onrampLink will direct consumer to the SphereOne Wallet site. Here, consumer can utilize SphereOne's many on-ramp providers to add funds into theirWallets.

Once consumer has successfully added funds to their Wallets, then consumer can resume their payment.

๐Ÿ“˜

It is a little inconvenient at the moment to handle this error flow manually. But more improvements will be made to handle that internally.

Transfer NFT

We must first have the user enter their pin code. If we do not do this, the transfer will not be triggered.

Note: At the moment we are only supporting Immutable X and Solana chains for NFT transfers.

Below is an example of how to prompt the pin code popup.

First in the page where the button that triggers the popup for the user to enter his pin code is located, we must add this piece of code, to receive the pin code response and store it inside the SDK.

// importing the initialized WebSDK
import { sphereoneSdk } from "your-imported-file";

// ...
useEffect(() => {
  sdk.pinCodeHandler()
}, [])

// ...

The method that opens the popup with the pin code display is called openPinCode() we have to pass as parameter the operation we want to perform, in this case: SEND_NFT. Below is an example of the complete code to open the popup and get the response.

// importing the initialized WebSDK
import { sphereoneSdk } from "your-imported-file";

// we need this piece of code to handle the callback for pin code popup
useEffect(() => {
  sdk.pinCodeHandler()
}, [])

const pincode = () => {
  try {
    // passing in the `chargeId` set
    sdk.openPinCode("SEND_NFT")
  } catch (e: any) {
    console.error(e)
  }
}
// ...

Once the user has entered the pin code, we are ready to call the transferNft function to start with the transfer of the NFT.

Below is example of how to call transferNFT in WebSDK:

// importing the initialized WebSDK
import { sphereoneSdk } from "your-imported-file";

const transferNft = async () => {
  try {
    await sphereoneSdk.transferNft({
      chain: "nft_chain", // we recommend to use our enum `SupportedChains`. Ex: SupportedChains.ETHEREUM
    	fromAddress: "nft_owner_wallet",
    	toAddress: "destination_address",
    	nftTokenAddress: "nft_token_address",
    	tokenId?: "nft_token_id", // this parameter is only not required if the chain is SOLANA
    	reason?: "custom_message"
    });
  } catch (e: any) {
    console.error(e);
  }
};

// ...

With this we should have already made the transfer of NFT successfully, in case of any error with the blockchain during the transfer, the response of the function will include a message with the error.

Sign Out

To sign out of WebSDK, please invoke the WebSDK's logout functionality: logout()

import { sphereoneSdk } from "./your-implementation-file";

const logout = () => {
  try {
    sphereoneSdk.logout();
    setIsLoggedIn(false); // set internal state on client side to false
  } catch (e: any) {
    console.error(e);
  }
};

This should clear the current login session, and allow user to re-login again.

Pin code

Add new pin code

To add a new pin code to a user who does not currently have a pin code created, proceed as follows:

import { sphereoneSdk } from "./your-implementation-file";

const addPincode = () => {
  try {
    sphereoneSdk.addPinCode();
  } catch (e: any) {
    console.error(e);
  }
};

Executing the addPincode() method will open a popup window, in which the user will be asked to enter and confirm their new pin code. Upon successful addition of this new pin code, a confirmation window will appear confirming that this new code was added for the user.

Open pin code popup

At the moment there are two operations for which you would need to open the popup for the user to enter his pin code, in both cases it is necessary for the user to enter the pin code configured in their account for security reasons.

  • Pay a charge
  • Send an NFT

Below is an example code to open the pin code window for the first case of paying a charge. It is necessary to pass as a parameter the chargeId

// importing the initialized WebSDK
import { sphereoneSdk } from "your-imported-file";

// ...
// these are from previous section from: https://docs.sphereone.xyz/docs/create-charge#web-sdk
const [chargeId, setChargeId] = useState("");
// ... refer to `Create a Charge/Transaction` Section example

// we need this piece of code to handle the callback for pin code popup
useEffect(() => {
  sdk.pinCodeHandler()
}, [])

const pincode = () => {
  try {
    // passing in the `chargeId` set
    sdk.openPinCode(chargeId)
  } catch (e: any) {
    console.error(e)
  }
}
// ...

In case you want to send an NFT to another wallet, it is very similar only that we have to pass the SEND_NFT operation as a parameter. Below is an example code to perform this operation.

// importing the initialized WebSDK
import { sphereoneSdk } from "your-imported-file";
// ...

// we need this piece of code to handle the callback for pin code popup
useEffect(() => {
  sdk.pinCodeHandler()
}, [])

const pincode = () => {
  try {
    // passing in the `SEND_NFT` operation
    sdk.openPinCode("SEND_NFT")
  } catch (e: any) {
    console.error(e)
  }
}
// ...

Notes:

  • It is necessary to have the pinCodeHandler method in order to handle the pin code response.
  • If the user does not enter his pin code, the payCharge or transferNft method will fail.

Whatโ€™s Next