> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beem.africa/llms.txt
> Use this file to discover all available pages before exploring further.

# USSD callback

> Implement the callback endpoint that receives USSD session events from Beem.

When a subscriber dials your USSD code, Beem POSTs session events to your callback URL. Your application processes each event and returns the next menu prompt until the session ends.

See [Receive USSD session callback](/api-reference/ussd/receive-ussd-session-callback) for the interactive API reference.

***

## Callback flow

```text theme={null}
Subscriber dials *123#
        │
        ▼
Beem USSD Hub
        │
        │ POST /your/callback
        ▼
Your application
        │
        │ JSON menu response
        ▼
Beem USSD Hub → Subscriber screen
```

***

## Inbound request fields

Beem sends a JSON body on every session step:

| Field                | Type          | Description                                                             |
| -------------------- | ------------- | ----------------------------------------------------------------------- |
| `command`            | string        | `initiate`, `continue`, or `terminate`                                  |
| `msisdn`             | string        | Subscriber mobile number                                                |
| `operator`           | string        | Network operator (`vodacom`, `tigo`, `airtel`, `halotel`, `ttcl`, etc.) |
| `session_id`         | string        | Unique session identifier                                               |
| `payload.request_id` | string/number | Step identifier (`0` on initiate)                                       |
| `payload.response`   | string/number | Subscriber input (`0` at session start)                                 |

***

## Outbound response fields

Return HTTP `200` with a JSON body:

| Field                | Type          | Description                             |
| -------------------- | ------------- | --------------------------------------- |
| `msisdn`             | string        | Echo subscriber number                  |
| `operator`           | string        | Echo operator                           |
| `session_id`         | string        | Echo session ID                         |
| `command`            | string        | Next command: `continue` or `terminate` |
| `payload.request_id` | string/number | Step identifier for your menu           |
| `payload.request`    | string        | Menu text shown to the subscriber       |

<Warning>
  In your **response**, the payload field is `request` (the menu text). In Beem's **inbound** request, the equivalent subscriber input field is `response`.
</Warning>

***

## Sample requests

<Tabs>
  <Tab title="Initiate">
    ```json theme={null}
    {
      "command": "initiate",
      "msisdn": "255762089337",
      "session_id": "4574",
      "operator": "vodacom",
      "payload": { "request_id": 0, "response": 0 }
    }
    ```
  </Tab>

  <Tab title="Continue">
    ```json theme={null}
    {
      "command": "continue",
      "msisdn": "255762089337",
      "session_id": "6545",
      "operator": "vodacom",
      "payload": { "request_id": "112322", "response": "2556730000002" }
    }
    ```
  </Tab>

  <Tab title="Terminate">
    ```json theme={null}
    {
      "command": "terminate",
      "msisdn": "255762089337",
      "session_id": "7845",
      "operator": "vodacom",
      "payload": { "request_id": "12323", "response": "1" }
    }
    ```
  </Tab>
</Tabs>

***

## Sample responses

<Tabs>
  <Tab title="Menu prompt">
    ```json theme={null}
    {
      "msisdn": "2556730893370",
      "operator": "vodacom",
      "session_id": "33545",
      "command": "continue",
      "payload": {
        "request_id": "1",
        "request": "enter amount"
      }
    }
    ```
  </Tab>

  <Tab title="End session">
    ```json theme={null}
    {
      "msisdn": "2556730893370",
      "operator": "vodacom",
      "session_id": "66545",
      "command": "terminate",
      "payload": {
        "request_id": "2",
        "request": "Thank you. Session ended."
      }
    }
    ```
  </Tab>
</Tabs>

***

## Sample implementations

<Tabs>
  <Tab title="Node.js">
    ```javascript theme={null}
    const express = require("express");
    const app = express();

    app.use(express.json());

    const ussdMenu = [{ text: "enter phone number" }, { text: "enter amount" }];

    app.post("/ussd/callback", (req, res) => {
      let {
        command,
        msisdn,
        session_id,
        operator,
        payload: { request_id, response },
      } = req.body;

      const request = ussdMenu[request_id]?.text || "Invalid option";
      command = request_id + 1 === ussdMenu.length ? "terminate" : "continue";

      res.json({
        msisdn,
        operator,
        session_id,
        command,
        payload: { request_id, request },
      });
    });

    app.listen(4000, () => console.log("USSD callback on port 4000"));
    ```
  </Tab>

  <Tab title="GitHub">
    [beem-ussd-api-sample — callback](https://github.com/beemafrica/beem-ussd-api-sample/tree/master/callback/)

    Sample code in Node.js, PHP, Python, .NET, and Java.
  </Tab>
</Tabs>

***

## Session commands

| Command     | When Beem sends it               | Your typical response                        |
| ----------- | -------------------------------- | -------------------------------------------- |
| `initiate`  | Subscriber first dials your code | Show main menu (`command: continue`)         |
| `continue`  | Subscriber selects an option     | Show next prompt or terminate                |
| `terminate` | Session is closing               | Acknowledge and close (`command: terminate`) |

Respond within the operator timeout window (typically a few seconds) to avoid session failure.
