The [Moov ACH Gateway](https://github.com/moov-io/achgateway) is a customizable payment gateway that enables automated ACH operations including file uploading and downloading. When paired with our [test harness](https://github.com/moov-io/ach-test-harness), which acts as a financial institution, achgateway serves as the final puzzle piece for ACH transactions. It also utilizes [Moov ACH](https://github.com/moov-io/ach) by flattening batches, merging files, and validating files to ensure transfers are cost effective and reliable. We’ll cover how to set up the service and run through a sample use case in the sections below.

## Background

Think of achgateway as an automated software engine capable of supporting a variety of input/output sources and broadcasting a stream of events for other services to consume. Inspired by our [paygate project](https://github.com/moov-io/paygate), achgateway makes several major improvements over paygate such as support for use in a highly available setup and the ability to merge multiple input sources (HTTP, Kafka, etc.) into ACH files for your ODFI. It continues to offer options for encoding and encryption. Additionally, users can divide uploads into groups via shards and point the gateway toward multiple ODFIs. These features provide significant flexibility when building real-world ACH transfer scenarios.

One use case of the gateway is for micro-deposits, where small amounts of money are submitted to an account for validation purposes. The service can be configured to upload a group of Same-Day ACH micro-deposit transfers at the end of day, optimizing cost and performance. Lastly, notifications can be triggered by successful uploads or errors. We currently support Slack, email, and PagerDuty for these alerts.

## Initial setup

- To get started with a default instance of achgateway, first [install Docker](https://docs.docker.com/get-docker/) on your system and clone the project.

- From the [`./examples/getting-started/`](https://github.com/moov-io/achgateway/tree/master/examples/getting-started) directory, run `docker compose up`. This step may take a minute to complete and will run the latest image on port 8484 with Prometheus metrics on port 9494.

- Based on the sample configuration being used, the ach-test-harness will save files into [`./testdata/ftp-server/`](https://github.com/moov-io/achgateway/tree/master/testdata/ftp-server) after achgateway uploads them. There, you will find some ACH files to experiment with.

### TLS and HTTP

achgateway supports listening over TLS for inbound files in v0.6 and later. To enable this, simply set the TLS config under the `Inbound` section.

```yaml
Inbound:
  HTTP:
    BindAddress: ":8484"
    TLS:
      CertFile: "/path/to/certificate.pem"
      KeyFile: "/path/to/private.key"
```

## Submitting files

When individual files are submitted to achgateway for upload, they are loaded into a queue. Incoming files are assigned a shard key, which serves as a unique identifier and maps to a shard name. Shards tell the gateway when and where to send files by specifying upload times (cutoff windows) and an `uploadAgent`. Assigning multiple keys to the same name enables grouped uploads, each with their own customizable behavior.

Below, you’ll find how shards are defined in a basic `config.yml` file:

```yaml
Sharding:
    Shards:
      - name: "testing"
        cutoffs:
          timezone: "America/Los_Angeles"
          windows:
            - "10:30"
            - "14:00"
        uploadAgent: "local-ftp"
        output:
          format: "nacha"
    Mappings:
      "foo": "testing"
```

Notice how the shard key `foo` is mapped to `testing` and will upload to `local-ftp`. Try queueing up a file with:

```bash
curl -XPOST "localhost:8484/shards/foo/files/f4" --data @./testdata/ppd-valid.json
```

## Uploading files

Cutoff times trigger queued files to upload. In production, these would match Nacha’s [ACH submission deadlines](https://www.nacha.org/resources/same-day-ach-faqs-0) to optimize uploads. Rather than wait for a cutoff to occur in real time, manually trigger one with:

```bash
curl -XPUT "localhost:9494/trigger-cutoff"
```

Observe how the file we submitted earlier appears in the local FTP server’s filesystem under the `outbound` directory. Files are validated, flattened (optionally), and merged before upload to reduce costs as much as possible. Outbound ACH file names are built from a template like `YYYYMMDD-HHMMSS.ach`, which can be defined in the gateway configuration. In our example, the uploaded file name will be set to something like `20210719-170711.ach`. Note that time is formatted as a 24-hour clock in GMT.

## Downloading files

Connected ODFIs may generate certain files like returns, corrections, and pre-notifications. The achgateway can periodically check for these files and download them into a filesystem location on a scheduled interval. In our example, files in the FTP server’s `reconciliation` and `returned` folders are eligible for download. You can manually trigger inbound file processing with:

```bash
curl -XPUT "localhost:9494/trigger-inbound"
```

Notice how `ppd-debit.ach` and `return-web.ach` will be removed from the FTP server.

## High availability

achgateway is designed to be run in coordination with multiple identical instances. This allows for resilience in guaranteeing file uploads and sharing the load across multiple instances. To enable this, point achgateway toward a healthy [Consul cluster](https://www.consul.io/) so it can elect leadership for each shard just prior to upload.

```yaml
Consul:
  Address: "127.0.0.1:8500"
  Scheme: "http"
  SessionPath: "achgateway/shards/"
```

Each instance of achgateway accepts all files to prepare for merging and uploading later on. At a cutoff time, each instance will prepare the merged files and attempt to become the leader. When an instance obtains leadership, it implies that it’s the sole leader and can upload the merged files.

Non-leader instances will skip uploading files in the current batch and continue onto the next batch of files to upload. In the future, we plan to support accepting/rejecting specific shard keys or handling only a fraction of encountered keys in each instance. Both of these options are strategies to help achgateway scale toward millions of entries processed during a cutoff time.

## Summary

To explore additional achgateway features like audit trails, file encryption, notifications, and error alerts, we recommend checking out our [project documentation](https://github.com/moov-io/achgateway/blob/master/docs/README.md) and [full configuration specification](https://github.com/moov-io/achgateway/blob/master/docs/CONFIGURATION.md). We hope this walkthrough helps you get started with the gateway and serves as a quick refresher for current users. If you have any questions or suggestions for the project, please contact the Moov team on [Slack](https://slack.moov.io/) (#ach channel) or [submit an issue](https://github.com/moov-io/achgateway/issues/new).
