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

# Onboard a customer

> Create a customer, link its bank accounts and payroll providers, request mandates, and follow them until they are active.

To receive a customer's CODA or CODB files, Codaclean needs the customer, its bank accounts or payroll providers, and a signed mandate for each of them.

<Steps>
  <Step title="Create the customer">
    Call [`POST /customers/new`](/api/endpoints/create-customer) with:

    * the customer's `enterpriseNumber` (formatted `0123.456.789`, without `BE`), `name` and `accountingRef`;
    * its `address`: `street`, `zipCode`, `municipality`, `country` (`street2` is optional);
    * its `contact`: `name`, `function`, `email` and `language` (`fr`, `nl` or `en`). Mandate signature requests are sent to this person, in this language.

    You can include `bankAccounts` (IBAN only) and `payrollProviders` (code only) in the same call, or add them later:

    * [`POST /customers/{customerId}/bank-accounts/{iban}/new`](/api/endpoints/add-bank-account)
    * [`POST /customers/{customerId}/payroll-providers/{code}/new`](/api/endpoints/add-payroll-provider)

    <Warning>
      - **Bank accounts:** send the IBAN only. Codaclean derives the BIC and the bank name from it.
      - **Payroll providers:** send the Codaclean code of the payroll provider, not its name. Look it up with [`POST /payroll-providers`](/api/endpoints/list-payroll-providers).
    </Warning>

    If the customer already exists in the accounting firm, find it with [`POST /customers`](/api/endpoints/search-customers) (for example by `enterpriseNumber`) and add what is missing.

    **Required scope:** `customers:write`
  </Step>

  <Step title="Request the mandates">
    Request one mandate per bank account and one per payroll provider:

    * CODA: [`POST /customers/{customerId}/bank-accounts/{iban}/mandates/new`](/api/endpoints/request-coda-mandate)
    * CODB: [`POST /customers/{customerId}/payroll-providers/{code}/mandates/new`](/api/endpoints/request-codb-mandate)

    For bank accounts, the bank determines the product.

    Codaclean requests a CODA mandate when the bank supports it, and otherwise a CODAlight consent through a connector. In both cases, you receive CODA files.

    <Warning>
      Only one mandate can be in progress per IBAN, and per payroll provider. A second request returns `409 mandateAlreadyRequested`.

      Send a request only once, and do not repeat it before the mandate appears in `POST /mandates`: until then, a duplicate is not detected.

      If a mandate must be replaced, for example after the customer's details changed, the user can do it in MyCodaclean.
    </Warning>

    **Required scope:** `mandates:write`
  </Step>

  <Step title="Follow the mandates">
    Mandate requests are processed **asynchronously**. The request call only confirms that Codaclean received it, and returns no mandate identifier.

    Poll [`POST /mandates`](/api/endpoints/search-mandates) to follow them, for example with `customerId` and `updatedSince` set to the time of your last poll.

    Each mandate has a `status` that changes as it progresses.

    **Required scope:** `mandates:read`
  </Step>
</Steps>

## Customer registered by another accounting firm

An enterprise number can belong to only one accounting firm.

If another firm already registered it, creating the customer returns `403 belongsToAnotherTenant`, and it cannot be added.

The accountant must then contact Codaclean support to start a transfer procedure, which requires the end customer's agreement.

## Choosing a connector

Some banks are reachable through several CODAlight connectors. In that case, the mandate request returns `422 connectorSelectionRequired` with a list of `candidates`.

Call the endpoint again with the chosen `connectorId` in the body. Codaclean remembers the choice for the bank account.

## Mandate statuses

| Status                       | CODA | CODB | Meaning                                                                                                                                                                        |
| ---------------------------- | ---- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `created`                    | ✓    | ✓    | Request created, being processed.                                                                                                                                              |
| `waitingForSigner`           | ✓    | ✓    | Waiting for the customer to sign.                                                                                                                                              |
| `expired`                    | ✓    | ✓    | Not signed within 3 months. The user can send it again from MyCodaclean.                                                                                                       |
| `rejectedBySigner`           | ✓    | ✓    | The signer declined.                                                                                                                                                           |
| `waitingForBank`             | ✓    |      | Signed, waiting for the bank.                                                                                                                                                  |
| `confirmedByBank`            | ✓    |      | Confirmed by the bank, but no file received yet.                                                                                                                               |
| `rejectedByBank`             | ✓    |      | Rejected by the bank.                                                                                                                                                          |
| `unsupportedBank`            | ✓    |      | The bank is not supported.                                                                                                                                                     |
| `waitingForPayrollProvider`  |      | ✓    | Signed, waiting for the payroll provider.                                                                                                                                      |
| `rejectedByPayrollProvider`  |      | ✓    | Rejected by the payroll provider.                                                                                                                                              |
| `unsupportedPayrollProvider` |      | ✓    | The payroll provider is not supported.                                                                                                                                         |
| `finished`                   | ✓    | ✓    | **Active**: the signing process is complete and files are being received. Shown as "Active" in MyCodaclean. Excluded from `POST /mandates` unless `includeFinished` is `true`. |
| `renewalRequired`            | ✓    |      | CODAlight only: the consent has ended and must be renewed by the customer.                                                                                                     |
| `error`                      | ✓    | ✓    | An error occurred. See the `error` field.                                                                                                                                      |

## CODAlight consents

A CODAlight consent is reported with `product: "CODA"`.

It is time-limited: `validUntil` is the end of the consent. After that date, the mandate moves to `renewalRequired` until the customer renews the consent.

## Good to know

* Mandates not signed within **3 months** expire. The user can send them again from MyCodaclean.
* Codaclean automatically sends regular reminders to end customers who still have to sign or renew a mandate.
* Get the list of supported banks with [`POST /banks`](/api/endpoints/list-banks).
* Get the list of available payroll providers, with their codes, with [`POST /payroll-providers`](/api/endpoints/list-payroll-providers).
