{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"992bd16e-84dc-4ef6-8cad-7ab6bea23bba","name":"OnePipe v1 - Documentation","description":"This suite of APIs provides access to an array of payment-related services like card charging, airtime, bill payment, instant loans and KYC lookup services. Some of these services come from multiple providers like Interswitch, Flutterwave and Paystack, but OnePipe wraps around them an abstraction layer with one major goal: To provide a  consistent interface to integrators regardless of underlying service provider. That way, you can switch between providers at any time, based on quality of service, business justification, etc. without starting a new integration project or changing your systems in any way.\n\n\n# Want to try it quickly?\n\nFast try\n1. Click the *run in postman* button to import the collection.\n2. Base url: `https://409a9dcf-73e5-41bb-aa2e-ba6c286173a3.mock.pstmn.io`\n3. Try the various endpoints against the mock server\n\nActual transactions\n1. Send an email to integration @ onepipe.io\n2. We would contact you with a neatly prepped postman collection and instructions to follow\n3. Then grant you temporary access to a public sandbox\n \n\n# The principles behind OnePipe\n1. Ability to add multiple providers for the same service\n2. A standard unified API interface encapsulating all feature set available across providers\n3. Ability to setup as many apps as possible and determine which provider should fulfill the service for each app. \n4. Planned: Rules based provider selection.\n\n![The general principles behind OnePipe](http://www.onepipe.io/docs/principles.jpg \"The general principles behind OnePipe\")\n\n# Index of services & providers\nHere's the list of services versus providers available at the moment. It's a list that will grow with time as we complete more integrations.\n\n## Charge\nProvide card details, OnePipe forwards to selected provider, provider debits the linked account. The underlying provider may prompt for OTP, therefore you’d supply the OTP via a follow-on call. If a charge is successful, you’d get back a charge-token with which you can initiate future transactions without providing card details afresh. Providers are:\n1. Paystack\n2. Rave by Flutterwave\n3. Quickteller\n \n## Airtime\nProvide card details, mobile number and network. OnePipe forwards to selected provider, provider debits the linked account and credits the attached number with airtime. The underlying provider may prompt for OTP, therefore you’d supply the OTP via a follow-on call. If a transaction is successful, you’d get back a charge-token with which you can initiate future transactions without providing card details afresh. Providers are:\n1. Quickteller\n \n## Bill payment\nProvide card details, customer id and a biller code. OnePipe forwards to selected provider, provider debits the linked account and makes the payment to the biller code provided. The underlying provider may prompt for OTP, therefore you’d supply the OTP via a follow-on call. If a transaction is successful, you’d get back a charge-token with which you can initiate future transactions without providing card details afresh. Providers are:\n1. Quickteller\n \n## Micro-loan request (instant)\nAfter verifying a customer’s mobile number, provide same number and OnePipe will forward to underlying provider to evaluate what loan amounts (short term, instant loans) can be extended to the user. Customer selects one of the offers and you can forward back to the provider via OnePipe for the provider to credit the account. Usually instantly. Providers are:\n1. Interswitch Lending Services\n \n## Estimated risk score for loans\nAfter verifying a customer’s mobile number, provide same number and OnePipe will forward to underlying provider to evaluate what loan amounts (short term, instant loans) can be extended to the user as well as the estimated attendant risk. Providers are:\n1. SecondScore\n\n## Linked cards & accounts lookup\nAfter verifying a customer’s mobile number, provide same number and OnePipe will forward to underlying provider to get a list of cards and accounts known with the customer on that provider’s platforms. Providers are:\n1. Interswitch Lending Services\n\n## Linked account lookup\nProvide a customer’s card details and OnPipe will forward to the underlying provider to obtain the account number linked to it. Providers are:\n1. Quickteller\n\n## Account information\nProvide a customer’s bank account number and OnPipe will forward to the underlying provider to obtain metadata like name, etc. Providers are:\n1. Quickteller\n\n\n\n# Getting access to the APIs\nAccess to the APIs can only be via any of the OnePipe partners. Banks, gateways and payment service providers. Once granted access under their account, you will receive an invite email to set your password.\n1. Set up your password\n2. Login with newly set password\n3. Generate your **API key** and **secret**\n\n# General API information\nThe APIs are fairly RESTFUL and organized around the main services you would be interacting with. You can simply import this collection from the top right of the page into your **Postman**.\n\nThe root url currently sits at:\n\n```\nhttps://api.onepipe.io\n```\n\n\n# Authentication headers\nAuthenticate your API calls by including your API key in the Authorization header of every request you make. You can manage your API keys from your dashboard.\n\n***Sample Authorization Header:***\n```\nAuthorization: Bearer {api_key}\n```\n\nAlso, every request requires you to provide a unique `request-ref` per call. Then You'd need to add a custom header called `Signature` that's an MD5 hash of that `request-ref` and your `api-secret` separated by a semi-colon. `;`.\n\n***Sample Signature Header:***\n```\nSignature:MD5Hash(request_ref;client_secret)\n```\n\nYour complete header for evey single call will look like:\n\n\tContent-Type:application/json\n\tAuthorization:Bearer {{api_key}}\n\tSignature:{{MD5Hash(request_ref;client_secret)}}\n\n# What requests would look like\nFor all requests, you'd put a JSON object in the body of your API call. All payloads have the following high level construct:\n\n```json\n\t{\n\t  \"request_ref\":\"0000000001\",\n\t  \"request_type\":\"charge | airtime | bill-payment | transfer\",\n\t  \"auth\": {\n\t    \"type\": \"card | account | token | override\", \n\t    \"secure\": \"YKBOxtdD8kZHqG7JO0C9TZ\"\n\t  },\n\t  \"transaction\": {\n\t    \"amount\": \"10000\",\n\t    \"transaction_ref\": \"000001\",\n\t    \"transaction_desc\": \"Payment for services\",\n\t    \"transaction_ref-parent\": \"000001\",\n\t    \"customer\":{\n\t    \t\"customer_ref\": \"000001\",\n\t    \t\"firstname\": \"Kola\",\n\t  \t\t\"surname\": \"Eboe\",\n\t    \t\"email\": \"kolaebue@gmail.com\",\n\t    \t\"mobile_no\": \"2348009871412\"\n\t    }\n\t  }\n\t}\n```\n\n|*Field*|*Type*|*Requirement*|*Description*|\n|request_ref|string|compulsory|Takes unique value for every request made to OnePipe|\n|request_type|string|compulsory|This should be set to the servicetransfer_funds|\n|auth.type|string|compulsory|Depending on the source of fund. This can be set to either bank.account, card, token orwallet|\n|auth.secure|string|compulsory|This is the encrypted value of the source of fund. Depending on the auth type, this can be either bank account, card details, token or wallet details. See [details|https://onepipe.atlassian.net/wiki/spaces/KB/pages/201555991/Encryption+in+OnePipe] on how to encrypt the secure field.|\n|auth.provider|string|compulsory|This should be set to the name of the Provider|\n|auth.route_mode|string|N/A|This can be set tonull|\n|transaction.mock_mode|string|optional|This can be set to either live or inspect. If left as null, value will fall back to the state of the service set on the console.|\n|transaction.transaction_desc|string|optional|Description of your transaction|\n|transaction.transaction_ref_parent|string|optional|Takes value of a (parent) transaction reference|\n|transaction.customer.customer_ref|string|compulsory|Identifier for customer|\n|transaction.customer.firstname|string|optional|First name of customer|\n|transaction.customer.surname|string|optional|Surname of customer|\n|transaction.customer.email|string|optional|Email address of customer|\n|transaction.customer.mobile_no|string|optional|Phone number of customer|\n|transaction.amount|big int|compulsory|This is the amount (kobo) to be transferred|\n|transaction.transaction_ref|string|compulsory|Takes unique value for every transaction call to OnePipe.|\n|transaction.meta|object|optional|Json object of your arbitrary transaction parameters|\n|transaction.details|object|varies per transaction type|JSON object of transaction type specific elements|\n\n# What responses would look like\nFor all responses, you'd get a JSON object in the body of the response you receive. All payloads have the following high level construct:\n\n```json\n\t{\n\t    \"status\": \"Processing | WaitingForOTP | ProcessingOTP | Successful-Failed | OfflineValidating | OfflineValidated | OfflineNotifying | OfflineNotified\",\n\t    \"message\": \"The transaction has been processed successully\",\n\t    \"data\": {\n\t    \t\"provider_responde_code\":\"00\",\n\t    \t\"provider\": \"RAVE\",\n\t        \"errors\": [],\n\t        \"error\": null,\n\t        \"charge_token\": \"Kz5Dev7BenV9HmLNB\",\n\t        \"paymentoptions\": []\n\t    }\n\t}\n```\n\n* **status**: Indicates the state of the request, whether successful, failed or anything in between\n* **message**: Provides a text description of the state of the request and at times a message for the customer\n* **data**: Will contain much more details of the outcome of the request. The values within this could vary by request type or endpoint called but some standard elements would be in almost all calls\n* **provider_response_code**: The actual response code receieved from the underlyig provider, e.g. `00` for Quickteller\n* **provider**: The provider that was used to process the request\n* **errors**: In case of a failed transaction, this contains the lists of errors that occurred while processing the transaction\n* **error**: This contain the most important error that hinders the successful completion of the transaction.\nWe highly recommend that developers use the Errors field to determine the result of an API call. As an empty Errors node indicate a successful transaction.\n\n\n**NOTE**: Some API calls may have response elements that are only applicable to those API calls. You will see examples in the provided postman collection and across the documentation.\n\n# OnePipe standard status codes\n* **Successful**: For  all requests that were successfully processed\n* **Failed**: If a request fails. Read the errors object(s)\n* **[Anything else]**: This would vary per endpoint called. Applicable values would be in the documentation for that endpoint.\n\n# HTTP Status Codes\n* **200**: A successful request occurred, do note that the description field on the response can contain further steps to be carried on this transaction\n* **400**: Data validation error occurred due to inconsistent data supplied by the client\n* **401**: Invalid request authorization, which might be due to invalid API key or the client is not registered for the service being accessed.\n* **500**: An internal server error at our End, this should be reported if it persists.\n\n# Encryption of Secure element\nFor Custom Implementation of card or token Encryption, do use Triple DES Encryption Algorithm with your Client application secret key as the encryption key \n\nE.g. \n\n```\nTripleDES.encrypt(\"{card.Pan};{card.Cvv};{card.Expdate};{card.Pin}\",secretKey)\n```\n\n**NOTE** Expiry date is MMyy\n\n## Sample encryption in Java\n\n\tMessageDigest md = MessageDigest.getInstance(\"md5\");\n    byte[] digestOfPassword = md.digest(key.getBytes(\"UTF-16LE\"));\n \n    byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);\n    \n    for (int j = 0, k = 16; j < 8;) {\n        keyBytes[k++] = keyBytes[j++];\n    }\n \n    SecretKey secretKey = new SecretKeySpec(keyBytes, 0, 24, \"DESede\");\n \n    IvParameterSpec iv = new IvParameterSpec(new byte[8]);\n    Cipher cipher = Cipher.getInstance(\"DESede/CBC/PKCS5Padding\");\n \n    cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);\n \n    byte[] plainTextBytes = toBeEncrypted.getBytes(\"UTF-16LE\");\n    byte[] cipherText = cipher.doFinal(plainTextBytes);\n \n    String output = new String(Base64.encodeBase64(cipherText));\n \n    return output;\n\n## Sample encryption in C-Sharp\n\n\tstring encryptedText = \"\";\n    MD5 md5 = new MD5CryptoServiceProvider();\n    TripleDES des = new TripleDESCryptoServiceProvider();\n    des.KeySize = 128;\n    des.Mode = CipherMode.CBC;\n    des.Padding = PaddingMode.PKCS7;\n\n    byte[] md5Bytes = md5.ComputeHash(Encoding.Unicode.GetBytes(key));\n\n    byte[] ivBytes = new byte[8];\n\n\n    des.Key = md5Bytes;\n\n    des.IV = ivBytes;\n\n    byte[] clearBytes = Encoding.Unicode.GetBytes(TextToEncrypt);\n\n    ICryptoTransform ct = des.CreateEncryptor();\n    using (MemoryStream ms = new MemoryStream())\n    {\n        using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))\n        {\n            cs.Write(clearBytes, 0, clearBytes.Length);\n            cs.Close();\n        }\n        encryptedText = Convert.ToBase64String(ms.ToArray());\n    }\n\n    return encryptedText;\n\n## Sample encryption in PHP\n\n\tfunction EncryptV2($encryption_key,$data)\n\t{\n\t    $source = mb_convert_encoding($encryption_key, 'UTF-16LE', 'UTF-8');\n\t\n\t    $key = md5($source, true);\n\t\n\t    $key .= substr($key, 0, 8);\n\t\n\t     // a 128 bit (16 byte) key\n\t     // append the first 8 bytes onto the end\n\t\n\t\n\t    //Pad for PKCS7\n\t    $block = mcrypt_get_block_size('tripledes', 'cbc');\n\t    $len = strlen($data);\n\t    $padding = $block - ($len % $block);\n\t    $data .= str_repeat(chr($padding),$padding);\n\t\n\t\n\t\n\t    $iv =  \"\\0\\0\\0\\0\\0\\0\\0\\0\";\n\t\n\t    $encData = mcrypt_encrypt('tripledes', $key, $data, 'cbc',$iv);\n\t\n\t    echo base64_encode($encData);\n\t}\n\n## Sample encryption in Node.js\n\n\tconst crypto = require('crypto');\n\n\tfunction encrypt(sharedKey, plainText) {\n\t\tconst bufferedKey = Buffer.from(sharedKey, 'utf16le');\n\n\t\tconst key = crypto.createHash('md5').update(bufferedKey).digest();\n\t\tconst newKey = Buffer.concat([key, key.slice(0, 8)]);\n\t\tconst IV = Buffer.alloc(8, '\\0');\n\n\t\tconst cipher = crypto.createCipheriv('des-ede3-cbc', newKey, IV).setAutoPadding(true);\n\t\treturn cipher.update(plainText, 'utf8', 'base64') + cipher.final('base64');\n\t}\n\n    \n# Switching providers for a service\nAll services subscribed to in your application are attached to providers that will end up fulfilling such service(s) on request. You can switch providers as you wish by managing the application from your dashboard and editing the service details. Also, for some endpoints, you can explicitly set the provider you would like to be used in the request payload. You would see examples in the documentation for the endpoints that support this.\n\n# Bank CBN Codes\nAnywhere bank codes are required in the API specification (bank_code), this refers to the CBN bank codes. Details of all bank codes can be found [here](https://sandbox.interswitchng.com/docbase/docs/autogate-file-transfer/appendix/bank-cbn-codes/).\n\n# Test cards\n* Paystack - Test cards [here](https://developers.paystack.co/docs/test-cards)\n* Flutterwave - Test cards [here](https://developer.flutterwave.com/docs/test-cards)\n* Quickteller - Test cards [here](https://sandbox.interswitchng.com/docbase/docs/interswitch-payment-gateway-mobile-inappsdk-implementation/test-cards/)  =>  Pan:5061040000000000306   Pin:1234   CVV:123  EXP:1901\n\n\n\n\nNow let's dive deeper into specific API calls.","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":false,"owner":"6358444","team":242895,"collectionId":"992bd16e-84dc-4ef6-8cad-7ab6bea23bba","publishedId":"S11GRKVh","public":true,"publicUrl":"https://v1.docs.onepipe.io","privateUrl":"https://go.postman.co/documentation/6358444-992bd16e-84dc-4ef6-8cad-7ab6bea23bba","customColor":{"top-bar":"1F3946","right-sidebar":"303030","highlight":"EF5B25"},"documentationLayout":"classic-double-column","version":"8.10.1","publishDate":"2019-07-04T12:23:06.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{},"logos":{}},"statusCode":200},"environments":[],"user":{"authenticated":false,"permissions":{"publish":false}},"run":{"button":{"js":"https://run.pstmn.io/button.js","css":"https://run.pstmn.io/button.css"}},"web":"https://www.getpostman.com/","team":{"logo":"https://res.cloudinary.com/postman/image/upload/t_team_logo_pubdoc/v1/team/a27a425324c006dd1f53f07becf2d5c16478567dd1dde25001728b716c749aa8","favicon":"https://res.cloudinary.com/postman/image/upload/v1547191824/team/zjhn0lwn04wuxbe90rhq.ico"},"isEnvFetchError":false,"languages":"[{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"HttpClient\"},{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"RestSharp\"},{\"key\":\"curl\",\"label\":\"cURL\",\"variant\":\"cURL\"},{\"key\":\"dart\",\"label\":\"Dart\",\"variant\":\"http\"},{\"key\":\"go\",\"label\":\"Go\",\"variant\":\"Native\"},{\"key\":\"http\",\"label\":\"HTTP\",\"variant\":\"HTTP\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"OkHttp\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"Unirest\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"Fetch\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"jQuery\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"XHR\"},{\"key\":\"c\",\"label\":\"C\",\"variant\":\"libcurl\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Axios\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Native\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Request\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Unirest\"},{\"key\":\"objective-c\",\"label\":\"Objective-C\",\"variant\":\"NSURLSession\"},{\"key\":\"ocaml\",\"label\":\"OCaml\",\"variant\":\"Cohttp\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"cURL\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"Guzzle\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"HTTP_Request2\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"pecl_http\"},{\"key\":\"powershell\",\"label\":\"PowerShell\",\"variant\":\"RestMethod\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"http.client\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"Requests\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"httr\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"RCurl\"},{\"key\":\"ruby\",\"label\":\"Ruby\",\"variant\":\"Net::HTTP\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"Httpie\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"wget\"},{\"key\":\"swift\",\"label\":\"Swift\",\"variant\":\"URLSession\"}]","languageSettings":[{"key":"csharp","label":"C#","variant":"HttpClient"},{"key":"csharp","label":"C#","variant":"RestSharp"},{"key":"curl","label":"cURL","variant":"cURL"},{"key":"dart","label":"Dart","variant":"http"},{"key":"go","label":"Go","variant":"Native"},{"key":"http","label":"HTTP","variant":"HTTP"},{"key":"java","label":"Java","variant":"OkHttp"},{"key":"java","label":"Java","variant":"Unirest"},{"key":"javascript","label":"JavaScript","variant":"Fetch"},{"key":"javascript","label":"JavaScript","variant":"jQuery"},{"key":"javascript","label":"JavaScript","variant":"XHR"},{"key":"c","label":"C","variant":"libcurl"},{"key":"nodejs","label":"NodeJs","variant":"Axios"},{"key":"nodejs","label":"NodeJs","variant":"Native"},{"key":"nodejs","label":"NodeJs","variant":"Request"},{"key":"nodejs","label":"NodeJs","variant":"Unirest"},{"key":"objective-c","label":"Objective-C","variant":"NSURLSession"},{"key":"ocaml","label":"OCaml","variant":"Cohttp"},{"key":"php","label":"PHP","variant":"cURL"},{"key":"php","label":"PHP","variant":"Guzzle"},{"key":"php","label":"PHP","variant":"HTTP_Request2"},{"key":"php","label":"PHP","variant":"pecl_http"},{"key":"powershell","label":"PowerShell","variant":"RestMethod"},{"key":"python","label":"Python","variant":"http.client"},{"key":"python","label":"Python","variant":"Requests"},{"key":"r","label":"R","variant":"httr"},{"key":"r","label":"R","variant":"RCurl"},{"key":"ruby","label":"Ruby","variant":"Net::HTTP"},{"key":"shell","label":"Shell","variant":"Httpie"},{"key":"shell","label":"Shell","variant":"wget"},{"key":"swift","label":"Swift","variant":"URLSession"}],"languageOptions":[{"label":"C# - HttpClient","value":"csharp - HttpClient - C#"},{"label":"C# - RestSharp","value":"csharp - RestSharp - C#"},{"label":"cURL - cURL","value":"curl - cURL - cURL"},{"label":"Dart - http","value":"dart - http - Dart"},{"label":"Go - Native","value":"go - Native - Go"},{"label":"HTTP - HTTP","value":"http - HTTP - HTTP"},{"label":"Java - OkHttp","value":"java - OkHttp - Java"},{"label":"Java - Unirest","value":"java - Unirest - Java"},{"label":"JavaScript - Fetch","value":"javascript - Fetch - JavaScript"},{"label":"JavaScript - jQuery","value":"javascript - jQuery - JavaScript"},{"label":"JavaScript - XHR","value":"javascript - XHR - JavaScript"},{"label":"C - libcurl","value":"c - libcurl - C"},{"label":"NodeJs - Axios","value":"nodejs - Axios - NodeJs"},{"label":"NodeJs - Native","value":"nodejs - Native - NodeJs"},{"label":"NodeJs - Request","value":"nodejs - Request - NodeJs"},{"label":"NodeJs - Unirest","value":"nodejs - Unirest - NodeJs"},{"label":"Objective-C - NSURLSession","value":"objective-c - NSURLSession - Objective-C"},{"label":"OCaml - Cohttp","value":"ocaml - Cohttp - OCaml"},{"label":"PHP - cURL","value":"php - cURL - PHP"},{"label":"PHP - Guzzle","value":"php - Guzzle - PHP"},{"label":"PHP - HTTP_Request2","value":"php - HTTP_Request2 - PHP"},{"label":"PHP - pecl_http","value":"php - pecl_http - PHP"},{"label":"PowerShell - RestMethod","value":"powershell - RestMethod - PowerShell"},{"label":"Python - http.client","value":"python - http.client - Python"},{"label":"Python - Requests","value":"python - Requests - Python"},{"label":"R - httr","value":"r - httr - R"},{"label":"R - RCurl","value":"r - RCurl - R"},{"label":"Ruby - Net::HTTP","value":"ruby - Net::HTTP - Ruby"},{"label":"Shell - Httpie","value":"shell - Httpie - Shell"},{"label":"Shell - wget","value":"shell - wget - Shell"},{"label":"Swift - URLSession","value":"swift - URLSession - Swift"}],"layoutOptions":[{"value":"classic-single-column","label":"Single Column"},{"value":"classic-double-column","label":"Double Column"}],"versionOptions":[],"environmentOptions":[{"value":"0","label":"No Environment"}],"canonicalUrl":"https://v1.docs.onepipe.io/view/metadata/S11GRKVh"}