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

# Cleo Pay Quickstart: Send Your First ACH Payment via API

> Follow five steps to send your first ACH payment with Cleo Pay: verify a bank account, add a vendor contact, and call POST /v1/payments.

This guide walks you through the end-to-end flow from a fresh API token to a completed ACH payment. You'll link your business bank account, verify it with micro-deposits, create a vendor contact, and send your first payment — all via the REST API. Each step builds on the previous one, so work through them in order.

<Steps>
  <Step title="Get your API token">
    Obtain a JWT from Cleo Pay and set it as an environment variable so you can reuse it across all the following commands.

    ```bash theme={null}
    export CLEO_TOKEN="<your_token>"
    ```

    Every request must include this token in the `Authorization` header:

    ```
    Authorization: Bearer $CLEO_TOKEN
    ```

    <Tip>
      Keep your token in an environment variable or a secrets manager. Never hard-code it in your application source code or commit it to version control.
    </Tip>

    Verify your token works by fetching your bank accounts (an empty list is a valid, successful response):

    ```bash theme={null}
    curl --request GET \
      --url https://api.cleo-pay.com/v1/bank-accounts \
      --header "Authorization: Bearer $CLEO_TOKEN"
    ```
  </Step>

  <Step title="Link a bank account">
    Add your business checking or savings account. You'll need the full account number and routing number — these are accepted on write but never returned in responses (only the last 4 digits are returned).

    ```bash theme={null}
    curl --request POST \
      --url https://api.cleo-pay.com/v1/bank-accounts \
      --header "Authorization: Bearer $CLEO_TOKEN" \
      --header "Content-Type: application/json" \
      --data '{
        "holderName": "Acme Corp",
        "name": "Acme Main Checking",
        "accountNumber": "123456789012",
        "routingNumber": "021000021",
        "type": "checking"
      }'
    ```

    **Response:**

    ```json theme={null}
    {
      "id": "ba_01hq2k5r8e4vabc123",
      "status": "pending_verification",
      "type": "checking",
      "connectionType": "manual",
      "name": "Acme Main Checking",
      "institutionName": null,
      "accountNumberLast4": "9012",
      "routingNumberLast4": "0021",
      "isDefault": false,
      "microDepositsInitiatedAt": "2025-03-15T14:00:00Z",
      "microDepositsCompletedAt": null,
      "verificationAttempts": 0
    }
    ```

    Save the `id` from the response — you'll need it in the next step.

    ```bash theme={null}
    export BANK_ACCOUNT_ID="ba_01hq2k5r8e4vabc123"
    ```

    <Tip>
      Two small micro-deposits (each under \$0.10) will be sent to the account within 1–2 business days. Check the account statement to find the exact amounts before proceeding to the next step.
    </Tip>
  </Step>

  <Step title="Verify the bank account with micro-deposits">
    Once the two micro-deposits appear in your bank statement, submit both amounts to verify ownership. Amounts are provided as decimal dollar strings (e.g. `"0.05"` for five cents).

    ```bash theme={null}
    curl --request POST \
      --url https://api.cleo-pay.com/v1/bank-accounts/$BANK_ACCOUNT_ID/verify-micro-deposits \
      --header "Authorization: Bearer $CLEO_TOKEN" \
      --header "Content-Type: application/json" \
      --data '{
        "amount1": "0.05",
        "amount2": "0.08"
      }'
    ```

    **Response:**

    ```json theme={null}
    {
      "id": "ba_01hq2k5r8e4vabc123",
      "status": "verified",
      "type": "checking",
      "connectionType": "manual",
      "name": "Acme Main Checking",
      "accountNumberLast4": "9012",
      "routingNumberLast4": "0021",
      "isDefault": false,
      "microDepositsInitiatedAt": "2025-03-15T14:00:00Z",
      "microDepositsCompletedAt": "2025-03-17T10:22:00Z",
      "verificationAttempts": 1
    }
    ```

    When `status` changes to `"verified"`, the account is ready to fund payments.

    <Warning>
      You have a maximum of **3 verification attempts**. If you enter incorrect amounts 3 times, the account will move to `unverified` and you will need to link a new account.
    </Warning>
  </Step>

  <Step title="Create a contact (vendor)">
    Create the vendor or payee you want to pay. Supply their bank account details so Cleo Pay knows where to send funds.

    ```bash theme={null}
    curl --request POST \
      --url https://api.cleo-pay.com/v1/contacts \
      --header "Authorization: Bearer $CLEO_TOKEN" \
      --header "Content-Type: application/json" \
      --data '{
        "displayName": "Globex Supplies LLC",
        "type": "payee",
        "emails": ["billing@globex-supplies.com"],
        "bankAccount": {
          "accountNumber": "987600001234",
          "routingNumber": "021000021",
          "type": "checking"
        }
      }'
    ```

    **Response:**

    ```json theme={null}
    {
      "id": "con_01hq9r2m7tuvwxyz",
      "type": "payee",
      "status": "active",
      "displayName": "Globex Supplies LLC",
      "emails": ["billing@globex-supplies.com"],
      "phone": null,
      "paymentDirection": "can_be_paid",
      "paymentReady": true,
      "netTerms": null,
      "bankAccount": {
        "accountNumberLast4": "1234",
        "routingNumberLast4": "0021"
      },
      "taxInfo": null,
      "createdAt": "2025-03-17T11:00:00Z",
      "updatedAt": "2025-03-17T11:00:00Z",
      "archivedAt": null
    }
    ```

    Save the contact `id`:

    ```bash theme={null}
    export CONTACT_ID="con_01hq9r2m7tuvwxyz"
    ```

    <Tip>
      Check that `paymentReady` is `true` before sending a payment. A `false` value means the contact is missing required details (such as a bank account) and the payment will enter a `held` status.
    </Tip>
  </Step>

  <Step title="Send a payment">
    Send an ACH payment directly to your contact. Specify the amount in cents and reference your verified bank account as the funding source.

    ```bash theme={null}
    curl --request POST \
      --url https://api.cleo-pay.com/v1/payments \
      --header "Authorization: Bearer $CLEO_TOKEN" \
      --header "Content-Type: application/json" \
      --data '{
        "contactId": "'$CONTACT_ID'",
        "amountCents": 250000,
        "bankAccountId": "'$BANK_ACCOUNT_ID'",
        "clearing": "STANDARD"
      }'
    ```

    **Response:**

    ```json theme={null}
    {
      "payments": [
        {
          "id": "pay_01hrx5t9k2mnopqr",
          "status": "scheduled",
          "amountCents": 250000,
          "contactId": "con_01hq9r2m7tuvwxyz",
          "bankAccountId": "ba_01hq2k5r8e4vabc123",
          "clearing": "STANDARD",
          "scheduledAt": null,
          "createdAt": "2025-03-17T11:05:00Z"
        }
      ]
    }
    ```

    Your payment is now `scheduled` and will move to `processing` once the ACH window opens, and finally to `completed` when funds settle.

    <Tip>
      To pay a specific invoice instead of sending to a contact directly, replace `contactId` and `amountCents` with `payableId`. The payment will be applied against the payable's remaining balance automatically.
    </Tip>
  </Step>
</Steps>

## What's next?

* **[Payables](/concepts/payables)** — model invoices and track payment progress against them.
* **[Contacts](/concepts/contacts)** — manage vendor details, payment direction, and tax info.
* **[Bank Accounts](/concepts/bank-accounts)** — understand the full verification lifecycle.
* **[Payments](/concepts/payments)** — explore clearing speeds, scheduling, and partial payments.
