Getting Started

Moov's PayGate project provides an HTTP REST endpoint for submitting and receiving ACH payments and builds upon a suite of services offered by Moov, including ACH, Watchman, and FED. Each of these services must be running and reachable by PayGate. We provide several examples of setting up a complete installation using Docker Compose, Kubernetes, or directly using the provided binaries.

Running PayGate locally using Docker Compose (Quickest)

PayGate can be quickly ran using the provided Docker Compose file. Note that you may need to adjust some environment variables in this file before running it, for example the DEFAULT_ROUTING_NUMBER account variable.

First, install Docker Compose for your platform. Then clone the repository and run docker-compose up within it.

$ git clone
$ cd paygate
$ docker-compose up -d

That's it! Your PayGate endpoint should be accessible at http://localhost:8082. You can verify paygate is running with curl http://localhost:8082/ping and monitor the health with curl http://localhost:9092/live.

Running PayGate using Kubernetes (Advanced)

Moov uses Kubernetes for deploying its own infrastructure on development and production machines. The instructions on the readme are a good place to start. Follow the instructions from the local development section on the infra readme.

Running from source

PayGate can run directly from source using Go, but the required services need to be running as well. The default port 8082 is used unless otherwise specified as an attribute -http.addr and needs environment variables setup beforehand as outlined here.

# With Golang and git installed:
$ git clone
$ cd paygate
$ go run .

Testing endpoints

In order to check that the services are running, moov provides an api tool (apitest) for testing the endpoints with binaries you can download. Once downloaded running apitest -local will create Customer, Receiver, Depository, and a Transfer against your local docker compose stack.

# For Linux
$ wget
$ mv apitest-linux-amd64 apitest && chmod +x apitest

# For OSX
$ wget
$ mv apitest-darwin-amd64 apitest && chmod +x apitest

# For docker compose setup or the running binaries using default values.
$ ./apitest -local

# For Tilt setup using Kubernetes
$ ./apitest -dev

# For other options, run
$ ./apitest -help

Configuring Data

After confirming that the services are running correctly, there are several things needed before ACH transactions can be created/processed using PayGate. Listed below are the steps necessary:

  1. Setup a Depository for the Originator (ODFI)
  2. Setup a Depository for the Receiver as well (RDFI)
  3. Setup an Originator with customer information
  4. Setup a Receiver with customer information
  5. Then you can create a Transfer between these two FIs


The HTTP header X-User-ID is required and used to isolate objects (such as Depository, Originator, Receiver, Gateway, Transfer) when using paygate in a multi-tenant setup. This is useful if you're managing transfers for multiple customers/users or multiple Financial Institutions. The value for this header can be a UTF-8 string, but typically it is a random alphanumeric string.

Setup FTP

PayGate currently requires the FTP configuration to be manually setup in the database. See here for more information.


MySQL is a database which applications or developers connect to over the network. This means to configure paygate's FTP and file upload configuration a developer needs to connect to the database.

# Connect using host, username and password for your setup
$ mysql -h localhost:3306 -u paygate

> INSERT INTO ftp_configs (routing_number, hostname, username, password) VALUES ('000000000', 'localhost:22', 'myusername', 'mypassword');

> INSERT INTO cutoff_times (routing_number, cutoff, location) VALUES ('000000000', '1700', 'America/New_York');

> INSERT INTO file_transfer_configs (routing_number, inbound_path, outbound_path, return_path) VALUES ('000000000', '/inbound', '/outbound', '/returns');


If using the Docker Compose and sqlite (DATABASE_TYPE=sqlite) script above, you need to mount the /data volume of the paygate section in docker-compose.yml file like so:

    image: moov/paygate:v0.5.0-dev
      - "8082:8082"
      - "9092:9092"
    command: ["-http.addr", ":8082"]
      ACCOUNTS_ENDPOINT: 'http://accounts:8085'
      ACH_ENDPOINT: 'http://ach:8080'
      FED_ENDPOINT: 'http://fed:8086'
      CUSTOMERS_ENDPOINT: 'http://customers:8087'
      - .:/data
      - ach
      - accounts
      - fed
      - customers
      - auth
This will attach the /data volume within the image to the same directory in which the docker-compose.yml file resides.

To setup FTP, run the following commands on the now exposed paygate.db file, changing the dummy string values below:

# Setup credentials for sqlite3
$ sqlite3 paygate.db "INSERT INTO ftp_configs (routing_number, hostname, username, password) VALUES ('000000000', 'localhost:22', 'myusername', 'mypassword');"

# Setup cutoff times
$ sqlite3 paygate.db "INSERT INTO cutoff_times (routing_number, cutoff, location) VALUES ('000000000', '1700', 'America/New_York');"

# Setup ftp directories
$ sqlite3 paygate.db "INSERT INTO file_transfer_configs (routing_number, inbound_path, outbound_path, return_path) VALUES ('000000000', '/inbound', '/outbound', '/returns');"
The command may need to be ran with elevated privileges, using sudo or another method. The database will also need to be writable.

Verify FTP configuration

Paygate's admin HTTP interface offers endpoints to check these values were setup (default on port :9092).

curl -s -X GET http://localhost:9092/configs/uploads | jq .
  "cutoffTimes": [
      "RoutingNumber": "121042882",
      "Cutoff": 1700,
      "Location": "America/New_York"
  "ftpConfigs": [
      "RoutingNumber": "121042882",
      "Hostname": "localhost:2121",
      "Username": "admin",
      "Password": "1****6"
  "fileTransferConfigs": [
      "RoutingNumber": "121042882",
      "InboundPath": "inbound/",
      "OutboundPath": "outbound/",
      "ReturnPath": "returned/"