Skip to main content

Transfer Funds API

Overview

The Transfer Funds API moves money in a single-call, eliminating the multi-step quote flow. Real-Time Payment (RTP) and Instant Network Transfer (INT) rails are supported.

See PCI scope to fully understand your PCI burden when tokenizing data.

PCI scope

You have three options when tokenizing data, each with different PCI burdens:

  • Direct API call: When you tokenize directly with tokenizeCardPaymentMethod, raw card data passes through your servers and puts you in full PCI DSS scope.
  • Highnote SDK: When you use a Highnote SDK, card data never touches your servers and passes from the customer's browser to Highnote. You stay out of PCI scope, or at a much lower level like SAQ A.
  • PCI-compliant vendor: Using a vendor is the middle ground. You can call the API directly but the PCI compliant vendor handles the PCI-sensitive part, keeping you out of full PCI scope.

Payment strategy

Specify the rail in preferredPaymentStrategy:

StrategyRailDescription
[RTP]Real-Time PaymentsPush funds from a Highnote FinancialAccount to an external bank account via destination.usBankAccount with bankTransferDetails.
[INSTANT_NETWORK_TRANSFER]Instant Network TransferPush funds to or pull funds from a tokenized external card via Visa Direct or Mastercard Send.
[] or not providedFails with USER_ERROR listing supported strategies.

Transfer options

Each row below shows the calls required to complete one transfer; an empty cell means the flow ends at the previous step. Rows 1–3 complete the transfer in a single transferFunds call.

Row 4 shows the UnifiedFundsTransfer flow, which separates fetching a fee quote (createUnifiedFundsTransferQuote) from initiating the transfer (initiateUnifiedFundsTransfer) so you can show the customer fees before committing.

RailStep 1Step 2Step 3
RTPtransferFunds
RTPTokenize accounttransferFunds
INTTokenize card (as a reusable token)transferFunds
INTTokenize card (as a reusable token)createUnifiedFundsTransferQuoteinitiateUnifiedFundsTransfer
  • RTP Transfers: Consent is required via bankTransferDetails.consent. See Consent below for the required fields.
  • Instant Network Transfers: Consent is not required; card authorization serves as implicit consent.

Source and destination

  • The source can be a Highnote FinancialAccount ID or a PaymentMethodToken ID.
  • The destination can be a Highnote FinancialAccount ID, a PaymentMethodToken ID, or raw US bank account details provided inline.
  • The amount can be defined under source.amount or destination.amount.

Network fees

Fees Highnote charges you for using the rail.

  • RTP: Fees are invoiced monthly.
  • INT: Fees are charged to the subscriber per transaction.

Customer fees

Use customerFees on transferFunds to collect a subscriber-defined fee atomically with the transfer — for example, a convenience fee, service fee, or processing fee. Each entry in the array describes one fee.

Each TransferFundsCustomerFeeInput accepts:

FieldTypeDescription
customerFeeCodeString!Code identifying the fee category — e.g., "CONVENIENCE_FEE", "SERVICE_FEE", "PROCESSING_FEE". You define this value.
descriptionStringOptional memo for the fee.
fixedAmountAmountInputFixed fee amount. Combined with basisPoints if both are provided.
basisPointsIntFee as basis points of the transfer amount; 100 = 1%. Cannot exceed 10000 (100%).
minAmountAmountInputFloor: if the calculated fee falls below this, the fee is raised to minAmount.
maxAmountAmountInputCap: if the calculated fee exceeds this, the fee is capped to maxAmount.
chargeFromTransferFundsChargeFromTypeSOURCE (added to the source debit) or DESTINATION (subtracted from the destination credit).
destinationTransferFundsCustomerFeeDestinationInputThe Highnote account that receives the fee, as { id: <FINANCIAL_ACCOUNT_ID> }.

Provide at least one of fixedAmount or basisPoints. The calculated fee is fixedAmount + (transferAmount × basisPoints / 10000), then bounded by minAmount and maxAmount if either is provided. Currency on every amount must match the transfer currency.

Charge from source

When chargeFrom: SOURCE, the fee is added to the source debit so the destination receives the full transfer amount.

customerFees example — 2.5% convenience fee, capped, paid by source
{
"customerFees": [
{
"customerFeeCode": "CONVENIENCE_FEE",
"basisPoints": 250,
"minAmount": { "currencyCode": "USD", "value": 100 },
"maxAmount": { "currencyCode": "USD", "value": 1000 },
"chargeFrom": "SOURCE",
"destination": { "id": "<FINANCIAL_ACCOUNT_ID>" },
"description": "2.5% convenience fee"
}
]
}

