# Ubuntu Skill Circles API
Node.js/Express integration for Africa's Talking USSD callbacks and outbound SMS.
## 1. SDK Setup
Install dependencies:
```bash
npm install
```
Create your local environment file from `.env.example` and fill in the sandbox API key from your Africa's Talking sandbox app:
```dotenv
AT_USERNAME=sandbox
AT_API_KEY=your_sandbox_api_key
AT_SENDER_ID=AFRICASTKNG
PORT=3000
```
For sandbox requests, `AT_USERNAME` is always `sandbox`; it is not your dashboard login name. Never commit `.env`. `src/config/africastalking.js` initializes the official SDK once and exports its reusable client and SMS service.
Run the API:
```bash
npm run dev
```
The USSD callback is `POST /ussd`. Africa's Talking sends `application/x-www-form-urlencoded`, so `express.urlencoded()` must be enabled. It expects an HTTP 200 response with `text/plain`. The SDK is needed for outbound APIs such as SMS; receiving USSD is a normal public HTTP webhook.
Africa's Talking allows at most 10 seconds for a USSD callback. `src/app.js` applies an 8-second application deadline, leaving time to return a valid fallback before the provider closes the request. Keep database lookups indexed and never put AI matching or SMS sending in the active USSD request.
## 2. How USSD State Works
Africa's Talking makes a new HTTP request after each user response. Your server does not hold an open conversation. Typical callback bodies are:
| Screen | `sessionId` | `text` |
| --- | --- | --- |
| Welcome | `ATUid_abc123` | `""` |
| User selects mentor | `ATUid_abc123` | `"1"` |
| User selects Technology | `ATUid_abc123` | `"1*1"` |
| User selects Swahili | `ATUid_abc123` | `"1*1*2"` |
The gateway keeps the same `sessionId` for that dial-in and sends the full input history in `text`, separated by `*`. `src/services/ussdService.js` reconstructs the current screen from that cumulative path. This is deliberately stateless: it works after a process restart and when requests reach different server ins …