├── .gitignore ├── .yarn.lock.swp ├── LICENSE ├── README.md ├── deploy.sh ├── docs ├── .vuepress │ ├── config.js │ ├── public │ │ ├── create-apikey.png │ │ ├── create-apiuser.png │ │ ├── create-apiuser1.png │ │ ├── create-apiuser2.png │ │ ├── create-apiuser3.png │ │ ├── create-apiuser4.png │ │ ├── create_apikey.png │ │ ├── create_apiuser.png │ │ ├── get-apiuser.png │ │ ├── get-balance.png │ │ ├── get_apiuser_details.png │ │ ├── logon-partnerportal.png │ │ ├── momo.png │ │ ├── oauth_img.png │ │ ├── portal_create_apiuser.png │ │ ├── portal_create_user_submission.png │ │ ├── preapproval.png │ │ ├── products.png │ │ ├── register-app.png │ │ ├── request-response.png │ │ ├── request-to-pay.png │ │ ├── transfer.png │ │ ├── validate-account.png │ │ ├── validate_account_holder.png │ │ ├── your-applications.png │ │ └── your-subscriptions.png │ ├── style.styl │ └── theme │ │ ├── AlgoliaSearchBox.vue │ │ ├── DropdownLink.vue │ │ ├── DropdownTransition.vue │ │ ├── Home.vue │ │ ├── Layout.vue │ │ ├── NavLink.vue │ │ ├── NavLinks.vue │ │ ├── Navbar.vue │ │ ├── NotFound.vue │ │ ├── Page.vue │ │ ├── SWUpdatePopup.vue │ │ ├── SearchBox.vue │ │ ├── Sidebar.vue │ │ ├── SidebarButton.vue │ │ ├── SidebarGroup.vue │ │ ├── SidebarLink.vue │ │ ├── fonts │ │ ├── MTNBrighterSans-Bold.ttf │ │ └── MTNBrighterSans-Regular.ttf │ │ ├── search.svg │ │ ├── styles │ │ ├── arrow.styl │ │ ├── code.styl │ │ ├── config.styl │ │ ├── custom-blocks.styl │ │ ├── mobile.styl │ │ ├── nprogress.styl │ │ ├── theme.styl │ │ ├── toc.styl │ │ └── wrapper.styl │ │ └── util.js ├── README.md ├── api-description │ └── README.md ├── brand-guidelines │ └── README.md ├── common-error-codes │ └── README.md ├── introduction │ └── README.md ├── quickstart │ └── README.md ├── testing │ └── README.md └── use-cases │ └── README.md ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | *.map 9 | dist/demo.html 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | package-lock.json 16 | 17 | # Editor directories and files 18 | .bitmap 19 | .idea 20 | .vscode 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | 26 | # firebase stuff 27 | firebase.json 28 | .firebase.rc -------------------------------------------------------------------------------- /.yarn.lock.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/.yarn.lock.swp -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Sparkplug 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | MTN MoMo Logo 4 | 5 |

