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.

Capabilities

Before an external card can send or receive funds through an Instant Network Transfer, Highnote verifies that the card is eligible. The result of this verification is expressed as capabilities — two independent assessments of what the card can do:

Each capability has a status of ENABLED, REQUIRES_REVIEW, or DISABLED. A card must have ENABLED status on the relevant capability before you can initiate a transfer. The two capabilities are evaluated independently and may have different statuses for the same card.

Capabilities are returned in the response from createReusablePaymentMethodToken (Step 2).

How status is determined

When you create a reusable payment method token, Highnote submits a verification request to the card's issuer. The issuer's response, combined with card network data, determines each capability's status through a series of checks.

The destination and source capabilities have different risk profiles, so some checks apply differently. Pushing money to a card (destination) requires the card network to support receiving funds, but is more lenient on identity matching. Pulling money from a card (source) does not require network-level eligibility, but demands stronger identity verification because it authorizes a debit.

  • Gate 1: Issuer approval. If the issuer declines the verification request, both capabilities are immediately DISABLED. No further checks are performed.
  • Gate 2: OCT eligibility (destination only). If the card is not eligible for OCT transactions, the destination capability is DISABLED regardless of any other results. Source capability is unaffected by this gate because pulling funds does not use OCT.

If both gates pass, Highnote scores two verification checks independently — ANI (Account Name Inquiry) and AVS (Address Verification System) — then combines them. CVV is also part of the verification request but does not affect capabilities status; it only factors into the issuer's approve or decline decision.

Account Name Inquiry

ANI compares the cardholder name you submit against the name on file with the issuer. Because pulling funds demands stronger identity confidence, ANI applies stricter thresholds to the source capability:

ANI ResultDestination (Push/OCT)Source (Pull/AFT)
Full name matchENABLEDENABLED
ANI not performedENABLEDENABLED
Partial match (first, last, or middle name only)ENABLEDREQUIRES_REVIEW
No matchREQUIRES_REVIEWDISABLED
No match vs. partial match

Both first and last name must fail to match to produce a no-match result. If either first or last name matches, the result is a partial match.

Address Verification System

AVS compares the billing address you submit against the address on file with the issuer. AVS scores the same for both capabilities:

AVS ResultStatus
Full address matchENABLED
AVS not performedENABLED
Street address match onlyREQUIRES_REVIEW
Postal code match onlyREQUIRES_REVIEW
No address matchREQUIRES_REVIEW

Combining ANI and AVS

Highnote takes the ANI and AVS statuses for each capability and applies a worst status wins rule. If either check produces DISABLED, the final status is DISABLED. If either produces REQUIRES_REVIEW, the final status is REQUIRES_REVIEW. The status is ENABLED only when both checks are ENABLED.

For example, if ANI produces ENABLED but AVS produces REQUIRES_REVIEW, the final status for that capability is REQUIRES_REVIEW.

Decision flows

The following diagrams show the full decision flow for each capability.

Destination capability (receive funds / push / OCT)

Issuer approved?
├── No ──────────────────────────────── DISABLED
└── Yes
└── Card OCT-eligible?
├── No ──────────────────────── DISABLED
└── Yes
├── ANI score:
│ ├── Full match ──────── ENABLED
│ ├── Not performed ───── ENABLED
│ ├── Partial match ───── ENABLED
│ └── No match ────────── REQUIRES_REVIEW

├── AVS score:
│ ├── Full match ──────── ENABLED
│ ├── Not performed ───── ENABLED
│ └── Partial/no match ── REQUIRES_REVIEW

└── Final: worst of ANI + AVS wins

Source capability (send funds / pull / AFT)

Issuer approved?
├── No ──────────────────────────────── DISABLED
└── Yes
├── ANI score:
│ ├── Full match ──────────────── ENABLED
│ ├── Not performed ───────────── ENABLED
│ ├── Partial match ───────────── REQUIRES_REVIEW
│ └── No match ────────────────── DISABLED

