Create Transfer
curl --request POST \
--url https://api.hopnow.io/v1/accounts/{account_id}/transfers \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'X-API-Key: <api-key>' \
--data '
{
"source": {},
"destination": {},
"amount": "<string>",
"currency": "<string>",
"reference": "<string>",
"internal_note": "<string>"
}
'import requests
url = "https://api.hopnow.io/v1/accounts/{account_id}/transfers"
payload = {
"source": {},
"destination": {},
"amount": "<string>",
"currency": "<string>",
"reference": "<string>",
"internal_note": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
'X-API-Key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
source: {},
destination: {},
amount: '<string>',
currency: '<string>',
reference: '<string>',
internal_note: '<string>'
})
};
fetch('https://api.hopnow.io/v1/accounts/{account_id}/transfers', 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.hopnow.io/v1/accounts/{account_id}/transfers",
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([
'source' => [
],
'destination' => [
],
'amount' => '<string>',
'currency' => '<string>',
'reference' => '<string>',
'internal_note' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"X-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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.hopnow.io/v1/accounts/{account_id}/transfers"
payload := strings.NewReader("{\n \"source\": {},\n \"destination\": {},\n \"amount\": \"<string>\",\n \"currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"internal_note\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("X-API-Key", "<api-key>")
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.hopnow.io/v1/accounts/{account_id}/transfers")
.header("Idempotency-Key", "<idempotency-key>")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"source\": {},\n \"destination\": {},\n \"amount\": \"<string>\",\n \"currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"internal_note\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hopnow.io/v1/accounts/{account_id}/transfers")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source\": {},\n \"destination\": {},\n \"amount\": \"<string>\",\n \"currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"internal_note\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"object": "<string>",
"account_id": "<string>",
"source": {},
"destination": {},
"amount": "<string>",
"currency": "<string>",
"status": "<string>",
"reference": "<string>",
"internal_note": "<string>",
"created": "<string>",
"updated": "<string>",
"created_by": "<string>",
"updated_by": "<string>"
}Transfers
Create Transfer
Move funds between the trading account and one of the account’s virtual accounts, or between two virtual accounts, in the same currency
POST
/
v1
/
accounts
/
{account_id}
/
transfers
Create Transfer
curl --request POST \
--url https://api.hopnow.io/v1/accounts/{account_id}/transfers \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'X-API-Key: <api-key>' \
--data '
{
"source": {},
"destination": {},
"amount": "<string>",
"currency": "<string>",
"reference": "<string>",
"internal_note": "<string>"
}
'import requests
url = "https://api.hopnow.io/v1/accounts/{account_id}/transfers"
payload = {
"source": {},
"destination": {},
"amount": "<string>",
"currency": "<string>",
"reference": "<string>",
"internal_note": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
'X-API-Key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
source: {},
destination: {},
amount: '<string>',
currency: '<string>',
reference: '<string>',
internal_note: '<string>'
})
};
fetch('https://api.hopnow.io/v1/accounts/{account_id}/transfers', 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.hopnow.io/v1/accounts/{account_id}/transfers",
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([
'source' => [
],
'destination' => [
],
'amount' => '<string>',
'currency' => '<string>',
'reference' => '<string>',
'internal_note' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"X-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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.hopnow.io/v1/accounts/{account_id}/transfers"
payload := strings.NewReader("{\n \"source\": {},\n \"destination\": {},\n \"amount\": \"<string>\",\n \"currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"internal_note\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("X-API-Key", "<api-key>")
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.hopnow.io/v1/accounts/{account_id}/transfers")
.header("Idempotency-Key", "<idempotency-key>")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"source\": {},\n \"destination\": {},\n \"amount\": \"<string>\",\n \"currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"internal_note\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hopnow.io/v1/accounts/{account_id}/transfers")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source\": {},\n \"destination\": {},\n \"amount\": \"<string>\",\n \"currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"internal_note\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"object": "<string>",
"account_id": "<string>",
"source": {},
"destination": {},
"amount": "<string>",
"currency": "<string>",
"status": "<string>",
"reference": "<string>",
"internal_note": "<string>",
"created": "<string>",
"updated": "<string>",
"created_by": "<string>",
"updated_by": "<string>"
}A transfer is a same-currency book transfer inside one account. At least one leg must be a virtual account: trading account → virtual account, virtual account → trading account, or virtual account → virtual account. Converting between currencies is done with FX, not with a transfer.
Transfers settle synchronously: the source is debited and the destination credited in the same request, and the returned transfer is already
completed.
Requires an API key with write access on the payments scope.
Path Parameters
string
required
The account’s external ID (starts with
acct_)Headers
string
required
Key for this transfer: any string up to 255 characters, a UUID recommended but not enforced. Scoped to the account: replaying it with the same payload returns the original transfer with
200, and with a different payload 409 IDEMPOTENCY_CONFLICT. See Idempotency.Request Body
object
required
Balance location to debit. Either
{"type": "trading_account"} or {"type": "virtual_account", "virtual_account_id": "va_…"}. The virtual account must belong to this account, be active, and hold the transfer currency.object
required
Balance location to credit, same shape as
source. Trading account → trading account is rejected, and the two legs cannot be the same virtual account.string
required
Transfer amount as a decimal string, greater than 0. The available balance of the source leg must cover it.
string
required
Currency code, for example
USD. Both legs settle in this currency; a trading-account leg uses the trading account’s balance in this currency.string
Optional reference shown on the transfer (max 255 characters)
string
Optional internal note, never shown to counterparties (max 500 characters)
Response
Returns201 with the new transfer, or 200 with the existing transfer when the Idempotency-Key was already used with the same payload.
string
Transfer identifier (starts with
trf_)string
Always returns
"transfer"string
Account ID
object
Balance location debited:
{"type": "trading_account"} or {"type": "virtual_account", "virtual_account_id": "va_…"}object
Balance location credited, same shape as
sourcestring
Transfer amount (decimal)
string
Transfer currency code
string
Transfer status. Transfers settle synchronously, so a successful response is always
completed; failed is reserved for transfers that could not be posted.string
Reference, or
nullstring
Internal note, or
nullstring
ISO 8601 timestamp when created
string
ISO 8601 timestamp when last updated
string
ID of the API key that created the transfer (starts with
ak_)string
Actor that last updated the transfer, or
nullErrors
| Status | code | When |
|---|---|---|
404 | RESOURCE_NOT_FOUND | A virtual_account_id does not belong to this account |
409 | IDEMPOTENCY_CONFLICT | The Idempotency-Key was already used with a different payload; details.transfer_id is the existing transfer |
422 | TRANSFER_TRADING_TO_TRADING | Both legs are trading_account |
422 | TRANSFER_SAME_LOCATION | Both legs are the same virtual account |
422 | VIRTUAL_ACCOUNT_INACTIVE | A virtual account leg is not active |
422 | CURRENCY_MISMATCH | A virtual account leg is not denominated in currency |
422 | INSUFFICIENT_FUNDS | The source leg’s available balance is below amount; details.available carries the current available balance |
Request Example
{
"source": {"type": "trading_account"},
"destination": {"type": "virtual_account", "virtual_account_id": "va_7f3k2m9p4q1w8e5r3t6y0u2i"},
"amount": "250.00",
"currency": "USD",
"reference": "Fund operating account"
}
Response Example
{
"id": "trf_6h2k9m4p1w8e5r3t6y0u2i4a",
"object": "transfer",
"account_id": "acct_9f2a7c1e6a2b4f3c9b8d2e5a",
"source": {"type": "trading_account"},
"destination": {"type": "virtual_account", "virtual_account_id": "va_7f3k2m9p4q1w8e5r3t6y0u2i"},
"amount": "250.00",
"currency": "USD",
"status": "completed",
"reference": "Fund operating account",
"internal_note": null,
"created": "2026-01-15T10:00:00Z",
"updated": "2026-01-15T10:00:00Z",
"created_by": "ak_9a3yfd2ro3jeoqqalbx8jew1",
"updated_by": null
}