Skip to main content

Instant Network Transfers

Overview

Highnote Instant Network Transfer (INT) is a specific payment rail within Highnote's instant payments suite that enables your cardholders to make near real-time domestic money movements between cards, both personal and business.

The INT payment rail facilitates card-to-card transfers from Highnote-issued payment cards to eligible external debit and prepaid cards, operating through Visa Direct and Mastercard Send (a Mastercard Move platform).

Instant Network Transfers are implemented through Highnote's Unified Funds Transfer (UFT) framework, using the UnifiedFundsTransfer API object to handle the technical processing of these card-to-card transactions.

transfer funds api

You can also send Instant Network Transfers with the Transfer Funds API which lets you move money in a single call by setting a strategy and without getting a quote.

Notification events

The Highnote platform sends notification events for the Unified Funds Transfer and its associated Instant Network Transfer. See the Events Reference (scroll to the bottom of the page if not taken there).

Creating an instant payment

Creating an instant payment requires the following steps:

no reversals or refunds

You cannot reverse or refund Instant Network Transfers. As soon as an INT completes, the funds are considered “good funds,” and the transfer cannot be undone.

To reverse the money movement of a completed Instant Network Transfer, you must run another follow-on INT. All associated fees are charged to you.

Step 1. Generate single-use Payment Method Token

You can use the Highnote Checkout SDK or Secure Inputs SDK to tokenize a customer's card data as a single-use PaymentMethodToken. Integrate either SDK in your application on the page where the customer enters their card and saves their payment method.

Summary of the SDK token flow
  1. Fetch client token with generatePaymentMethodTokenizationClientToken: Your server gets a client token from Highnote for authentication.
  2. Initialize SDK: You pass the client token to renderCheckout() (with other configurations).
  3. Customer presses Submit button: This triggers an onTokenizeSuccess callback whereby the SDK tokenizes the card data and returns a PaymentMethodToken representing the customer's card data.
  4. Pass PaymentMethodToken to your server: Your server can securely authenticate with Highnote's API to complete the payment process.
The single-use PaymentMethodToken is valid for 3 hours.

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",
},
});

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.

Step 2. Associate Payment Method Token with customer ID

Capabilities

Capabilities are available immediately in the mutation response but may take a few moments to appear in subsequent queries due to eventual consistency.

In this step, you associate the single-use PaymentMethodToken from Step 1 with the customer's ID, thereby making it a reusable token. The reusable PaymentMethodToken is only effective if capabilities status returns as ENABLED.

Use the mutation createReusablePaymentMethodToken and set paymentMethodTokenId to the single-use PaymentMethodToken (e.g., "tkpmc_single_use_1"). The response returns a checkoutToken (e.g., "tkpmc_1").

You only need to create a reusable PaymentMethodToken once per customer.
CreateReusablePaymentMethodToken
Query
mutation CreateReusablePaymentMethodToken(
$input: CreateReusablePaymentMethodTokenInput!
) {
createReusablePaymentMethodToken(input: $input) {
__typename
... on PaymentMethodToken {
instrument {
__typename
... on PaymentCardInstrument {
brand
last4
capabilities {
__typename
... on InstantNetworkTransferDestinationPaymentInstrumentCapability {
createdAt
status
updatedAt
}
}
}
}
checkoutToken: token(scope: ECOMMERCE) {
... on ScopedPaymentMethodToken {
token
}
}
}
}
}
Variables
{
  "input": {
    "paymentMethodTokenId": "tkpmc_single_use_1",
    "customerIdentifier": "ps_customerIdentifier",
    "idempotencyKey": "idempotencyKey"
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"createReusablePaymentMethodToken": {
"__typename": "PaymentMethodToken",
"instrument": {
"__typename": "PaymentCardInstrument",
"brand": "VISA",
"last4": "4242",
"capabilities": [
{
"__typename": "InstantNetworkTransferDestinationPaymentInstrumentCapability",
"createdAt": "2025-07-11T23:28:18.977Z",
"status": "ENABLED",
"updatedAt": "2025-07-11T23:28:18.977Z"
}
]
},
"checkoutToken": {
"token": "tkpmc_1"
}
}
}
}

Verification request

With the mutation createReusablePaymentMethodToken (Step 2), the Highnote platform submits a verification request to the issuer through the card network.

This verification includes checks for:

  • ANI (Account Name Inquiry)
  • AVS (Address Verification System)
  • CVV (Card Verification Value)

The combined results determine the capabilities status of the payment card. The verification must be approved to achieve ENABLED or REQUIRES_REVIEW status.

Capabilities status

The capability status enum has 3 possible values:

