Close Virtual Account
curl --request POST \
--url https://api.usezentra.com/api/v1/virtual-accounts/{id}/close \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"reason": "<string>"
}
'import requests
url = "https://api.usezentra.com/api/v1/virtual-accounts/{id}/close"
payload = { "reason": "<string>" }
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({reason: '<string>'})
};
fetch('https://api.usezentra.com/api/v1/virtual-accounts/{id}/close', 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.usezentra.com/api/v1/virtual-accounts/{id}/close",
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([
'reason' => '<string>'
]),
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.usezentra.com/api/v1/virtual-accounts/{id}/close"
payload := strings.NewReader("{\n \"reason\": \"<string>\"\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.usezentra.com/api/v1/virtual-accounts/{id}/close")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.usezentra.com/api/v1/virtual-accounts/{id}/close")
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 \"reason\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"error": {
"code": "NOT_FOUND",
"message": "Account not found",
"details": null
},
"meta": {
"path": "/api/v1/virtual-accounts/va_missing/close",
"method": "POST"
}
}
{
"error": {
"code": "FAILED_PRECONDITION",
"message": "Account cannot be closed in its current state",
"details": null
},
"meta": {
"path": "/api/v1/virtual-accounts/va_abc123xyz/close",
"method": "POST"
}
}
Virtual Accounts
Close Virtual Account
POST /api/v1/virtual-accounts//close - Close a virtual account
POST
/
api
/
v1
/
virtual-accounts
/
{id}
/
close
Close Virtual Account
curl --request POST \
--url https://api.usezentra.com/api/v1/virtual-accounts/{id}/close \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"reason": "<string>"
}
'import requests
url = "https://api.usezentra.com/api/v1/virtual-accounts/{id}/close"
payload = { "reason": "<string>" }
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({reason: '<string>'})
};
fetch('https://api.usezentra.com/api/v1/virtual-accounts/{id}/close', 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.usezentra.com/api/v1/virtual-accounts/{id}/close",
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([
'reason' => '<string>'
]),
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.usezentra.com/api/v1/virtual-accounts/{id}/close"
payload := strings.NewReader("{\n \"reason\": \"<string>\"\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.usezentra.com/api/v1/virtual-accounts/{id}/close")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.usezentra.com/api/v1/virtual-accounts/{id}/close")
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 \"reason\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"error": {
"code": "NOT_FOUND",
"message": "Account not found",
"details": null
},
"meta": {
"path": "/api/v1/virtual-accounts/va_missing/close",
"method": "POST"
}
}
{
"error": {
"code": "FAILED_PRECONDITION",
"message": "Account cannot be closed in its current state",
"details": null
},
"meta": {
"path": "/api/v1/virtual-accounts/va_abc123xyz/close",
"method": "POST"
}
}
Close a virtual account for the authenticated tenant.
Endpoint
POST /api/v1/virtual-accounts/{id}/close
Path Parameters
Virtual account ID.
Request Body
Optional closure reason. It is forwarded to the internal service path, but it is not currently echoed back in the response body.
Response
Returns the updated virtual account object withstatus set to closed.
Example Request
const closedAccount = await client.virtualAccounts.close('va_abc123xyz', {
reason: 'customer_request'
});
console.log(`Account ${closedAccount.accountNumber} closed`);
console.log(`Status: ${closedAccount.status}`);
closed_account = client.virtual_accounts.close(
'va_abc123xyz',
reason='customer_request'
)
print(f"Account {closed_account.account_number} closed")
print(f"Status: {closed_account.status}")
$closedAccount = $client->virtualAccounts->close('va_abc123xyz', [
'reason' => 'customer_request'
]);
echo "Account {$closedAccount->account_number} closed\n";
echo "Status: {$closedAccount->status}";
curl -X POST https://api.usezentra.com/api/v1/virtual-accounts/va_abc123xyz/close \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "customer_request"
}'
Example Response
{
"data": {
"id": "va_abc123xyz",
"tenant_id": "tenant_123",
"customer_id": "cus_1234567890",
"account_number": "0123456789",
"account_name": "John Doe",
"bank_code": "wema-bank",
"bank_name": "Wema Bank",
"provider": "paystack_dva",
"status": "closed",
"account_type": "standard",
"total_received_minor": 500000,
"transaction_count": 5,
"metadata": {
"purpose": "collections"
},
"expires_at": null,
"created_at": "2026-03-07T10:30:00Z",
"updated_at": "2026-03-07T16:00:00Z"
},
"meta": {
"timestamp": "2026-03-07T16:00:00Z",
"requestId": "req_123"
}
}
Error Responses
{
"error": {
"code": "NOT_FOUND",
"message": "Account not found",
"details": null
},
"meta": {
"path": "/api/v1/virtual-accounts/va_missing/close",
"method": "POST"
}
}
{
"error": {
"code": "FAILED_PRECONDITION",
"message": "Account cannot be closed in its current state",
"details": null
},
"meta": {
"path": "/api/v1/virtual-accounts/va_abc123xyz/close",
"method": "POST"
}
}
Important Notes
Treat account closure as irreversible in your integration. Do not assume the account can be reopened later.
The current reviewed response returns the updated account record. Fields like
closure_reason and closed_at are not part of the current response contract.Next Steps
Create New Account
Generate another account
List Accounts
Review existing accounts
Was this page helpful?
⌘I