For a $500.00 transfer with this fee, the source is debited $510.00, the destination receives $500.00, and the fee account receives $10.00.

Charge from destination

When chargeFrom: DESTINATION, the fee is subtracted from the destination credit so the source pays the full transfer amount.

customerFees example — $1 service fee with a $2.50 floor, paid by destination
{
"customerFees": [
{
"customerFeeCode": "SERVICE_FEE",
"fixedAmount": { "currencyCode": "USD", "value": 100 },
"minAmount": { "currencyCode": "USD", "value": 250 },
"chargeFrom": "DESTINATION",
"destination": { "id": "<FINANCIAL_ACCOUNT_ID>" },
"description": "Service fee (min $2.50)"
}
]
}

For a $50.00 transfer with this fee, the source is debited $50.00, the destination receives $47.50 (the $1.00 fixed fee was raised to the $2.50 floor), and the fee account receives $2.50.

Real-Time Payments

Real-Time Payments (RTP) is a push payment; funds are pushed from a Highnote FinancialAccount to an external bank account.

There are three ways to pass account information on the RTP rail:

  • Inline raw details via destination.usBankAccount
  • Verified ExternalFinancialBankAccount ID via destination.id (with Plaid or Finicity)
  • NonVerifiedExternalUSFinancialBankAccount ID via destination.id (stored but unverified)

While you can use a verified bank account and create an ExternalFinancialBankAccount, you can also provide bank account details inline via destination.usBankAccount. This bypasses third-party bank verification (Plaid/Finicity) entirely.

The bank account details (account number, routing number) are provided directly in the request (no Plaid verification required). RTP transfers require bankTransferDetails on the source, which captures payment-related information and the customer's consent. See Consent and Idempotency below.

RTP requires you to record the customer's consent inside bankTransferDetails on the source. TransferFundsBankTransferDetailsInput has two required fields:

FieldTypeDescription
paymentRelatedInformationString!Free-form payment details that may surface to the recipient (e.g., "Invoice 0123456789 Payment 999.99 USD"). Availability and presentation depend on the receiving institution.
consentTransferAgreementConsentInput!The customer's consent record.

The TransferAgreementConsentInput object captures who authorized the transfer, when, and which consent template they accepted:

FieldTypeDescription
authorizedPersonIdID!ID of the individual authorizing the transfer. Use the accountHolderId for Person account holders, or the primaryAuthorizedPersonId for Business account holders.
consentTimestampString!ISO 8601 timestamp marking when consent was given (for example, 2026-04-25T14:30:00Z).
template.consentTemplateIdString!Identifier of the consent template your customer accepted. You define this value.
template.consentTemplateVersionString!Version of the consent template your customer accepted. You define this value.
bankTransferDetails (RTP source)
{
"bankTransferDetails": {
"paymentRelatedInformation": "Invoice 0123456789 Payment 999.99 USD",
"consent": {
"authorizedPersonId": "<AUTHORIZED_PERSON_ID>",
"consentTimestamp": "2026-04-25T14:30:00Z",
"template": {
"consentTemplateId": "<YOUR_CONSENT_TEMPLATE_ID>",
"consentTemplateVersion": "<YOUR_CONSENT_TEMPLATE_VERSION>"
}
}
}
}

Idempotency

Provide an idempotencyKey on every transferFunds request to prevent duplicate transfers when retrying after network errors or timeouts.

  • Generate a fresh UUID v4 per logical transfer.
  • Reuse the same key when retrying so Highnote recognizes the request as a retry rather than creating a duplicate transfer.

See Idempotency for the full specification.

Push to verified bank account

Highnote Financial Account to an External Bank Account

RTP transfers are asynchronous. The initial response status is typically PROCESSING. The final COMPLETED or FAILED status arrives via notification events.

