---
title: Send a client batch
slug: tutorials/api/ach/send-a-client-batch
description: Guides for registering the relevant webhooks, submitting a client batch of payments and cancelling the batch.



docTags: 
createdAt: 2024-08-09T12:42:32.265Z
---

## What you will learn

✅ How to submit a client batch of payments

✅ How to cancel the batch

:::hint{type="info"}
The tutorial assumes you have a knowledge of APIs and how they work. For more information on sending API see [API basics](docId\:pUTTCwQ5SKLzxYzIn5D1b) for more details.
:::

The tutorial uses these API endpoints:

| API                                                                            | Description                                                                       |
| ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------- |
| [POST /ach/v1/client-batches](docId:0Hu-sm4gNXr4XbIZCHkTA)                     | Submits 2 or more payments from the same Cross River account number as a batch    |
| [POST /ach/v1/client-batches/&#x7B;id}/cancel](docId\:u_LIED3U9ey-YoPB_707j)   | Cancels all the payments in the batch that have not yet been completely processed |

:::hint{type="warning"}
**IMPORTANT**

- Do not poll the APIs for status updates and reconciliation purposes.
- Incorporate webhooks into the payment reconciliation process.
:::

## Before you begin

Make sure you have:

- [API credentials](docId\:Z-MVwOV-p00-xX082NabK)
- Partner ID
- Account Number
- [Registered](docId\:BN5XtgkJogBe-CtwomCbS) the following webhook events:

| Webhook              | Description                                                                        |
| -------------------- | ---------------------------------------------------------------------------------- |
| `Ach.Batch.Imported` | Notifies you that the client batch has been imported                               |
| `Ach.Batch.Canceled` | Notifies you that all pending or on-hold payments in the client batch are canceled |

## Submit a client batch

Use a client batch when you have several transfers to or from the same account. For example, for payroll. In this tutorial the example account number is **2207975570**. The following 5 different actions appear in the sample code.

| Name            | Account number | Transaction type | Service type | Amount | Routing number | Account type | Standard Entry Class (SEC) codes |
| --------------- | -------------- | ---------------- | ------------ | ------ | -------------- | ------------ | -------------------------------- |
| John Wick       | 12345678       | Push             | SameDay      | 113    | 021000021      | Checking     | PPD                              |
| Cleveland Brown | 2342123458     | Pull             | Standard     | 243591 | 021000021      | Checking     | PPD                              |
| Matt Cauthon    | 2342123458     | Pull             | Standard     | 50     | 021000021      | Checking     | PPD                              |
| Perrin Aybara   | 2342123458     | Push             | Standard     | 2750   | 021000021      | Checking     | PPD                              |
| Elayne Trakand  | 2342123458     | Pull             | SameDay      | 15000  | 021000021      | Checking     | PPD                              |

:::::WorkflowBlock
::::WorkflowBlockItem
Call `POST ach/v1/client-batches`. The details of each payment are defined by the call attributes. Values for these attributes must be provided for *each* payment in the batch.

:::hint{type="warning"}
**IMPORTANT**
We strongly recommend that you include an idempotency key in your request header to provide duplicate protection should the payment fail. Read more about [idempotency keys](docId\:xQC2lRsG0xVv_9NMkqxKk).
:::

:::hint{type="info"}
Money amounts in API calls and responses are written without a decimal point between the dollars and the cents.
:::

```curl
POST ach/v1/client-batches
{
{
  "payments": [
    {
      "accountNumber": "2207975570",
      "receiver": {
        "routingNumber": "021000021",
        "accountNumber": "12345678",
        "accountType": "Checking",
        "name": "John Wick"
      },
      "secCode": "PPD",
      "description": "string",
      "transactionType": "Push",
      "amount": 113,
      "serviceType": "SameDay"
      },
{
      "accountNumber": "2207975570",
      "receiver": {
        "routingNumber": "021000021",
        "accountNumber": "2342123458",
        "accountType": "Checking",
        "name": "Cleveland Brown"
      },
      "secCode": "PPD",
      "description": "string",
      "transactionType": "Pull",
      "amount": 243591,
      "serviceType": "Standard"
    },
{
      "accountNumber": "2207975570",
      "receiver": {
        "routingNumber": "021000021",
        "accountNumber": "2342123458",
        "accountType": "Checking",
        "name": "Matt Cauthon"
      },
      "secCode": "PPD",
      "description": "string",
      "transactionType": "Pull",
      "amount": 50,
      "serviceType": "Standard"
    },
{
      "accountNumber": "2207975570",
      "receiver": {
        "routingNumber": "021000021",
        "accountNumber": "2342123458",
        "accountType": "Checking",
        "name": "Perrin Aybara"
      },
      "secCode": "PPD",
      "description": "string",
      "transactionType": "Push",
      "amount": 2750,
      "serviceType": "Standard"
    },
{
      "accountNumber": "2207975570",
      "receiver": {
        "routingNumber": "021000021",
        "accountNumber": "2342123458",
        "accountType": "Checking",
        "name": "Elayne Trakand"
      },
      "secCode": "PPD",
      "description": "string",
      "transactionType": "Pull",
      "amount": 15000,
      "serviceType": "SameDay"
    }
  ]
}
```
::::

::::WorkflowBlockItem
A successful API call returns a JSON response with the details of the client batch record that contains the client batch ID (in our case, **fcb7188f-e051-4f5b-addd-afaa00eadb3a**) and individual `paymentIdentifiers`. The identifiers appear in the response in the order that the payments were listed in the request. So in our case, the payment to **John Wick** is assigned `paymentIdentifier` **04793f3-13d9-4d52-b57e-afaa00eb6c74**, the payment from **Cleveland Brown** corresponds to **dbe36253-06d1-462a-9117-afaa00eb6c74**, and so on.

:::CodeblockTabs
Sample client batch response

```json
{
  "id": "fcb7188f-e051-4f5b-addd-afaa00eadb3a",
  "referenceId": "CB0461724AAWT",
  "status": "Processing",
  "accountNumber": "2207975570",
  "paymentCount": 5,
  "debitTotal": 258641,
  "creditTotal": 2863,
  "importCount": 0,
  "productId": "cc62e17f-5912-483e-9e42-aed30112fbb6",
  "partnerId": "1e5d3f04-ae24-4af6-9e30-aecf012b99dd",
  "createdAt": "2023-02-15T09:15:05.1486312-05:00",
  "lastModifiedAt": "2023-02-15T09:15:05.1486312-05:00",
  "paymentIdentifiers": [
    "f04793f3-13d9-4d52-b57e-afaa00eb6c74",
    "dbe36253-06d1-462a-9117-afaa00eb6c74",
    "1e1a08c7-1e60-452b-b22b-afaa00eb6c74",
    "a0bc6816-e85e-4ba6-bf9a-afaa00eb6c74",
    "6ed9ea59-2522-4550-8e5d-afaa00eb6c74"
    ]
}
```
:::

The `status` attribute in the response indicates that your batch is **processing**. It does not indicate that the batch was imported successfully.

The `importCount` attribute in the response indicates how many payments were imported (meaning originated) out of the total at the time of the response.

When the `status` of the client batch changes to **imported&#x20;**&#x74;he `Ach.Batch.Imported` webhook event fires.

:::hint{type="info"}
The `status `in the webhook refers to the webhook status, not the client batch status.
:::

:::CodeblockTabs
Ach.Batch.Imported webhook

```json
{
  "id": "b060d47c-7ab5-4a34-8803-afaa00ec617e",
  "eventName": "Ach.Batch.Imported",
  "status": "Pending",
  "partnerId": "1e5d3f04-ae24-4af6-9e30-aecf012b99dd",
  "createdAt": "2023-02-15T09:20:38.18-05:00",
  "resources": [
    "ach/v1/client-batches/fcb7188f-e051-4f5b-addd-afaa00eadb3a"
  ],
  "details": [
    {
      "clientBatchId": "fcb7188f-e051-4f5b-addd-afaa00eadb3a",
      "accountNumber": "2207975570"
    }
  ]
}

```
:::



For example, when the Federal Reserve accepts the payment the status changes to **processing**, which triggers the `Ach.Payment.Sent` event. Every status change from this point on triggers the event until the payment posts to the receiving account (status: **complete**).
::::
:::::

## Cancel a payment in the batch

Sometimes it's most efficient to cancel a client batch before all the payments have imported rather than try to cancel a large number of payments individually. Call the cancel batch API to cancel any pending or on-hold payments within a batch.

Call `POST /v1/client-batches/{id}/cancel` to cancel the batch. Use the client batch ID: the id value (in our case, **fcb7188f-e051-4f5b-addd-afaa00eadb3a**) received in the response to the `POST ach/v1/client-batches` call.

```curl
curl -X POST
--header 'Accept: application/json'
--header 'Authorization: Bearer '<token>'

https://sandbox.crbcos.com/ACH/v1/client-batches/fcb7188f-e051-4f5b-addd-afaa00eadb3a/cancel'
```

A successful API call returns a JSON response with the details of the client batch record that contains the individual payment identifiers of all payments that were canceled. (Payments with a **Completed** status cannot be canceled.) The status in the response is **Canceling**. As with the client batch request above, each identifier returned corresponds to the order in which the payments were presented in the request.

```json
{
  "id": "fc0d501d-c36b-45b4-a0d5-afaa00eb6c74",
  "referenceId": "CB0460UJR6DNA",
  "status": "Canceling",
  "accountNumber": "2207975570",
  "paymentCount": 5,
  "debitTotal": 258641,
  "creditTotal": 2863,
  "importCount": 5,
  "productId": "cc62e17f-5912-483e-9e42-aed30112fbb6",
  "partnerId": "1e5d3f04-ae24-4af6-9e30-aecf012b99dd",
  "createdAt": "2023-02-15T09:17:09.077-05:00",
  "importedAt": "2023-02-15T09:17:19.123-05:00",
  "lastModifiedAt": "2023-02-15T09:17:26.8406542-05:00",
  "paymentIdentifiers": [
    "6ed9ea59-2522-4550-8e5d-afaa00eb6c74",
    "dbe36253-06d1-462a-9117-afaa00eb6c74",
    "1e1a08c7-1e60-452b-b22b-afaa00eb6c74",
    "f04793f3-13d9-4d52-b57e-afaa00eb6c74",
    "a0bc6816-e85e-4ba6-bf9a-afaa00eb6c74"
  ]
}
```

When the cancellation is complete, it triggers the `Ach.Batch.Canceled` webhook event. Note the client batch ID (in this case , **fcb7188f-e051-4f5b-addd-afaa00eadb3a**) corresponds to the client batch ID used in the cancellation request.

```json
{
  "id": "a6593026-ea2c-42b1-ae57-afaa00ec84b2",
  "eventName": "Ach.Batch.Canceled",
  "status": "Pending",
  "partnerId": "1e5d3f04-ae24-4af6-9e30-aecf012b99dd",
  "createdAt": "2023-02-15T09:21:08.21-05:00",
  "resources": [
    "ach/v1/client-batches/0d4cf4dd-bcbd-4eb7-878d-afaa00ec59c0"
  ],
  "details": [
    {
      "clientBatchId": "fcb7188f-e051-4f5b-addd-afaa00eadb3a",
      "accountNumber": "2207975570"
    }
  ]
}

```