StatusIssuer VerificationName Matching
ENABLEDApprovedFull name match (first AND last), OR ANI not performed
REQUIRES_REVIEWApprovedPartial name match (first OR last)
DISABLEDApprovedNo name match (neither first NOR last name matched)
DISABLEDDeclinedAny result

Simulating capabilities status

You can simulate these values with the following card data. Currently, only Visa cards support simulating capabilities.

Card NetworkPANCVV/CVCExpirationNameAddress
Visa4000 0000 0000 0010111Any future dateJohn Doe1234 Visa St, Visa, CA 12345

Polling capabilities status changes

To detect changes to the capabilities status after initial tokenization (e.g., from REQUIRES_REVIEWENABLED), poll for the Customer object with the list of reusable payment methods (each will have a list of capabilities and their latest status). You can remove the checkoutToken object from the query.

The following query demonstrates polling on the Customer object:

query FindCustomer($customerIdentifier: String!) {
customer(customerIdentifier: $customerIdentifier) {
__typename
... on Customer {
customerIdentifier
cards: wallet(
first: 10
filterBy: { paymentMethodType: { equals: PAYMENT_CARD } }
) {
__typename
... on PaymentMethodConnection {
edges {
node {
... on PaymentMethodToken {
id
usage
instrument {
__typename
... on PaymentCardInstrument {
brand
last4
expiryYear
expiryMonth
capabilities {
__typename
... on InstantNetworkTransferDestinationPaymentInstrumentCapability {
status
createdAt
updatedAt
}
}
cardHolder {
fullName
email
billingAddress {
streetAddress
extendedAddress
locality
region
postalCode
countryCodeAlpha3
}
}
}
}
checkoutToken: token(scope: ECOMMERCE) {
__typename
... on ScopedPaymentMethodToken {
token
scope
}
}
createdAt
updatedAt
}
}
}
}
}
referenceNode {
__typename
... on USPersonAccountHolder {
id
name {
givenName
familyName
}
email
}
... on USBusinessAccountHolder {
id
businessProfile {
id
name {
legalBusinessName
}
website
}
}
}
}
}
}

Step 3. Get single-use Scoped Payment Method Token

Ensure that your reusable payment methods token has capabilities status = ENABLED.

You can get a unique single-use ScopedPaymentMethodToken by querying the Customer object with the reusable payment method token. Set token to the reusable PaymentMethodToken (e.g., "tkpmc_1").

{
"checkoutToken": {
"__typename": "ScopedPaymentMethodToken",
"token": "tkpmc_1",
"scope": "ECOMMERCE"
}
}

Step 4. Create a Unified Funds Transfer Quote

Quotes are valid for 30 minutes. Once a quote expires, you must generate a new one.

Before you can initiate a card-to-card Unified Funds Transfer, you must first request a quote for the fees to present to the user. All fees come out of the subscriber's financial account.

To create a quote for fees, set the following inputs:

  • Set source.id as the ID of a Highnote FinancialAccount owned by user.
  • Set source.amount as the amount to send.
  • Set destination.id as the ScopedPaymentMethodToken.

Each UnifiedFundsTransferQuote has an expiresAt value indicating how long the quote is valid. Reference that timestamp to ensure the quote is still valid when offering it to the user.

You are now ready to use the following mutation to create a UnifiedFundsTransferQuote in a quote state. You may get back multiple quotes depending on the fee and time estimate.

CreateTransferQuote
Query
mutation CreateTransferQuote($input: CreateUnifiedFundsTransferQuoteInput!) {
createUnifiedFundsTransferQuote(input: $input) {
__typename
... on CreateUnifiedFundsTransferQuoteResult {
quotes {
id
source {
node {
... on FinancialAccount {
id
}
}
amount {
currencyCode
value
decimalPlaces
}
}
destination {
node {
... on PaymentMethodToken {
id
}
}
amount {
currencyCode
value
decimalPlaces
}
}
transferDetail {
timeEstimate
feeTotal {
value
decimalPlaces
}
}
idempotencyKey
expiresAt
}
}
}
}
Variables
{
  "input": {
    "source": {
      "id": "ac_1",
      "amount": {
        "currencyCode": "USD",
        "value": "15000"
      }
    },
    "destination": {
      "id": "tkpmc_1"
    },
    "idempotencyKey": "idempotencyKey"
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"createUnifiedFundsTransferQuote": {
"__typename": "CreateUnifiedFundsTransferQuoteResult",
"quotes": [
{
"quoteIdentifier": "woquo_1",
"source": {
"node": {
"id": "ac_1"
},
"amount": {
"currencyCode": "USD",
"value": 15000,
"decimalPlaces": 2
}
},
"destination": {
"node": {
"id": "tkpmc_1"
},
"amount": {
"currencyCode": "USD",
"value": 14737,
"decimalPlaces": 2
}
},
"transferDetails": {
"timeEstimate": "3 seconds",
"feeTotal": {
"value": 263,
"decimalPlaces": 2
}
},
"idempotencyKey": "idempotencyKey",
"expiresAt": "2022-01-01T00:00:00Z"
},
{
"quoteIdentifier": "woquo_2",
"source": {
"node": {
"id": "ac_1"
},
"amount": {
"currencyCode": "USD",
"value": 15000,
"decimalPlaces": 2
}
},
"destination": {
"node": {
"id": "tkpmc_1"
},
"amount": {
"currencyCode": "USD",
"value": 15000,
"decimalPlaces": 2
}
},
"transferDetails": {
"timeEstimate": "2-5 days",
"feeTotal": {
"value": 0,
"decimalPlaces": 2
}
},
"idempotencyKey": "idempotencyKey",
"expiresAt": "2022-01-01T00:00:00Z"
}
]
}
}
}