transferFunds — RTP (inline bank details)
Query
mutation TransferFunds($input: TransferFundsInput!) {
transferFunds(input: $input) {
__typename
... on UnifiedFundsTransfer {
id
status
failureReason
createdAt
updatedAt
source {
node {
... on FinancialAccount {
id
}
}
amount {
currencyCode
value
decimalPlaces
}
}
destination {
node {
... on USBankAccount {
last4
routingNumber
accountType
name {
givenName
middleName
familyName
}
}
}
amount {
currencyCode
value
decimalPlaces
}
}
externalIdentifier
idempotencyKey
memo
steps {
__typename
... on UnifiedFundsTransferInitiateRequestStep {
id
status
failureReason
createdAt
}
... on UnifiedFundsTransferRtpStep {
id
status
failureReason
createdAt
transfer {
id
status
}
}
}
}
}
}
Variables
{
  "input": {
    "source": {
      "id": "ac_merchant_settlement_account",
      "amount": {
        "currencyCode": "USD",
        "value": "50000"
      }
    },
    "destination": {
      "usBankAccount": {
        "accountNumber": "123456789",
        "routingNumber": "021000021",
        "accountType": "CHECKING",
        "firstName": "John",
        "middleName": "Michael",
        "lastName": "Doe"
      },
      "bankTransferDetails": {
        "paymentRelatedInformation": "Invoice #12345 payment",
        "consent": {
          "consentTimestamp": "2026-01-20T14:30:00Z",
          "authorizedPersonId": "per_john_doe_123",
          "template": {
            "consentTemplateId": "rtp_authorization_v1",
            "consentTemplateVersion": "2.0"
          }
        }
      }
    },
    "idempotencyKey": "550e8400-e29b-41d4-a716-446655440001",
    "memo": "Payout via RTP",
    "externalIdentifier": "INVOICE-12345",
    "strategy": {
      "preferredPaymentStrategy": [
        "RTP"
      ]
    }
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"transferFunds": {
"__typename": "UnifiedFundsTransfer",
"id": "wouft_1",
"status": "PROCESSING",
"failureReason": null,
"createdAt": "2026-01-20T14:30:01Z",
"updatedAt": "2026-01-20T14:30:01Z",
"source": {
"node": {
"id": "ac_merchant_settlement_account"
},
"amount": {
"currencyCode": "USD",
"value": 50000,
"decimalPlaces": 2
}
},
"destination": {
"node": {
"last4": "6789",
"routingNumber": "021000021",
"accountType": "CHECKING",
"name": {
"givenName": "John",
"middleName": "Michael",
"familyName": "Doe"
}
},
"amount": {
"currencyCode": "USD",
"value": 49500,
"decimalPlaces": 2
}
},
"externalIdentifier": "INVOICE-12345",
"idempotencyKey": "550e8400-e29b-41d4-a716-446655440001",
"memo": "Payout via RTP",
"steps": [
{
"__typename": "UnifiedFundsTransferInitiateRequestStep",
"id": "woustep_1",
"status": "COMPLETED",
"failureReason": null,
"createdAt": "2026-01-20T14:30:01Z"
},
{
"__typename": "UnifiedFundsTransferRtpStep",
"id": "woustep_2",
"status": "PROCESSING",
"failureReason": null,
"createdAt": "2026-01-20T14:30:01Z",
"transfer": {
"id": "rtp_1",
"status": "PROCESSING"
}
}
]
}
}
}

Push to non-verified bank account

Highnote Financial Account to a Non-Verified External Bank Account

If the bank account was previously created via addNonVerifiedExternalUSFinancialBankAccount, you can pass its ID directly instead of providing inline bank details. Consent via bankTransferDetails is still required.

