{"id":37014114,"url":"https://github.com/sparors/laravel-ussd","last_synced_at":"2026-01-14T01:24:05.460Z","repository":{"id":37003311,"uuid":"259912909","full_name":"sparors/laravel-ussd","owner":"sparors","description":"Create ussd with ease","archived":false,"fork":false,"pushed_at":"2025-03-20T20:46:51.000Z","size":161,"stargazers_count":64,"open_issues_count":0,"forks_count":42,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-11-27T16:34:28.179Z","etag":null,"topics":["laravel","laravel-package","library","package","php","ussd"],"latest_commit_sha":null,"homepage":"https://sparors.github.io/ussd-docs/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sparors.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":"contributing.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-29T11:58:35.000Z","updated_at":"2025-03-27T09:49:38.000Z","dependencies_parsed_at":"2025-03-20T21:51:08.551Z","dependency_job_id":"6039d159-45e0-4a14-89b9-5cc535d1fee1","html_url":"https://github.com/sparors/laravel-ussd","commit_stats":{"total_commits":57,"total_committers":4,"mean_commits":14.25,"dds":"0.17543859649122806","last_synced_commit":"d520b243d2a522b8c12c073cda96673cb84f3db1"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/sparors/laravel-ussd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sparors%2Flaravel-ussd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sparors%2Flaravel-ussd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sparors%2Flaravel-ussd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sparors%2Flaravel-ussd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sparors","download_url":"https://codeload.github.com/sparors/laravel-ussd/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sparors%2Flaravel-ussd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28407696,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T00:40:43.272Z","status":"ssl_error","status_checked_at":"2026-01-14T00:40:42.636Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["laravel","laravel-package","library","package","php","ussd"],"created_at":"2026-01-14T01:24:04.632Z","updated_at":"2026-01-14T01:24:05.438Z","avatar_url":"https://github.com/sparors.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Laravel Ussd\n\n[![Latest Version on Packagist][ico-version]][link-packagist]\n[![Total Downloads][ico-downloads]][link-downloads]\n[![Build Status][ico-github]][link-github]\n\nBuild Ussd (Unstructured Supplementary Service Data) applications with laravel without breaking a sweat.\n\n## Installation\n\nYou can install the package via composer:\n\n``` bash\ncomposer require sparors/laravel-ussd:^3.0-beta\n```\n\nFor older version use\n\n``` bash\ncomposer require sparors/laravel-ussd:^2.0\n```\n\nLaravel Ussd provides zero configuration out of the box. To publish the config, run the vendor publish command:\n\n``` bash\nphp artisan vendor:publish --provider=\"Sparors\\Ussd\\UssdServiceProvider\" --tag=ussd-config\n```\n\n## Usage\n\nFor older version look here: [V2 README](./v2.readme.md)\n\n### Creating USSD menus\n\n```php\n\u003c?php\n\nnamespace App\\Ussd\\States;\n\nuse App\\Ussd\\Actions\\TransferAccountAction;\nuse Sparors\\Ussd\\Attributes\\Paginate;\nuse Sparors\\Ussd\\Attributes\\Transition;\nuse Sparors\\Ussd\\Context;\nuse Sparors\\Ussd\\Contracts\\State;\nuse Sparors\\Ussd\\Decisions\\Equal;\nuse Sparors\\Ussd\\Decisions\\Fallback;\nuse Sparors\\Ussd\\Decisions\\In;\nuse Sparors\\Ussd\\Menu;\nuse Sparors\\Ussd\\Record;\nuse Sparors\\Ussd\\Traits\\WithPagination;\n\n#[Transition(to: TransferAccountAction::class, match: new Equal(1))]\n#[Transition(to: TransferAmountState::class, match: new In(2, 3), callback: [self::class, 'setTransferType'])]\n#[Transition(to: NewAccountNameState::class, match: new Equal(4))]\n#[Transition(to: HelplineState::class, match: new Equal(5))]\n#[Transition(to: InvalidInputState::class, match: new Fallback())]\n#[Paginate(next: new Equal('#'), previous: new Equal('0'))]\nclass CustomerMenuState implements State\n{\n    use WithPagination;\n\n    public function render(): Menu\n    {\n        return Menu::build()\n            -\u003eline('Banc')\n            -\u003elisting($this-\u003egetItems(), page: $this-\u003ecurrentPage(), perPage: $this-\u003eperPage())\n            -\u003ewhen($this-\u003ehasPreviousPage(), fn (Menu $menu) =\u003e $menu-\u003eline('0. Previous'))\n            -\u003ewhen($this-\u003ehasNextPage(), fn (Menu $menu) =\u003e $menu-\u003eline('#. Next'))\n            -\u003etext('Powered by Sparors');\n    }\n\n    public function setTransferType(Context $context, Record $record)\n    {\n        $transferType = '2' === $context-\u003einput() ? 'deposit' : 'withdraw';\n\n        $record-\u003eset('transfer_type', $transferType);\n    }\n\n    public function getItems(): array\n    {\n        return [\n            'Transfer',\n            'Deposit',\n            'Withdraw',\n            'New Account',\n            'Helpline',\n        ];\n    }\n\n    public function perPage(): int\n    {\n        return 3;\n    }\n}\n```\n\nAn example of a final state\n\n``` php\n\u003c?php\n\nnamespace App\\Ussd\\States;\n\nuse Sparors\\Ussd\\Attributes\\Terminate;\nuse Sparors\\Ussd\\Contracts\\State;\nuse Sparors\\Ussd\\Menu;\nuse Sparors\\Ussd\\Record;\n\n#[Terminate]\nclass GoodByeState implements State\n{\n    public function render(Record $record): Menu\n    {\n       return Menu::build()-\u003etext('Bye bye ' . $record-\u003eget('name'));\n    }\n}\n```\n\nDue to some limitation with PHP 8.0, you can not pass class instance to attributes. So to overcome this limitation, you can pass an array with the full class path as the first element and the rest should be argument required. eg.\n\n``` php\n\u003c?php\n\nnamespace App\\Ussd\\States;\n\nuse Sparors\\Ussd\\Attributes\\Transition;\nuse Sparors\\Ussd\\Contracts\\State;\nuse Sparors\\Ussd\\Menu;\n\n#[Transition(MakePaymentAction::class, [Equal::class, 1])]\n#[Transition(InvalidInputState::class, Fallback::class)]\nclass WelcomeState implements State\n{\n    public function render(): Menu\n    {\n       return Menu::build()-\u003etext('Welcome');\n    }\n}\n```\n\n### Building USSD\n\n```php\n\u003c?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Ussd\\Actions\\MenuAction;\nuse App\\Ussd\\Responses\\AfricasTalkingResponse;\nuse App\\Ussd\\States\\WouldYouLikeToContinueState;\nuse Illuminate\\Http\\Request;\nuse Sparors\\Ussd\\Context;\nuse Sparors\\Ussd\\ContinuingMode;\nuse Sparors\\Ussd\\Ussd;\n\nclass UssdController extends Controller\n{\n    public function __invoke(Request $request)\n    {\n        $lastText = $request-\u003einput('text') ?? '';\n\n        if (strlen($lastText) \u003e 0) {\n            $lastText = explode('*', $lastText);\n            $lastText = end($lastText);\n        }\n\n        return Ussd::build(\n            Context::create(\n                $request-\u003einput('sessionId'),\n                $request-\u003einput('phoneNumber'),\n                $lastText\n            )\n            -\u003ewith(['phone_number' =\u003e $request-\u003einput('phoneNumber')])\n        )\n        -\u003euseInitialState(MenuAction::class)\n        -\u003euseContinuingState(ContinuingMode::CONFIRM, now()-\u003eaddMinute(), WouldYouLikeToContinueState::class)\n        -\u003euseResponse(AfricasTalkingResponse::class)\n        -\u003erun();\n    }\n}\n```\n\n### Conditional Branching\n\nUse USSD action to conditional decide which state should be the next.\n\n``` php\n\u003c?php\n\nnamespace App\\Http\\Ussd\\Actions;\n\nuse Sparors\\Ussd\\Contracts\\Action;\nuse App\\Http\\Ussd\\States\\PaymentSuccessState;\nuse App\\Http\\Ussd\\States\\PaymentErrorState;\n\nclass MakePayment extends Action\n{\n    public function execute(Record $record): string\n    {\n        $response = Http::post('/payment', [\n            'phone_number' =\u003e $record-\u003ephoneNumber\n        ]);\n\n        if ($response-\u003eok()) {\n            return PaymentSuccessState::class;\n        }\n\n        return PaymentErrorState::class;\n    }\n}\n```\n\n### Group logic with USSD configurator\n\nYou can use configurator to simplify repetitive parts of your application so they can be shared easily.\n\n```php\n\u003c?php\n\nnamespace App\\Http\\Ussd\\Configurators;\n\nuse Sparors\\Ussd\\Contracts\\Configurator;\n\nclass Nsano implements Configurator\n{\n    public function configure(Ussd $ussd): void\n    {\n        $ussd-\u003esetResponse(function (string $message, int $terminating) {\n            return [\n                'USSDResp' =\u003e [\n                    'action' =\u003e $termination ? 'prompt': 'input',\n                    'menus' =\u003e '',\n                    'title' =\u003e $message\n                ]\n            ];\n        });\n    }\n}\n?\u003e\n```\n\n### Testing\n\nYou can easily test how your ussd application with our testing utilities\n\n``` php\n\u003c?php\n\nnamespace App\\Tests\\Feature;\n\nuse Sparors\\Ussd\\Ussd;\n\nfinal class UssdTest extends TestCase\n{\n    public function test_ussd_runs()\n    {\n        Ussd::test(WelcomeState::class)\n            -\u003eadditional(['network' =\u003e 'MTN', 'phone_number' =\u003e '123123123'])\n            -\u003eactingAs('isaac')\n            -\u003estart()\n            -\u003eassertSee('Welcome...')\n            -\u003eassertContextHas('network', 'MTN')\n            -\u003eassertContextHas('phone_number')\n            -\u003eassertContextMissing('name')\n            -\u003einput('1')\n            -\u003eassertSee('Now see the magic...')\n            -\u003eassertRecordHas('choice');\n    }\n}\n```\n\n## Documentation\n\nYou'll find the documentation on [https://github.com/sparors/laravel-ussd/wiki](https://github.com/sparors/laravel-ussd/wiki) for V3 and [https://sparors.github.io/ussd-docs](https://sparors.github.io/ussd-docs/) for V2.\n\n## Change log\n\nPlease see the [changelog](changelog.md) for more information on what has changed recently.\n\n## Contributing\n\nPlease see [contributing.md](contributing.md) for details and a todolist.\n\n## Security\n\nIf you discover any security related issues, please email isaacsai030@gmail.com instead of using the issue tracker.\n\n## Credits\n\n- [Sparors Inc][link-author]\n- [All Contributors][link-contributors]\n\n## License\n\nMIT. Please see the [license file](LICENSE) for more information.\n\n[ico-version]: https://img.shields.io/packagist/v/sparors/laravel-ussd.svg?style=flat-square\n[ico-downloads]: https://img.shields.io/packagist/dt/sparors/laravel-ussd.svg?style=flat-square\n[ico-github]: https://img.shields.io/github/actions/workflow/status/sparors/laravel-ussd/php.yml?style=flat-square\n\n[link-packagist]: https://packagist.org/packages/sparors/laravel-ussd\n[link-downloads]: https://packagist.org/packages/sparors/laravel-ussd\n[link-github]: https://github.com/sparors/laravel-ussd/actions/workflows/php.yml\n[link-author]: https://github.com/sparors\n[link-contributors]: ../../contributors\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsparors%2Flaravel-ussd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsparors%2Flaravel-ussd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsparors%2Flaravel-ussd/lists"}