Step 5. Initiate a Unified Funds Transfer

Once the user has chosen a quote, you can initiate the transfer. Use a UnifiedFundsTransferQuote.quoteIdentifier that has not expired to start the transfer.

InitiateUnifiedFundsTransfer
Query
mutation InitiateUnifiedFundsTransfer(
$input: InitiateUnifiedFundsTransferInput!
) {
initiateUnifiedFundsTransfer(input: $input) {
__typename
... on UnifiedFundsTransfer {
id
source {
node {
... on FinancialAccount {
id
}
}
amount {
currencyCode
value
decimalPlaces
}
}
destination {
node {
... on PaymentMethodToken {
id
}
}
amount {
currencyCode
value
decimalPlaces
}
}
externalIdentifier
idempotencyKey
steps {
... on UnifiedFundsTransferInitiateRequestStep {
status
createdAt
}
... on UnifiedFundsTransferInstantNetworkTransferStep {
status
createdAt
transfer {
... on InstantNetworkTransfer {
id
createdAt
updatedAt
status
failureReason
}
}
}
}
}
}
}
Variables
{
  "input": {
    "id": "woquo_1"
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"initiateUnifiedFundsTransfer": {
"__typename": "UnifiedFundsTransfer",
"id": "wouft_1",
"source": {
"node": {
"id": "ac_1"
}
},
"destination": {
"node": {
"id": "tkpmc_1"
}
},
"externalIdentifier": "externalIdentifier",
"idempotencyKey": "idempotencyKey",
"steps": [
{
"status": "COMPLETED",
"createdAt": "2025-07-11T19:22:37.510Z"
},
{
"status": "PROCESSING",
"createdAt": "2025-07-11T19:22:37.510Z",
"transfer": {
"id": "eftip_1",
"createdAt": "2025-07-11T19:22:37.223Z",
"updatedAt": "2025-07-11T19:22:37.229Z",
"status": "PENDING",
"failureReason": null
}
}
]
}
}
}

Query existing Unified Funds Transfer

To look up an existing Unified Funds Transfer, use the following query:

GetInstantNetworkTransfer
Query
query GetInstantNetworkTransfer($id: ID!) {
node(id: $id) {
__typename
id
... on UnifiedFundsTransfer {
status
steps {
__typename
... on UnifiedFundsTransferInstantNetworkTransferStep {
__typename
transfer {
... on InstantNetworkTransfer {
createdAt
destination {
node {
__typename
... on PaymentMethodToken {
id
}
}
}
status
events {
__typename
type
}
externalIdentifier
failureReason
id
idempotencyKey
updatedAt
}
}
}
}
}
}
}
Variables
{
"id": "wouft_1"
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"node": {
"__typename": "UnifiedFundsTransfer",
"id": "wouft_1",
"status": "PROCESSING",
"steps": [
{
"__typename": "UnifiedFundsTransferInitiateRequestStep"
},
{
"__typename": "UnifiedFundsTransferInstantNetworkTransferStep",
"transfer": {
"createdAt": "2025-07-10T22:30:59.749Z",
"destination": {
"node": {
"__typename": "PaymentMethodToken",
"id": "pm_1"
}
},
"status": "COMPLETED",
"events": [
{
"__typename": "InstantNetworkTransferEvent",
"type": "PUSH_PAYMENT"
},
{
"__typename": "InstantNetworkTransferEvent",
"type": "CLEAR_PUSH_PAYMENT_FUND"
},
{
"__typename": "InstantNetworkTransferEvent",
"type": "AUTHORIZED_PUSH_PAYMENT_FUND"
}
],
"externalIdentifier": "",
"failureReason": null,
"id": "eftip_1",
"idempotencyKey": "idempotencyKey",
"updatedAt": "2025-07-10T22:31:09.876Z"
}
}
]
}
}
}