Skip to main content
A business can pay on two rails, Dwolla and Cleo Pay. It keeps both and picks one per payment. The business’s default rail only applies when a payment names no rail and no source. The other rail stays usable.

List what the business can pay from

The key needs payments:initiate, bank-accounts:read or bank-accounts:write.
Sources on the default rail come first. isDefault marks the source a payment uses when it names nothing. availableCents is set on the balance only, and only when the key can read payments or the balance. When canPay is false, unavailableReason says why and actionUrl (when set) links to the web page where your user fixes it: New reasons may be added. Treat an unknown reason as “cannot pay from this source now”.

Pay from a source

Copy the chosen item’s pay fields into POST /v1/payments: The listing never includes achAuthorizationAccepted. A list is not consent. Add it yourself, and only after your user has accepted the ACH debit authorization for the linked bank.
Paying from the linked bank is not available through the API yet. fundingSource: "BANK" answers 403 feature_unavailable, and the linked bank lists with canPay: false and unavailableReason: "bank_funding_unavailable". Pay from the balance or a Dwolla bank. When Cleo turns bank funding on, it records your API key and the request’s IP address with the authorization.

How Cleo picks the rail

Cleo reads the fields you send in this order:
  1. If you send paymentRail, that is the rail.
  2. Otherwise, if you send fundingSource, the rail is Cleo Pay.
  3. Otherwise, if bankAccountId is one of the business’s Dwolla banks, the rail is Dwolla.
  4. Otherwise, the business’s default rail applies.
Cleo then checks that the business can send on that rail. It does not fall back to the other rail. Some combinations are refused with 400 validation_error, so a field is never silently ignored: A bankAccountId that is not one of the business’s banks answers 404 not_found. On Cleo Pay, an omitted fundingSource pays from the balance. The older body { "payableId": "...", "bankAccountId": "..." } still works. A Dwolla bank in it pays on Dwolla, whatever the default rail. Any other bank id on a business whose default rail is Cleo Pay pays from the Cleo Pay balance. The response always says which rail and source were used.

Retries keep their rail

A bill whose last payment failed is retried on the rail of that failed payment, never on the current default. When nothing moved yet, the retry also uses the same source. If you pay such a bill with POST /v1/payments, name that rail and source. Anything else answers validation_error with the fields to send. See Cancel and retry.