Transfers

We describe funds movement across the Moov platform as a Transfer.

Transfers occur between a source and destination payment method, which represents how and where money should move. The only other required field is an amount.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const moov = new Moov({});

const transfer = await moov.transfers.create({
  source: {
    paymentMethodID: "SOURCE_PAYMENT_METHOD_ID",
  },
  destination: {
    paymentMethodID: "DESTINATION_PAYMENT_METHOD_ID",
  },
  amount: {
    value: 100,
    currency: "USD"
  },
});

Moov funds flow diagram

Flow of funds

All transfers facilitated with Moov involve money moving in, out, through, or within the Moov platform. Since all funds flow through Moov, a single transfer can take advantage of multiple payment rails which allows you to tailor the cost, speed, and risk of each payment to your particular use case.

Source
Bank accounts
Debit / credit cards
Wallets
right_key
Destination
Bank accounts
Wallets

Transfer responses

Moov uses standard HTTP status codes to communicate the outcome of all Moov API requests. The following table summarizes the possible responses after submitting a Create transfer POST /transfers [request] (/api/#operation/createTransfer).

warning
Receiving a 2xx response code does not indicate that the payment was successful. Use the X-Wait-For: rail-response header in your POST request to get the full response from the payment network and be prepared to handle timeouts.
HTTP code Moov status message Description
200
OK
Successfully created a transfer If you included the X-Wait-For header in your request, you will receive a synchronous response with transfer details from the payment network. Subscribe to the transfer.updated webhook event for updates on the transfer status and rail-specific details as they become available.
201
Created
Transfer was successfully created but an error occurred while getting the synchronous response. The asynchronous response object will be returned. Moov is currently unable return the full transfer object as a response, so you will only receive the asynchronous response object. To retrieve full rail-specific details at a later time, use the transfers GET endpoint. Subscribe to the transfer.updated webhook event for updates.
202
Accepted
A transfer or refund was successfully created but a timeout occurred while waiting for a synchronous response. Rail-specific details may be missing from the response object. A timeout occurred with the payment network, so you will only receive the asynchronous response object. To retrieve full rail-specific details at a later time, use the transfers GET endpoint. Subscribe to the transfer.updated webhook event for updates.
400
Bad request
Invalid request, an error message will be available in the response body. There was an issue with the request payload. Follow the error message instructions and double check your request against the request body schema in the API reference.
409
Conflict
Attempted to create a transfer using duplicate X-Idempotency-Key header Retry the request with a different X-Idempotency-Key header
422
Unprocessable content
The request body could not be processed The error message will let you know how long to wait (in milliseconds) before you can retry
429
Too many requests
Request was refused due to rate limiting The error message will let you know how long to wait (in milliseconds) before you can retry
tip
If you receive a 202 response, do not mark the transfer as successful. For payments related to physical goods, make sure that nothing ships until rail-specific transfer details are available. Either perform a subsequent GET for the transfer details or subscribe to the transfer.updated webhook event.

Transfer statuses

A transfer can have the following statuses:

Status Description
queued A transfer that is part of a group will have the queued status until the preceding transfer has successfully completed
pending The transfer is in progress, but not yet completed
completed The transfer has completed
canceled A transfer that is part of a group can fail and subsequent transfers will be marked as canceled
failed The transfer did not succeed
reversed The transfer completed, but funds were returned to the source

Rail specific statuses are also available under the source and destination. You can view rail-specific statuses in our other guides:

Source

The source of a transfer represents the first stage of a transfer, when it is being funded. Transfers can be funded by external linked bank accounts, payment cards, or a Moov wallet balance. The following payment method types can be used as the source of a transfer:

  • ach-debit-fund: fund payouts or add funds to a Moov wallet from a linked bank account
  • ach-debit-collect: pull funds from a linked bank account for bill payment, direct debit, or e-check type use-cases
  • moov-wallet: fund a payout or withdraw funds from the Moov platform
  • card-payment: initiate a payment from a linked credit or debit card

Destination

The destination represents the final stage of a transfer and the ultimate recipient of the funds. The following payment method types can be used as the destination of a transfer.

  • ach-credit-standard: disburse funds to a linked bank account
  • ach-credit-same-day: disburse funds to a linked bank account using same-day processing
  • rtp-credit* : disburse funds to a linked bank account in near real time
  • moov-wallet: add funds to a Moov wallet for multiple use cases
*RTP® is not yet generally available on Moov. Contact us for more information.

Transfer options utility

Moov offers the transfer options POST endpoint as an easy way to know which payment methods can be used in a transfer.

Some payment methods can only be used as the source or destination, and not all payment method combinations are valid options. The payment methods available for use also depend on the capabilities of the source and destination accounts. Transfer-options takes this business logic into account as well as network-specific restrictions such as maximum payment amounts to ensure a valid transfer request.

The IDs (for both accounts and payment methods) are optional in the example below.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
  "source": {
    "accountID": "4528aba-b9a1-11eb-8529-0242ac13003", 
    "paymentMethodID": "ec7e1848-dc80-4ab0-8827-dd7fc0737b43" 
  },
  "destination": {
    "accountID": "ec7e1848-dc80-4ab0-8827-dd7fc0737b43", 
    "paymentMethodID": "4528aba-b9a1-11eb-8529-0242ac13003" 
  },
  "amount": {
    "value": 100,
    "currency": "usd"
  }
}

To use transfer-options, make a request to the transfers POST endpoint with a Moov accountID or paymentMethodID and an amount.

  • Supplying a single accountID in the source{} or destination{}: will return a list of available payment methods
  • Supplying an accountID for both the source{} and destination{}: will return two lists of payment methods filtered on the capabilities of the transfer participants
  • Supplying one paymentMethodID and one accountID: will return a list of valid payment methods for the accountID provided

In practice, transfer-options can be used to present a menu of different options for how and where you want money to move.

FAQ

Why did a transfer fail?
Transfers can fail for a number of reasons related to the source or destination, or due to insufficient funds. Learn more through our guide on transfer failures.
Can I re-start a transfer that never completed?
Depending on the status of the transfer, you may be able to replay that transfer. Transfers in a “non-terminal” state (such as a child transfer stuck in queued) can be replayed by Moov, but transfers with the failed status are in a “terminal state”, meaning they cannot be replayed in our system. For reinitiating transfers that were in a terminal state, you will need to create a brand new transfer with the same details.
Why is my LIST transfers request taking so long?
When you run a LIST transfers request, you retrieve 200 transfers at a time. You can advance past a results set of 200 transfers by using the skip parameter (for example, if you set skip= 10, you will see a results set of 200 transfers after the first 2000). However, if you are searching a high volume of transfers, the request will likely process very slowly. To get faster performance, restrict the data as much as you can by using the StartDateTime and EndDateTime parameters for a limited period of time. You can run multiple requests in smaller time window increments until you’ve retrieved all the transfers you need.

Articles in this section