Get virtual account onboarding status for a user
curl --request GET \
--url https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding \
--header 'partner-api-key: <api-key>'import requests
url = "https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding"
headers = {"partner-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'partner-api-key': '<api-key>'}};
fetch('https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding', 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.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"partner-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("partner-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding")
.header("partner-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["partner-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"hasVirtualAccount": false,
"canRequest": true,
"status": "NOT_STARTED",
"missingRequirements": []
}
}Virtual Accounts
Get Virtual Account Status (User)
Returns everything you need to decide whether to request a virtual account for a user: whether they already have one, whether a request would be accepted right now, the state of their latest onboarding, and any identity data still missing. Safe to poll while an onboarding is in flight.
GET
/
api
/
partner
/
v2
/
banks
/
users
/
{userId}
/
banking-onboarding
Get virtual account onboarding status for a user
curl --request GET \
--url https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding \
--header 'partner-api-key: <api-key>'import requests
url = "https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding"
headers = {"partner-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'partner-api-key': '<api-key>'}};
fetch('https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding', 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.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"partner-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("partner-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding")
.header("partner-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.capa.fi/api/partner/v2/banks/users/{userId}/banking-onboarding")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["partner-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"hasVirtualAccount": false,
"canRequest": true,
"status": "NOT_STARTED",
"missingRequirements": []
}
}Returns everything you need to decide whether to request a named virtual account for a user: whether they already have one, whether a request would be accepted right now, the state of their latest onboarding, and whether their KYB is still outstanding. See the Virtual Accounts guide for the full flow.
Currently available for the United States (
US) only. country is required — any other value is rejected with 400.
This endpoint is read-only and safe to poll while an onboarding is in flight.
Reading the Response
| Field | Description |
|---|---|
hasVirtualAccount | The user already has an active virtual account in this country. |
canRequest | A request right now would be accepted — KYB complete, no existing virtual account, and no onboarding in flight. Use this to gate a “Get an account” button. |
status | State of the user’s most recent onboarding for this country. |
missingRequirements | What is still outstanding on the user’s KYB. Empty once KYB is complete. |
Status Values
status | Meaning |
|---|---|
NOT_STARTED | No onboarding has ever been created for this user and country. |
IN_PROGRESS | Submitted to the banking provider, awaiting a decision. Keep polling. |
COMPLETED | Approved and provisioned. The account is available from List Bank Accounts. |
FAILED | The onboarding did not complete. canRequest returns to true, so it can be retried. |
status: "COMPLETED" and hasVirtualAccount: true are related but not identical. status reflects the onboarding record; hasVirtualAccount reflects whether an active account actually exists for the user today. Gate your UI on canRequest, and fetch the account details once hasVirtualAccount is true.Polling
There is no webhook for virtual account onboarding. After aSUBMITTED response, poll this endpoint until status is COMPLETED or FAILED. Provider approval typically takes minutes to hours, so poll every few minutes rather than every few seconds.
Error Codes
Common Errors
| HTTP Status | Code | Message |
|---|---|---|
| 401 | UNAUTHORIZED | ”API Key is missing” |
| 401 | UNAUTHORIZED | ”Invalid API Key format” |
| 401 | UNAUTHORIZED | ”Invalid API Key” |
| 403 | INVALID_PARTNER_FLOW | ”The partner has an invalid flow.” |
User Ownership Errors
| HTTP Status | Code | Message |
|---|---|---|
| 401 | UNAUTHORIZED | ”Partner information is required for this operation” |
| 401 | UNAUTHORIZED | ”User is not associated with the partner” |
Endpoint-Specific Errors
| HTTP Status | Code | Message |
|---|---|---|
| 400 | INVALID_USER_INPUT_ERROR | ”Invalid User Input” — country is missing, not US, or userId is not a valid UUID |
| 404 | NOT_FOUND_ERROR | ”User not found” |
Authorizations
API key for the affiliated partner performing the request.
Path Parameters
The ID of the user to check. Must belong to the authenticated partner.
Example:
"8374f327-38bd-4b0b-b8a7-2524599eb903"
Query Parameters
The country whose banking onboarding to check. Only US is currently supported.
Available options:
US Example:
"US"