ACH (eCheck) Direct Debit

Use the Finix API to debit a bank account.


ACH (also called eCheck) Direct Debit enables you to directly debit a buyers bank account.

In compliance with NACHA’s bank account validation rule, before proceeding with any ACH transactions Finix automatically validates a bank account the first time it's being used, or after a change has been made. If the bank account is flagged as invalid, the transaction is blocked. This helps prevent fraud and decreases the chances of an ACH return.

When creating a Transfer that debits a bank account, the following values get returned for bank_account_validation_check:

  • NOT_ATTEMPTED: Default value for new bank accounts that haven’t been validated yet.
  • VALID: Bank account was found to be open and accepts ACH.
  • INVALID: Could not validate bank account. Creating an ACH Transfer with a bank account that’s marked as INVALID will result in a failure. Please reach out to the bank account holder for a new form of payment.
  • INCONCLUSIVE: Bank account validation was inconclusive. Bank accounts that are marked as INCONCLUSIVE can be processed to create an ACH Transfer .

ACH transactions can get rejected for up to sixty days for a variety of reasons including insufficient funds, closed accounts, or a revoked authorization (i.e. dispute). Because of the 60 day threshold, Finix can configure a delay in the settling of an ACH.

For example, your application can implement a six day delay to give the buyer more time and feel more confident that the ACH will not be rejected. To configure this delay, reach out to your Finix point of contact or email the Finix Support team.

Before You Begin

Before you can process ACH payments, you need the following:

Creating an ACH (eCheck) Sale

First create a Payment Instrument to represent your buyer's bank account.

  • Use Finix Hosted Fields to collect the buyer's bank account details and other payment information.
info

You must create another Identity for your buyer separate from the merchant Identity. Associate the buyer Identity with the bank account you tokenize.

Create a Transfer with the Payment Instrument you created to debit funds directly from the buyer's bank account.

Copy
Copied
curl https://finix.sandbox-payments-api.com/transfers \
    -H "Content-Type: application/vnd.json+api" \
    -H 'Finix-Version:2022-02-01' \
    -u  USsRhsHYZGBPnQw8CByJyEQW:8a14c2f9-d94b-4c72-8f5c-a62908e5b30e \
    -d '{
	    "amount": 6031,
	    "currency": "USD",
	    "fee": 603,
	    "merchant": "MUeDVrf2ahuKc9Eg5TeZugvs",
	    "source": "PIr1Ru7ewBkEYVVn7SP1u5FW",
	    "tags": {
	        "order_number": "21DFASJSAKAS"
	    }
	}'

Direct debit Transfers return a response with type DEBIT.

  • When a reversal or return gets processed a Transfer with type REVERSAL and a subtype SYSTEM is automatically created and subtracts the amount from the future settlement.

Example Response:

