> ## Documentation Index
> Fetch the complete documentation index at: https://docs.treasuryprime.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ACH Transfer

> An Automated Clearing House (ACH) transfer is an electronic funds transfer between two accounts at different banks. It allows for credits (sending money) and debits (receiving money), and is generally cheaper when compared to other available methods, but also most-often slower. This guide will examine the process of sending money to another account using ACH (also known as a credit), though you can also receive money from an account (a debit) using this same method.

### This guide uses the following endpoints

* [`/account`](/reference/account)
* [`/counterparty`](/reference/get_counterparty)
* [`/ach`](/reference/ach)
* [`/webhook`](/reference/webhook)

### To create an ACH transfer you will need to

1. [Get the account ID](#1-get-the-account-id)
2. [Get the Counterparty ID](#2-get-the-counterparty-id)
3. [Create the ACH transfer](#3-create-the-ach-transfer)
4. [Get status updates](#4-get-status-updates)

## 1. Get the Account ID

The first step in creating an ACH transfer is to obtain the ID of the account the funds will be transferred from.

<Warning>
  Both a savings and checking account have been pre-created in the Developer Sandbox for testing purposes; however, you can also create and use your own bank accounts if you prefer.
</Warning>

To retrieve an account ID, make a `GET` request to the `account` endpoint.

<CodeGroup>
  ```bash bash theme={null}
  curl -u $API_KEY_ID:$API_SECRET_KEY https://api.treasuryprime.com/account
  ```
</CodeGroup>

This will return a list of of Account objects. In order to make an ACH transfer, you will need the account ID which is stored in the `id` property of each account object.

<CodeGroup>
  ```bash bash theme={null}
  {
    "data": [
      {
        "account_type": "savings",
        "bank_id": "bank_treasuryprime",
        "updated_at": "2021-02-01T16:32:34Z",
        "currency": null,
        "routing_number": "000000000",
        "account_number": "123000012345",
        "id": "acct_qda4pJZfpzn4fc",
        "created_at": "2021-01-13T15:05:14Z",
        "userdata": null
      },
      {
        "account_type": "checking",
        "bank_id": "bank_treasuryprime",
        "updated_at": "2021-02-01T16:32:34Z",
        "currency": null,
        "routing_number": "000000000",
        "account_number": "123000067890",
        "id": "acct_wVwR87rxhMRdwD",
        "created_at": "2021-01-13T15:05:13Z",
        "userdata": null
      }
    ],
    "total_estimated": 10
  }
  ```
</CodeGroup>

## 2. Get the Counterparty ID

The next piece of data required for an ACH is the ID of the Counterparty (the person or entity on the other side of that transaction) or put more simply: Who the funds are being transferred to. If you have not yet created a Counterparty in your Developer Sandbox, read the next section for instructions on how to accomplish this. Otherwise, feel free to skip ahead to [Retrieve an existing Counterparty](#retrieve-an-existing-counterparty).

### Create a Counterparty

Creating a Counterparty requires making a `POST` request to the `counterparty` endpoint, and passing along the name of person or entity who owns the account, as well as three pieces of data required for ACH:

1. The ACH specific bank account number
2. The account type (checking or savings)
3. The routing number

<CodeGroup>
  ```bash bash theme={null}
  curl -u $API_KEY_ID:$API_SECRET_KEY https://api.treasuryprime.com/counterparty \
    -H 'Content-Type: application/json' \
    -d '{
          "name_on_account": "Adam Smith",
          "ach": {
            "account_number": "12345678",
            "account_type": "checking",
            "routing_number": "87654321"
          }
        }'
  ```
</CodeGroup>

Assuming no errors are encountered, the response will contain a Counterparty object containing an `id` property representing the counterparty ID.

<CodeGroup>
  ```bash bash theme={null}
  {
    "created_at": "2021-02-25T01:23:24Z",
    "updated_at": "2021-02-25T01:23:24Z",
    "ach": {
      "account_number": "12345678",
      "account_type": "checking",
      "routing_number": "87654321"
    },
    "wire": null,
    "name": "Adam Smith",
    "name_on_account": "Adam Smith",
    "id": "cp_v1p3ay8w4b0x",
    "userdata": null
  }
  ```
</CodeGroup>

### Retrieve an Existing Counterparty

To find the IDs of any existing Counterparty objects, make a `GET` request to the `counterparty` endpoint

<CodeGroup>
  ```bash bash theme={null}
  curl -u $API_KEY_ID:$API_SECRET_KEY https://api.treasuryprime.com/counterparty
  ```
</CodeGroup>

This will return a list of all existing Counterparty objects you have created (or empty if none are found). Each Counterparty object contains an `id` property representing the counterparty ID.

<CodeGroup>
  ```bash bash theme={null}
  {
    "data": [
      {
        "created_at": "2021-02-25T01:23:24Z",
        "updated_at": "2021-02-25T01:23:24Z",
        "ach": {
          "account_number": "12345678",
          "account_type": "checking",
          "routing_number": "87654321"
        },
        "wire": null,
        "name": "Adam Smith",
        "name_on_account": "Adam Smith",
        "id": "cp_v1p3ay8w4b0x",
        "userdata": null
      },
      ...
    ]
  }
  ```
</CodeGroup>

## 3. Create the ACH Transfer

With the Account ID, and Counterparty ID, the ACH transfer can now be made. But first a final note on two additional properties. The `direction` property specifies whether this transfer is a credit or debit (in this case a credit since money is being sent), and the `sec_code` which specifies the type of transfer according to the ACH Network. More details on those topics can be found in the [ACH documentation](/reference/ach).

> The protocol that underlies the ACH network is batch-oriented and does not provide success responses (only error responses). As a result, ACH transfers follow a particular workflow as they are processed by the network. You can track a transfer's progress by checking the status attribute on the ACH object.

Enough details, let's make the transfer!

<CodeGroup>
  ```bash bash theme={null}
  curl -u $API_KEY_ID:$API_SECRET_KEY https://api.treasuryprime.com/ach \
      -H 'Content-Type: application/json' \
      -d '{
            "account_id": "acct_1234567890",
            "amount": "100.00",
            "counterparty_id": "cp_0987654321",
            "direction": "credit",
            "sec_code": "ppd",
  		  "service": "standard"
          }'
  ```
</CodeGroup>

If no errors were encountered, a new ACH Object is returned. To find out when the transfer is complete requires watching for status updates which will be covered next.

<CodeGroup>
  ```bash bash theme={null}
  {
    "description": null,
    "amount": "100.00",
    "service": "standard",
    "counterparty_id": "cp_0987654321",
    "bankdata": null,
    "bank_id": "bank_treasuryprime",
    "account_id": "acct_1234567890",
    "addenda": [],
    "org_id": "org_treasuryprime",
    "batch_key": null,
    "effective_date": "2021-02-25",
    "updated_at": "2021-02-25T01:32:57Z",
    "status": "pending",
    "id": "ach_5merj00eudnp",
    "error": null,
    "sec_code": "ppd",
    "direction": "credit",
    "created_at": "2021-02-25T01:32:57Z",
    "userdata": null
  }
  ```
</CodeGroup>

## 4. Get Status Updates

There are two ways to find out when the status of the ACH transfer has changed:

### Manually Checking for Status Updates

By making a `GET` request to the `ach` endpoint and passing in the `id` of the ACH transfer you'd like the status for. This will return an ACH object with the latest status.

<CodeGroup>
  ```bash bash theme={null}
  curl -u $API_KEY_ID:$API_SECRET_KEY https://api.treasuryprime.com/ach/:id
  ```
</CodeGroup>

Note the `status` has been changed to "sent".

<CodeGroup>
  ```bash bash theme={null}
  {
    "description": null,
    "amount": "100.00",
    "service": "standard",
    "counterparty_id": "cp_0987654321",
    "bankdata": null,
    "bank_id": "bank_treasuryprime",
    "account_id": "acct_1234567890",
    "addenda": [],
    "org_id": "org_treasuryprime",
    "batch_key": null,
    "effective_date": "2021-02-25",
    "updated_at": "2021-01-04T20:30:27Z",
    "status": "sent",
    "id": "ach_5merj00eudnp",
    "error": null,
    "sec_code": "ppd",
    "trace_number": "24015053925610",
    "direction": "credit",
    "created_at": "2021-02-25T01:32:57Z",
    "userdata": null
  }
  ```
</CodeGroup>

<Tip>
  Once an ACH reaches `sent` status, the `trace_number` field contains an identifier assigned by the originating bank. You can use this to help your customers track payments. See [Tracking originated ACH payments with trace numbers](/docs/ach#tracking-originated-ach-payments-with-trace-numbers) for details.
</Tip>

### Listening for Status Updates with Webhooks

By registering a webhook to respond to the `ach.update` event, you can be notified of changes in the status of the ACH transfer when they occur.

<CodeGroup>
  ```bash bash theme={null}
  curl https://api.treasuryprime.com/webhook \\
      -u "$API_KEY_ID:$API_SECRET_KEY" \\
      -H 'Content-Type: application/json' \\
      -d '{
             "event": "ach.update",
             "url": "https://example.application.com/notify"
          }'
  ```
</CodeGroup>

Once the `ach.update` webhook notification is received, follow the steps outlined above to obtain the latest status of the transfer, or simply make a `GET` request to the URL specified in the `url` property of the data object.

<CodeGroup>
  ```bash bash theme={null}
  {
    "event": "ach.update",
    "op": "update",
    "id": "ach_01123456789",
    "url": "https://api.treasuryprime.com/ach/ach_01123456789"
  }
  ```
</CodeGroup>

## Canceling an ACH Transfer

An ACH transfer originated on the Treasury Prime platform may be canceled while it is in a `status` of `pending`. Once the ACH transitions from `pending` to `processing`, it may no longer be canceled. To cancel an ACH, call the [Update an ACH](https://docs.treasuryprime.com/reference/patch_ach-id) endpoint to update its status to `canceled` as shown below.

<CodeGroup>
  ```bash bash theme={null}
  $ curl -u $API_KEY_ID:$API_SECRET_KEY https://api.treasuryprime.com/ach/ach_1029384756 \
      -X PATCH \
      -H 'Content-Type: application/json' \
      -d '{
            "status": "canceled"
          }'
  ```
</CodeGroup>

Canceling a `pending` ACH can also be done directly in the Treasury Prime Dashboard app for users with the required permissions.

***

What’s Next

Once the ACH Transfer object reaches a status of "sent", then the transfer is complete! Congratulations on making your first ACH transfer. If you'd like to dig deeper, check out the [ACH API documentation](/reference/ach). And since you're already on a hot-streak, why not try out [Issuing Debit Cards](/docs/issuing-a-card)?

* [Table of Contents](#)
* * * [This guide uses the following endpoints](#this-guide-uses-the-following-endpoints)
    * [To create an ACH transfer you will need to](#to-create-an-ach-transfer-you-will-need-to)
  * [1. Get the Account ID](#1-get-the-account-id)
  * [2. Get the Counterparty ID](#2-get-the-counterparty-id)
  * * [Create a Counterparty](#create-a-counterparty)
    * [Retrieve an Existing Counterparty](#retrieve-an-existing-counterparty)
  * [3. Create the ACH Transfer](#3-create-the-ach-transfer)
  * [4. Get Status Updates](#4-get-status-updates)
  * * [Manually Checking for Status Updates](#manually-checking-for-status-updates)
    * [Listening for Status Updates with Webhooks](#listening-for-status-updates-with-webhooks)