6 | 7 | 8 | 9 | # MTN MoMo API Documentation 10 | 11 | > The purpose of this site is to detail the design principles, objects, behaviours and error handling for the MTN Mobile Money API. 12 | 13 | At the heart of our brand is the will to enable and support local development & transformation through technology. With that in mind, through this portal we start the journey of exposing our Mobile Money APIs to the public thus easing access for Developers and Entrepreneurs who wish to innovate. 14 | 15 | # Documentation 16 | 17 | ## Online 18 | 19 | [Online](https://mtn-momo-api-documentation.firebaseapp.com/) 20 | 21 | ## Locally 22 | 23 | Clone the repo and change directory into it 24 | 25 | ``` 26 | git clone https://github.com/sparkplug/mtn-momo-api-documentation.git 27 | cd mtn-momo-api-documentation 28 | ``` 29 | 30 | Make sure you have Yarn or NPM installed. You should then install `Vuepress` locally or globally 31 | 32 | ``` 33 | # install globally 34 | yarn global add vuepress # OR npm install -g vuepress 35 | 36 | # install as a local dependency 37 | yarn add -D vuepress # OR npm install -D vuepress 38 | 39 | ``` 40 | 41 | You can now run it locally: 42 | 43 | ``` 44 | yarn docs:dev # OR npm run docs:dev 45 | ``` 46 | 47 | To generate static assets: 48 | 49 | ``` 50 | yarn docs:build # Or npm run docs:build 51 | ``` 52 | 53 | ## License 54 | 55 | MIT -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # abort on errors 4 | set -e 5 | 6 | # build 7 | npm run docs:build 8 | 9 | # navigate into the build output directory 10 | cd docs/.vuepress/dist 11 | 12 | # if you are deploying to a custom domain 13 | # echo 'www.example.com' > CNAME 14 | 15 | git init 16 | git add -A 17 | git commit -m 'deploy' 18 | 19 | # if you are deploying to https://.github.io 20 | # git push -f git@github.com:/.github.io.git master 21 | 22 | # if you are deploying to https://.github.io/ 23 | git push -f git@github.com:sparkplug/mtn-momo-api-documentation.git master:gh-pages 24 | 25 | cd - -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: 'MTN Mobile Money API', 3 | description: 'Official API Documentation', 4 | base: '/mtn-momo-api-documentation/', 5 | themeConfig: { 6 | sidebarDepth: 3, 7 | sidebar: [ 8 | '/', 9 | ['/introduction/', 'Introduction'], 10 | ['/quickstart/', 'Quickstart Guide'], 11 | ['/api-description/', 'API User & API Key Management'], 12 | ['/use-cases/', 'Use Cases'], 13 | ['/testing/', 'Testing'], 14 | ['/common-error-codes/', 'Common Error Codes'], 15 | ['/brand-guidelines/', 'Brand Guidelines'] 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/.vuepress/public/create-apikey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/create-apikey.png -------------------------------------------------------------------------------- /docs/.vuepress/public/create-apiuser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/create-apiuser.png -------------------------------------------------------------------------------- /docs/.vuepress/public/create-apiuser1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/create-apiuser1.png -------------------------------------------------------------------------------- /docs/.vuepress/public/create-apiuser2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/create-apiuser2.png -------------------------------------------------------------------------------- /docs/.vuepress/public/create-apiuser3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/create-apiuser3.png -------------------------------------------------------------------------------- /docs/.vuepress/public/create-apiuser4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/create-apiuser4.png -------------------------------------------------------------------------------- /docs/.vuepress/public/create_apikey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/create_apikey.png -------------------------------------------------------------------------------- /docs/.vuepress/public/create_apiuser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/create_apiuser.png -------------------------------------------------------------------------------- /docs/.vuepress/public/get-apiuser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/get-apiuser.png -------------------------------------------------------------------------------- /docs/.vuepress/public/get-balance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/get-balance.png -------------------------------------------------------------------------------- /docs/.vuepress/public/get_apiuser_details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/get_apiuser_details.png -------------------------------------------------------------------------------- /docs/.vuepress/public/logon-partnerportal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/logon-partnerportal.png -------------------------------------------------------------------------------- /docs/.vuepress/public/momo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/momo.png -------------------------------------------------------------------------------- /docs/.vuepress/public/oauth_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/oauth_img.png -------------------------------------------------------------------------------- /docs/.vuepress/public/portal_create_apiuser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/portal_create_apiuser.png -------------------------------------------------------------------------------- /docs/.vuepress/public/portal_create_user_submission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/portal_create_user_submission.png -------------------------------------------------------------------------------- /docs/.vuepress/public/preapproval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/preapproval.png -------------------------------------------------------------------------------- /docs/.vuepress/public/products.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/products.png -------------------------------------------------------------------------------- /docs/.vuepress/public/register-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/register-app.png -------------------------------------------------------------------------------- /docs/.vuepress/public/request-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/request-response.png -------------------------------------------------------------------------------- /docs/.vuepress/public/request-to-pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/request-to-pay.png -------------------------------------------------------------------------------- /docs/.vuepress/public/transfer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/transfer.png -------------------------------------------------------------------------------- /docs/.vuepress/public/validate-account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/validate-account.png -------------------------------------------------------------------------------- /docs/.vuepress/public/validate_account_holder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/validate_account_holder.png -------------------------------------------------------------------------------- /docs/.vuepress/public/your-applications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/your-applications.png -------------------------------------------------------------------------------- /docs/.vuepress/public/your-subscriptions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/public/your-subscriptions.png -------------------------------------------------------------------------------- /docs/.vuepress/style.styl: -------------------------------------------------------------------------------- 1 | .home .hero img 2 | max-height 300px 3 | 4 | .search-box .suggestion a 5 | white-space normal 6 | 7 | @font-face { 8 | font-family: "MTN Brighter Sans"; 9 | src: url("/theme/fonts/MTNBrighterSans-Regular.ttf") format("truetype"); 10 | font-weight: 300; 11 | font-style:normal; 12 | font-display:auto; 13 | text-rendering:optimizeLegibility; 14 | } 15 | 16 | @font-face { 17 | font-family: "MTN Brighter Sans"; 18 | src: url("/theme/fonts/MTNBrighterSans-Bold.ttf") format("truetype"); 19 | font-weight: 700; 20 | font-style:normal; 21 | font-display:auto; 22 | text-rendering:optimizeLegibility; 23 | } 24 | 25 | body { 26 | font-family: "MTN Brighter Sans","Helvetica Neue",Helvetica,Arial,sans-serif; 27 | font-weight: 300 28 | } 29 | 30 | h1,h2,h3,h4,h5,h6 { 31 | font-family: "MTN Brighter Sans","Helvetica Neue",Helvetica,Arial,sans-serif; 32 | font-weight: 700 33 | } -------------------------------------------------------------------------------- /docs/.vuepress/theme/AlgoliaSearchBox.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 60 | 61 | 157 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/DropdownLink.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 78 | 79 | 182 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/DropdownTransition.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 28 | 29 | 34 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/Home.vue: -------------------------------------------------------------------------------- 1 | 50 | 51 | 71 | 72 | 162 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/Layout.vue: -------------------------------------------------------------------------------- 1 | 58 | 59 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/NavLink.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 50 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/NavLinks.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 117 | 118 | 152 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/Navbar.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 87 | 88 | 134 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/NotFound.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 27 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/Page.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 196 | 197 | 247 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/SWUpdatePopup.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 60 | 61 | 86 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/SearchBox.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 153 | 154 | 239 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/Sidebar.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 80 | 81 | 114 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/SidebarButton.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 29 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/SidebarGroup.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 43 | 44 | 78 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/SidebarLink.vue: -------------------------------------------------------------------------------- 1 | 60 | 61 | 92 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/fonts/MTNBrighterSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/theme/fonts/MTNBrighterSans-Bold.ttf -------------------------------------------------------------------------------- /docs/.vuepress/theme/fonts/MTNBrighterSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkplug/mtn-momo-api-documentation/5d1fe685975058104e9fe66f0cbdb68dc891fdb9/docs/.vuepress/theme/fonts/MTNBrighterSans-Regular.ttf -------------------------------------------------------------------------------- /docs/.vuepress/theme/search.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/styles/arrow.styl: -------------------------------------------------------------------------------- 1 | @require './config' 2 | 3 | .arrow 4 | display inline-block 5 | width 0 6 | height 0 7 | &.up 8 | border-left 4px solid transparent 9 | border-right 4px solid transparent 10 | border-bottom 6px solid $arrowBgColor 11 | &.down 12 | border-left 4px solid transparent 13 | border-right 4px solid transparent 14 | border-top 6px solid $arrowBgColor 15 | &.right 16 | border-top 4px solid transparent 17 | border-bottom 4px solid transparent 18 | border-left 6px solid $arrowBgColor 19 | &.left 20 | border-top 4px solid transparent 21 | border-bottom 4px solid transparent 22 | border-right 6px solid $arrowBgColor 23 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/styles/code.styl: -------------------------------------------------------------------------------- 1 | @require './config' 2 | 3 | .content 4 | code 5 | color lighten($textColor, 20%) 6 | padding 0.25rem 0.5rem 7 | margin 0 8 | font-size 0.85em 9 | background-color rgba(27,31,35,0.05) 10 | border-radius 3px 11 | 12 | .content 13 | pre, pre[class*="language-"] 14 | line-height 1.4 15 | padding 1.25rem 1.5rem 16 | margin 0.85rem 0 17 | background-color $codeBgColor 18 | border-radius 6px 19 | overflow auto 20 | code 21 | color #fff 22 | padding 0 23 | background-color transparent 24 | border-radius 0 25 | 26 | div[class*="language-"] 27 | position relative 28 | background-color $codeBgColor 29 | border-radius 6px 30 | .highlight-lines 31 | user-select none 32 | padding-top 1.3rem 33 | position absolute 34 | top 0 35 | left 0 36 | width 100% 37 | line-height 1.4 38 | .highlighted 39 | background-color rgba(0, 0, 0, 66%) 40 | pre, pre[class*="language-"] 41 | background transparent 42 | position relative 43 | z-index 1 44 | &::before 45 | position absolute 46 | z-index 3 47 | top 0.8em 48 | right 1em 49 | font-size 0.75rem 50 | color rgba(255, 255, 255, 0.4) 51 | &:not(.line-numbers-mode) 52 | .line-numbers-wrapper 53 | display none 54 | &.line-numbers-mode 55 | .highlight-lines .highlighted 56 | position relative 57 | &:before 58 | content ' ' 59 | position absolute 60 | z-index 3 61 | left 0 62 | top 0 63 | display block 64 | width $lineNumbersWrapperWidth 65 | height 100% 66 | background-color rgba(0, 0, 0, 66%) 67 | pre 68 | padding-left $lineNumbersWrapperWidth + 1 rem 69 | vertical-align middle 70 | .line-numbers-wrapper 71 | position absolute 72 | top 0 73 | width $lineNumbersWrapperWidth 74 | text-align center 75 | color rgba(255, 255, 255, 0.3) 76 | padding 1.25rem 0 77 | line-height 1.4 78 | br 79 | user-select none 80 | .line-number 81 | position relative 82 | z-index 4 83 | user-select none 84 | font-size 0.85em 85 | &::after 86 | content '' 87 | position absolute 88 | z-index 2 89 | top 0 90 | left 0 91 | width $lineNumbersWrapperWidth 92 | height 100% 93 | border-radius 6px 0 0 6px 94 | border-right 1px solid rgba(0, 0, 0, 66%) 95 | background-color $codeBgColor 96 | 97 | 98 | for lang in $codeLang 99 | div{'[class~="language-' + lang + '"]'} 100 | &:before 101 | content ('' + lang) 102 | 103 | div[class~="language-javascript"] 104 | &:before 105 | content "js" 106 | 107 | div[class~="language-typescript"] 108 | &:before 109 | content "ts" 110 | 111 | div[class~="language-markup"] 112 | &:before 113 | content "html" 114 | 115 | div[class~="language-markdown"] 116 | &:before 117 | content "md" 118 | 119 | div[class~="language-json"]:before 120 | content "json" 121 | 122 | div[class~="language-ruby"]:before 123 | content "rb" 124 | 125 | div[class~="language-python"]:before 126 | content "py" 127 | 128 | div[class~="language-bash"]:before 129 | content "sh" 130 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/styles/config.styl: -------------------------------------------------------------------------------- 1 | // colors 2 | $accentColor = #fccc00 3 | $textColor = #2c3e50 4 | $borderColor = #eaecef 5 | $codeBgColor = #282c34 6 | $arrowBgColor = #000 7 | 8 | // layout 9 | $navbarHeight = 3.6rem 10 | $sidebarWidth = 20rem 11 | $contentWidth = 740px 12 | 13 | // responsive breakpoints 14 | $MQNarrow = 959px 15 | $MQMobile = 719px 16 | $MQMobileNarrow = 419px 17 | 18 | // code 19 | $lineNumbersWrapperWidth = 3.5rem 20 | $codeLang = js ts html md vue css sass scss less stylus go java c sh yaml py 21 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/styles/custom-blocks.styl: -------------------------------------------------------------------------------- 1 | .custom-block 2 | .custom-block-title 3 | font-weight 600 4 | margin-bottom -0.4rem 5 | &.tip, &.warning, &.danger 6 | padding .1rem 1.5rem 7 | border-left-width .5rem 8 | border-left-style solid 9 | margin 1rem 0 10 | &.tip 11 | background-color #f3f5f7 12 | border-color #42b983 13 | &.warning 14 | background-color rgba(255,229,100,.3) 15 | border-color darken(#ffe564, 35%) 16 | color darken(#ffe564, 70%) 17 | .custom-block-title 18 | color darken(#ffe564, 50%) 19 | a 20 | color $textColor 21 | &.danger 22 | background-color #ffe6e6 23 | border-color darken(red, 20%) 24 | color darken(red, 70%) 25 | .custom-block-title 26 | color darken(red, 40%) 27 | a 28 | color $textColor 29 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/styles/mobile.styl: -------------------------------------------------------------------------------- 1 | @require './config' 2 | 3 | $mobileSidebarWidth = $sidebarWidth * 0.82 4 | 5 | // narrow desktop / iPad 6 | @media (max-width: $MQNarrow) 7 | .sidebar 8 | font-size 15px 9 | width $mobileSidebarWidth 10 | .page 11 | padding-left $mobileSidebarWidth 12 | 13 | // wide mobile 14 | @media (max-width: $MQMobile) 15 | .sidebar 16 | top 0 17 | padding-top $navbarHeight 18 | transform translateX(-100%) 19 | transition transform .2s ease 20 | .page 21 | padding-left 0 22 | .theme-container 23 | &.sidebar-open 24 | .sidebar 25 | transform translateX(0) 26 | &.no-navbar 27 | .sidebar 28 | padding-top: 0 29 | 30 | // narrow mobile 31 | @media (max-width: $MQMobileNarrow) 32 | h1 33 | font-size 1.9rem 34 | .content 35 | div[class*="language-"] 36 | margin 0.85rem -1.5rem 37 | border-radius 0 38 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/styles/nprogress.styl: -------------------------------------------------------------------------------- 1 | #nprogress 2 | pointer-events none 3 | .bar 4 | background $accentColor 5 | position fixed 6 | z-index 1031 7 | top 0 8 | left 0 9 | width 100% 10 | height 2px 11 | .peg 12 | display block 13 | position absolute 14 | right 0px 15 | width 100px 16 | height 100% 17 | box-shadow 0 0 10px $accentColor, 0 0 5px $accentColor 18 | opacity 1.0 19 | transform rotate(3deg) translate(0px, -4px) 20 | .spinner 21 | display block 22 | position fixed 23 | z-index 1031 24 | top 15px 25 | right 15px 26 | .spinner-icon 27 | width 18px 28 | height 18px 29 | box-sizing border-box 30 | border solid 2px transparent 31 | border-top-color $accentColor 32 | border-left-color $accentColor 33 | border-radius 50% 34 | animation nprogress-spinner 400ms linear infinite 35 | 36 | .nprogress-custom-parent 37 | overflow hidden 38 | position relative 39 | 40 | .nprogress-custom-parent #nprogress .spinner, 41 | .nprogress-custom-parent #nprogress .bar 42 | position absolute 43 | 44 | @keyframes nprogress-spinner 45 | 0% 46 | transform rotate(0deg) 47 | 100% 48 | transform rotate(360deg) 49 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/styles/theme.styl: -------------------------------------------------------------------------------- 1 | @require './config' 2 | @require './nprogress' 3 | @require './code' 4 | @require './custom-blocks' 5 | @require './arrow' 6 | @require './wrapper' 7 | @require './toc' 8 | 9 | .home .hero img 10 | max-height 280px 11 | 12 | .search-box .suggestion a 13 | white-space normal 14 | 15 | @font-face { 16 | font-family: "MTN Brighter Sans"; 17 | src: url("../fonts/MTNBrighterSans-Regular.ttf") format("truetype"); 18 | font-weight: 300; 19 | font-style:normal; 20 | font-display:auto; 21 | text-rendering:optimizeLegibility; 22 | } 23 | 24 | @font-face { 25 | font-family: "MTN Brighter Sans"; 26 | src: url("../fonts/MTNBrighterSans-Bold.ttf") format("truetype"); 27 | font-weight: 700; 28 | font-style:normal; 29 | font-display:auto; 30 | text-rendering:optimizeLegibility; 31 | } 32 | 33 | body { 34 | font-family: "MTN Brighter Sans","Helvetica Neue",Helvetica,Arial,sans-serif; 35 | font-weight: 300 36 | } 37 | 38 | h1,h2,h3,h4,h5,h6 { 39 | font-family: "MTN Brighter Sans","Helvetica Neue",Helvetica,Arial,sans-serif; 40 | font-weight: 700 41 | } 42 | 43 | html, body 44 | padding 0 45 | margin 0 46 | 47 | body 48 | font-family "MTN Brighter Sans" -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif 49 | -webkit-font-smoothing antialiased 50 | -moz-osx-font-smoothing grayscale 51 | font-size 16px 52 | color $textColor 53 | 54 | .page 55 | padding-left $sidebarWidth 56 | 57 | .navbar 58 | position fixed 59 | z-index 20 60 | top 0 61 | left 0 62 | right 0 63 | height $navbarHeight 64 | background-color #fff 65 | box-sizing border-box 66 | border-bottom 1px solid $borderColor 67 | 68 | .sidebar-mask 69 | position fixed 70 | z-index 9 71 | top 0 72 | left 0 73 | width 100vw 74 | height 100vh 75 | display none 76 | 77 | .sidebar 78 | font-size 15px 79 | background-color #fff 80 | width $sidebarWidth 81 | position fixed 82 | z-index 10 83 | margin 0 84 | top $navbarHeight 85 | left 0 86 | bottom 0 87 | box-sizing border-box 88 | border-right 1px solid $borderColor 89 | overflow-y auto 90 | 91 | .content:not(.custom) 92 | @extend $wrapper 93 | > *:first-child 94 | margin-top $navbarHeight 95 | a:hover 96 | text-decoration underline 97 | p.demo 98 | padding 1rem 1.5rem 99 | border 1px solid #ddd 100 | border-radius 4px 101 | img 102 | max-width 100% 103 | 104 | .content.custom 105 | padding 0 106 | margin 0 107 | img 108 | max-width 100% 109 | 110 | a 111 | font-weight 500 112 | color $accentColor 113 | text-decoration none 114 | 115 | p a code 116 | font-weight 400 117 | color $accentColor 118 | 119 | kbd 120 | background #eee 121 | border solid 0.15rem #ddd 122 | border-bottom solid 0.25rem #ddd 123 | border-radius 0.15rem 124 | padding 0 0.15em 125 | 126 | blockquote 127 | font-size 1.2rem 128 | color #999 129 | border-left .25rem solid #dfe2e5 130 | margin-left 0 131 | padding-left 1rem 132 | 133 | ul, ol 134 | padding-left 1.2em 135 | 136 | strong 137 | font-weight 600 138 | 139 | h1, h2, h3, h4, h5, h6 140 | font-weight 600 141 | line-height 1.25 142 | .content:not(.custom) > & 143 | margin-top (0.5rem - $navbarHeight) 144 | padding-top ($navbarHeight + 1rem) 145 | margin-bottom 0 146 | &:first-child 147 | margin-top -1.5rem 148 | margin-bottom 1rem 149 | + p, + pre, + .custom-block 150 | margin-top 2rem 151 | &:hover .header-anchor 152 | opacity: 1 153 | 154 | h1 155 | font-size 2.2rem 156 | 157 | h2 158 | font-size 1.65rem 159 | padding-bottom .3rem 160 | border-bottom 1px solid $borderColor 161 | 162 | h3 163 | font-size 1.35rem 164 | 165 | a.header-anchor 166 | font-size 0.85em 167 | float left 168 | margin-left -0.87em 169 | padding-right 0.23em 170 | margin-top 0.125em 171 | opacity 0 172 | &:hover 173 | text-decoration none 174 | 175 | code, kbd, .line-number 176 | font-family source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace 177 | 178 | p, ul, ol 179 | line-height 1.7 180 | 181 | hr 182 | border 0 183 | border-top 1px solid $borderColor 184 | 185 | table 186 | border-collapse collapse 187 | margin 1rem 0 188 | display: block 189 | overflow-x: auto 190 | 191 | tr 192 | border-top 1px solid #dfe2e5 193 | &:nth-child(2n) 194 | background-color #f6f8fa 195 | 196 | th, td 197 | border 1px solid #dfe2e5 198 | padding .6em 1em 199 | 200 | .custom-layout 201 | padding-top $navbarHeight 202 | 203 | .theme-container 204 | &.sidebar-open 205 | .sidebar-mask 206 | display: block 207 | &.no-navbar 208 | .content:not(.custom) > h1, h2, h3, h4, h5, h6 209 | margin-top 1.5rem 210 | padding-top 0 211 | .sidebar 212 | top 0 213 | .custom-layout 214 | padding-top 0 215 | 216 | 217 | @media (min-width: ($MQMobile + 1px)) 218 | .theme-container.no-sidebar 219 | .sidebar 220 | display none 221 | .page 222 | padding-left 0 223 | 224 | @require './mobile.styl' 225 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/styles/toc.styl: -------------------------------------------------------------------------------- 1 | .table-of-contents 2 | .badge 3 | vertical-align middle 4 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/styles/wrapper.styl: -------------------------------------------------------------------------------- 1 | $wrapper 2 | max-width $contentWidth 3 | margin 0 auto 4 | padding 2rem 2.5rem 5 | @media (max-width: $MQNarrow) 6 | padding 2rem 7 | @media (max-width: $MQMobileNarrow) 8 | padding 1.5rem 9 | 10 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/util.js: -------------------------------------------------------------------------------- 1 | export const hashRE = /#.*$/ 2 | export const extRE = /\.(md|html)$/ 3 | export const endingSlashRE = /\/$/ 4 | export const outboundRE = /^(https?:|mailto:|tel:)/ 5 | 6 | export function normalize (path) { 7 | return decodeURI(path) 8 | .replace(hashRE, '') 9 | .replace(extRE, '') 10 | } 11 | 12 | export function getHash (path) { 13 | const match = path.match(hashRE) 14 | if (match) { 15 | return match[0] 16 | } 17 | } 18 | 19 | export function isExternal (path) { 20 | return outboundRE.test(path) 21 | } 22 | 23 | export function isMailto (path) { 24 | return /^mailto:/.test(path) 25 | } 26 | 27 | export function isTel (path) { 28 | return /^tel:/.test(path) 29 | } 30 | 31 | export function ensureExt (path) { 32 | if (isExternal(path)) { 33 | return path 34 | } 35 | const hashMatch = path.match(hashRE) 36 | const hash = hashMatch ? hashMatch[0] : '' 37 | const normalized = normalize(path) 38 | 39 | if (endingSlashRE.test(normalized)) { 40 | return path 41 | } 42 | return normalized + '.html' + hash 43 | } 44 | 45 | export function isActive (route, path) { 46 | const routeHash = route.hash 47 | const linkHash = getHash(path) 48 | if (linkHash && routeHash !== linkHash) { 49 | return false 50 | } 51 | const routePath = normalize(route.path) 52 | const pagePath = normalize(path) 53 | return routePath === pagePath 54 | } 55 | 56 | export function resolvePage (pages, rawPath, base) { 57 | if (base) { 58 | rawPath = resolvePath(rawPath, base) 59 | } 60 | const path = normalize(rawPath) 61 | for (let i = 0; i < pages.length; i++) { 62 | if (normalize(pages[i].path) === path) { 63 | return Object.assign({}, pages[i], { 64 | type: 'page', 65 | path: ensureExt(rawPath) 66 | }) 67 | } 68 | } 69 | console.error(`[vuepress] No matching page found for sidebar item "${rawPath}"`) 70 | return {} 71 | } 72 | 73 | function resolvePath (relative, base, append) { 74 | const firstChar = relative.charAt(0) 75 | if (firstChar === '/') { 76 | return relative 77 | } 78 | 79 | if (firstChar === '?' || firstChar === '#') { 80 | return base + relative 81 | } 82 | 83 | const stack = base.split('/') 84 | 85 | // remove trailing segment if: 86 | // - not appending 87 | // - appending to trailing slash (last segment is empty) 88 | if (!append || !stack[stack.length - 1]) { 89 | stack.pop() 90 | } 91 | 92 | // resolve relative path 93 | const segments = relative.replace(/^\//, '').split('/') 94 | for (let i = 0; i < segments.length; i++) { 95 | const segment = segments[i] 96 | if (segment === '..') { 97 | stack.pop() 98 | } else if (segment !== '.') { 99 | stack.push(segment) 100 | } 101 | } 102 | 103 | // ensure leading slash 104 | if (stack[0] !== '') { 105 | stack.unshift('') 106 | } 107 | 108 | return stack.join('/') 109 | } 110 | 111 | export function resolveSidebarItems (page, route, site, localePath) { 112 | const { pages, themeConfig } = site 113 | 114 | const localeConfig = localePath && themeConfig.locales 115 | ? themeConfig.locales[localePath] || themeConfig 116 | : themeConfig 117 | 118 | const pageSidebarConfig = page.frontmatter.sidebar || localeConfig.sidebar || themeConfig.sidebar 119 | if (pageSidebarConfig === 'auto') { 120 | return resolveHeaders(page) 121 | } 122 | 123 | const sidebarConfig = localeConfig.sidebar || themeConfig.sidebar 124 | if (!sidebarConfig) { 125 | return [] 126 | } else { 127 | const { base, config } = resolveMatchingConfig(route, sidebarConfig) 128 | return config 129 | ? config.map(item => resolveItem(item, pages, base)) 130 | : [] 131 | } 132 | } 133 | 134 | function resolveHeaders (page) { 135 | const headers = groupHeaders(page.headers || []) 136 | return [{ 137 | type: 'group', 138 | collapsable: false, 139 | title: page.title, 140 | children: headers.map(h => ({ 141 | type: 'auto', 142 | title: h.title, 143 | basePath: page.path, 144 | path: page.path + '#' + h.slug, 145 | children: h.children || [] 146 | })) 147 | }] 148 | } 149 | 150 | export function groupHeaders (headers) { 151 | // group h3s under h2 152 | headers = headers.map(h => Object.assign({}, h)) 153 | let lastH2 154 | headers.forEach(h => { 155 | if (h.level === 2) { 156 | lastH2 = h 157 | } else if (lastH2) { 158 | (lastH2.children || (lastH2.children = [])).push(h) 159 | } 160 | }) 161 | return headers.filter(h => h.level === 2) 162 | } 163 | 164 | export function resolveNavLinkItem (linkItem) { 165 | return Object.assign(linkItem, { 166 | type: linkItem.items && linkItem.items.length ? 'links' : 'link' 167 | }) 168 | } 169 | 170 | export function resolveMatchingConfig (route, config) { 171 | if (Array.isArray(config)) { 172 | return { 173 | base: '/', 174 | config: config 175 | } 176 | } 177 | for (const base in config) { 178 | if (ensureEndingSlash(route.path).indexOf(base) === 0) { 179 | return { 180 | base, 181 | config: config[base] 182 | } 183 | } 184 | } 185 | return {} 186 | } 187 | 188 | function ensureEndingSlash (path) { 189 | return /(\.html|\/)$/.test(path) 190 | ? path 191 | : path + '/' 192 | } 193 | 194 | function resolveItem (item, pages, base, isNested) { 195 | if (typeof item === 'string') { 196 | return resolvePage(pages, item, base) 197 | } else if (Array.isArray(item)) { 198 | return Object.assign(resolvePage(pages, item[0], base), { 199 | title: item[1] 200 | }) 201 | } else { 202 | if (isNested) { 203 | console.error( 204 | '[vuepress] Nested sidebar groups are not supported. ' + 205 | 'Consider using navbar + categories instead.' 206 | ) 207 | } 208 | const children = item.children || [] 209 | return { 210 | type: 'group', 211 | title: item.title, 212 | children: children.map(child => resolveItem(child, pages, base, true)), 213 | collapsable: item.collapsable !== false 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /momo.png 4 | actionText: Introduction → 5 | actionLink: /introduction/ 6 | footer: MIT Licensed | Copyright © 2018-present MTN Uganda 7 | --- 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/api-description/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: API User & API Key Management 3 | sidebarDepth: 3 4 | --- 5 | 6 | # API User and API Key Management 7 | 8 | ## Authentication 9 | 10 | There are two credentials used in the Open API. 11 | 12 | - Subscription Key 13 | - API User and API Key for Oauth 2.0 14 | 15 | The subscription key is used to give access to APIs in the API Manager portal. A user is assigned a subscription Key as and when the user subscribes to products in the API Manager Portal. 16 | 17 | The API User and API Key are used to grant access to the wallet system in a specific country. API user and Key are wholly managed by the merchant through Partner Portal. 18 | 19 | Merchants are allowed to generate/revoke API Keys through the Partner Portal. 20 | 21 | However, on Sandbox Environment a Provisioning API is exposed to enable developers generate own API User and API Key for testing purposes only. 22 | 23 | ### Subscription Key 24 | The subscription key is part of the header of all request sent to the API Manager. The subscription key can be found under user profile in the API Manager Portal. 25 | 26 | The subscription key is assigned to the `Ocp-Apim-Subscription-Key` parameter of the header. 27 | 28 | ### API User And API Key Management 29 | The API user and API key are provisioned differently in the sandbox and production environment. 30 | 31 | In the Sandbox a provisioning API is used to create the API User and API Key, whereas in the production environment the provisioning is done through the Merchant Portal. 32 | 33 | The sections below describe the different steps required in creating API User and API key in Sandbox and Production Environments. 34 | 35 | ## Sandbox Provisioning 36 | 37 | ### Create API User 38 | 39 | Create API User 40 | 41 | a) The Provider sends a POST `{baseURL}/apiuser` request to Wallet platform. 42 | 43 | b) The Provider specifies the UUID Reference ID in the request Header and the subscription Key. 44 | 45 | c) Reference ID will be used as the User ID for the API user to be created. 46 | 47 | d) Wallet Platform creates the User and responds with 201 48 | 49 | ### Example 50 | 51 | **Request:** 52 | 53 | POST `{baseURL}/apiuser HTTP/1.1` 54 | 55 | Host: `momodeveloper.mtn.com` 56 | 57 | X-Reference-Id: `c72025f5-5cd1-4630-99e4-8ba4722fad56` 58 | 59 | Ocp-Apim-Subscription-Key: `d484a1f0d34f4301916d0f2c9e9106a2`{"providerCallbackHost": "clinic.com"} 60 | 61 | **Response:** 62 | 63 | ```201 Created``` 64 | 65 | 66 | ## Create API Key 67 | 68 | Create API Key 69 | 70 | a) The Provider sends a POST `{baseURL}/apiuser/{APIUser}/apikey` request to Wallet platform. 71 | 72 | b) The Provider specifies the API User in the URL and subscription Key in the header. 73 | 74 | c) Wallet Platform creates the API Key and responds with 201 Created with the newly Created API Key in the Body. 75 | 76 | d) Provider now has both API User and API Key created. 77 | 78 | ### Example 79 | 80 | **Request:** 81 | 82 | POST `{baseURL}/apiuser/c72025f5-5cd1-4630-99e4-8ba4722fad56/apikey HTTP/1.1` 83 | 84 | Host: `momodeveloper.mtn.com` 85 | 86 | Ocp-Apim-Subscription-Key: `d484a1f0d34f4301916d0f2c9e9106a2` 87 | 88 | **Response:** 89 | ``` 90 | HTTP/1.1 201 Created 91 | date: Wed, 10 Oct 2018 09:16:15 GMT 92 | content-type: application/json;charset=utf-8 93 | content-length: 45 94 | { 95 | "apiKey": "f1db798c98df4bcf83b538175893bbf0" 96 | } 97 | ``` 98 | ### GET API User Details 99 | 100 | It is possible to fetch API user details such as Call Back Host. However, it is not possible to fetch the API key. 101 | 102 | Provider shall be required to generate a new Key should they lose the existing one. 103 | 104 | Get API User Details 105 | 106 | a) The Provider sends a GET `{baseURL}/apiuser/{APIUser}` request to Wallet platform. 107 | 108 | b) The Provider specifies the API User in the URL and subscription Key in the header. 109 | 110 | c) Wallet Platform responds with 200 Ok and details of the user. 111 | 112 | d) TargetEnvironment is preconfigured to sandbox in the Sandbox environment, therefore Providers will not have the option of setting it to a different parameter. 113 | 114 | ### Example 115 | 116 | GET `{baseURL}/apiuser/ c72025f5-5cd1-4630-99e4-8ba4722fad56` 117 | 118 | Host: `momodeveloper.mtn.com` 119 | 120 | Ocp-Apim-Subscription-Key: `d484a1f0d34f4301916d0f2c9e9106a2` 121 | 122 | **Response:** 123 | ``` 124 | HTTP/1.1 200 Accepted 125 | date: Wed, 10 Oct 2018 09:16:15 GMT 126 | { 127 | "providerCallbackHost": "clinic.com", 128 | "targetEnvironment": "sandbox" 129 | } 130 | ``` 131 | 132 | ## Production Provisioning 133 | 134 | Production API User and API Key are provisioned and managed on the Partner Portal 135 | 136 | Partner Portal is the wallet portal granted to partners after Go-Live. The credentials for this portal are shared with partners after Go-live. 137 | 138 | ### Log on to Partner Portal 139 | 140 | The URL and Credentials for partner portal are to be obtained after Go-live 141 | 142 | logon-partnerportal 143 | 144 | ### Create API user 145 | 146 | Partner shall Click on the Top right under user profile to access the option. 147 | 148 | Partner shall click on the Create API user Option shown below. 149 | 150 | create-apiuser1 151 | 152 | Partner shall fill the in the callback URL and select a transaction wallet. 153 | 154 | create-apiuser2 155 | 156 | The table below describes the different fields required when creating an API User 157 | 158 | | Field | Optionality | Description | 159 | | ------------- | ------------- | ------------- | 160 | | Account | Mandatory | Drop down option with available wallet. Partner shall choose main Transaction Wallet | 161 | | Provider Callback Host | Mandatory | Partner Subdomain.Example `www.myshop.com` | 162 | | Payment Server URL | Mandatory | This shall be the callback url Example: `https://myshop.com/payments` | 163 | | Gateway URL | Optional | This should be left empty. | 164 | 165 | Partner shall click Ok after filling all the mandatory fields. 166 | 167 | Upon submission ECW creates the API User and API key. API Key is displayed as a flash message as shown below. 168 | 169 | create-apiuser3 170 | 171 | Its also possible for partner to delete and re-cerate an API User. 172 | 173 | ## Oauth 2.0 174 | 175 | The Open API is using Oauth 2.0 token for authentication of request. Client will request an access token using Client Credential Grant according to RFC 6749. The token received is according to RFC 6750 Bearer Token. 176 | 177 | The API user and API key are used in the basic authentication header when requesting the access token. The API user and key are managed in the Partner GUI for the country where the account is located. The Partner can create and manage API user and key from the Partner GUI. 178 | 179 | In the case of the Sandbox, the API Key and API User are managed through a Provisioning API as described on 3.2.2 180 | 181 | The received token has an expiry time. The same token can be used for transactions until it expires. A new token is requested by using the `POST` /token service in the same way as the initial token. The new token can be requested for before the previous one has expired to avoid authentication failure due to expired token. 182 | 183 | > **Important:** 184 | The token must be treated as a credential and kept secret. The party that have access to the token will be authenticated as the user that requested the token. 185 | The below sequence describes the flow for requesting a token and using the token in a request. 186 | 187 | oauth_img 188 | 189 | a) Provider system requests an access token using the API Key and API user as authentication. 190 | b) Wallet platform authenticates credentials and responds with the access token 191 | c) Provider system will use the access token for any request that is sent to Wallet Platform, e.g. `POST /requesttopay` 192 | 193 | **Note: The same token shall be used if it is not expired.** 194 | 195 | ## API Methods 196 | 197 | The API is using POST, GET, PUT methods. This section gives an overview of the interaction sequence used in the API and the usage of the methods. 198 | 199 | ### POST 200 | 201 | POSTmethod is used for creating a resource in Wallet Platform. The request includes a reference id which is used to uniquely identify the specific resource that are created by the POST request. If a POST is using a reference id that is already used, then a duplication error response will be sent to the client. 202 | 203 | Example: `POST /requesttopay` 204 | 205 | The `POST` is an asynchronous method. The Wallet Platform will validate the request to ensure that it is correct according to the API specification and then answer with HTTP 202 Accepted. The created resource will get status PENDING. Once the request has been processed the status will be updated to SUCCESSFUL or FAILED. The requester may then be notified of the final status through callback as described in 4.1 206 | 207 | ### GET 208 | 209 | GET is used for requesting information about a specific resource. The URL in the GET shall include the reference of the resource. If a resource was created with POST then the reference id that was provided in the request is used as the identity of the resource. 210 | 211 | Example: 212 | 213 | `POST /requesttopay` request is sent with X-Reference-Id = `11377cbe-374c-43f6-a019-4fb70e57b617` 214 | 215 | `GET /requesttopay/11377cbe-374c-43f6-a019-4fb70e57b617` will return the status of the request. 216 | 217 | ### PUT 218 | 219 | The `PUT` method is used by the Open API when sending callbacks. Callback is sent if a callback URL is included in the `POST` request. The Wallet Platform will only send the callback once. There is no retry on the callback if the Partner system does not respond. If the callback is not received, then the Partner system can use GET to validate the status. 220 | 221 | 222 | ## Onto the use cases 223 | 224 | Now we are ready to take a look at our [Use Cases](/use-cases/) to see how you can use our API. -------------------------------------------------------------------------------- /docs/brand-guidelines/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Brand Guidelines 3 | sidebarDepth: 2 4 | --- 5 | 6 | # Brand Guidelines 7 | 8 | MTN MoMo 9 | 10 | The MTN MoMo logo will only be used at the payment stage of your customer journey. Below are the brand guidelines for use of the MTN Brand: 11 | 12 | - When used the logo sits in the bottom right hand corner of the messaging, against a white yellow background 13 | - The distance between the logo and the border to the right and border to the bottom is always equal and equivalent size to the blue bulb that forms the MTN logo 14 | - The size of the logo will occupy the rectangle space of the ad where it features, sclaed to feature prominently relative to all the other content in the ad 15 | - The MTN yellow pantone is: 16 | - Pantone 123 C 17 | - CMYK - C:0 M:20 Y:100 K:0 18 | - RGB - R:255 G:203 B:5 19 | - HEX - #ffcc00 20 | 21 | Reference to or usage of the MTN MoMo logo in other instances other than at the payment stage in the customer journey, will be restricted a statement of endorsement i.e. Supported by MTN MoMo. The use of the MTN MoMo in these instances is prohibited. 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/common-error-codes/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Common Error Codes 3 | sidebarDepth: 2 4 | --- 5 | 6 | ## Common Error Codes 7 | 8 | The complete definitions of error codes are found in the swagger documentation. Below is the list of error codes available. 9 | 10 | Generic Error Codes 11 | 12 | | HTTP Code | Error Response Code | Description | 13 | | ------------- |-------------| -----| 14 | | 409 | N/A | Duplicated Reference Id. Cannot create new recourse | 15 | | 404 | N/A | Reference Id not found. Requested resource does not exist. | 16 | | 400 | N/A | Bad request. Request does not follow the specification. | 17 | | 401 | N/A | Authentication failed. Credentials not valid | 18 | | 500 | NOT_ALLOWED | Authorization failed. User does not have permission. | 19 | | 500 | NOT_ALLOWED_TARGET_ENVIRONMENT | Internal Error. | 20 | | 500 | INVALID_CALLBACK_URL_HOST | Not allowed target environment | 21 | | 500 | INVALID_CURRENCY | Callback URL with different host name then configured for API User | 22 | | 500 | INTERNAL_PROCESSING_ERROR | Currency not supported on the requested account | 23 | | 503 | SERVICE_UNAVAILABLE | Default error code used when there is no specific error mapping. | 24 | 25 | ## Preapproval Error Codes 26 | 27 | | HTTP Code | Error Response Code | Description | 28 | | ---------- |--------| ----- | 29 | | 500 | PAYER_NOT_FOUND | Payer not found | 30 | 31 | ## RequestToPay Error Codes 32 | 33 | | HTTP Code | Error Response Code | Description | 34 | | ------------- |-------------| -----| 35 | | 500 | PAYER_NOT_FOUND | Payer not found. Account holder is not registered. | 36 | | 500 | PAYEE_NOT_ALLOWED_TO_RECEIVE | Payee cannot receive funds due to e.g. transfer limit. | 37 | 38 | 39 | ## Transfer Error Codes 40 | 41 | | HTTP Code | Error Response Code | Description | 42 | | ------------- |-------------| -----| 43 | | 500 | NOT_ENOUGH_FUNDS | Not enough funds on payer account | 44 | | 500 | PAYER_LIMIT_REACHED | Not allowed to end due to Payer limit reached | 45 | | 500 | PAYEE_NOT_FOUND | Payee not found. Account holder is not registered | 46 | 47 | ## Validate Account Holder Error Codes 48 | 49 | | HTTP Code | Error Response Code | Description | 50 | | ------------- |-------------| -----| 51 | | 404 | N/A | Account holder is not found | 52 | -------------------------------------------------------------------------------- /docs/introduction/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | --- 4 | 5 | # Introduction 6 | 7 | The purpose of this site is to detail the design principles, objects, behaviours and error handling for the MTN Mobile Money API. The overriding goal of the API is to enable all parties to implement MTN Mobile Money APIs in a flexible, yet consistent manner. We hope to achieve this by the implementing the following principles: 8 | 9 | - Use of REST architectural principles 10 | - Providing a set of well-defined objects that are abstracted from the underlying object representations held in the various mobile money systems. This allows an API client to construct an API message without requiring specific knowledge of the target server implementation. 11 | - Creation of a standard set of transaction types and other key enumerations, removing the need for developers to map for each and every API implementation. 12 | - Use of ISO international standards for enumerators such as currency and country codes 13 | - Use of supplementary metadata and sub-types to enable use case and/or mobile money provider-specific properties to be conveyed where necessary. 14 | - Recognising that no common mobile money account identifier exists, use of a flexible construct to enable the target account(s) and transaction parties to be identified using one or multiple identifier types. 15 | 16 | The Open API is as JSON REST API that is used by Partner systems to access services in the Wallet platform. The Open API exposes services that are used by e.g. online merchants for managing payments and other financial services. This document gives an overview of the structure of the API. 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/quickstart/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Quickstart 3 | sidebarDepth: 0 4 | --- 5 | 6 | # Quickstart Guide 7 | 8 | Y'ello, in this section we'll walk you through getting up and running on our Mobile Money Open API. 9 | 10 | Here you will: 11 | 12 | 1. Signup For An Account 13 | 2. Subscribe To Our Products 14 | 3. Manage Your Subscriptions 15 | 4. Register Your App 16 | 5. Generate API User and API Key 17 | 18 | ## 1. Signup For An Account 19 | 20 | Follow this link to our developer portal and [signup](https://momodeveloper.mtn.com/signup) for an account. You should receive a confirmation email in your inbox. 21 | 22 | ::: tip 23 | An account activation link will be sent in an email. The activation link expires within 24 hours of it being sent, and you will need to register for another account. 24 | ::: 25 | 26 | ## 2. Subscribe To Our Products 27 | 28 | In the Products page on our developer portal you should see 4 items you can subscrbe to: 29 | - Collection Widget 30 | - Collections 31 | - Disbursements 32 | - Remittances 33 | 34 | ### Note: 35 | 36 | Each product will have a dropdown with a brief description, a link to the corresponding documentation and `Subscribe` button. 37 | 38 | products 39 | 40 | - Click `Subscribe` to generate access to the Product. 41 | 42 | ## 3. Manage Your Subscriptions 43 | 44 | Developers are issued a `Primary Key` and `Secondary Key` for every product. 45 | 46 | Both primary and secondary Subscription key provides access to the API. Without one of them a developer cannot access any of the APIs. 47 | 48 | Subscriptions are stored under the user profile and have no expiry. 49 | 50 | Here you can view the status of the package, date it started, conduct cancellation or activation actions, and also show or regenerate your `Primary Key` and `Secondary Key` 51 | 52 | your-subscriptions.png 53 | 54 | 55 | ## 4. Register your App 56 | 57 | Here is where you register all of your apps. 58 | 59 | Click the `Register Application` button to create your first app. When you are done creating your first app, it might look something like this: 60 | 61 | your-applications.png) 62 | 63 | 64 | ## 5. Generate API User and API Key 65 | 66 | You are now almost ready to start we building with our Mobile Money Open API. The next thing we need to do is to Provision the API User and API Key using the Sandbox Provisioning API. We do this in the next section. 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 81 | 82 | 83 | 179 | -------------------------------------------------------------------------------- /docs/testing/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Testing 3 | sidebarDepth: 2 4 | --- 5 | 6 | ## Testing 7 | 8 | To facilitate testing a set of predefined users and Test accounts are provided. These users and accounts have a predefined test scenario. A developer needs to [Signup](https://momodeveloper.mtn.com/signup) and [Subscribe](https://momodeveloper.mtn.com/products) to a Product before accessing any of the APIs. 9 | 10 | The Sandbox URL is: 11 | [https://momodeveloper.mtn.com/docs/services/collection/operations/requesttopay-POST](https://momodeveloper.mtn.com/docs/services/collection/operations/requesttopay-POST) 12 | 13 | 14 | 15 | ## OAuth Token 16 | 17 | OAuth Token is generated from the merchants’ API Key and Secret. The `API Key` and `API Secret` can be obtained through the provisioning API in Sandbox, as described in the [API User and API Key Management](/api-description/#sandbox-provisioning) section. 18 | 19 | ## Target Environment 20 | 21 | The Target Environment used in Testing is “sandbox” 22 | 23 | ## Test Currency 24 | 25 | The currency used in Sandbox is `EUR` 26 | 27 | ## Test Numbers 28 | 29 | The following Numbers are predefined with respective response for all Testcases 30 | 31 | | Number | Response | 32 | | ------------- |-------------| 33 | | 46733123450 | Failed | 34 | | 46733123451 | Rejected | 35 | | 46733123452 | Timeout | 36 | | 46733123453 | Ongoing (will answer pending first and if requested again after 30 seconds it will respond success)| 37 | | 46733123454 | Pending | 38 | | Any Other Number | Success | 39 | -------------------------------------------------------------------------------- /docs/use-cases/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Use Cases 3 | sidebarDepth: 2 4 | --- 5 | 6 | # Use Cases 7 | 8 | Here you'll find the variety of ways that you can use the API: 9 | 10 | 1. Request To Pay 11 | 2. Pre-Approval 12 | 3. Transfer 13 | 4. Validate Account Holder 14 | 5. Get Balance 15 | 16 | 17 | ## Request to Pay 18 | 19 | Request to Pay service is used for requesting a payment from a customer (Payer). This can be used by e.g. an online web shop to request a payment for a customer. The customer is requested to approve the transaction on the customer client. 20 | 21 | request-to-pay 22 | 23 | a) Customer (Payer) have selected product(s) in the merchant web shop and decided to check out. Customer select to pay with Mobile Money. 24 | 25 | b) The provider system collects the account information for the customer e.g. mobile number and calculate the total amount of the products. 26 | 27 | c) The provider system sends a request to pay (POST /requesttopay) operation to Wallet Platform. This request includes the amount and customer (Payer) account holder number. 28 | 29 | d) Wallet Platform will respond with HTTP 202 Accepted to the provider system 30 | 31 | e) Provider shall inform the customer that a payment needs to be approved, by giving information on the merchant web page. For example, the merchant could show information that payment is being processed and that customer needs to approve using the own client, e.g. USSD, mobile app. 32 | 33 | f) Wallet Platform will process the request so that the customer can approve the payment. The request to pay will be in PENDING state until the customer have approved/Rejected the payment. 34 | 35 | g) The Customer (Payer) will use his/her own client to review the payment. Customer can approve or reject the payment. 36 | 37 | h) Wallet platform will transfer the funds if the customer approves the payment. Status of the payment is updated to SUCCESSFUL or FAILED. 38 | 39 | i) If a callback URL was provided in the POST /requesttopay then a callback will be sent once the request to pay have reached a final state (SUCCESSFUL, FAILED). Note the callback will only be sent once. There is no retry. 40 | 41 | j) GET request can be used for validating the status of the transaction. GET is used if the partner system has not requested a callback by providing a callback URL or if the callback was not received. 42 | 43 | ## Pre-Approval 44 | 45 | Pre-approval is used to setup an auto debit towards a customer. The Partner can request a pre-approval from the customer. Once the customer has approved then the partner can debit the customer account without authorization from the customer. 46 | 47 | The call flow for setting up a pre-approval is like the request to pay use case. The following picture describes the sequence for pre-approval. 48 | 49 | preapproval 50 | 51 | a) The Provider sends a POST /preapproval request to Wallet platform. 52 | 53 | b) Provider shall inform the customer that pre-approval needs to be approved. 54 | 55 | c) Customer (Payer) will use the own client to view the pre-approval request. Customer can approve or reject the request. 56 | 57 | d) Callback will be sent if a callback URL was provided in the POST request. The callback is sent when the request has reach a final state (Successful, Failed). 58 | 59 | e) The Provider can use the GET request to validate the status of the pre-approval. 60 | 61 | ## Transfer 62 | 63 | Transfer is used for transferring money from the provider account to a customer. 64 | 65 | The below sequence gives an overview of the flow of the transfer use case. 66 | 67 | transfer 68 | 69 | a) The Provider sends a POST /transfer request to Wallet platform. 70 | 71 | b) Wallet platform will directly respond to indicate that the request is received and will be processed. 72 | 73 | c) Wallet platform will authorize the request to ensure that the transfer is allowed. The funds will be transferred from the provider account to the d) Payee account provided in the transfer request. 74 | 75 | e) Callback will be sent if a callback URL was provided in the POST request. The callback is sent when the request has reach a final state (SUCCESSFUL, FAILED). 76 | 77 | f) The Provider can use the GET request to validate the status of the transfer. 78 | 79 | ## Validate Account Holder 80 | 81 | Validate account holder can be used to do a validation if a customer is active and able to receive funds. The use case will only validate that the customer is available and active. It does not validate that a specific amount can be received. 82 | 83 | The sequence for the validate account holder is described below. 84 | 85 | validate-account 86 | 87 | a) The Partner can send a `GET /accountholder` request to validate is a customer is active. The Partner provides the id of that customer as part of the URL 88 | 89 | b) Wallet platform will respond with `HTTP 200` if the account holder is active. 90 | 91 | ## Get Balance 92 | 93 | Get balance request is used to check the balance on the default account connected to the API User. The following is the sequence flow for get balance use case. 94 | 95 | get-balance 96 | 97 | 98 | a) The partner will send a GET /account/balance request 99 | 100 | b) Wallet platform will respond with the available balance on the API user account. 101 | 102 | # Let's get testing 103 | 104 | We now have an understanding of the structure of the API, let us test it! -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "vuepress": "^0.14.2" 4 | }, 5 | "scripts": { 6 | "docs:dev": "vuepress dev docs", 7 | "docs:build": "vuepress build docs" 8 | } 9 | } 10 | --------------------------------------------------------------------------------