Copy
Copied
{
  "id" : "TR6Gnj38UyPW3CoukdL9WaR1",
  "created_at" : "2022-10-10T05:34:16.13Z",
  "updated_at" : "2022-10-10T05:34:16.68Z",
  "additional_buyer_charges" : null,
  "additional_healthcare_data" : null,
  "address_verification" : null,
  "amount" : 662154,
  "amount_requested" : 662154,
  "application" : "APgPDQrLD52TYvqazjHJJchM",
  "currency" : "USD",
  "destination" : null,
  "externally_funded" : "UNKNOWN",
  "failure_code" : null,
  "failure_message" : null,
  "fee" : 0,
  "idempotency_id" : null,
  "merchant_identity" : "IDuqZpDw28f2KK6YuDk4jNLg",
  "messages" : [ ],
  "raw" : null,
  "ready_to_settle_at" : null,
  "security_code_verification" : null,
  "source" : "PImmCg3Po7oNi7jaZcXhfkEu",
  "state" : "PENDING",
  "statement_descriptor" : "FNX*DUNDER MIFFLIN",
  "subtype" : "API",
  "tags" : { },
  "trace_id" : "236e1149-9b83-4b79-bfaf-7ff810dcf601",
  "type" : "DEBIT",
  "_links" : {
    "application" : {
      "href" : "https://finix.sandbox-payments-api.com/applications/APgPDQrLD52TYvqazjHJJchM"
    },
    "self" : {
      "href" : "https://finix.sandbox-payments-api.com/transfers/TR6Gnj38UyPW3CoukdL9WaR1"
    },
    "merchant_identity" : {
      "href" : "https://finix.sandbox-payments-api.com/identities/IDuqZpDw28f2KK6YuDk4jNLg"
    },
    "payment_instruments" : {
      "href" : "https://finix.sandbox-payments-api.com/transfers/TR6Gnj38UyPW3CoukdL9WaR1/payment_instruments"
    },
    "reversals" : {
      "href" : "https://finix.sandbox-payments-api.com/transfers/TR6Gnj38UyPW3CoukdL9WaR1/reversals"
    },
    "fees" : {
      "href" : "https://finix.sandbox-payments-api.com/transfers/TR6Gnj38UyPW3CoukdL9WaR1/fees"
    },
    "disputes" : {
      "href" : "https://finix.sandbox-payments-api.com/transfers/TR6Gnj38UyPW3CoukdL9WaR1/disputes"
    },
    "source" : {
      "href" : "https://finix.sandbox-payments-api.com/payment_instruments/PImmCg3Po7oNi7jaZcXhfkEu"
    },
    "fee_profile" : {
      "href" : "https://finix.sandbox-payments-api.com/fee_profiles/FPvCQUcnsueN3Bc3zR1qCBG8"
    }
  }
}

Like other Transfers, the response will get updated (usually within an hour) with a timestamp in ready_to_settle_at. ready_to_settle_at details when the Transfer will get included in the next Settlement that closes for the Merchant.

You'll also receive a webhook created event with entity transfer.

Example ACH (eCheck) Transfer Created
Copy
Copied
{
  "type": "created",
  "entity": "transfer",
  "occurred_at": "2022-09-01T20:36:20.588717",
  "_embedded": {
    "transfers": [
      {
        "idempotency_id": null,
        "amount": 6031,
        "trace_id": "0156ff8f-88c1-4090-8eb6-9f33218b0ec5",
        "failure_code": null,
        "fee": 603,
        "destination": null,
        "raw": null,
        "created_at": "2022-09-01T20:36:08.13Z",
        "source": "PIr1Ru7ewBkEYVVn7SP1u5FW",
        "merchant_identity": "IDuqZpDw28f2KK6YuDk4jNLg",
        "failure_message": null,
        "type": "DEBIT",
        "tags": {
          "order_number": "21DFASJSAKAS"
        },
        "statement_descriptor": "FNX*FINIX FLOWERS",
        "additional_buyer_charges": null,
        "ready_to_settle_at": null,
        "application": "APgPDQrLD52TYvqazjHJJchM",
        "updated_at": "2022-09-01T20:36:08.69Z",
        "subtype": "API",
        "externally_funded": "UNKNOWN",
        "messages": [],
        "currency": "USD",
        "id": "TRoom5emPxiP1TRAmHcSjHgz",
        "state": "PENDING"
      }
    ]
  }
}

For more information, see Paying out Transfers.

Refunding or Reversing an ACH (eCheck) Sale

Reversing an ACH (eCheck) debit is similar to reversing a Transfer.

To refund an ACH (eCheck) debit, create a Transfer reversal using the id of the original ACH (eCheck) debit Transfer that you want to reverse.

Copy
Copied
curl https://finix.sandbox-payments-api.com/transfers/TR6Gnj38UyPW3CoukdL9WaR1/reversals \
    -H "Content-Type: application/vnd.json+api" \
    -u  USsRhsHYZGBPnQw8CByJyEQW:8a14c2f9-d94b-4c72-8f5c-a62908e5b30e \
    -d  '
  {
  "refund_amount" : 6031,
  "tags" : {
      "test" : "refund"
    }
  }'

A successful response returns 201 and the newly created Transfer with type REVERSAL.

