> ## 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.

# Manage Vendors and Payees in Cleo Pay

> Create, update, archive, and restore vendor contacts in Cleo Pay. Learn how to set up payees with bank accounts and tax information.

Contacts in Cleo Pay represent the vendors, suppliers, and payees you send money to. Each contact stores identity information, bank account details for ACH delivery, and optional tax information for 1099 reporting. Before you can send a payment to a contact, the contact must be **payment-ready**.

***

## Contact types

Cleo Pay supports two contact types:

| Type       | Description                                                                                  |
| ---------- | -------------------------------------------------------------------------------------------- |
| `payee`    | An external vendor or payee you manage directly. You supply their bank account details.      |
| `business` | Another business that uses the Cleo Pay platform. Their account details are managed by them. |

When creating contacts via the API, you will most commonly work with the `payee` type.

***

## Create a contact

<Steps>
  <Step title="POST /v1/contacts — provide contact details">
    Submit a `POST /v1/contacts` request with at minimum a `displayName`. Provide as much additional detail as possible — particularly `bankAccount` and `taxInfo` — so the contact is payment-ready right away.

    | Field             | Type      | Description                                     |
    | ----------------- | --------- | ----------------------------------------------- |
    | `displayName`     | string    | Human-readable name for the contact (required). |
    | `emails`          | string\[] | One or more email addresses.                    |
    | `phone`           | string    | Contact phone number.                           |
    | `address`         | object    | Mailing address.                                |
    | `bankAccount`     | object    | Bank account details for ACH payments.          |
    | `taxInfo`         | object    | Tax information for 1099 reporting.             |
    | `allowDuplicates` | boolean   | Set to `true` to bypass duplicate detection.    |

    The `address` object supports the following fields:

    | Field       | Type   | Description                            |
    | ----------- | ------ | -------------------------------------- |
    | `streetOne` | string | Primary street address line.           |
    | `streetTwo` | string | Secondary address line (optional).     |
    | `city`      | string | City.                                  |
    | `stateCode` | string | Two-letter US state code (e.g., `NY`). |
    | `zipCode`   | string | ZIP code.                              |

    The `bankAccount` object accepts `accountNumber` (write-only), `routingNumber` (write-only), and `accountType` (`checking` or `savings`).

    The `taxInfo` object accepts `legalName`, `taxIdType` (`ein` or `ssn`), and `taxId` (write-only).

    ```bash title="Create a fully populated contact" theme={null}
    curl --request POST \
      --url https://api.cleo-pay.com/v1/contacts \
      --header 'Authorization: Bearer <token>' \
      --header 'Content-Type: application/json' \
      --data '{
        "displayName": "Acme Supplies LLC",
        "emails": ["ap@acmesupplies.com", "billing@acmesupplies.com"],
        "phone": "+15555550100",
        "address": {
          "streetOne": "123 Main St",
          "streetTwo": "Suite 400",
          "city": "New York",
          "stateCode": "NY",
          "zipCode": "10001"
        },
        "bankAccount": {
          "accountNumber": "123456789012",
          "routingNumber": "021000021",
          "accountType": "checking"
        },
        "taxInfo": {
          "legalName": "Acme Supplies LLC",
          "taxIdType": "ein",
          "taxId": "123456789"
        }
      }'
    ```

    <Warning>
      By default, Cleo Pay **blocks duplicate contacts** — if a contact with the same name or email already exists, the request returns a `409 Conflict`. To intentionally create a duplicate, include `"allowDuplicates": true` in your request body.
    </Warning>

    A successful response returns the full `Contact` object:

    ```json title="Contact created" theme={null}
    {
      "id": "contact_01hwxyz111",
      "displayName": "Acme Supplies LLC",
      "type": "payee",
      "status": "active",
      "paymentReady": true,
      "emails": ["ap@acmesupplies.com", "billing@acmesupplies.com"],
      "phone": "+15555550100",
      "address": {
        "streetOne": "123 Main St",
        "streetTwo": "Suite 400",
        "city": "New York",
        "stateCode": "NY",
        "zipCode": "10001"
      },
      "taxInfo": {
        "legalName": "Acme Supplies LLC",
        "taxIdType": "ein",
        "taxId": "**-***6789"
      },
      "netTerms": null,
      "createdAt": "2024-06-01T10:00:00Z",
      "updatedAt": "2024-06-01T10:00:00Z"
    }
    ```
  </Step>

  <Step title="Check paymentReady">
    After creation, verify that `paymentReady: true` in the response. A contact is payment-ready when it has both a bank account and tax information on file.

    If `paymentReady` is `false`, any payment to this contact will be created in `held` status and will not process until the missing information is added.
  </Step>

  <Step title="Update a contact with PATCH">
    Use `PATCH /v1/contacts/{id}` to update mutable fields. Only the fields you include in the request body are changed — all other fields remain unchanged.

    The following fields are updatable for all contact types:

    | Field         | Type   | Notes               |
    | ------------- | ------ | ------------------- |
    | `displayName` | string |                     |
    | `netTerms`    | number | Minimum value: `0`. |

    The following fields are updatable for `payee` contacts only:

    | Field     | Type      | Notes                                  |
    | --------- | --------- | -------------------------------------- |
    | `emails`  | string\[] | Replaces all existing email addresses. |
    | `phone`   | string    |                                        |
    | `address` | object    |                                        |

    ```bash title="Update a contact's net terms" theme={null}
    curl --request PATCH \
      --url https://api.cleo-pay.com/v1/contacts/contact_01hwxyz111 \
      --header 'Authorization: Bearer <token>' \
      --header 'Content-Type: application/json' \
      --data '{
        "netTerms": 30
      }'
    ```
  </Step>
