Hooks#

Hooks are a way to extend the functionality of USSDK using your own APIs. With hooks, you’re able to do the following:

  • Customize welcome message based on user’s phone number
  • Perform validation of input
  • Save responses to your database
  • Check authorization

The sky is your limit.

Hooks are optional. But when specified, they’re called before the step is rendered. This is so that, responses returned can be used to decide on how to render the current step. Hooks can also be used to validate the input from previous steps.

While that may sound unusual to a lot of people, this design helps simplify the hook process.

Your API endpoint#

You can implement the API endpoint with any language or technology of choice. This endpoint should accept a POST request and return a JSON encoded response. The endpoint will receive the following body:

{
  "input": {"key": "2"},
  "props": {
    "session": {"msisdn": "0240000001", "network": "sim"},
    "values": {"name": "James", "action": 1}
  }
}

Based on these properties, you can do whatever you like then return any JSON response. If you’re not going to use any part of the response in the step, you can just return a null.

Let’s look at a hook implementation in Javascript:

const app = express()
app.use(bodyParser())

app.post('/check-balance', async (req, res) => {
  const phone = req.body.props.session.msisdn
  const account = await db.accounts.find({where: { phone }})

  return res.json({ balance: account.balance.value })
})

Now you can set the message template on the step->message to something like:

You have GHS{{balance}} in your account

Note that, using an endpoint on localhost cannot work. You have to host your API endpoint. Or use tunnel services like ngrok to proxy to your local server.

Step/input validation#

Sometimes, the input to a step is not our expectation. For example, if a step asks for PIN and the user entered the wrong one, then we cannot proceed right? In that case, we should be able to ask the user to enter the PIN again (or maybe quit the app).

USSDK offers a number of ways to handle errors or control the flow of your USSD application. This is done by returning a response from your hook with a response code within 4XX and a specified format. This format is discussed below.

Note that when a step doesn’t accept a custom input but menu keys, USSDK automatically checks that the input matches one of the menu keys and asks the user to retry the step.

Retries#

If a user needs to retry a step, you can return a 4XX response from your API endpoint in the format:

{
  "action": "retry",
  "message": "Incorrect PIN. Try again."
}

If you return a retry on the entry step, the session is only allowed to end (as there’s nothing to retry).

Back#

You can also prevent the user from proceeding with the session and only direct them back to the previous screen. This is done by responding with a status code of 4XX and a body of

{
  "action": "back",
  "message": "You're not allowed to access this detail"
}

When presenting this to the user, USSDK includes a menu item “#) Back” to the screen. When the user presses ”#”, they’re sent to the previous screen. If this happens on the very first/entry screen, the session is only allowed to end.

Note that, message is not required. A default message “Could not proceed” is shown to the user.

End#

You can choose to abruptly end the session. This time not allowing retries or navigating back. In that case, you can send a 4XX response with:

{
  "action": "end",
  "message": "We can't do this anymore"
}

Inbuilt Hooks#

There are some hooks that USSDK provides by default.

Hook Playground#

USSDK is all about making the building USSDK applications seamless. When beginning a project, we may not have our API endpoints ready to be used with hooks. In such cases, you can use the Hook Playground to compose dummy responses that you can use with your steps — long before you are ready to implement them. This can help save time and iterate quickly.

The Hook Playground is an easy-to-use interface where you supply the JSON you expect to receieve at each step (of your USSD application). You can compose as many endpoints you need.

Securing API access#

To prevent abuse of your API services, you may need to verify that a request is coming from USSDK. To do this you have to verify the request.

To get a copy of your secret key, access your app’s editor and go to the Step tab. Make sure to deselect any step node. You’ll see a section in the right panel to copy your secret key.

The following is a Javascript implementation on how to verify the request. data comes from request body.

// Secret should be kept in an env variable
const secret = "dLNPXPgZxgmJfmxtNJDMCX5HG";
function verifySignature(signature: string, data: any) {
	const hmac = crypto.createHmac("sha256", secret);
	hmac.update(JSON.stringify(data));
	const digest = hmac.digest("hex");

	return digest === signature;
}

// to verify the request
app.post("/some-endpoint", (req, res) => {
  const signature = req.headers["X-USSDK-Signature"]
  if (!verifySignature(signature, req.body)) {
    return res.status(401).json(
      {action: "end", message: "Failed to verify request"},
    )
  }
  ...
})