Copy
Copied
{
  "id" : "TRnqh2Mt6pnnPumxvenDmVjX",
  "created_at" : "2022-10-10T05:36:19.18Z",
  "updated_at" : "2022-10-10T05:36:19.27Z",
  "additional_buyer_charges" : null,
  "additional_healthcare_data" : null,
  "address_verification" : null,
  "amount" : 6031,
  "amount_requested" : 6031,
  "application" : "APgPDQrLD52TYvqazjHJJchM",
  "currency" : "USD",
  "destination" : "PImmCg3Po7oNi7jaZcXhfkEu",
  "externally_funded" : "UNKNOWN",
  "failure_code" : null,
  "failure_message" : null,
  "fee" : 0,
  "idempotency_id" : null,
  "merchant_identity" : "IDuqZpDw28f2KK6YuDk4jNLg",
  "messages" : [ ],
  "raw" : null,
  "ready_to_settle_at" : null,
  "security_code_verification" : null,
  "source" : null,
  "state" : "PENDING",
  "statement_descriptor" : "FNX*DUNDER MIFFLIN",
  "subtype" : "API",
  "tags" : {
    "test" : "refund"
  },
  "trace_id" : "5cc0ab4e-3609-4a13-a9c3-b435328360c1",
  "type" : "REVERSAL",
  "_links" : {
    "application" : {
      "href" : "https://finix.sandbox-payments-api.com/applications/APgPDQrLD52TYvqazjHJJchM"
    },
    "self" : {
      "href" : "https://finix.sandbox-payments-api.com/transfers/TRnqh2Mt6pnnPumxvenDmVjX"
    },
    "parent" : {
      "href" : "https://finix.sandbox-payments-api.com/transfers/TR6Gnj38UyPW3CoukdL9WaR1"
    },
    "destination" : {
      "href" : "https://finix.sandbox-payments-api.com/payment_instruments/PImmCg3Po7oNi7jaZcXhfkEu"
    },
    "merchant_identity" : {
      "href" : "https://finix.sandbox-payments-api.com/identities/IDuqZpDw28f2KK6YuDk4jNLg"
    },
    "payment_instruments" : {
      "href" : "https://finix.sandbox-payments-api.com/transfers/TRnqh2Mt6pnnPumxvenDmVjX/payment_instruments"
    },
    "fee_profile" : {
      "href" : "https://finix.sandbox-payments-api.com/fee_profiles/FPvCQUcnsueN3Bc3zR1qCBG8"
    }
  }
}

The state of the Transfer reversal will update to SUCCEEDED when the reversal gets successfully processed. Buyers will see the refund returned as a credit within 5-10 business days, depending on their bank. ACH (eCheck) reversals can’t get canceled once processed.

Handling an ACH (eCheck) Return

An ACH (eCheck) gets returned when either the credited or debited bank account can't be found. Reasons an ACH (eCheck) could return includes a typo was made when the Transfer was getting created, insufficient funds, or the bank account doesn't exist.

It can take anywhere from 2-5 days for an ACH (eCheck) debit to get returned. When an ACH (eCheck) gets returned, you receive two webhook updated events

One for debiting the seller:

  • entity - transfer
  • type - REVERSE
  • sub_type - SYSTEM

Another for the return credit:

  • entity - transfer
  • type - TRANSFER
  • sub_type - PLATFORM__CREDIT

ACH (eCheck) returns appear on the Finix Dashboard as a REVERSAL on the Refunds tab.

