curl --request POST \
--url https://api.platform.chipper.ai/v1/virtual-accounts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"currency": "<string>",
"externalReference": "<string>",
"metadata": {}
}
'import requests
url = "https://api.platform.chipper.ai/v1/virtual-accounts"
payload = {
"currency": "<string>",
"externalReference": "<string>",
"metadata": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({currency: '<string>', externalReference: '<string>', metadata: {}})
};
fetch('https://api.platform.chipper.ai/v1/virtual-accounts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.platform.chipper.ai/v1/virtual-accounts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'currency' => '<string>',
'externalReference' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.platform.chipper.ai/v1/virtual-accounts"
payload := strings.NewReader("{\n \"currency\": \"<string>\",\n \"externalReference\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.platform.chipper.ai/v1/virtual-accounts")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"currency\": \"<string>\",\n \"externalReference\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.platform.chipper.ai/v1/virtual-accounts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"currency\": \"<string>\",\n \"externalReference\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"virtualAccount": {
"id": "va_k3m9x2pq7wz4t6vbn8hd",
"status": "active",
"currency": "NGN",
"bank": "Wema Bank",
"accountNumber": "7812345678",
"accountName": "Chipper / Acme Ltd",
"externalReference": "customer-8841",
"createdAt": "2026-08-01T09:12:44.000Z",
"metadata": {},
"updatedAt": "2023-11-07T05:31:56Z"
}
}{
"error": "validation_error",
"message": "Request validation failed",
"requestId": "req_q7vei435zifs51ia0lqr"
}{
"error": "unauthorized",
"message": "Invalid API key",
"requestId": "req_q7vei435zifs51ia0lqr"
}{
"error": "forbidden",
"message": "API key does not have the required scope",
"requestId": "req_q7vei435zifs51ia0lqr"
}{
"error": "unprocessable",
"message": "A GHS account needs an organization representative. Set one at PUT /v1/organization/representative.",
"requestId": "req_q7vei435zifs51ia0lqr"
}{
"error": "provider_error",
"message": "UMB error: This phone number is already registered at UMB to a different Ghana Card",
"requestId": "req_q7vei435zifs51ia0lqr"
}Create a virtual account
Provisions a dedicated bank account number your customer can transfer into from any bank. Every deposit is credited to your balance in that currency and fires a collection.completed webhook, with no polling and no manual reconciliation. Typically one per customer: set externalReference to your customer id so deposits map back.
GHS accounts need an organization representative first. They are real accounts at UMB, opened against a named Ghanaian identity: the person set at PUT /v1/organization/representative. Without one, production returns 422; sandbox uses your organization owner’s name instead. Every GHS account’s accountName is the representative’s name as the bank holds it, which is the name your customer sees at their bank.
curl --request POST \
--url https://api.platform.chipper.ai/v1/virtual-accounts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"currency": "<string>",
"externalReference": "<string>",
"metadata": {}
}
'import requests
url = "https://api.platform.chipper.ai/v1/virtual-accounts"
payload = {
"currency": "<string>",
"externalReference": "<string>",
"metadata": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({currency: '<string>', externalReference: '<string>', metadata: {}})
};
fetch('https://api.platform.chipper.ai/v1/virtual-accounts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.platform.chipper.ai/v1/virtual-accounts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'currency' => '<string>',
'externalReference' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.platform.chipper.ai/v1/virtual-accounts"
payload := strings.NewReader("{\n \"currency\": \"<string>\",\n \"externalReference\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.platform.chipper.ai/v1/virtual-accounts")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"currency\": \"<string>\",\n \"externalReference\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.platform.chipper.ai/v1/virtual-accounts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"currency\": \"<string>\",\n \"externalReference\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"virtualAccount": {
"id": "va_k3m9x2pq7wz4t6vbn8hd",
"status": "active",
"currency": "NGN",
"bank": "Wema Bank",
"accountNumber": "7812345678",
"accountName": "Chipper / Acme Ltd",
"externalReference": "customer-8841",
"createdAt": "2026-08-01T09:12:44.000Z",
"metadata": {},
"updatedAt": "2023-11-07T05:31:56Z"
}
}{
"error": "validation_error",
"message": "Request validation failed",
"requestId": "req_q7vei435zifs51ia0lqr"
}{
"error": "unauthorized",
"message": "Invalid API key",
"requestId": "req_q7vei435zifs51ia0lqr"
}{
"error": "forbidden",
"message": "API key does not have the required scope",
"requestId": "req_q7vei435zifs51ia0lqr"
}{
"error": "unprocessable",
"message": "A GHS account needs an organization representative. Set one at PUT /v1/organization/representative.",
"requestId": "req_q7vei435zifs51ia0lqr"
}{
"error": "provider_error",
"message": "UMB error: This phone number is already registered at UMB to a different Ghana Card",
"requestId": "req_q7vei435zifs51ia0lqr"
}Authorizations
Your API key: sk_test_… (sandbox) or sk_live_… (production).
Body
Response
The provisioned account, ready to receive transfers.
Show child attributes
Show child attributes