Collect ACH payments

Note: Only business accounts have the ability to collect payments.

If you’re looking to collect funds via ACH from other accounts, this guide covers the flow for your use case. Some examples of this scenario include:

  • A subscription-based platform collecting payments from their users
  • A utility service charging their customers for a monthly usage fee
  • A supplier collecting payments from a business

Note that this use case is only available for businesses accounts. For the purposes of this guide, we’ll use an example where you will be building a hypothetical utility bill payment platform. The key players in this scenario are:

  • The utility company (the account collecting funds)
  • The customer (the account being charged)

For the purposes of this guide, we’ll assume that you’ve created a Moov account and obtained your API keys. For more detailed instructions, see our quick start guide. Refer to the collecting ACH payments guide for an overview of the steps below.

1. Set up the account collecting funds

Start by creating a Moov account for the utility company. Request the collect-funds capability for the utility company’s account. You will need to submit specific data about the business and its representatives to Moov for verification before the capability is enabled. See our capabilities guide for a list of required information.

Every eligible Moov account automatically comes with a Moov wallet, so you won’t need any additional setup to collect payments with a wallet.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
curl -X POST "https://api.moov.io/accounts" \
  -H "Authorization: Bearer {token}" \
  --data-raw '{
    "accountType": "business",
    "profile": {
      "business": {
        "legalBusinessName": "Neighborhood Utility",
        "businessType": "incorporatedNonProfit"
      }
    },
    "capabilities": ["collect-funds"],
    "foreignId": "your-correlation-id"
  }'\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const moov = new Moov(credentialsObject);

const accountPayload = {
  accountType: "business",
  profile: {
    business: {
      legalBusinessName: "Neighborhood Utility",
      businessType: "incorporatedNonProfit"
    }
  },
  foreignId: "your-correlation-id",
  capabilities: ["collect-funds"]
};

const account = await moov.accounts.create(accountPayload);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const moov = Moov(token);

const accountPayload = {
  accountType: "business",
  profile: {
    business: {
      legalBusinessName: "Neighborhood Utility",
      businessType: "incorporatedNonProfit"
    }
  },
  foreignId: "your-correlation-id",
  capabilities: ["collect-funds"]
};

const account = await moov.accounts.create({accountPayload});

2. Set up the account to collect from

Add a Moov account for the customer and provide their legal name and phone or email address.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
curl -X POST "https://api.moov.io/accounts" \
  -H "Authorization: Bearer {token}" \
  --data-raw '{
    "accountType": "individual",
    "profile": {
      "individual": {
        "email": "julesjacksonyoga@moov.io",
        "name": {
          "firstName": "Jules",
          "lastName": "Jackson"
        }
      }
    },
    "foreignID": "your-correlation-id"
  }'\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const moov = new Moov(credentialsObject);

const accountPayload = {  
  accountType: "individual",
  profile: {
    individual: {
      email: "julesjacksonyoga@moov.io",
      name: {
        firstName: "Jules",
        lastName: "Jackson"
      }
    }
  },
  foreignID: "your-correlation-id"
};

const account = await moov.accounts.create(accountPayload);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const moov = Moov(token);

const accountPayload = {  
  accountType: "individual",
  profile: {
    individual: {
      email: "julesjacksonyoga@moov.io",
      name: {
        firstName: "Jules",
        lastName: "Jackson"
      }
    }
  },
  foreignID: "your-correlation-id"
};

const account = await moov.accounts.create({accountPayload});

3. Add a bank account for the customer

Start by adding a bank account for the customer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
curl -X POST "https://api.moov.io/accounts/{accountID}/bank-accounts" \
  -H "Authorization: Bearer {token}" \
  --data-raw '{
    "account": {
      "accountNumber": "0004321567000",
      "bankAccountType": "checking",
      "holderName": "Jules Jackson",
      "holderType": "individual",
      "routingNumber": "123456789"
    }
  }'\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const moov = new Moov(credentialsObject);

const accountID = "accountID";
const bankAccountPayload = {
  bankAccount: {
    accountNumber: "0004321567000",
    bankAccountType: "checking",
    holderName: "Jules Jackson",
    holderType: "individual",
    routingNumber: "123456789"
  }
}

const response = await moov.bankaccounts.link(accountID, bankAccountPayload);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const moov = Moov(token);

const accountID = "accountID";
const bankAccountPayload = {
  accountNumber: "0004321567000",
  bankAccountType: "checking",
  holderName: "Jules Jackson",
  holderType: "individual",
  routingNumber: "123456789"
};