</Steps>

***

## Archive and unarchive contacts

Archiving removes a contact from default list queries without permanently deleting them. This is useful for vendors you no longer work with but want to retain for historical records.

**Archive a contact:**

```bash title="Archive a contact" theme={null}
curl --request POST \
  --url https://api.cleo-pay.com/v1/contacts/contact_01hwxyz111/archive \
  --header 'Authorization: Bearer <token>'
```

**Unarchive a contact:**

```bash title="Unarchive a contact" theme={null}
curl --request POST \
  --url https://api.cleo-pay.com/v1/contacts/contact_01hwxyz111/unarchive \
  --header 'Authorization: Bearer <token>'
```

Both endpoints require no request body and return the updated `Contact` object with the new `status` value.

| Status     | Description                                                                  |
| ---------- | ---------------------------------------------------------------------------- |
| `active`   | Contact is active and appears in default list queries.                       |
| `archived` | Contact is hidden from default list queries. Can be unarchived.              |
| `revoked`  | Contact has been revoked by the Cleo Pay platform. **Cannot be unarchived.** |

<Warning>
  A contact with `status: revoked` has been suspended at the platform level. You cannot unarchive or send payments to a revoked contact. Reach out to Cleo Pay support for more information.
</Warning>

***

## Filter the contacts list

When listing contacts with `GET /v1/contacts`, use query parameters to narrow your results. By default, the endpoint returns both `active` and `archived` contacts; revoked contacts are excluded unless explicitly requested.

| Parameter | Values               | Description                                                                   |
| --------- | -------------------- | ----------------------------------------------------------------------------- |
| `type`    | `payee`, `business`  | Filter by contact type.                                                       |
| `status`  | `active`, `archived` | Filter by contact status. Defaults to returning active and archived contacts. |
| `search`  | string               | Free-text search across name and email fields.                                |

```bash title="List active payee contacts matching 'acme'" theme={null}
curl --request GET \
  --url 'https://api.cleo-pay.com/v1/contacts?type=payee&status=active&search=acme' \
  --header 'Authorization: Bearer <token>'
```

See the [Pagination reference](/reference/pagination) for details on `page` and `pageSize` parameters.