Example ACH (eCheck) Return Webhook Event
Copy
Copied
{
  "type": "updated",
  "entity": "transfer",
  "occurred_at": "2022-09-01T20:49:23.437609",
  "_embedded": {
    "transfers": [
      {
        "idempotency_id": null,
        "amount": 6031,
        "trace_id": "0156ff8f-88c1-4090-8eb6-9f33218b0ec5",
        "failure_code": null,
        "fee": 603,
        "destination": null,
        "raw": null,
        "created_at": "2022-09-01T20:36:08.13Z",
        "source": "PIr1Ru7ewBkEYVVn7SP1u5FW",
        "merchant_identity": "IDuqZpDw28f2KK6YuDk4jNLg",
        "failure_message": null,
        "type": "REVERSE",
        "tags": {
          "order_number": "21DFASJSAKAS"
        },
        "statement_descriptor": "FNX*FINIX FLOWERS",
        "additional_buyer_charges": null,
        "ready_to_settle_at": null,
        "application": "APgPDQrLD52TYvqazjHJJchM",
        "updated_at": "2022-09-01T20:49:23.43",
        "subtype": "MERCHANT_CREDIT_ADJUSTMENT",
        "externally_funded": "UNKNOWN",
        "messages": [],
        "currency": "USD",
        "id": "TRoom5emPxiP1TRAmHcSjHgz",
        "state": "PENDING"
      }
    ]
  }
}

Handling an ACH (eCheck) Refund Return

Banks manage the ACH networks and often pre-fund transactions, before debiting funds from the buyers bank account.

When an ACH (eCheck) refund gets returned, two Transfers get created to credit the funds back to the original bank account. The webhook events you receive, with subtype:

  • PLATFORM_DEBIT: one Transfer to debit funds that were preemptively credited
  • MERCHANT_CREDIT one Transfer to return the funds back to the original bank account.
Example ACH (eCheck) Merchant Debit
Copy
Copied
{
  "type": "updated",
  "entity": "transfer",xs
  "occurred_at": "2022-09-01T20:49:23.437609",
  "_embedded": {
    "transfers": [
      {
        "idempotency_id": null,
        "amount": 6031,
        "trace_id": "0156ff8f-88c1-4090-8eb6-9f33218b0ec5",
        "failure_code": null,
        "fee": 603,
        "destination": null,
        "raw": null,
        "created_at": "2022-09-01T20:36:08.13Z",
        "source": "PIr1Ru7ewBkEYVVn7SP1u5FW",
        "merchant_identity": "IDuqZpDw28f2KK6YuDk4jNLg",
        "failure_message": null,
        "type": "REVERSE",
        "tags": {
          "order_number": "21DFASJSAKAS"
        },
        "statement_descriptor": "FNX*FINIX FLOWERS",
        "additional_buyer_charges": null,
        "ready_to_settle_at": null,
        "application": "APgPDQrLD52TYvqazjHJJchM",
        "updated_at": "2022-09-01T20:49:23.43",
        "subtype": "MERCHANT_DEBIT_ADJUSTMENT",
        "externally_funded": "UNKNOWN",
        "messages": [],
        "currency": "USD",
        "id": "TRoom5emPxiP1TRAmHcSjHgz",
        "state": "PENDING"
      }
    ]
  }
}
Example ACH (eCheck) Platform Credit
Copy
Copied
{
  "type": "updated",
  "entity": "transfer",xs
  "occurred_at": "2022-09-01T20:49:23.437609",
  "_embedded": {
    "transfers": [
      {
        "idempotency_id": null,
        "amount": 6031,
        "trace_id": "0156ff8f-88c1-4090-8eb6-9f33218b0ec5",
        "failure_code": null,
        "fee": 603,
        "destination": null,
        "raw": null,
        "created_at": "2022-09-01T20:36:08.13Z",
        "source": "PIr1Ru7ewBkEYVVn7SP1u5FW",
        "merchant_identity": "IDuqZpDw28f2KK6YuDk4jNLg",
        "failure_message": null,
        "type": "REVERSE",
        "tags": {
          "order_number": "21DFASJSAKAS"
        },
        "statement_descriptor": "FNX*FINIX FLOWERS",
        "additional_buyer_charges": null,
        "ready_to_settle_at": null,
        "application": "APgPDQrLD52TYvqazjHJJchM",
        "updated_at": "2022-09-01T20:49:23.43",
        "subtype": "PLATFORM_CREDIT",
        "externally_funded": "UNKNOWN",
        "messages": [],
        "currency": "USD",
        "id": "TRoom5emPxiP1TRAmHcSjHgz",
        "state": "PENDING"
      }
    ]
  }
}