├── AVS score:
│ ├── Full match ──────────────── ENABLED
│ ├── Not performed ───────────── ENABLED
│ └── Partial/no match ────────── REQUIRES_REVIEW

└── Final: worst of ANI + AVS wins

Simulating capabilities

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

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

Query for status changes

To detect changes to the capabilities status after initial tokenization (e.g., from REQUIRES_REVIEWENABLED), query 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.

FindCustomerCapabilities
Query
query FindCustomerCapabilities($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
}
}
}
}
}
}
Variables
{
"customerIdentifier": "<YOUR_CUSTOMER_ID>"
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"customer": {
"__typename": "Customer",
"customerIdentifier": "<YOUR_CUSTOMER_ID>",
"cards": {
"__typename": "PaymentMethodConnection",
"edges": [
{
"node": {
"id": "<PAYMENT_METHOD_TOKEN>",
"usage": "MULTI_USE",
"instrument": {
"__typename": "PaymentCardInstrument",
"brand": "VISA",
"last4": "0010",
"expiryYear": "2028",
"expiryMonth": "12",
"capabilities": [
{
"__typename": "InstantNetworkTransferDestinationPaymentInstrumentCapability",
"status": "ENABLED",
"createdAt": "2026-04-21T12:00:00.000Z",
"updatedAt": "2026-04-21T12:00:00.000Z"
}
],
"cardHolder": {
"fullName": "John Doe",
"email": "john.doe@example.com",
"billingAddress": {
"streetAddress": "1234 Visa St",
"extendedAddress": null,
"locality": "Visa",
"region": "CA",
"postalCode": "12345",
"countryCodeAlpha3": "USA"
}
}
},
"checkoutToken": {
"__typename": "ScopedPaymentMethodToken",
"token": "<PAYMENT_METHOD_TOKEN>",
"scope": "ECOMMERCE"
},
"createdAt": "2026-04-21T12:00:00.000Z",
"updatedAt": "2026-04-21T12:00:00.000Z"
}
}
]
},
"referenceNode": {
"__typename": "USPersonAccountHolder",
"id": "<PERSON_ACCOUNT_HOLDER_ID>",
"name": {
"givenName": "John",
"familyName": "Doe"
},
"email": "john.doe@example.com"
}
}
}
}

Capability status-change events

When a capability transitions, Highnote sends a notification event so your integration can react without polling. The four events that fire on the PaymentMethodToken are:

Webhook event nameWhen it fires
PAYMENT_METHOD_CAPABILITY_STATUS_ENABLED_EVENTA capability moved to ENABLED (the card can be used in the corresponding direction).
PAYMENT_METHOD_CAPABILITY_STATUS_DISABLED_EVENTA capability moved to DISABLED (the card cannot be used in the corresponding direction).
PAYMENT_METHOD_CAPABILITY_STATUS_REQUIRES_REVIEW_EVENTA capability moved to REQUIRES_REVIEW (the card requires manual review by Highnote Operations before it can be used).
PAYMENT_METHOD_CAPABILITY_STATUS_REVIEWED_EVENTA capability previously in REQUIRES_REVIEW was reviewed. Inspect capability.status for the outcome (ENABLED or DISABLED).

Highnote sends one notification per capability status change — the destination and source capabilities fire independently. For payload examples and the destination/source webhook-aliasing pattern, see Capabilities events in the Events reference.

How capabilities gate transactions

A transfer cannot be initiated unless the relevant capability on the external card is ENABLED:

The two capabilities are independent — the same card may be ENABLED for one direction and REQUIRES_REVIEW or DISABLED for the other. If you attempt to initiate a transfer against a card whose capability is not ENABLED in the relevant direction, the transfer fails before the network sees it.

Event lifecycle

An Instant Network Transfer involves three distinct event categories that fire across two stages — verification (when the card is added to the vault) and execution (when a transfer is initiated):

