{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"420e1f8e-65ae-485e-adf7-2b0dca80d632","name":"Viscount API","description":"Viscount Payment APIs provide a secure, scalable, and efficient solution for businesses looking to modernize their payment infrastructure. They enable organizations to seamlessly collect, process, and manage payments while maintaining full control over financial operations. By simplifying complex workflows, businesses can focus more on growth, customer experience, and innovation.\n\nThrough easy integration, Viscount APIs allow payment capabilities to be embedded directly into applications, delivering a smooth and reliable user experience. The platform supports both static and dynamic bank accounts, offering the flexibility to design payment flows that suit different business models, while ensuring transactions are processed securely and in real time.\n\nDesigned for both startups and established enterprises, Viscount Payment APIs offer a dependable foundation for scaling payment operations. Backed by a robust infrastructure and dedicated support team, the platform enables businesses to improve efficiency, enhance transaction experiences, and confidently operate in today’s digital economy.\n\n# **Getting Started**\n\nTo integrate Viscount Payment APIs, you must complete a simple onboarding process to ensure compliance and secure access.\n\n**Step 1: Create a Corporate Account**\n\nRegister your business via the corporate portal ([https://corporate.viscountbank.com](https://corporate.viscountbank.com)) by providing accurate company details. This establishes your organization as an authorized entity.\n\n**Step 2: Complete KYC Verification**\n\nSubmit the required documents for KYC verification. Once approved, your account will be activated, and you will gain access to both Sandbox (testing) and Live (production) environments to begin integration.\n\n## **API Environments**\n\nViscount Payment APIs provide two environments—**Sandbox (Test)** and **Live (Production)**—to support development, testing, and deployment. This ensures integrations are stable and reliable before processing real transactions.\n\n### **Sandbox (Test)**\n\nThe Sandbox environment allows you to simulate all API features without real financial transactions. You can test payment flows, generate mock account details, simulate transfers, trigger errors, and validate webhooks. It is ideal for development, debugging, and end-to-end testing.\n\n### **Live (Production)**\n\nThe Live environment is used for real transactions. Once testing is complete, your integration can be moved to Live, where payments are processed against actual accounts. This enables businesses to securely collect payments and operate at full scale.\n\n# **API Security and Authentication Framework**\n\nThe Viscount Payment API employs a multi-layered authentication and validation framework designed to ensure the security, integrity, and reliability of all transactions.\n\nThis framework is built on three core components:\n\n### **Secret Key Authentication**\n\nAll API requests must include a valid Secret Key in the request headers. The Secret Key serves as the primary method of identifying and authorising API clients. Secret Keys are issued through the Viscount Corporate Internet Banking portal and are unique to each client application. Separate keys are provided for Sandbox and Live environments.\n\n### **IP Authorisation**\n\nIn addition to Secret Key authentication, Viscount enforces IP whitelisting across all environments. Only requests originating from pre-registered server IP addresses are accepted. Any request from an unregistered IP address is automatically rejected, significantly reducing the risk of unauthorised access.\n\n### **Idempotency Control**\n\nEach API request must include a unique Request Key. This key enables idempotency control, ensuring that duplicate requests, whether caused by network timeouts, client retries, or connectivity issues, are processed only once. This prevents duplicate transactions and maintains data consistency across all operations.\n\nTogether, these measures provide a robust security posture that protects against unauthorised access, prevents duplicate processing, and ensures the integrity of every transaction processed through the Viscount Payment API.\n\n# **Generating Request Key**\n\nThe Request Key is a unique identifier included in every API request to enable idempotency control. It is composed of four segments concatenated together to produce a key that is virtually impossible to duplicate.\n\n**Structure**\n\n| Segment | Length | Description |\n| --- | --- | --- |\n| Timestamp | 14 characters | Current date and time in `YYYYMMDDHHmmss` format. |\n| Number Block | 28 characters | Seven random numbers that sum to 1,000, each zero-padded to 4 digits. |\n| Alpha Block 1 | 7 characters | Seven random uppercase letters. |\n| Digit Block | 30 characters | Thirty random digits. |\n| Alpha Block 2 | 20 characters | Twenty random uppercase letters. |\n\nImplementation: PHP\n\n``` php\nfunction generateRequestKey(): string\n{\n    $date = date('YmdHis');\n    // 7 random numbers that sum to 1000, each zero-padded to 4 digits\n    $numbers = [];\n    $remaining = 1000;\n    for ($i = 0; $i < 6; $i++) {\n        $max = min($remaining - (6 - $i), 9999);\n        $n = rand(1, $max);\n        $numbers[] = $n;\n        $remaining -= $n;\n    }\n    $numbers[] = $remaining;\n    shuffle($numbers);\n    $numPart = implode('', array_map(fn($n) => str_pad($n, 4, '0', STR_PAD_LEFT), $numbers));\n    // 7 random uppercase letters\n    $alpha7 = '';\n    for ($i = 0; $i < 7; $i++) {\n        $alpha7 .= chr(rand(65, 90));\n    }\n    // 30 random digits\n    $digits30 = '';\n    for ($i = 0; $i < 30; $i++) {\n        $digits30 .= rand(0, 9);\n    }\n    // 20 random uppercase letters\n    $alpha20 = '';\n    for ($i = 0; $i < 20; $i++) {\n        $alpha20 .= chr(rand(65, 90));\n    }\n    return $date . $numPart . $alpha7 . $digits30 . $alpha20;\n}\n\n ```\n\n**Implementation: Javascript**\n\n``` javascript\nfunction generateRequestKey() {\n    const now = new Date();\n    const date = now.getFullYear().toString()\n        + String(now.getMonth() + 1).padStart(2, '0')\n        + String(now.getDate()).padStart(2, '0')\n        + String(now.getHours()).padStart(2, '0')\n        + String(now.getMinutes()).padStart(2, '0')\n        + String(now.getSeconds()).padStart(2, '0');\n    // 7 random numbers that sum to 1000, each zero-padded to 4 digits\n    const numbers = [];\n    let remaining = 1000;\n    for (let i = 0; i < 6; i++) {\n        const max = Math.min(remaining - (6 - i), 9999);\n        const n = Math.floor(Math.random() * max) + 1;\n        numbers.push(n);\n        remaining -= n;\n    }\n    numbers.push(remaining);\n    numbers.sort(() => Math.random() - 0.5);\n    const numPart = numbers.map(n => String(n).padStart(4, '0')).join('');\n    // 7 random alphabets\n    let alpha7 = '';\n    for (let i = 0; i < 7; i++) {\n        alpha7 += String.fromCharCode(65 + Math.floor(Math.random() * 26));\n    }\n    // 30 random digits\n    let digits30 = '';\n    for (let i = 0; i < 30; i++) {\n        digits30 += Math.floor(Math.random() * 10);\n    }\n    // 20 random alphabets\n    let alpha20 = '';\n    for (let i = 0; i < 20; i++) {\n        alpha20 += String.fromCharCode(65 + Math.floor(Math.random() * 26));\n    }\n    return date + numPart + alpha7 + digits30 + alpha20;\n}\n\n ```\n\n# **Collecting Payment**\n\nViscount enables you to collect payments through two primary channels: Bank Transfers and Direct Debits.\n\n### **Bank Transfers**\n\nWith Bank Transfers, you can generate dedicated virtual accounts for your customers to make payments directly into. Viscount supports two types of virtual accounts:\n\n_Static Virtual Accounts_ are permanent accounts assigned to individual customers. A static account can be used repeatedly by the same customer for multiple transactions, making it ideal for recurring payments, subscriptions, and long-term customer relationships.\n\n_Dynamic Virtual Accounts_ are single-use accounts generated for a specific transaction. Once payment is received, the account is automatically closed. Dynamic accounts are suited for one-off payments such as invoices, checkout flows, and payment links.\n\n### **Direct Debits**\n\nDirect Debits allow you to debit a customer's bank account directly, based on an authorised mandate. Viscount supports two mandate types:\n\n_One-Time Mandates_ authorise a single debit of a specified amount from the customer's account. The mandate expires automatically once the transaction is completed.\n\n_Recurring Mandates_ authorise repeated debits over a defined period. This is ideal for loan repayments, subscription billing, and scheduled collections where the customer has granted standing authorisation.\n\nAll payment collection methods are accessible through the Viscount Payment API, with real-time transaction notifications delivered via webhooks.\n\n## **Making Payments**\n\nThe Viscount Payment API enables you to send money to any bank account in Nigeria — whether within Viscount or to any other commercial bank.\n\n**Single Transfers**\n\nInitiate individual transfers to any bank account in real time. Each transfer is processed instantly with a unique reference for tracking and verification.\n\n**Bulk Transfers**\n\nSend payments to multiple recipients in a single API call. Bulk transfers are ideal for salary disbursements, vendor payments, commission payouts, and any scenario requiring high-volume disbursements. Each transfer within a batch is tracked individually, with status updates available per transaction.\n\nAll transfers — whether single or bulk, internal or external — support full transaction verification, real-time status tracking, and webhook notifications upon completion.\n\n# **Response Format**\n\nThe Viscount Payment API returns two HTTP status codes:\n\n#### **200 — Success**\n\nA successful request returns a JSON response containing `status`, `message`, and `data`. The `status` field will always be `success`, and the `data` field contains the relevant response payload.\n\n``` json\n{\n    \"status\": \"success\",\n    \"message\": \"Successful\",\n    \"data\": {\n        \"reference\": \"VST20260411143200\",\n        \"transaction_id\": \"TXN_0012345\",\n        \"amount\": 50000\n    }\n}\n\n ```\n\n### **400 — Error**\n\nA failed request returns a JSON response containing `status` and `message` only. The `status` field will always be `error`, and the `message` field provides a description of what went wrong. No `data` field is included in error responses.\n\n``` json\n{\n    \"status\": \"error\",\n    \"message\": \"Invalid source account number.\"\n}\n\n ```\n\n# **Webhooks**\n\nWebhooks are an essential part of your integration with Viscount. They allow Viscount to notify your application in real time when events occur on your account, such as a successful payment or a completed transfer.\n\nA webhook URL is an endpoint on your server that receives these notifications. When an event occurs, Viscount sends a POST request to your endpoint with a JSON body containing the event type, the associated data, and a timestamp.\n\n**Supported Events**\n\n| Event | Description |\n| --- | --- |\n| `transaction-new` | A successful credit is received on a virtual account or any account |\n| `transfer-successful` | An outbound money transfer has been completed successfully |\n| transfer-error | An outbound money transfer that has error |\n\n### **Payload: Successful Credit on Account**\n\nTriggered when a payment is received on any account, including virtual accounts.\n\n``` json\n{\n    \"event_type\": \"transaction-new\",\n    \"data\": {\n        \"transaction_id\": \"TXN_0012345\",\n        \"account_number\": \"82791089010\",\n        \"reference\": \"de92ui22\",\n        \"transaction_type\": \"CREDIT\"\n    },\n    \"timestamp\": \"2026-04-11T14:23:45+00:00\"\n}\n\n ```\n\n### **Payload: Successful Money Transfer**\n\nTriggered when an outbound transfer to another bank account is completed.\n\n``` json\n{\n    \"event_type\": \"transfer-successful\",\n    \"data\": {\n        \"reference\": \"de92ui22\"\n    },\n    \"timestamp\": \"2026-04-11T14:23:45+00:00\"\n}\n\n ```\n\n### **Webhook Security**\n\nWhen enabling webhooks, you are required to set a secret hash. Since webhook URLs are publicly accessible, this hash allows you to verify that incoming requests originate from Viscount.\n\nChoose a random, secure value as your secret hash and store it as an environment variable on your server. Do not hardcode it in your application.\n\nWhen a webhook is triggered, Viscount uses the secret hash to sign the request body using HMAC-SHA256. The resulting signature is included in the `X-Viscount-Signature` header of the webhook request.\n\nTo verify the webhook, compute the HMAC-SHA256 hash of the raw request body using your secret hash and compare the result with the value in the `X-Viscount-Signature` header. If the values do not match, discard the request — it did not originate from Viscount.\n\n**Example: Verifying in Node.js**\n\n``` python\nimport hmac, hashlib, os\nsecret = os.environ['VISCOUNT_WEBHOOK_SECRET']\npayload = request.get_data()\nsignature = request.headers.get('X-Viscount-Signature', '')\nexpected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()\nif not hmac.compare_digest(expected, signature):\n    abort(401)\n# Signature valid — process the event\nevent = request.get_json()\n\n ```\n\n### **Handling Webhooks**\n\nYour endpoint should return a `200` status code as quickly as possible to acknowledge receipt. Perform any time-consuming processing asynchronously after sending the acknowledgement. If Viscount does not receive a `200` response, the delivery will be recorded as failed.\n\nAlways use the raw request body for signature verification. Parsing the JSON first and re-encoding it may alter key ordering or formatting, causing the signature comparison to fail.","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":false,"owner":"53732763","team":14752781,"collectionId":"420e1f8e-65ae-485e-adf7-2b0dca80d632","publishedId":"2sBXitBn16","public":true,"publicUrl":"https://documenter-api.postman.tech/view/53732763/2sBXitBn16","privateUrl":"https://go.postman.co/documentation/53732763-420e1f8e-65ae-485e-adf7-2b0dca80d632","customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"documentationLayout":"classic-single-column","customisation":{"metaTags":[{"name":"description","value":"Viscount Payment APIs provide a secure, scalable, and efficient solution for businesses looking to modernize their payment infrastructure."},{"name":"title","value":""}],"appearance":{"default":"dark","themes":[{"name":"dark","logo":"https://content.pstmn.io/a27fc9f5-0848-44f6-a12b-8906f1563fa3/ViBMb2dvIDEuanBnICgxKS5qcGVn","colors":{"top-bar":"212121","right-sidebar":"303030","highlight":"FF6C37"}},{"name":"light","logo":"https://content.pstmn.io/a27fc9f5-0848-44f6-a12b-8906f1563fa3/ViBMb2dvIDEuanBnICgxKS5qcGVn","colors":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"}}]}},"version":"8.10.1","publishDate":"2026-04-13T08:05:23.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{"title":"","description":"Viscount Payment APIs provide a secure, scalable, and efficient solution for businesses looking to modernize their payment infrastructure."},"logos":{"logoLight":"https://content.pstmn.io/a27fc9f5-0848-44f6-a12b-8906f1563fa3/ViBMb2dvIDEuanBnICgxKS5qcGVn","logoDark":"https://content.pstmn.io/a27fc9f5-0848-44f6-a12b-8906f1563fa3/ViBMb2dvIDEuanBnICgxKS5qcGVn"}},"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/83e3e10c26fe52e1aa7b16f76beec491d0d1cc9b3c05f9cd74e9fc63407dffcc","favicon":""},"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://documenter.gw.postman.com/view/metadata/2sBXitBn16"}