moov.accounts.bankAccounts.link({accountID, bankAccountPayload});

Initiate micro-deposits

After you’ve added a bank account, the customer must initiate and complete the micro-deposit verification process before you can pull funds from their account. Alternatively, you can verify bank accounts with instant account verification (IAV). Read more on how to link bank accounts with MX or Plaid.

1
2
curl -X POST "https://api.moov.io/accounts/{accountID}/bank-accounts/{bankAccountID}/micro-deposits" \
  -H "Authorization: Bearer {token}" \
1
2
3
4
5
6
const moov = new Moov(credentialsObject);

const accountID = "accountID";
const bankAccountID = "bankAccountID";

const response = await moov.bankAccounts.initMicroDeposits(accountID, bankAccountID);
1
2
3
4
5
6
const moov = Moov(token);

const accountID = "accountID";
const bankAccountID = "bankAccountID";

moov.accounts.bankAccounts.startMicroDepositVerification({accountID, bankAccountID});

Confirm micro-deposits

Once the micro-deposit values have landed in the user’s bank account, complete the micro-deposit verification process by confirming the values.

1
2
3
4
5
6
7
8
curl -X POST "https://api.moov.io/accounts/{accountID}/bank-accounts/{bankAccountID}/micro-deposits" \
  -H "Authorization: Bearer {token}" \
  --data-raw '{
    "amounts": [
      18,
      21
    ]
  }'\
1
2
3
4
5
6
7
const moov = new Moov(credentialsObject);

const accountID = "accountID";
const bankAccountID = "bankAccountID";
const microDeposits = [18, 21]

const response = await moov.bankAccounts.completeMicroDeposits(accountID, bankAccountID, microDeposits);
1
2
3
4
5
6
7
const moov = Moov(token);

const accountID = "accountID";
const bankAccountID = "bankAccountID";
const microDeposits = [18, 21]

moov.accounts.bankAccounts.completeMicroDepositVerification({accountID, bankAccountID, microDeposits});

4. Get payment methods

Once you’ve set up the utility company and the customer’s accounts, you’re ready to collect a payment. First, you can get a list of the available payment methods from the transfer options endpoint.

When collecting a payment using ACH, you will always use a payment method of type ach-debit-collect for the transfer source. Transfer options will also provide available payment methods for disbursement of the collected funds (for example, the utility company’s Moov wallet).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
curl -X POST "https://api.moov.io/transfer-options" \
  -H "Authorization: Bearer {token}" \
  --data-raw '{
    "amount": {
      "value": 100,
      "currency": "USD"
    }
    "destination": {
      "accountID": "UUID"
    },
    "source": {
      "accountID": "UUID"
    }
  }'\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const moov = new Moov(credentialsObject);

const sourceAccountID = "sourceAccountID";
const destinationAccountID = "destinationAccountID";
const transferOptions = {
  amount: {
    value: 100, 
    currency: "USD"
  },
  destination: {
    accountID: destinationAccountID
  },
  source: {
    accountID: sourceAccountID
  }
}

const options = await moov.transfers.getTransferOptions(transferOptions);

5. Initiate the transfer

Once you’ve selected the payment methods for the transaction, you can initiate a transfer between the two accounts, using the payment method IDs for the wallet and bank account you got earlier in the transfer options request.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
curl -X POST "https://api.moov.io/transfers" \
  -H "Authorization: Bearer {token}" \
  -H "X-Idempotency-Key: UUID" \
  -H "X-Wait-For: rail-response" \
  --data-raw '{
    "amount": {
      "value": 100,
      "currency": "USD"
    },
    "destination": {
      "paymentMethodID": "UUID"
    },
    "source": {
      "paymentMethodID": "UUID"
    },
    "description": "Optional transaction description."
  }'\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
mc := moov.NewClient()

mc.CreateTransfer(ctx, moov.CreateTransfer{
  Amount: moov.Amount{
    Currency: "usd",
    Value:    100, // $1.00
  },
  Destination: moov.CreateTransfer_Destination{
    PaymentMethodID: "UUID",
  },
  Source: moov.CreateTransfer_Source{
    PaymentMethodID: "UUID", 
  },
  Description: "Optional transaction description.",
})
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const moov = new Moov(credentialsObject);

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

What’s next

Feel free to explore Moov.js, our in-browser JavaScript SDK. Or, if you’re interested in other use cases, you can dive into our guides:

Summary Beta