StageEvent categoryObjectWhat it represents
Verification$0 VerificationPaymentTransactionThe issuer-side check that runs at vaulting and drives capability status.
ExecutionInstant Network Transfer eventInstantNetworkTransferEventA step in the end-to-end transfer (initial request, authorization, clearing).
ExecutionAcquiring Payment TransactionPaymentTransactionThe ISO message exchange with Visa Direct or Mastercard Send plus risk checks.

Verification stage

When you call createReusablePaymentMethodToken, Highnote submits a $0 verification to the issuer.

The verification's outcome combined with the BIN's eligibility data drives capability status as described in How status is determined.

The verification PaymentTransaction is exposed on the capability via the verificationPaymentTransaction field for traceability — query it to see the issuer's response codes (ANI, AVS, CVV) and the resulting status.

Execution stage — Instant Network Transfer events

When a transfer is initiated (via the Transfer Funds API or initiateUnifiedFundsTransfer), an InstantNetworkTransfer is created with status PENDING.

The transfer fires through the following InstantNetworkTransferEventType values, observable via the events field on the transfer:

Event typeWhen it fires
INITIAL_REQUESTThe transfer was requested.
COMPLIANCE_REVIEWA compliance review event was created during the lifecycle.
AUTHORIZE_PULL_PAYMENT_FUNDThe pull (debit / AFT) was authorized.
AUTHORIZE_PUSH_PAYMENT_FUNDThe push (credit / OCT) was authorized.
PULL_PAYMENTFunds were pulled from the source card.
PUSH_PAYMENTFunds were pushed to the destination card.
CLEAR_PULL_PAYMENT_FUNDThe pull cleared.
CLEAR_PUSH_PAYMENT_FUNDThe push cleared. The transfer transitions to COMPLETED.
REVERSE_PULL_PAYMENT_FUNDThe pull was reversed (failure path).
REVERSE_PUSH_PAYMENT_FUNDThe push was reversed (failure path).

The InstantNetworkTransferStatus transitions through PENDINGCOMPLETED (or FAILED). When the status is FAILED, the event's failureReason field is populated with one of the InstantNetworkTransferFailureReason values — for example, ANI_VERIFICATION_FAILED, COMPLIANCE_VERIFICATION_FAILED, or BAD_CVV.

Execution stage — webhook notifications

For integrations that prefer event-driven processing over polling, Highnote also delivers higher-level UFT and INT lifecycle webhook notifications:

Webhook event nameWhen it fires
UNIFIED_FUNDS_TRANSFER_INITIATED_EVENTA Unified Funds Transfer was initiated.
INSTANT_NETWORK_TRANSFER_INITIATED_EVENTThe INT portion of the UFT was initiated.
INSTANT_NETWORK_TRANSFER_COMPLETED_EVENTThe INT portion completed. Funds are good and the transfer cannot be reversed.
INSTANT_NETWORK_TRANSFER_FAILED_EVENTThe INT portion failed. Inspect failureReason on the associated event.
UNIFIED_FUNDS_TRANSFER_COMPLETED_EVENTThe UFT completed end-to-end.
UNIFIED_FUNDS_TRANSFER_FAILED_EVENTThe UFT failed end-to-end.

For payload schemas and full webhook details, see Unified funds transfer and Instant network transfer in the Events reference.

Acquiring Payment Transaction settlement

The associated PaymentTransaction (accessible via InstantNetworkTransferEvent.associatedPaymentTransaction) tracks the network ISO message exchange and risk checks. It remains in PENDING status until disbursement completes — typically T+1 business day, with weekend transfers (Fri/Sat/Sun) settling Monday.

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. Make Payment Method Token reusable

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"
}
}
}
}

The response includes capability statuses that determine whether the card can send or receive funds. See Capabilities for how these statuses are determined and how to simulate them.

Step 3. Get single-use Scoped Payment Method Token

Ensure that your reusable payment method 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"
}
}
]
}
}
}