transferFunds — RTP (non-verified account)
Query
mutation TransferFunds($input: TransferFundsInput!) {
transferFunds(input: $input) {
__typename
... on UnifiedFundsTransfer {
id
status
failureReason
createdAt
updatedAt
source {
node {
... on FinancialAccount {
id
}
}
amount {
currencyCode
value
decimalPlaces
}
}
destination {
node {
... on USBankAccount {
last4
routingNumber
accountType
name {
givenName
familyName
}
}
}
amount {
currencyCode
value
decimalPlaces
}
}
externalIdentifier
idempotencyKey
memo
steps {
__typename
... on UnifiedFundsTransferInitiateRequestStep {
id
status
failureReason
createdAt
}
... on UnifiedFundsTransferRtpStep {
id
status
failureReason
createdAt
transfer {
id
status
}
}
}
}
... on UserError {
errors {
code
description
errorPath
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{
  "input": {
    "source": {
      "id": "ac_3",
      "amount": {
        "currencyCode": "USD",
        "value": 3501
      },
      "bankTransferDetails": {
        "paymentRelatedInformation": "Payment description here",
        "consent": {
          "consentTimestamp": "2026-02-20T06:06:51.890Z",
          "authorizedPersonId": "ps_3",
          "template": {
            "consentTemplateId": "consent",
            "consentTemplateVersion": "0"
          }
        }
      }
    },
    "destination": {
      "usBankAccount": {
        "accountNumber": "0123456789",
        "routingNumber": "074000010",
        "accountType": "CHECKING",
        "firstName": "Clemens",
        "lastName": "McKenzie"
      }
    },
    "idempotencyKey": "UUID_v4",
    "strategy": {
      "preferredPaymentStrategy": [
        "RTP"
      ]
    },
    "externalIdentifier": "UUID_v4",
    "memo": "Payout via RTP"
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"transferFunds": {
"__typename": "UnifiedFundsTransfer",
"id": "wouft_3",
"status": "PROCESSING",
"failureReason": null,
"createdAt": "2026-02-20T06:06:52Z",
"updatedAt": "2026-02-20T06:06:52Z",
"source": {
"node": {
"id": "ac_3"
},
"amount": {
"currencyCode": "USD",
"value": 3501,
"decimalPlaces": 2
}
},
"destination": {
"node": {
"last4": "6789",
"routingNumber": "074000010",
"accountType": "CHECKING",
"name": {
"givenName": "Clemens",
"familyName": "McKenzie"
}
},
"amount": {
"currencyCode": "USD",
"value": 3501,
"decimalPlaces": 2
}
},
"externalIdentifier": "UUID_V4",
"idempotencyKey": "UUID_v4",
"memo": "Payout via RTP",
"steps": [
{
"__typename": "UnifiedFundsTransferInitiateRequestStep",
"id": "woustep_5",
"status": "COMPLETED",
"failureReason": null,
"createdAt": "2026-02-20T06:06:52Z"
},
{
"__typename": "UnifiedFundsTransferRtpStep",
"id": "woustep_6",
"status": "PROCESSING",
"failureReason": null,
"createdAt": "2026-02-20T06:06:52Z",
"transfer": {
"id": "rtp_2",
"status": "PROCESSING"
}
}
]
}
}
}

RTP eligibility of receiving bank

Not all US banks participate in RTP. The Transfer Funds API does not check participation before submitting; if the receiving bank does not support RTP, the transfer fails and does not fall back to same-day ACH.

To check whether a receiving bank supports RTP before initiating a transfer, use The Clearing House (TCH) references:

When the receiving bank does not support RTP, the response surfaces failureReason: "NETWORK_NOT_SUPPORTED" on both the top-level UnifiedFundsTransfer and the UnifiedFundsTransferRtpStep:


Example failure response: NETWORK_NOT_SUPPORTED
{
"data": {
"node": {
"__typename": "UnifiedFundsTransfer",
"id": "wouft_210d83ba021e4b599a38b1672291334e",
"source": {
"node": {
"__typename": "FinancialAccount",
"id": "ac_c02204z8mb5n6h3rd1jmu0of9rkat65rpqwq"
},
"amount": {
"value": 775
}
},
"destination": {
"node": {
"__typename": "USBankAccount",
"last4": "6789",
"routingNumber": "111111118"
},
"amount": {
"value": 775
}
},
"status": "FAILED",
"failureReason": "NETWORK_NOT_SUPPORTED",
"steps": [
{
"__typename": "UnifiedFundsTransferRtpStep",
"status": "FAILED",
"failureReason": "NETWORK_NOT_SUPPORTED",
"createdAt": "2026-04-23T20:34:02.340Z",
"transfer": {
"__typename": "OriginatedRtpTransfer",
"id": "efrtp_4876b2519e55494d85db84883a5f275d",
"createdAt": "2026-04-23T20:34:06.040Z",
"updatedAt": "2026-04-23T20:34:24.897Z",
"status": "FAILED",
"failureReason": "NETWORK_NOT_SUPPORTED",
"source": {
"node": {
"__typename": "FinancialAccount",
"id": "ac_c02204z8mb5n6h3rd1jmu0of9rkat65rpqwq"
},
"amount": {
"value": 775
}
},
"destination": {
"node": {
"__typename": "USBankAccount",
"last4": "6789",
"routingNumber": "111111118",
"accountType": "CHECKING"
},
"amount": {
"value": 775
}
},
"events": null,
"bankTransferDetails": {
"paymentRelatedInformation": "Dev-live test"
}
}
},
{
"__typename": "UnifiedFundsTransferInitiateRequestStep",
"status": "COMPLETED",
"failureReason": null,
"createdAt": "2026-04-23T20:34:02.340Z"
}
]
}
}
}

Instant Network Transfer

Card transfers do not require consent; card authorization serves as implicit consent.

Instant Network Transfers move funds between a Highnote FinancialAccount and a tokenized external card (with a PaymentMethodToken) through Visa Direct or Mastercard Send. Both push to card and Pull from card are supported.

The external card must be tokenized before initiating the transfer using the Secure Inputs SDK or Checkout SDK. See Instant Network Transfers for the full flow, which includes creating a reusable token.

Tokenize with Checkout SDK

Follow the guide on setting up the Checkout SDK. When initializing the SDK, configure the submitButton text to be Submit instead of "Pay":

renderCheckout({
clientToken,
additionalFormSections: {
cardHolderName: true,
billingAddress: true,
},
submitButton: {
text: "Submit",
},
});

Tokenize with Secure Inputs SDK

Follow the guide on setting up the Secure Inputs SDK. When tokenizing, additional cardholder data is required for OFAC and AVS compliance checks — namely, fullName and billingAddress.

Push to card (Visa Direct OCT / Mastercard MoneySend Payment)

Highnote Financial Account to tokenized external card

An OCT (Original Credit Transaction) pushes funds from a Highnote Financial Account to a tokenized external card.

transferFunds — INT OCT Payment
Query
mutation TransferFunds($input: TransferFundsInput!) {
transferFunds(input: $input) {
__typename
... on UnifiedFundsTransfer {
id
status
failureReason
createdAt
updatedAt
source {
node {
... on FinancialAccount {
id
}
}
amount {
currencyCode
value
decimalPlaces
}
}
destination {
node {
... on PaymentMethodToken {
id
}
}
amount {
currencyCode
value
decimalPlaces
}
}
externalIdentifier
idempotencyKey
memo
steps {
__typename
... on UnifiedFundsTransferInitiateRequestStep {
id
status
failureReason
createdAt
}
... on UnifiedFundsTransferInstantNetworkTransferStep {
id
status
failureReason
createdAt
transfer {
... on InstantNetworkTransfer {
id
createdAt
updatedAt
status
failureReason
}
}
}
}
}
... on UserError {
errors {
code
description
errorPath
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{
  "input": {
    "source": {
      "id": "ac_2",
      "amount": {
        "currencyCode": "USD",
        "value": "10000"
      }
    },
    "destination": {
      "id": "tkpmc_2"
    },
    "idempotencyKey": "UUID_v4",
    "memo": "Card payout",
    "strategy": {
      "preferredPaymentStrategy": [
        "INSTANT_NETWORK_TRANSFER"
      ]
    }
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"transferFunds": {
"__typename": "UnifiedFundsTransfer",
"id": "wouft_2",
"status": "PROCESSING",
"failureReason": null,
"createdAt": "2026-01-20T15:00:01Z",
"updatedAt": "2026-01-20T15:00:01Z",
"source": {
"node": {
"id": "ac_2"
},
"amount": {
"currencyCode": "USD",
"value": 10000,
"decimalPlaces": 2
}
},
"destination": {
"node": {
"id": "tkpmc_2"
},
"amount": {
"currencyCode": "USD",
"value": 10000,
"decimalPlaces": 2
}
},
"externalIdentifier": null,
"idempotencyKey": "UUID_v4",
"memo": "Card payout",
"steps": [
{
"__typename": "UnifiedFundsTransferInitiateRequestStep",
"id": "woustep_3",
"status": "COMPLETED",
"failureReason": null,
"createdAt": "2026-01-20T15:00:01Z"
},
{
"__typename": "UnifiedFundsTransferInstantNetworkTransferStep",
"id": "woustep_4",
"status": "PROCESSING",
"failureReason": null,
"createdAt": "2026-01-20T15:00:01Z",
"transfer": {
"id": "int_1",
"status": "PROCESSING"
}
}
]
}
}
}

Pull from card (Visa Direct AFT / Mastercard MoneySend Funding)

tokenized external card to Highnote Financial Account

An AFT (Account Funding Transaction) pulls funds from a tokenized external card into a Highnote FinancialAccount. The mutation is the same — swap the source and destination:

INT AFT Funding
{
"input": {
"source": {
"id": "pmt_tokenized_card_123",
"amount": {
"currencyCode": "USD",
"value": "10000"
}
},
"destination": {
"id": "ac_destination_financial_account"
},
"idempotencyKey": "550e8400-e29b-41d4-a716-446655440001",
"memo": "Card funding",
"strategy": {
"preferredPaymentStrategy": ["INSTANT_NETWORK_TRANSFER"]
}
}
}